The purpose of this configuration is to allow the letsencrypt-auto
script to function properly from a centralized configuration management host. This allows for managing/automating the creation, deployment and renewal of certificates without resorting to retrieving trust related data from the less trusted managed hosts.
An added bonus is that the auth data stored with the renewal configuration is not littered across the enterprise.
This particular collector configuration is contingent upon the server certificate having the host IP addressses in its Subject Alternative Name list. Is it neccessary? That is a question that you must answer for yourself. Internal and external addresses are readily available by way of our automation infrastructure--one less dependency to worry about.
The request contents itself is not particularly sensitive--the connection from letsencrypt
comes in on port 80!
We have an existing, internal CA infrastructure that automatically generates and deploys system-specific server and client certs. The encryption is useful when connecting to databases or API endpoints; however, in this case, the most important feature is the authentication of the connection. Both local and remote managed systems can proxy connections back to the collector.
# openssl x509 -in /etc/ssl/certs/collector_server.crt -noout -text
[...]
X509v3 extensions:
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Alternative Name:
DNS:mc-01.salt.revsys.000.prod.ec2.eu-c-2, DNS:52.27.33.198, IP Address:52.27.33.198, DNS:10.64.8.39, IP Address:10.64.8.39,
X509v3 Subject Key Identifier:
[...]
For those that are interested: You would think that specifying an IP address in the SAN list would be adequate. I thought thusly. Verily, I was wrong. Some client libraries soil themselves if the target for the SSL request is not listed as a DNS
element. Other client libraries work as expected using the IP and IPv6 categories.
server {
listen 49152 ssl;
server_name 10.64.8.39;
server_name 52.27.33.198;
access_log /var/log/nginx/letsencrypt_access.log;
error_log /var/log/nginx/letsencrypt_error.log debug;
location ~ "^/.well-known/acme-challenge/([\w_-]{43})$" {
alias /var/www/nginx/le/.well-known/acme-challenge/$1;
}
include /etc/nginx/mime.types;
include /etc/nginx/ssl.conf;
ssl_certificate /etc/ssl/certs/<your.server.cert.here>;
ssl_certificate_key /etc/ssl/private/<your.server.rsa.key.here>;
ssl_verify_client on;
ssl_client_certificate /etc/ssl/certs/<cert for CA that signs your client certificates>;
ssl_crl /etc/ssl/certs/<signing CA crl>;
access_log /var/log/nginx/letsencrypt_access.log;
error_log /var/log/nginx/letsencrypt_error.log;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 16 100k;
}
We have other web things running on the collector--they all use app-specific ssl certificates and leverage NGiNX's SNI functionality. SNI gets a bit gummed up if you throw IP addresses as server names at it. If you don't find yourself in this sort of situation, using the standard port works just as well.
server {
listen 80;
error_log /var/log/nginx/sites_error.log;
server_name www.something.revsys.com;
location ~ "^/(.well-known/acme-challenge/[\w_-]{43})$" {
access_log /var/log/nginx/le_something.log;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 16 100k;
proxy_redirect off;
proxy_ssl_trusted_certificate /etc/ssl/certs/revsys_root/ca.crt;
proxy_ssl_certificate /etc/ssl/client/revsys_root/salt-minion-X.crt
proxy_ssl_certificate_key /etc/ssl/private/salt-minion-X.key
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_pass https://10.64.8.39:49152;
}
location / {
[...];
}
}
This can be used by itself as an initial nginx service deployment configuration. Once a letsencrypt certificate is available, the actual site SSL configuration bits can be appended to the server block. Since we already have an existing CA in place, our initial deployments include internal site-specific certificates that are replaced during subsequent runs.
This mechanism can be easily tested by creating a file on the collector: echo 'whee!' > /var/www/nginx/le/.well-known/acme-challenge/0000000000000000000000000000000000000000
(<- 44 zeros)
From a remote system:
$ curl http://www.mysystem.domain/.well-known/acme-challenge/0000000000000000000000000000000000000000000
whee!
Once this is in place, from the collector:
# /opt/letsencrypt/letsencrypt-auto certonly --webroot -w /var/www/nginx/le -d www.something.revsys.com
Checking for new version...
Requesting root privileges to run letsencrypt...
/root/.local/share/letsencrypt/bin/letsencrypt certonly --webroot -w /var/www/nginx/le -d www.something.revsys.com
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/www.something.revsys.com/fullchain.pem. Your
cert will expire on 2016-07-25. To obtain a new version of the
certificate in the future, simply run Let's Encrypt again.
- If you like Let's Encrypt, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https
If you maintain the letsencrypto-auto
storage paths, all of your shiny new certificates will appear in /etc/letsencrypt/live/<fqdn of all the things>
.
Version Information:
program | version |
---|---|
nginx | 1.9.7 |
openssl | 1.0.1f |
letsencrypt | 0.6.0.dev0 |