Configuration¶
In order to get this plugin to work, the web server must enabled in its
configuration to accept and verify client certificates. This module requires
that at least the subject “distinguished name” is present in the WSGI
environment dictionary, though it prefers similar mod_ssl
variables
(sharing the same prefix and only different that the proper suffix is an
underscore and the name of the attribute type). We chose to prefer this over
the unparsed distinguised name to avoid making a double calculation (parsing
done by both mod_ssl
and our Python code), and to avoid possible bugs.
Apache¶
With mod_wsgi¶
You will need to enable mod_wsgi
and mod_ssl
:
$ a2enmod wsgi
$ a2enmod ssl
Note
This document will not cover how to configure Apache’s mod_wsgi.
Then will need to modify your configuration file to include the following directives to your site:
<VirtualHost yoursite:443>
# your directives here
# to turn on the mod_ssl engine
SSLEngine On
SSLCertificateFile /path/to/your/server/certificate.crt
SSLCertificateKeyFile /path/to/your/server/key.key
# this CA will check your client certificate
SSLCACertificateFile /path/to/the/ca/certificate.crt
# this will turn on client certification verification
SSLVerifyClient require
# This depth will allow us to check for self signed certificates and
# with our CA already specified
SSLVerifyDepth 2
</VirtualHost>
As reverse proxy¶
The configuration is very similar, but in this case you want to reissue the request to a backend or application server. First, enable the modules:
$ a2enmod ssl
$ a2enmod proxy
$ a2enmod proxy_http
The configuration file will have the same directives as in With mod_wsgi but will include the necessary ones for proxying the request:
<VirtualHost yoursite:443>
# your directives here
# to turn on the mod_ssl engine
SSLEngine On
SSLCertificateFile /path/to/your/server/certificate.crt
SSLCertificateKeyFile /path/to/your/server/key.key
# this CA will check your client certificate
SSLCACertificateFile /path/to/the/ca/certificate.crt
# this will turn on client certification verification
SSLVerifyClient require
# This depth will allow us to check for self signed certificates and
# with our CA already specified
SSLVerifyDepth 2
# Enable the reverse proxy
ProxyPass / http://yourbackendserver/ retry=5
ProxyPassReverse / http://yourbackendserver/
ProxyPreserveHost On
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
# In order to prevent HTTP header spoofing set this to empty strings,
# and then reset them to their correct value.
RequestHeader set SSL_CLIENT_S_DN ""
RequestHeader set SSL_CLIENT_I_DN ""
RequestHeader set SSL_CLIENT_S_DN_O ""
RequestHeader set SSL_CLIENT_S_DN_OU ""
RequestHeader set SSL_CLIENT_S_DN_CN ""
RequestHeader set SSL_CLIENT_S_DN_C ""
RequestHeader set SSL_CLIENT_S_DN_ST ""
RequestHeader set SSL_CLIENT_S_DN_L ""
RequestHeader set SSL_CLIENT_S_DN_Email ""
RequestHeader set SSL_CLIENT_I_DN_O ""
RequestHeader set SSL_CLIENT_I_DN_OU ""
RequestHeader set SSL_CLIENT_I_DN_CN ""
RequestHeader set SSL_CLIENT_I_DN_C ""
RequestHeader set SSL_CLIENT_I_DN_ST ""
RequestHeader set SSL_CLIENT_I_DN_L ""
RequestHeader set SSL_CLIENT_I_DN_Email ""
RequestHeader set SSL_SERVER_S_DN_OU ""
RequestHeader set SSL_CLIENT_VERIFY ""
<Location />
RequestHeader set SSL_CLIENT_S_DN "%{SSL_CLIENT_S_DN}s"
RequestHeader set SSL_CLIENT_I_DN "%{SSL_CLIENT_I_DN}s"
RequestHeader set SSL_CLIENT_S_DN_O "%{SSL_CLIENT_S_DN_O}s"
RequestHeader set SSL_CLIENT_S_DN_OU "%{SSL_CLIENT_S_DN_OU}s"
RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s"
RequestHeader set SSL_CLIENT_S_DN_C "%{SSL_CLIENT_S_DN_C}s"
RequestHeader set SSL_CLIENT_S_DN_ST "%{SSL_CLIENT_S_DN_ST}s"
RequestHeader set SSL_CLIENT_S_DN_L "%{SSL_CLIENT_S_DN_L}s"
RequestHeader set SSL_CLIENT_S_DN_Email "%{SSL_CLIENT_S_DN_Email}s"
RequestHeader set SSL_CLIENT_I_DN_O "%{SSL_CLIENT_I_DN_O}s"
RequestHeader set SSL_CLIENT_I_DN_OU "%{SSL_CLIENT_I_DN_OU}s"
RequestHeader set SSL_CLIENT_I_DN_CN "%{SSL_CLIENT_I_DN_CN}s"
RequestHeader set SSL_CLIENT_I_DN_C "%{SSL_CLIENT_I_DN_C}s"
RequestHeader set SSL_CLIENT_I_DN_ST "%{SSL_CLIENT_I_DN_ST}s"
RequestHeader set SSL_CLIENT_I_DN_L "%{SSL_CLIENT_I_DN_L}s"
RequestHeader set SSL_CLIENT_I_DN_Email "%{SSL_CLIENT_I_DN_Email}s"
RequestHeader set SSL_SERVER_S_DN_OU "%{SSL_SERVER_S_DN_OU}s"
RequestHeader set SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}s"
</Location>
</VirtualHost>
Headers modification¶
However, in your backend server the WSGI environment variables will not be
named with the default mod_ssl
key, instead they will be prefixed by HTTP_
(after all they are passed as custom HTTP headers). For example
SSL_CLIENT_S_DN
will become HTTP_SSL_CLIENT_S_DN
, so you will have to
be careful when using the identifier:
from repoze.who.plugins.x509 import X509Identifier
# We need to specify the full string for the key.
identifer = X509Identifier('HTTP_SSL_CLIENT_S_DN')
Nginx¶
Note
Nginx does not parse the distinguished name of neither the subject or the
issuer in to separate fields, so repoze.who.plugins.x509
tries its best
to parse from the given DN fields.
Warning
This module hasn’t been tested with nginx’s mod_wsgi.
As reverse proxy¶
You just to need to specify the following configuration in a readable Nginx configuration file:
server {
# enable ssl engine
listen 443 default ssl;
# specify our server certificates
ssl_certificate /path/to/your/server/certificate.crt;
ssl_certificate_key /path/to/your/server/key.key;
# enables client certification validation
ssl_verify_client on;
# this depth allows us to check self signed certificates and with the CA
# that we will specify.
ssl_verify_depth 2;
# this CA will enable us to check or "authenticate" our client certificate.
ssl_client_certificate /path/to/your/ca/certificate.crt;
ssl_protocols SSLv3 TLSv1;
location / {
proxy_pass http://yourbackendserver;
proxy_set_header Host $host;
# pass the distinguished name fields
proxy_set_header SSL_CLIENT_I_DN $ssl_client_i_dn;
proxy_set_header SSL_CLIENT_S_DN $ssl_client_s_dn;
proxy_set_header SSL_CLIENT_VERIFY $ssl_client_verify;
}
}
As with Apache’s configuration, your headers will not be as specified, but prefixed with HTTP_, and you will need to specify your identifier key accordingly. See Headers modification for an example of this configuration.