View Sidebar
Il était une fois, Proxmox derrière une IP unique …

Il était une fois, Proxmox derrière une IP unique …

22 août 2013 15 h 54 min8 comments

Amis du soir bonsoir,

Partie 1 : Présentation de proxmox et de la virtualisation
Partie 2 : Configuration du réseau interne
Partie 3 : Un petit Stress test pour la route
Partie 4 : Quelques optimisations Webserver
Partie 5 : HTTPS et IPV6
Partie 6 : Le Monitoring
Partie 7 : Les Backup

Voilà la suite du post d’hier sur proxmox et la virtualisation. Après la présentation, je vais rapidement présenter l’infra et les grandes lignes concernant la configuration.

J’aurai du l’appeler navi le datacenter 😛

L’infrastructure

J’étais pour le coup soumis à quelques contraintes externes, par exemple Kimsufi sur l’offre 2013 ne permet plus la prise en charge des IP-failover.
Cela aurait permis de faire pointer plusieurs IP sur un même serveur et ainsi de pouvoir attribuer une IP à certaines VM.

J’étais donc contraint d’avoir l’ip sur mon host et de devoir gérer moi-même le trafic entrant.
J’ai donc décidé assez simplement :

  • De mettre toutes mes VM en venet (donc sur un VLAN interne) et donc sans accès au net.
  • Ajouter une interface sur la machine Hote pour qu’elle puisse accéder au venet
  • Configurer la machine hôte pour autoriser le forwarding VLan<->Internet
  • Et finalement gérer les connections externe via du Nat et Iptables.

Donc depuis le réseau interne, les VM ont accès à internet sans problèmes.
Depuis internet, une IP (celle de la machine hôte) et en fonction des requêtes et du port utilisé on arrivera sur la VM adéquate.
Cela permet également de cacher son infra à des bots/robots qui tenterait de scanner les machines pour y trouver des failles.
Je vais donc vous décrire dans la suite de l’article, les différentes étapes permettant d’arriver à ce résultat.

La gestion des VM

Une fois installés, les VM sont des machines à part entière et les règles usuelles d’administration s’y appliquent.

  • généré des mots de passe aléatoire
  • penser à update régulièrement (voir l’automatiser)
  • éviter de laisser trop de ports ouverts, voir n’en laisser aucun (si vous n’utiliser par ssh par exemple).

Enfin je vais pas vous apprendre les bases communes à l’administration de tout serveur, il y a déjà de nombreux tuto sur le sujet.

Par contre petite subtilité fournie par proxmox, la possibilité depuis la machine hôte de se logger dans une VM.
C’est très rapide et ça évite d’avoir une connexion ssh par vm.

root@host>
# Pour vous logger sur la VM avec l'id 100 (ici network)
vzctl enter 100

root@network>

# On ressort de la VM et on récupère son prompt
exit
root@host>

C’est hyper pratique et on prend vite le coup de changer de VM à tout vas.
Attention à ne pas refaire exit, sinon vous allez killer votre console ssh 😛

La gestion du Nat

De ce coté là pas grand-chose de révolutionnaire. Pour faire simple, j’ai 2 interfaces vmbr0 (interface net) et vmbr0:0 (interface venet)

Premièrement, on active le forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

Deuxièmement, on devrait taper des règles IPTable mais comme je suis faignant, je vais vous filer un script qui fait ça à votre place.
Créé un premier fichier qui va servir à stocker votre configuration : /etc/nat.conf

#=================================================#
# Usage : #
# ip_outside:port ip_inside:port #
# #
# Exemple : #
# 200.200.200.200:533 10.0.0.1:53 #
#=================================================#

[votre ip publique]:80 192.168.0.10:80
[votre ip publique]:8080 192.168.0.12:80

Puis enregistrer le script suivant : run-nat.sh (vous pouvez le mettre où vous voulez, votre home est un bon endroit).

#!/bin/bash
iptables -t nat -F
iptables -t nat -X
iptables -t nat -Z
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o vmbr0 -j SNAT --to 200.200.200.200

function addNat {
iptables -t nat -A PREROUTING -p tcp -d $1 --dport $2 -i vmbr0 -j DNAT --to-destination $3:$4
}

if [ -f /etc/nat.conf ]
then
# Nettoyage du fichier de configuration
cat /etc/nat.conf | grep -v "^\s*#" | grep -v "^\s*$" |sed -e 's/^\s*//g' > /tmp/nat.$$.txt

while IFS=:- read ipout portout ipin portin
do
addNat $ipout $portout $ipin $portin
done < /tmp/nat.$$.txt

rm /tmp/nat.$$.txt

fi

Et voilà vous avez juste à mettre vos valeurs à la place des différentes adresses IP :

  • 192.168.0.0/24 (l’ip du réseau venet)
  • 200.200.200.200 (l’ip public du serveur)
  • /etc/nat.conf (le path où vous avez enregistré votre fichier de config)

Il ne reste plus qu’à

chmod +x run-nat.sh
./run-nat.sh

Et il va automatiquement nettoyer et réécrire vos règles iptables.
Attention quand même, les règles iptables ne sont pas persistantes, si le serveur reboot elles seront vidés, il faudra donc penser à lancer ce script au démarrage.

Vous suivez ?

Et pour le web, un reverse proxy

Pour ceux qui ont déjà fait du nat, c’est pratique, mais cela représente un gros inconvénient. On redirige un port vers une ip et donc une machine unique.
Or on a de fortes chances d’avoir plusieurs serveurs web sur son réseau (prod, dev, tools, …).

L’idée va donc être d’installer sur une VM ou l’hôte, un soft pour accepter les requêtes http et choisir automatiquement et de façon transparente quelle VM il faut utiliser.
C’est ce qu’on appelle un reverse proxy.

Il en existe de nombreux spécialisé dans leurs domaines : pound, haproxy, nginx, apache, …
J’ai choisi d’utiliser nginx car il est performant, permet de faire du cache et les fichiers de configurations reste facilement compréhensibles.

pour l’installation :

apt-get install nginx

Alors, pour le soft il y a assez peu de fichiers à connaître :

  • /etc/nginx/nginx.conf (le fichier de configuration par défaut)
  • /etc/nginx/sites-enabled/* (le dossier où vous enregistrez vos différents sites)

Et c’est presque tout, quand je vous avais dit que c’était facilement compréhensible.
Allez c’est parti pour la configuration custom.

Alors pour le fichier /etc/nginx/nginx.conf

# Two processes work well for a single CPU
user www-data;
worker_processes 2;

error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
use epoll;
}

http {
include /etc/nginx/mime.types;

# Nginx does the logging
access_log /var/log/nginx/access.log;

# TCP
sendfile on;
keepalive_timeout 65;
tcp_nodelay on;
server_names_hash_bucket_size 64;
server_tokens off;

# Have nginx do the compression, turn off Apache's mod_deflate
gzip on;
gzip_vary on;
gzip_http_version 1.1;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_comp_level 6;
gzip_min_length 1400;
gzip_proxied any;
# text/html mime type is automatically included for gzip, have to add the rest
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/rss+xml text/javascript;

# Definir une zone de cache appeller "STATIC de 1Go Max"
proxy_cache_path /var/cache/nginx levels=2:2:2 keys_zone=STATIC:1000m inactive=24h max_size=1g;
proxy_temp_path /var/lib/nginx/proxy;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

Et pendant qu’on y est, je vais, vous conseiller, de créer 2 fichiers supplémentaires (c’est facultatif, mais pratique pour la suite).
Ça permettra de séparer les données que l’on peut mettre en cache (js, img, css) des données qui doivent être accédées directement.

Fichier pour le proxy simple : /etc/nginx/proxy.conf

proxy_redirect off;

proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_hide_header X-Powered-By;
proxy_set_header Server "";

Fichier pour le proxy avec cache : /etc/nginx/proxy-cache.conf

proxy_redirect off;

proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_hide_header X-Powered-By;

# Clear a few headers we might not want to pass on
proxy_set_header Accept "";
proxy_set_header Connection "";
proxy_set_header Server "";

# Enable caching for the proxied requests using the STATIC storage
# Cache 200 (OK), as well as 301 and 302 (redirect) responses for 30m
proxy_cache STATIC;
proxy_cache_valid 200 301 302 30m;

proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;

# Allow using stale data (cached data that has expired) in the following cases:
# - an error has occurred while connecting to the server, sending a request to it, or reading its response
# - timeout occurred during the connection with the server, transfer the request or while reading response from the server
# - server returned a empty or incorrect answer
# - server returned an error status (500, 502-504)
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;

Donc pour résumer ce que font ces 3 fichiers de configuration :

  • ils permettent de camoufler les infos sur les serveurs web utilisés
  • ils permettent l’utilisation de cache
  • ils permettent le gzip automatique du contenu http

Voilà on est enfin parer pour définir tous ces domaines/serveurs internes dans /etc/nginx/sites-enabled/
Prenons le cas du /etc/nginx/sites-enabled/default (mais vous pouvez en créer plein d’autres dans ce dossier).

#
# Blog perso
#
server {
server_name blog.ganbaranai.fr blog.remilia.fr;

access_log /var/log/nginx/perso.access.log;
error_log /var/log/nginx/perso.error.log;

# On cache les fichiers statics 24h (css/js)
location ~*^.+(css|js)$ {
include proxy-cache.conf;
proxy_pass http://192.168.0.11:8080;
expires 24h;
}

# On cache les fichiers statics 1semaine (img/archives/doc)
location ~*^.+(swf|jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
include proxy-cache.conf;
proxy_pass http://192.168.0.11:8080;
expires 168h;
}

# On rend le reste directement
location / {
include proxy.conf;
proxy_pass http://192.168.0.11:8080;
}
}

#
# Default (port 80 sur perso)
#
server {
listen 80;
server_name ganbaranai.fr;

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

location / {
include proxy.conf;
proxy_pass http://192.168.0.11:80/;
}
}

Et comme ça vous pouvez définir des centaines de règles différentes pour gérer la façon dont on accède en http à vos services.
Les infos les plus utiles à comprendre sont :

listen 80; (on écoute toujours sur le port 80 de toute façon dans cet exemple).

server_name: test.domain.fr kikoo.domain.fr *.domain.fr; (nom de domaine qui va être concerné par cette règle).

access_log & error_log : ça parait évident, mais ça permet de séparer les logs par service, ce qui est assez pratique.

un ou plusieurs bloc ‘location’ : C’est un filtre qui match sur l’url « location / » est celui par défaut et sinon vous avez un peu plus haut celui pour matcher sur les extensions.

‘include proxy.conf’ ou ‘include proxy-cache.conf’ : voilà donc là vous devez enfin comprendre ce qu’on a fait juste avant. En fonction de la règle location, on va activer ou non le cache des fichiers.

expire : permet de définir un Expire HTTP pour forcer le cache par le browser du client.

proxy_pass : le champs le plus utile puisqu’il va vous permettre de choisir sur quelle IP/Port envoyer la requête.

Une fois que c’est fait, un petit

/etc/nginx/reload

Et il va recharger les fichiers de config et vous prévenir en cas de problèmes.
Et normalement c’est tout bon, il reste plus qu’à vérifier tout ça.

Ca roox Baby !!!!

Mais c’est pas trop lourd comme système pour du web ?

Et bah … effectivement, ça peut paraître compliqué, mais niveau performance, elles sont bien meilleures qu’un simple serveur web type apache.
Le Nginx ne fait rien d’autre que proxy et cache et il est très rapide pour ça (pas de php & co).
Et lorsqu’il a les fichiers en cache, il les sert directement au client sans recontacter le serveur web de la VM.
On a donc un serveur léger qui sert des fichiers static, et le serveur lourd derrière (apache la plupart du temps) qui ne va plus faire que générer les pages web.
Le serveur apache ne faisant presque plus rien, il rend les pages bien plus rapidement sans la moindre optimisation.

Voici d’ailleurs un exemple avec le blog et sa homepage :

  • Sans le cache, j’en suis à 49 requêtes HTTP sur le serveur apache (surtout des images)
  • Avec le cache, plus qu’une requête celle de la page php, tout le reste a été pris en charge par le cache de nginx.

J’en ai rapidement parlé plus tôt, mais un des autres avantages et le fait de cacher la signature des serveurs web utilisés.
De nombreux bots parcourent le web à la recherche de serveurs avec des versions bien précises sur lequel des failles ont été découvertes.
Le fait d’obfusquer ces informations et ne pas indiquer quel serveur, quel langage, quelle version sont utilisés rend plus difficiles les attaques automatisées.

Ça permet aussi de pouvoir faire cohabiter dans un même website des technos très différentes.
Sur mon domaine, j’ai actuellement du python, du ruby on rail, du lighttpd/nginx/apache suivant les services, mais le passage de l’un à l’autre est totalement transparent.
Moins de galères que reconfigurer pour chaque serveur expire, gzip, header http. Ici ce n’est géré que sur un seul point d’entrée, ce qui facilite la gestion.
Mais qui dit point d’entrée unique, dit aussi point sensible du réseau, il faudra donc penser à le dédoubler dès que possible.

Et voilà, vous pouvez aller faire autre chose …

Et voilà pour le pavé du jour, j’espère que ça vous aura été utile.

8 Comments

  • Superbe article, m’a été très utile, un enorme merci !

  • Tes articles sont très bien fait. Je viens d’en lire quelques uns et je voulais juste te féliciter pour ton travail.

    Continue comme ça ! C’est très enrichissant. Merci 😉

  • Merci beaucoup pour ces retours, ça fait plaisir que ça serve ^^

  • Bonjour,

    Serait-il possible d’avoir un modèle des lignes que vous avez renseigner cette partie :

    de mettre toutes mes VM en venet (donc sur un VLAN interne) et donc sans accès au net.
    ajouter une interface sur la machine Hote pour qu’elle puisse accéder au venet
    configurer la machine hôte pour autoriser le forwarding VLanInternet
    Et finalement gérer les connections externe via du Nat et Iptables.

  • Bonjour Manid,

    Huummmm que cherche tu as faire exactement ?
    Je ne vois pas trop comment t’aider sur le coup.

    Pour ce qui est de passer une VM en venet (réseau interne), cela se fait simplement dans l’interface web.
    Pour ce qui est d’activer l’ip forwarding (acces au net depuis tes VM) et le nat (accès a tes VM depuis le net), les commandes sont décrites dans la partie « La gestion du Nat ».

  • Au fait j’ai un serveur proxmox sur ma connexion perso. j’aimerais donc isoler mes vms ce qui correspond à la procédure que tu indiques. Par contre j’ai essayé plusieurs manips mais pas de communication de l’extérieur voici ce que j’ai actuellement au niveau de l’hôte proxmox :

    auto vmbr0
    iface vmbr0 inet static
    address 192.168.1.196
    netmask 255.255.255.0
    gateway 192.168.1.254
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0

  • Normalement ça devrait être assez simple. Cette partie n’a rien de spécifique avec proxmox, c’est juste de la config réseau. Fait juste attention à ne pas t’emmêler entre les ip du venet et les ip de ton réseau local (apparemment 192.168.1.*)

    Etape 1 : s’assurer que le serveur proxmox a bien accès au net (style ‘ping google.fr’ fonctionne bien). Si ce n’est pas le cas, c’est un simple problème de config réseau sur la machine hôte et c’est du debian tout ce qu’il y a de classique.

    Etape 2 : vérifier que la machine hôte ping tes VM. Normalement l’hote est automatiquement ajouté au venet, tu devrais donc pouvoir accéder aux VM

    Etape 3 : sur la machine hote, activer le forwarding ‘echo 1 > /proc/sys/net/ipv4/ip_forward’. A ce moment-là, tes VM devraient être en mesure de ping l’ip publique du serveur hôte ‘ping 192.168.1.196’.

    Etape 4 : s’il n’y a pas de problème de gateway ou de dns, tes vm devraient avoir accès au net

  • Qui pourrai m’aider, j’arrive pas a faire l étape du proxy sur proxmox en échange de rémunération , je suis depuis 4 jours dessus .
    Me contacter sur mon adresse email  » mickael222@hotmail.com « 

Leave a reply


Trackbacks