« Security/sevices/SSLCertificate/Apache » : différence entre les versions
| Ligne 1 : | Ligne 1 : | ||
== Introduction == | |||
Cette page explique les opérations nécessaires pour la configuration d'un serveur Apache v2 utilisant des certificats utilisateurs. Ces certificats pourront être révoqués facilement. | |||
== Pré-requis == | |||
*Le module ssl doit être activé dans la configuration d'Apache et la configuration ssl est incluse : | |||
:* Le module est chargé :<pre>LoadModule ssl_module modules/mod_ssl.so</pre> | |||
:* La configuration ssl est incluse :<pre>Include conf.d/ssl.conf</pre> | |||
* Le firewall est ouvert pour une connection '''https''' : port 443 | |||
== Préparation == | == Préparation == | ||
Version du 3 janvier 2013 à 11:20
Introduction
Cette page explique les opérations nécessaires pour la configuration d'un serveur Apache v2 utilisant des certificats utilisateurs. Ces certificats pourront être révoqués facilement.
Pré-requis
- Le module ssl doit être activé dans la configuration d'Apache et la configuration ssl est incluse :
- Le module est chargé :
LoadModule ssl_module modules/mod_ssl.so
- La configuration ssl est incluse :
Include conf.d/ssl.conf
- Le module est chargé :
- Le firewall est ouvert pour une connection https : port 443
Préparation
Création du répertoire des certificats
mkdir /etc/pki/httpd && cd /etc/pki/httpd
Création du fichier de configuration de nos futurs certificats
On créer le fichier <path>/etc/pki/httpd/ssl.cnf</path>
HOME = .
RANDFILE = .rand
[ca]
default_ca = ca_default
[ca_default]
dir = .
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/httpd_ca.crt
private_key = $dir/private/httpd_ca.key
serial = $dir/serial
crl = $dir/crl.pem
crlnumber = $dir/crlnumber
crl_extensions = crl_ext
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = 365
default_crl_days = 30
default_md = md5
preserve = no
policy = policy_match
[policy_match]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[req]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
string_mask = MASK:0x2002
[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = FR
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Languedoc-Roussillon
localityName = Locality Name (eg, city)
localityName_default = Beaucaire
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Home
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, your name or your server\'s hostname)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[req_attributes]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[usr_cert]
basicConstraints = CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
[ crl_ext ]
# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always
Création des scripts de gestion de certificats
Par simplicité, on va se servir de ces scripts pour générer les certificats des utilisateurs.
Script de génération des certificats
Fichier <path>/etc/pki/httpd/generate-certificate.sh</path>
#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1
if [[ "$user" == "" ]]
then
echo "Usage: $(basename $0) USER"
exit
fi
echo "Generate certificates for \"${user}\""
openssl genrsa -out certs/${user}.key 2048
cat ssl.cnf | sed 's/insert_hostname/'${user}'/'> ssl2.cnf
openssl req -config ssl2.cnf -new -nodes -out certs/${user}.csr -key certs/${user}.key
openssl ca -config ssl2.cnf \
-out certs/${user}.crt -outdir certs -infiles certs/${user}.csr
cat certs/${user}.crt certs/${user}.key > pem/${user}.pem
mv ssl2.cnf confs/${user}-ssl.cnf
Fichier <path>/etc/pki/httpd/generate-web-certificate.sh</path>
#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1
if [[ "$user" == "" ]]
then
echo "Usage: $(basename $0) USER"
exit
fi
echo "Generate web certificates for \"${user}\""
openssl pkcs12 -export -inkey certs/${user}.key -in certs/${user}.crt -CAfile ${caname}_ca.crt \
-out certs/${user}_browser_cert.p12
Script de revocation de certificats
Fichier <path>/etc/pki/httpd/revoke-certificate.sh</path>
#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1
if [[ "$user" == "" ]]
then
echo "Usage: $(basename $0) USER"
exit
fi
echo "Revoke certificates for \"${user}\""
openssl ca -revoke certs/${user}.crt -config ssl.cnf
# Save old certificate
x=1
while [ -f "certs/${user}.revoked.$x.crt" ]
do
x=$(( $x + 1 ))
done
mv certs/${user}.crt certs/${user}.revoked.$x.crt
# Regen CRL list
openssl ca -gencrl -config ssl.cnf -out crl.pem
Script de renouvellement de certificats
Fichier <path>/etc/pki/httpd/renew-certificate.sh</path>
Il faut révoquer l'ancien certificat et signer la demande de certificat créée initialement, basée sur sa clef privée.
L'ancien certificat se retrouve en cherchant dans le fichier index.txt le nom qualifié (DN) qui correspond à la requête. La procédure de révocation s'effectue ensuite avec le numéro de série <xx> et le fichier de certificat cert/<xx>.pem.
La signature de la nouvelle requête peut être manuelle pour s'assurer que les dates de validité du certificat seront correctes.
#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1
if [[ "$user" == "" ]]
then
echo "Usage: $(basename $0) USER"
exit
fi
echo "Renew certificates for \"${user}\""
./revoke-certificate.sh ${user}
openssl ca -config confs/${user}-ssl.cnf \
-out certs/${user}.crt -outdir certs -infiles certs/${user}.csr
cat certs/${user}.crt certs/${user}.key > ${user}.pem
Mise en place
Génération de l'autorité de certification
Toujours depuis le répertoire /etc/pki/httpd, on initialise notre générateur et on génère l’autorité de certification. Celle-ci se compose d'une paire clé/certificat qui servira à signer tous les autres certificats.
Ici, le CN sera obligatoirement le nom d'hôte du serveur (FQDN), les autres renseignements ne sont pas bloquants pour la suite.
cd /etc/pki/httpd/
mkdir {certs,newcerts,private,confs,crl,pem}
touch index.txt
echo 01 > serial
echo 01 > crlnumber
openssl genrsa -out private/httpd_ca.key 2048
openssl req -config ssl.cnf -new -x509 -days 3650 -key private/httpd_ca.key \
-out httpd_ca.crt -extensions v3_ca
Activation de la Liste des certificats révoqués : Certificate Revocation Lists (CRL)
On active la CRL en deux temps [1]
- création d'un lien en dur ( ou copie ) du fichier crl dans le répertoire crl
- création d'un lien symbolique de celui-ci en le nommant avec un hash ( donné par openssl )
cd /etc/pki/httpd/
ln crl.pem crl/
cd crl
ln -s crl.pem `openssl crl -hash -noout -in crl.pem`.r0
Génération du certificat pour Apache
Il faut créer un certificat valide pour le serveur
cd /etc/pki/httpd/
./generate-certificate.sh httpd
Configuration d'Apache
Fichier <path>/etc/httpd/conf.d/ssl.conf</path>
LoadModule ssl_module modules/mod_ssl.so
Listen 443
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 300
SSLMutex default
SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
<VirtualHost _default_:443>
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
SSLHonorCipherOrder on
SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
SSLCARevocationPath /etc/pki/httpd/crl/
SSLVerifyClient require
SSLVerifyDepth 2
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
SSLOptions +StdEnvVars +ExportCertData
</Files>
<Directory "/var/www/cgi-bin">
SSLOptions +StdEnvVars +ExportCertData
</Directory>
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>
Gérer les certificats des utilisateurs
Cette partie est la seule qui peut être exécuter plusieurs fois. Elle est très amplement facilitée par les scripts de gestion édités auparavant.
Ajout d'un utilisateur
L'autorisation d'accès d'un utilisateur est conditionné par un certificat web qui doit être importer dans le navigateur de celui-ci. Ce certificat web est une simple traduction du certificat openssl à qui il est étroitement associé. Le certificat web ne peut exister sans lui.
Généreration des certificats
cd /etc/pki/httpd/
./generate-certificate.sh <USER>
./generate-web-certificate.sh <USER>
Il ne reste plus qu'à donner de manière sécurisée le certificat web à l'utilisateur le fichier <path>/etc/pki/httpd/certs/<USER>_browser_cert.p12</path>, ainsi que le mot de passe associé.
Celui-ci devra l'importer dans son navigateur :
Révocation d'utilisateur
On révoque son certificat et celui-ci ne peut plus accéder au site.
cd /etc/pki/httpd/
./revoke-certificate.sh <USER>
Virtualhosts
Apache ne supporte pas le multi virtualhost de but en blanc sur une connection https, mais cela est toutefois possible sous certaines conditions :
- Les certificats et les clés sont partagées par tous les virtualhosts ( y compris le default ) et ceux-ci doivent être recopiés à chaque définition de virtualhost. De plus celles-ci doivent comporter le port :
<VirtualHost 192.168.0.100:443>
- Utilisation de la directive NameVirtualHost avec spécification du port :
NameVirtualHost 192.168.0.100:443
- Les autres définitions des virtualhosts accessibles en http doivent mentionner le port ( httpd-vhosts.conf ) :
<VirtualHost 192.168.0.100:80>
Fichier <path>/etc/httpd/conf.d/ssl.conf</path>
LoadModule ssl_module modules/mod_ssl.so
Listen 443
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 300
SSLMutex default
SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
<VirtualHost _default_:443>
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
SSLHonorCipherOrder on
SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
SSLCARevocationPath /etc/pki/httpd/crl/
SSLVerifyClient require
SSLVerifyDepth 2
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
SSLOptions +StdEnvVars +ExportCertData
</Files>
<Directory "/var/www/cgi-bin">
SSLOptions +StdEnvVars +ExportCertData
</Directory>
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>
<VirtualHost 192.168.0.100:443>
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
SSLHonorCipherOrder on
SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
SSLCARevocationPath /etc/pki/httpd/crl/
SSLVerifyClient require
SSLVerifyDepth 2
ServerAdmin root@localhost
DocumentRoot "/home/ssl-vhost"
ServerName ssl-vhost.localdomain
<Directory "/home/ssl-vhost">
AllowOverride none
Allow from all
Order allow,deny
</Directory>
LogLevel warn
ErrorLog "logs/ssl-vhost-error.log"
CustomLog "logs/ssl-vhost-access.log" common
TransferLog logs/ssl-vhost-access.log
</VirtualHost>
Utilisation avec PHP
Il faut activer la passation des paramètres SSL à PHP en rajoutant l'option ExportCertData[2]
Fichier <path>/etc/httpd/conf.d/ssl.conf</path>
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
SSLOptions +StdEnvVars +ExportCertData
</Files>
<Directory "/var/www/cgi-bin">
SSLOptions +StdEnvVars +ExportCertData
</Directory>
Quand un certificat d'un client est disponible, la variable globale $_SERVER contient beaucoup plus d'information, toutes préfixées avec SSL_CLIENT_.
- SSL_CLIENT_VERIFY est très importante et les information du certificat ne doivent pas être utilisées si cette variable n'est pas égale à SUCCESS. Cette variable est passée à NONE si il n'y a pas de certificat.
- SSL_CLIENT_M_SERIAL contient le numéro de série qui identifie le certificat unique associé depuis l'autorité de certification.
- Toutes les variables SSL_CLIENT_I_* sont à propos de l'autorité de certification.
- Toutes les variables SSL_CLIENT_S_* sont à propos de l'utilisateur.
Dans le cas qui nous intéresse, on vérifie le nom en lisant la varible SSL_CLIENT_S_DN_CN et l'email associé avec SSL_CLIENT_S_DN_Email.