Ajout de la création du certificat client et aide HAProxy
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
# HAProxy
|
||||
Cela consiste en la gestion des flux post firewall.
|
||||
|
||||
## Présentation des containers
|
||||
## Présentation des conteneurs
|
||||
|
||||
Deux containers Debian 10 identiques, un sur Alpha l'autre sur Bêta avec deux interfaces
|
||||
- Sur Alpha le container HAProxy a comme IP 10.0.0.3/24 sur DMZ et 10.0.1.3/24 sur CTF.
|
||||
- Sur Beta le container HAProxy a comme IP 10.0.0.4/24 sur DMZ et 10.0.1.4/24 sur CTF
|
||||
Deux conteneurs Debian 10 identiques, un sur Alpha l'autre sur Bêta avec deux interfaces :
|
||||
- Sur Alpha le conteneur HAProxy a comme IP 10.0.0.6/24 sur DMZ et 10.0.1.6/24 sur CTF.
|
||||
- Sur Beta le conteneur HAProxy a comme IP 10.0.0.7/24 sur DMZ et 10.0.1.7/24 sur CTF
|
||||
L'option Firewall PVE des interfaces est désactivée
|
||||
|
||||
## Objectifs et choix techniques
|
||||
|
||||
Trois objectifs pour la gestion du flux post-firewall
|
||||
Trois objectifs pour la gestion du flux post-firewall :
|
||||
- Redondance du proxy / load balanceur entre les deux nodes.
|
||||
- Séparation des flux (reverse public et reverse ctf).
|
||||
- Load balancing entre deux reverse proxy Nginx public (un sur chaque nodes).
|
||||
@@ -18,37 +18,42 @@ Trois objectifs pour la gestion du flux post-firewall
|
||||
- Vérification du certificat du client et de son CN si tentative de connexion au panel Proxmox (uniquement).
|
||||
|
||||
|
||||
Voici les choix techniques faits afin de répondre à ces objectifs
|
||||
Voici les choix techniques faits afin de répondre à ces objectifs :
|
||||
- Pour le load balancing entre les deux reverse proxy Nginx, on utilisera HAProxy.Le lien sécurisé sera entre l'utilisateur de HAProxy qui soumettra ensuite des requêtes HTTP à un des reverse proxy Nginx.
|
||||
- Pour la redondance du proxy entre les deux nodes, on utilisera keepalived et la technologie VRRP pour garantir la disponibilité du proxy via une ip virtuelle.
|
||||
- Pour la vérification du certificat client - uniquement si le client veut se connecter au panel Proxmox- on fera une première frontend à la couche 4 (TCP) pour les connexions https qui rediregera les connexions vers le panel sur une frontend dédié et le reste vers une frontend par défaut.
|
||||
- Pour les certificats SSL, nous allons utiliser Let's Encrypt avec un serveur Nginx local dédié à l'obtention des certificats et des scripts pour le dépoiement sur les deux containers HAProxy.
|
||||
- Pour les certificats SSL, nous allons utiliser Let's Encrypt avec un serveur Nginx local dédié à l'obtention des certificats et des scripts pour le dépoiement sur les deux conteneurs HAProxy.
|
||||
- La séparation des flux entre les deux reverse public et le reverse ctf ce fera au niveau de la seconde frontend par défaut tout comme le filtrage des requêtes par nom de domaine.
|
||||
|
||||
### Voilà un schéma résumé
|
||||
|
||||

|
||||
|
||||
## Création d'un canal d'échange par clé entre les deux containers
|
||||
Afin de pouvoir faire des scp de manière automatique entre les deux containers, il faut mettre en place une connexion ssh par clé en root entre les deux containers.
|
||||
## Création d'un canal d'échange par clé entre les deux conteneurs
|
||||
Afin de pouvoir faire des scp de manière automatique entre les deux conteneurs, il faut mettre en place une connexion ssh par clé en root entre les deux conteneurs.
|
||||
|
||||
Le procédé est le même, en voici les variantes,
|
||||
- Sur Alpha le container HAProxy aura comme IP 10.0.0.3
|
||||
- Sur Beta le container HAProxy aura comme IP 10.0.0.4
|
||||
Le procédé est le même, en voici les variantes :
|
||||
- Sur Alpha le conteneur HAProxy aura comme IP 10.0.0.6
|
||||
- Sur Beta le conteneur HAProxy aura comme IP 10.0.0.7
|
||||
|
||||
### /etc/ssh/sshd_config
|
||||
Remplacer la ligne concernée par
|
||||
```
|
||||
PermitRootLogin yes
|
||||
```
|
||||
```
|
||||
systemctl restart sshd
|
||||
```
|
||||
|
||||
### Génération et échange de la clé
|
||||
Utilisateur crée par le playbook Ansible
|
||||
```
|
||||
adduser hasync
|
||||
ssh-keygen -o -a 100 -t ed25519 -f /root/.ssh/id_ed25519
|
||||
|
||||
Alpha : ssh-copy-id -i /root/.ssh/id_ed25519 root@10.0.0.4
|
||||
Beta : ssh-copy-id -i /root/.ssh/id_ed25519 root@10.0.0.3
|
||||
Alpha : ssh-copy-id -i /root/.ssh/id_ed25519 root@10.0.0.7
|
||||
|
||||
Beta : ssh-copy-id -i /root/.ssh/id_ed25519 root@10.0.0.6
|
||||
```
|
||||
|
||||
### /etc/ssh/sshd_config
|
||||
@@ -57,28 +62,55 @@ Remplacer les lignes concernées par
|
||||
PermitRootLogin without-password
|
||||
PubkeyAuthentication yes
|
||||
```
|
||||
Il est maintenant possible de se connecter par clé entre les containers
|
||||
```
|
||||
systemctl restart sshd
|
||||
```
|
||||
Il est maintenant possible de se connecter par clé entre les conteneurs
|
||||
|
||||
|
||||
## Installation et configuration de HAProxy sur chaque node
|
||||
|
||||
Le procédé est le même, en voici les variantes,
|
||||
- Sur Alpha le container HAProxy aura comme IP 10.0.0.3
|
||||
- Sur Beta le container HAProxy aura comme IP 10.0.0.4
|
||||
Le procédé est le même, en voici les variantes :
|
||||
- Sur Alpha le conteneur HAProxy aura comme IP 10.0.0.6
|
||||
- Sur Beta le conteneur HAProxy aura comme IP 10.0.0.7
|
||||
|
||||
### Installation
|
||||
Faite par le playbook Ansible
|
||||
```
|
||||
apt-get update
|
||||
apt-get install -y haproxy hatop certbot nginx psmisc
|
||||
systemctl enable haproxy
|
||||
systemctl enable nginx
|
||||
```
|
||||
```
|
||||
rm /etc/nginx/sites-enabled/default
|
||||
rm /etc/nginx/sites-available/default
|
||||
rm /etc/letsencrypt/live/README
|
||||
mkdir -p /home/hasync/letsencrypt-requests
|
||||
mkdir -p /etc/ssl/letsencrypt
|
||||
```
|
||||
|
||||
### Certificat client
|
||||
|
||||
Pour la vérification du certificat du client, la méthode est dans la git. Il faut placer le ca.crt dans /home/hasync/pve.crt et ajouter le CN autorisé dans /home/hasync/allowed_cn.txt
|
||||
|
||||
### Configuration
|
||||
Voilà une rapide explication de la configuration faite
|
||||
- Une première frontend (all-web-in) de type TCP en écoute sur le port 443 qui vérifie si les requêtes tcp sont bien SSL et redirige tout vers la frontend principale via un proxy sauf les requêtes vers la panel Proxmox qui sont redirigées vers la frontend admin via un proxy.
|
||||
### Copie du certificat de la Web UI
|
||||
```
|
||||
Alpha :
|
||||
scp root@10.0.0.1:/etc/pve/local/pve-ssl.key .
|
||||
scp root@10.0.0.1:/etc/pve/local/pve-ssl.pem .
|
||||
|
||||
Beta :
|
||||
scp root@10.0.0.2:/etc/pve/local/pve-ssl.key .
|
||||
scp root@10.0.0.2:/etc/pve/local/pve-ssl.pem .
|
||||
|
||||
Ensuite :
|
||||
cat pve-ssl.key pve-ssl.pem > /etc/ssl/letsencrypt/crt
|
||||
```
|
||||
|
||||
### Configuration
|
||||
Voilà une rapide explication de la configuration :
|
||||
- Une première frontend (all-web-in) de type TCP en écoute sur le port 443 qui vérifie si les requêtes tcp sont bien SSL et redirige tout vers la frontend principale via un proxy sauf les requêtes vers la panel Proxmox qui sont redirigées vers la frontend admin via un proxy.
|
||||
- La frontend principale (user-web-in) de type http écoute sur le ports 80 et le proxy évoqué plus haut. Filtrage des requêtes ne respectant pas le nom de domaine et forçage du https sans www sinon rejet du packet. Redirection des requêtes Let's Encrypt vers un serveur Nginx local dédié aux certifications sinon séparation du flux avec d'un côté une backend s'occupant du load balancing entre les deux reverse proxy Nginx public et de l'autre une backend redirigeant vers le reverse proxy ctf à l'aide du nom de domaine.
|
||||
|
||||
#### /etc/haproxy/haproxy.cfg
|
||||
@@ -118,6 +150,7 @@ frontend all-web-in
|
||||
tcp-request inspect-delay 5s
|
||||
tcp-request content accept if { req_ssl_hello_type 1 }
|
||||
use_backend is-admin if { req_ssl_sni -i pve.krhacken.org }
|
||||
use_backend is-admin if { req_ssl_sni -i opn.krhacken.org }
|
||||
use_backend is-admin if { req_ssl_sni -i rspamd.krhacken.org }
|
||||
default_backend is-user
|
||||
|
||||
@@ -126,7 +159,7 @@ frontend user-web-in
|
||||
bind *:80 interface eth0
|
||||
bind abns@haproxy-user accept-proxy ssl accept-proxy no-sslv3 crt /etc/ssl/letsencrypt interface eth0
|
||||
acl host_letsencrypt path_beg /.well-known/acme-challenge
|
||||
acl authorized_host hdr_end(host) krhacken.fr.fr
|
||||
acl authorized_host hdr_end(host) krhacken.org
|
||||
acl mail hdr_end(host) mail.krhacken.org
|
||||
acl rspamd path_beg /rspamd/
|
||||
acl ctf_host hdr_end(host) ctf.krhacken.org
|
||||
@@ -147,11 +180,13 @@ frontend admin-in
|
||||
mode http
|
||||
bind abns@haproxy-admin accept-proxy ssl no-sslv3 crt /etc/ssl/letsencrypt ca-file /home/hasync/pve.crt verify required interface eth0
|
||||
acl is_auth ssl_c_s_dn(cn) -i -f /etc/haproxy/allowed_cn.txt
|
||||
acl opn hdr_end(host) opn.krhacken.org
|
||||
acl pve hdr_end(host) pve.krhacken.org
|
||||
acl rspamd hdr_end(host) rspamd.krhacken.org
|
||||
use_backend reverse-nginx if { ssl_fc_has_crt } is_auth rspamd
|
||||
use_backend pve-interface if { ssl_fc_has_crt } is_auth pve
|
||||
default_backend drop-http
|
||||
use_backend opn-interface if { ssl_fc_has_crt } is_auth opn
|
||||
default_backend drop-http
|
||||
|
||||
backend is-admin
|
||||
mode tcp
|
||||
@@ -172,15 +207,21 @@ backend pve-interface
|
||||
server pve-alpha 10.0.0.1:8006 check ssl verify none
|
||||
server pve-beta 10.0.0.2:8006 check ssl verify none
|
||||
|
||||
backend opn-interface
|
||||
mode http
|
||||
balance roundrobin
|
||||
server opn-alpha 10.0.0.3:443 check ssl verify none
|
||||
server opn-beta 10.0.0.4:443 check ssl verify none
|
||||
|
||||
backend reverse-nginx
|
||||
mode http
|
||||
balance roundrobin
|
||||
server reverse1 10.0.0.6:80 check
|
||||
server reverse2 10.0.0.7:80 check
|
||||
server reverse1 10.0.1.3:80 check
|
||||
server reverse2 10.0.1.4:80 check
|
||||
|
||||
backend nginx-ctf
|
||||
mode http
|
||||
server nginx-ctf1 10.0.2.5:80 check
|
||||
server nginx-ctf1 10.0.3.3:80 check
|
||||
|
||||
backend drop-http
|
||||
mode http
|
||||
@@ -189,14 +230,7 @@ backend drop-http
|
||||
|
||||
Une fois HAProxy configuré, il faut configurer le serveur Nginx permettant l'obtention des certificats Let's Encrypt.
|
||||
|
||||
```
|
||||
rm /etc/nginx/sites-enabled/default
|
||||
rm /etc/nginx/sites-available/default
|
||||
rm /etc/letsencrypt/live/README
|
||||
mkdir -p /home/hasync/letsencrypt-requests
|
||||
```
|
||||
|
||||
#### /etc/nginx/sites-availables/letsencrypt.conf
|
||||
#### /etc/nginx/sites-available/letsencrypt.conf
|
||||
```
|
||||
server {
|
||||
listen 8164;
|
||||
@@ -204,38 +238,24 @@ server {
|
||||
root /home/hasync/letsencrypt-requests;
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
ln -s /etc/nginx/sites-available/letsencrypt.conf /etc/nginx/sites-enabled/
|
||||
```
|
||||
### Démarrage des services
|
||||
```
|
||||
systemctl restart nginx.service
|
||||
systemctl restart haproxy.service
|
||||
```
|
||||
### Obtention des premiers certificats et déploiement
|
||||
```
|
||||
certbot certonly --webroot -w /home/hasync/letsencrypt-requests/ -d sub.krhacken.org
|
||||
```
|
||||
|
||||
Voici un script pour mettre en place les certificats Let's Encrypt au bon endroit qui s'occupe de propager les certificats sur l'autre container.
|
||||
```
|
||||
#!/bin/bash
|
||||
rm -f /etc/letsencrypt/live/README
|
||||
rm -rf /etc/ssl/letsencrypt/*
|
||||
for domain in $(ls /etc/letsencrypt/live); do
|
||||
cat /etc/letsencrypt/live/$domain/privkey.pem /etc/letsencrypt/live/$domain/fullchain.pem > /etc/ssl/letsencrypt/$domain.pem
|
||||
done
|
||||
scp -r /etc/ssl/letsencrypt/* root@10.0.0.3:/etc/ssl/letsencrypt
|
||||
ssh root@10.0.0.3 'systemctl restart haproxy.service'
|
||||
service haproxy restart
|
||||
```
|
||||
|
||||
## Mise en place de la haute disponibilité du load balanceur
|
||||
Voilà la configuration que nous allons mettre en place,
|
||||
- Sur Alpha le container HAProxy aura comme IP 10.0.0.3
|
||||
- Sur Beta le container HAProxy aura comme IP 10.0.0.4
|
||||
- L'IP virtuelle 10.0.0.5 sera attribuée en fonction de la disponibilité des load balanceur
|
||||
Voilà la configuration que nous allons mettre en place :
|
||||
- Sur Alpha le conteneur HAProxy aura comme IP 10.0.0.6
|
||||
- Sur Beta le conteneur HAProxy aura comme IP 10.0.0.7
|
||||
- L'IP virtuelle 10.0.0.8 sera attribuée en fonction de la disponibilité des load balanceur
|
||||
- La node Alpha sera le master et la node Beta sera le Slave
|
||||
|
||||
### Installation (commune au deux nodes)
|
||||
Faites par le playbook Ansible.
|
||||
```
|
||||
apt-get install -y keepalived
|
||||
systemctl enable keepalived.service
|
||||
@@ -260,13 +280,16 @@ vrrp_instance VI_1 {
|
||||
virtual_router_id 51
|
||||
priority 101 # 101 on master, 100 on backup
|
||||
virtual_ipaddress {
|
||||
10.0.0.5 # the virtual IP
|
||||
10.0.0.8 # the virtual IP
|
||||
}
|
||||
track_script {
|
||||
chk_haproxy
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
systemctl restart keepalived
|
||||
```
|
||||
|
||||
### Configuration sur Beta
|
||||
Comme décrite plus haut
|
||||
@@ -284,29 +307,53 @@ vrrp_instance VI_1 {
|
||||
virtual_router_id 51
|
||||
priority 100 # 101 on master, 100 on backup
|
||||
virtual_ipaddress {
|
||||
10.0.0.5 # the virtual IP
|
||||
10.0.0.8 # the virtual IP
|
||||
}
|
||||
track_script {
|
||||
chk_haproxy
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
systemctl restart keepalived
|
||||
```
|
||||
|
||||
#### Vérification
|
||||
Le retour de cette commande doit montrer l'adresse IP 10.0.0.5 sur Alpha
|
||||
Le retour de cette commande doit montrer l'adresse IP 10.0.0.8 sur Alpha
|
||||
```
|
||||
ip a | grep -e inet.*eth0
|
||||
```
|
||||
|
||||
## Renouvellement automatique des certificats
|
||||
A partir d'ici la configuration des NAT OPNSense est nécessaire.
|
||||
|
||||
Pour une question de simplicité d'administration, les certificats Let's Encrypt se renouvelleront automatiquement grâce à une crontab. Le problème est qu'un seul des deux containers sera accessible depuis l'extérieur. Il faut donc copier les certificats via scp entre les deux containers.
|
||||
### Obtention des premiers certificats et déploiement
|
||||
A faire sur le Master car c'est lui qui à un accès le DNAT du port 80
|
||||
```
|
||||
certbot certonly --webroot -w /home/hasync/letsencrypt-requests/ -d sub.krhacken.org
|
||||
```
|
||||
|
||||
### /home/hasync/renew.sh
|
||||
Voilà un script d'automatisation à mettre sur les deux containers
|
||||
Voici un script pour mettre en place les certificats Let's Encrypt au bon endroit qui s'occupe de propager les certificats sur l'autre conteneur (depuis Alpha vers Beta). Disponible dans `/root/install-certs.sh` si créer avec Ansible.
|
||||
```
|
||||
#!/bin/bash
|
||||
if [ "$(ip a | grep -c "10.0.0.5")" -ge 1 ]; then
|
||||
rm -f /etc/letsencrypt/live/README
|
||||
rm -rf /etc/ssl/letsencrypt/*
|
||||
for domain in $(ls /etc/letsencrypt/live); do
|
||||
cat /etc/letsencrypt/live/$domain/privkey.pem /etc/letsencrypt/live/$domain/fullchain.pem > /etc/ssl/letsencrypt/$domain.pem
|
||||
done
|
||||
scp -r /etc/ssl/letsencrypt/* root@10.0.0.7:/etc/ssl/letsencrypt
|
||||
ssh root@10.0.0.7 'service haproxy reload'
|
||||
service haproxy reload
|
||||
```
|
||||
|
||||
## Renouvellement automatique des certificats
|
||||
|
||||
Pour une question de simplicité d'administration, les certificats Let's Encrypt se renouvelleront automatiquement grâce à une crontab. Le problème est qu'un seul des deux conteneurs sera accessible depuis l'extérieur. Il faut donc copier les certificats via scp entre les deux conteneurs.
|
||||
|
||||
### /home/hasync/renew.sh
|
||||
Voilà un script d'automatisation à mettre sur les deux conteneurs. Déjà présent si installer avec Ansible.
|
||||
```
|
||||
#!/bin/bash
|
||||
if [ "$(ip a | grep -c "10.0.0.8")" -ge 1 ]; then
|
||||
certbot renew
|
||||
rm -rf /etc/ssl/letsencrypt/*
|
||||
for domain in $(ls /etc/letsencrypt/live); do
|
||||
@@ -316,7 +363,7 @@ if [ "$(ip a | grep -c "10.0.0.5")" -ge 1 ]; then
|
||||
else
|
||||
fi
|
||||
```
|
||||
Le script est stocké dans /home/hasync/renew.sh, voici la crontab à ajouter (crontab -e) sur les deux containers.
|
||||
Le script est stocké dans /home/hasync/renew.sh, voici la crontab à ajouter (crontab -e) sur les deux conteneurs.
|
||||
```
|
||||
0 4 */15 * * /bin/sh /home/hasync/renew.sh >/dev/null 2>&1
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user