Skip to content

TLS Everywhere

Introduction

TLS Everywhere chiffre toutes les communications entre les services OpenStack, les clients, et les backends. C'est une exigence pour les environnements de production sécurisés.

Prérequis

  • OpenStack fonctionnel
  • Autorité de certification (interne ou externe)
  • Hardening CIS appliqué

Points à apprendre

Architecture TLS

graph TB
    client["Client<br/>(CLI/Horizon)"]

    subgraph Edge["Edge (TLS External)"]
        haproxy["HAProxy<br/>TLS Termination<br/>Cert: public CA"]
    end

    subgraph Internal["Internal (TLS Internal)"]
        keystone["Keystone<br/>TLS<br/>Cert: internal CA"]
        nova["Nova<br/>TLS"]
        neutron["Neutron<br/>TLS"]
        glance["Glance<br/>TLS"]
    end

    subgraph Backend["Backend (TLS Backend)"]
        mariadb["MariaDB<br/>TLS<br/>Galera Encryption"]
        rabbitmq["RabbitMQ<br/>TLS"]
        ceph["Ceph<br/>TLS"]
    end

    client -->|HTTPS<br/>TLS 1.3| haproxy
    haproxy -->|HTTPS<br/>TLS 1.2+| keystone
    keystone -->|TLS| mariadb
    keystone -->|AMQPS| rabbitmq

Configuration Kolla TLS

# /etc/kolla/globals.yml

# === TLS External (clients → HAProxy) ===
kolla_enable_tls_external: "yes"
kolla_external_fqdn: "cloud.example.com"
kolla_external_fqdn_cert: "/etc/kolla/certificates/haproxy.pem"

# === TLS Internal (HAProxy → services) ===
kolla_enable_tls_internal: "yes"
kolla_internal_fqdn: "internal.cloud.example.com"

# === Backend TLS ===
kolla_enable_tls_backend: "yes"

# === CA Certificate ===
kolla_copy_ca_into_containers: "yes"
openstack_cacert: "/etc/pki/tls/certs/ca-bundle.crt"

# === TLS pour backends spécifiques ===
rabbitmq_enable_tls: "yes"
# mariadb_enable_tls: "yes"  # Activé avec tls_backend

Génération des certificats

#!/bin/bash
# generate-certs.sh

DOMAIN="example.com"
CA_DIR="/etc/kolla/certificates/ca"
CERT_DIR="/etc/kolla/certificates"

mkdir -p $CA_DIR $CERT_DIR

# === Créer CA interne ===
openssl genrsa -out $CA_DIR/ca-key.pem 4096

openssl req -x509 -new -nodes \
    -key $CA_DIR/ca-key.pem \
    -sha256 -days 3650 \
    -out $CA_DIR/ca.pem \
    -subj "/C=FR/ST=IDF/L=Paris/O=MyOrg/OU=IT/CN=OpenStack Internal CA"

# === Certificat HAProxy (external) ===
cat > $CERT_DIR/haproxy.cnf << EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
C = FR
ST = IDF
L = Paris
O = MyOrg
OU = Cloud
CN = cloud.${DOMAIN}

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = cloud.${DOMAIN}
DNS.2 = *.cloud.${DOMAIN}
IP.1 = 10.0.0.10
EOF

openssl genrsa -out $CERT_DIR/haproxy-key.pem 2048

openssl req -new \
    -key $CERT_DIR/haproxy-key.pem \
    -out $CERT_DIR/haproxy.csr \
    -config $CERT_DIR/haproxy.cnf

openssl x509 -req \
    -in $CERT_DIR/haproxy.csr \
    -CA $CA_DIR/ca.pem \
    -CAkey $CA_DIR/ca-key.pem \
    -CAcreateserial \
    -out $CERT_DIR/haproxy-cert.pem \
    -days 365 \
    -sha256 \
    -extensions v3_req \
    -extfile $CERT_DIR/haproxy.cnf

# Combiner pour HAProxy
cat $CERT_DIR/haproxy-cert.pem $CERT_DIR/haproxy-key.pem > $CERT_DIR/haproxy.pem

# === Certificats internes (par service) ===
for service in keystone nova neutron glance cinder heat octavia placement; do
    openssl genrsa -out $CERT_DIR/${service}-key.pem 2048

    openssl req -new \
        -key $CERT_DIR/${service}-key.pem \
        -out $CERT_DIR/${service}.csr \
        -subj "/C=FR/ST=IDF/L=Paris/O=MyOrg/OU=OpenStack/CN=${service}.internal"

    openssl x509 -req \
        -in $CERT_DIR/${service}.csr \
        -CA $CA_DIR/ca.pem \
        -CAkey $CA_DIR/ca-key.pem \
        -CAcreateserial \
        -out $CERT_DIR/${service}-cert.pem \
        -days 365 \
        -sha256
done

echo "Certificates generated in $CERT_DIR"

Configuration HAProxy TLS

# /etc/haproxy/haproxy.cfg (généré par Kolla)

global
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

frontend keystone_public
    bind 10.0.0.10:5000 ssl crt /etc/haproxy/certs/haproxy.pem
    default_backend keystone_public_back

backend keystone_public_back
    option httpchk GET /healthcheck
    http-check expect status 200
    server controller-1 10.0.0.11:5000 check ssl verify required ca-file /etc/haproxy/certs/ca.pem
    server controller-2 10.0.0.12:5000 check ssl verify required ca-file /etc/haproxy/certs/ca.pem
    server controller-3 10.0.0.13:5000 check ssl verify required ca-file /etc/haproxy/certs/ca.pem

Configuration MariaDB TLS

# /etc/kolla/config/mariadb/galera.cnf

[mysqld]
ssl-ca=/etc/mysql/ssl/ca.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem
require_secure_transport=ON

# Galera SSL
wsrep_provider_options="socket.ssl_key=/etc/mysql/ssl/server-key.pem;socket.ssl_cert=/etc/mysql/ssl/server-cert.pem;socket.ssl_ca=/etc/mysql/ssl/ca.pem"

Configuration RabbitMQ TLS

# /etc/kolla/config/rabbitmq/rabbitmq.conf

listeners.ssl.default = 5671
ssl_options.cacertfile = /etc/rabbitmq/ssl/ca.pem
ssl_options.certfile = /etc/rabbitmq/ssl/server-cert.pem
ssl_options.keyfile = /etc/rabbitmq/ssl/server-key.pem
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = true

# Désactiver le port non-TLS
listeners.tcp = none

Configuration OpenStack clients

# /etc/kolla/config/nova/nova.conf

[DEFAULT]
transport_url = rabbit://openstack:password@controller-1:5671,controller-2:5671,controller-3:5671//

[oslo_messaging_rabbit]
ssl = True
ssl_ca_file = /etc/pki/tls/certs/ca-bundle.crt

[keystone_authtoken]
cafile = /etc/pki/tls/certs/ca-bundle.crt

[glance]
cafile = /etc/pki/tls/certs/ca-bundle.crt

[neutron]
cafile = /etc/pki/tls/certs/ca-bundle.crt

[cinder]
cafile = /etc/pki/tls/certs/ca-bundle.crt

Vérification TLS

#!/bin/bash
# verify-tls.sh

echo "=== HAProxy External ==="
echo | openssl s_client -connect cloud.example.com:443 2>/dev/null | \
    openssl x509 -noout -subject -dates -issuer

echo -e "\n=== Keystone Internal ==="
echo | openssl s_client -connect 10.0.0.11:5000 2>/dev/null | \
    openssl x509 -noout -subject -dates

echo -e "\n=== MariaDB ==="
docker exec mariadb mysql -e "SHOW STATUS LIKE 'Ssl_cipher';"

echo -e "\n=== RabbitMQ ==="
docker exec rabbitmq rabbitmqctl status | grep -A5 "SSL"

echo -e "\n=== Test OpenStack CLI ==="
openstack token issue

Diagramme flux TLS

sequenceDiagram
    actor User
    participant HAProxy as HAProxy<br/>(TLS Term)
    participant Nova as Nova API
    participant RabbitMQ
    participant Compute as Nova Compute
    participant Glance
    participant DB as MariaDB

    User->>HAProxy: HTTPS (TLS 1.3)<br/>POST /servers
    HAProxy->>Nova: HTTPS (internal TLS)<br/>Client cert

    Nova->>DB: TLS<br/>Store instance
    Nova->>RabbitMQ: AMQPS<br/>Message

    RabbitMQ->>Compute: AMQPS<br/>Schedule

    Compute->>Glance: HTTPS<br/>Get image
    Compute->>RabbitMQ: AMQPS<br/>Update status

    RabbitMQ->>Nova: AMQPS
    Nova->>DB: TLS<br/>Update

    Nova-->>HAProxy: Response
    HAProxy-->>User: HTTPS<br/>201 Created

Exemples pratiques

Let's Encrypt avec certbot

# Pour les certificats publics
apt install certbot

# Obtenir le certificat
certbot certonly --standalone \
    -d cloud.example.com \
    --agree-tos \
    --email admin@example.com

# Créer le fichier HAProxy
cat /etc/letsencrypt/live/cloud.example.com/fullchain.pem \
    /etc/letsencrypt/live/cloud.example.com/privkey.pem \
    > /etc/kolla/certificates/haproxy.pem

# Renouvellement automatique
echo "0 3 * * * root certbot renew --quiet --post-hook 'docker restart haproxy'" \
    > /etc/cron.d/certbot

Test de connexion TLS

# Vérifier les cipher suites
nmap --script ssl-enum-ciphers -p 443 cloud.example.com

# Vérifier le certificat
curl -v https://cloud.example.com:5000/v3 2>&1 | grep -E "(SSL|TLS|certificate)"

# Test avec openssl
openssl s_client -connect cloud.example.com:443 -tls1_3

Ressources

Checkpoint

  • CA interne créée
  • Certificats générés pour tous les services
  • TLS external configuré (HAProxy)
  • TLS internal configuré (services)
  • TLS backend configuré (DB, MQ)
  • Vérification TLS réussie (openssl)
  • OpenStack CLI fonctionne avec TLS
  • Renouvellement automatique configuré