[[!toc levels=3]] # How to get an X.509 certificate for your new name ## The letsencrypt-domains git repository If not already done, clone git repos letsencrypt-domains and backup-keys. git clone ssh://git@git-rw.torproject.org/admin/letsencrypt-domains cd letsencrypt-domains git clone pauli.torproject.org:/srv/puppet.torproject.org/git/tor-backup-keys.git backup-keys ## Add your new name Add your domain name and optional alternative names (`SAN`) to the `domains` file: $EDIT domains ## Public key pinning If you do not want to use HPKP, skip this section. Generate backup [HPKP][]: [HPKP]: https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning ./bin/manage-backup-keys create See `tor-passwords/000-backup-keys` for the passphrase when prompted. The private key is a backup RSA certificate that can be used to rotate HTTPS certificates in case of a compromise, while respecting the pins sent as `Public-Key-Pins` headers. Push the new key to the backup-keys repo: cd backup-keys git status git add $yourfiles git commit git push cd .. ## Push the updated domain list to the letsencrypt-domains repo git diff domains git add domains git commit git push The last command will produce output from the `dehydrated` command which talks with the DNS primary (currently `nevii`) to fetch new keys and update old ones. The new keys and certs are being copied to the LDAP host (currently `pauli`) under `/srv/puppet.torproject.org/from-letsencrypt/`. Then [[Puppet]] pick those up in the `ssl` module. Use the `ssl::service` resource to deploy them. See the "Design" section below for more information on how that works. See also [[static-component]] for an example of how to deploy an encrypted virtual host and onion service. # Disabling HPKP To disable key pinning ([HPKP][]) on a given domain, just remove the backup key from the repository: cd backup-keys git rm example.torproject.org* git commit git push Then run Puppet on all affected hosts, for example the static mirrors: cumin 'C:roles::static_mirror_web' 'puppet agent -t' # Renewing a certificate before its expiry date If a certificate has been revoked, it should be renewed before its expiry date. To do so, you can drop a special file in the `per-domain-config` directory to change the expiry date range and run the script by hand. Create a file matching the primary domain name of the certificate on the DNS master: cat <<EOF > /srv/letsencrypt.torproject.org/repositories/letsencrypt-domains/per-domain-config/example.torproject.org RENEW_DAYS="85" EOF Here we tell the ACME client (dehydrated) to renew the cert if it is 85 days or older (instead of the 30 days period). Then run the script by hand (or wait for cron to do its thing): letsencrypt@nevii:~$ dehydrated-wrap --cron [...] Processing example.torproject.org with alternative names: example.torproject.org + Using certificate specific config file! + RENEW_DAYS = 85 + Checking domain name(s) of existing cert... unchanged. + Checking expire date of existing cert... + Valid till May 18 20:40:45 2020 GMT Certificate will expire (Less than 85 days). Renewing! + Signing domains... [..] Then remove the file. # Design How is this built anyways? When you push to the git repository on the `git-rw.torproject.org` server (currently `cupani`): 1. a per-repository hook gets called in `/srv/git.torproject.org/git-helpers/post-receive-per-repo.d/admin\%letsencrypt-domains/trigger-letsencrypt-server` 2. this hooks hits the DNS master over SSH (`letsencrypt@nevii`) and there the `authorized_keys` file hardcodes the command to `/srv/letsencrypt.torproject.org/bin/from-githost` 3. ... which in turns just calls `bin/update` in the same directory (`/srv/letsencrypt.torproject.org`) 4. ... which in turns pulls the `letsencrypt-domains` repository and runs `dehydrated-wrap --cron` with a special `BASE` variable that points dehydrated at our configuration, in `etc/dehydrated-config`, again in the same directory 5. Through that special configuration, the dehydrated command is configured to call a custom hook (`bin/le-hook`) which implements logic around the DNS-01 authentication challenge, notably adding challenges, bumping serial numbers in the primary nameserver, and waiting for secondaries to sync. Note that there's a configuration file for that hook in `/etc/dsa/le-hook.conf`. 6. The `le-hook` also pushes the changes around. The hook calls the `bin/deploy` file which installs the certificates files in `var/result`. 7. It also generates a Public Key Pin (PKP) hash with the `bin/get-pin` command and appends Diffie-Hellman paramets (`dh-$size.pem`) to the certificate chain. 8. It finally calls the `bin/push` command which runs `rsync` to the Puppet server, which in turns hardcodes the place where those files are dumped (in `pauli:/srv/puppet.torproject.org/from-letsencrypt`) through its `authorized_keys` file. 9. Finally, those certificates are collected by Puppet through the `ssl` module. Pay close attention to how the `tor-puppet/modules/apache2/templates/ssl-key-pins.erb` template works: it will not deploy key pinning if the backup `.pin` file is missing.