# SSL Block {#ssl-block} This NixOS module is a block that provides a contract to generate TLS certificates. It is implemented by: - [`shb.certs.cas.selfsigned`][10] and [`shb.certs.certs.selfsigned`][11]: Generates self-signed certificates, including self-signed CA thanks to the [certtool][1] package. - [`shb.certs.certs.letsencrypt`][12]: Requests certificates from [Let's Encrypt][2]. [1]: https://search.nixos.org/packages?channel=23.11&show=gnutls&from=0&size=50&sort=relevance&type=packages&query=certtool [2]: https://letsencrypt.org/ [10]: blocks-ssl.html#blocks-ssl-options-shb.certs.cas.selfsigned [11]: blocks-ssl.html#blocks-ssl-options-shb.certs.certs.selfsigned [12]: blocks-ssl.html#blocks-ssl-options-shb.certs.certs.letsencrypt ## Contract {#ssl-block-contract} The contract for this block is defined in [`/modules/contracts/ssl.nix`](@REPO@/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 {#ssl-block-impl} This sections explains how to generate certificates using the SSL block implementations. ### Self-Signed Certificates {#ssl-block-impl-self-signed} Defined in [`/modules/blocks/ssl.nix`](@REPO@/modules/blocks/ssl.nix). To use self-signed certificates, we must first generate at least one Certificate Authority (CA): ```nix 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: ```nix 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 {#ssl-block-impl-lets-encrypt} Defined in [`/modules/blocks/ssl.nix`](@REPO@/modules/blocks/ssl.nix). We can ask Let's Encrypt to generate a certificate with: ```nix 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: ```yaml LINODE_TOKEN=XYZ... ``` For other providers, see the [official instruction](https://go-acme.github.io/lego/dns/). ## Usage {#ssl-block-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: ```nix config.shb.certs...paths.cert config.shb.certs...paths.key ``` For example: ```nix 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: ```nix 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: ```nix 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: ```nix config.shb.certs.systemdService ``` ## Debug {#ssl-block-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 {#ssl-block-tests} This block is tested in [`/tests/vm/ssl.nix`](@REPO@/tests/vm/ssl.nix). ## Options Reference {#ssl-block-options} ```{=include=} options id-prefix: blocks-ssl-options- list-id: selfhostblocks-options source: @OPTIONS_JSON@ ```