4.6 KiB
SSL Block
This NixOS module is a block that provides a contract to generate TLS certificates.
It is implemented by:
shb.certs.cas.selfsigned
andshb.certs.certs.selfsigned
: Generates self-signed certificates, including self-signed CA thanks to the certtool package.shb.certs.certs.letsencrypt
: Requests certificates from Let's Encrypt.
Contract
The contract for this block is defined in /modules/contracts/ssl.nix
.
Every module implementing this contract provides the following options:
paths.cert
: Path to the cert file.paths.key
: Path to the key file.systemdService
: Systemd oneshot service used to generate the certificate. The Systemd service file name must include the.service
suffix. Downstream users of the certificate can use this option to wait for the certificate to be generated.
Implementations
This sections explains how to generate certificates using the SSL block implementations.
Self-Signed Certificates
Defined in /modules/blocks/ssl.nix
.
To use self-signed certificates, we must first generate at least one Certificate Authority (CA):
shb.certs.cas.selfsigned.myca = {
name = "My CA";
};
Every CA defined this way will be concatenated into the file /etc/ssl/certs/ca-certificates.cert
which means those CAs and all certificates generated by those CAs will be automatically trusted.
We can then generate one or more certificates signed by that CA:
shb.certs.certs.selfsigned = {
"example.com" = {
ca = config.shb.certs.cas.selfsigned.myca;
domain = "example.com";
};
"www.example.com" = {
ca = config.shb.certs.cas.selfsigned.myca;
domain = "www.example.com";
};
};
Let's Encrypt
Defined in /modules/blocks/ssl.nix
.
We can ask Let's Encrypt to generate a certificate with:
shb.certs.certs.letsencrypt."example.com" = {
domain = "example.com";
dnsProvider = "linode";
adminEmail = "admin@example.com";
credentialsFile = /path/to/secret/file;
additionalEnvironment = {
LINODE_HTTP_TIMEOUT = "10";
LINODE_POLLING_INTERVAL = "10";
LINODE_PROPAGATION_TIMEOUT = "240";
};
};
The credential file's content would be a key-value pair:
LINODE_TOKEN=XYZ...
For other providers, see the official instruction.
Usage
To use either a self-signed certificates or a Let's Encrypt generated one, we can reference the path where the certificate and the private key are located:
config.shb.certs.<implementation>.<name>.paths.cert
config.shb.certs.<implementation>.<name>.paths.key
For example:
config.shb.certs.selfsigned."example.com".paths.cert
config.shb.certs.selfsigned."example.com".paths.key
We can then configure Nginx to use those certificates:
services.nginx.virtualHosts."example.com" =
let
cert = config.shb.certs.selfsigned."example.com";
in
{
onlySSL = true;
sslCertificate = cert.paths.cert;
sslCertificateKey = cert.paths.key;
locations."/".extraConfig = ''
add_header Content-Type text/plain;
return 200 'It works!';
'';
};
To make sure the Nginx webserver can find the generated file, we will make it wait for the certificate to the generated:
systemd.services.nginx = {
after = [ config.shb.certs.selfsigned."example.com".systemdService ];
requires = [ config.shb.certs.selfsigned."example.com".systemdService ];
};
If needed, we can also wait on the CA bundle to be generated by waiting for the Systemd service:
config.shb.certs.systemdService
Debug
Each CA and Cert is generated by a systemd service whose name can be seen in systemdService
options below. You can then see the latest errors messages using journalctl
.
Tests
This block is tested in /tests/vm/ssl.nix
.
Options Reference
id-prefix: blocks-ssl-options-
list-id: selfhostblocks-options
source: @OPTIONS_JSON@