1
0
Fork 0
selfhostblocks/modules/blocks/ssl/docs/default.md
2024-01-19 10:48:10 -08:00

4.6 KiB

SSL Block

This NixOS module is a block that provides a contract to generate TLS certificates.

It is implemented by:

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@