SSL Generator Contract

Table of Contents

Contract Reference
Usage
Provided Implementations
Custom Implementation

This NixOS contract represents an SSL certificate generator. This contract is used to decouple generating an SSL certificate from using it. In practice, you can swap generators without updating modules depending on it.

Contract Reference

These are all the options that are expected to exist for this contract to be respected.

shb.contracts.ssl

Contract for SSL Certificate generator.

Type: anything

Declared by:

<selfhostblocks/modules/contracts/ssl/dummyModule.nix>
shb.contracts.ssl.paths

Paths where the files for the certificate will be located.

This option is the contract output of the shb.certs.certs SSL block.

Type: anything

Declared by:

<selfhostblocks/modules/contracts/ssl/dummyModule.nix>
shb.contracts.ssl.paths.cert

Path to the cert file.

Type: path

Declared by:

<selfhostblocks/modules/contracts/ssl/dummyModule.nix>
shb.contracts.ssl.paths.key

Path to the key file.

Type: path

Declared by:

<selfhostblocks/modules/contracts/ssl/dummyModule.nix>
shb.contracts.ssl.systemdService

Systemd oneshot service used to generate the certificate. Ends with the .service suffix.

Use this if downstream services must wait for the certificates to be generated before starting.

Type: string

Example: "cert-generator.service"

Declared by:

<selfhostblocks/modules/contracts/ssl/dummyModule.nix>

Usage

Let’s assume a module implementing this contract is available under the ssl variable:

let
  ssl = <...>;
in

To use this module, we can reference the path where the certificate and the private key are located with:

ssl.paths.cert
ssl.paths.key

We can then configure Nginx to use those certificates:

services.nginx.virtualHosts."example.com" = {
  onlySSL = true;
  sslCertificate = ssl.paths.cert;
  sslCertificateKey = ssl.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 = [ ssl.systemdService ];
  requires = [ ssl.systemdService ];
};

Provided Implementations

Multiple implementation are provided out of the box at SSL block.

Custom Implementation

To implement this contract, you must create a module that respects this contract. The following snippet shows an example.

{ lib, ... }:
{
  options.my.generator = {
    paths = lib.mkOption {
      description = ''
        Paths where certs will be located.

        This option implements the SSL Generator contract.
      '';
      type = contracts.ssl.certs-paths;
      default = {
        key = "/var/lib/my_generator/key.pem";
        cert = "/var/lib/my_generator/cert.pem";
      };
    };

    systemdService = lib.mkOption {
      description = ''
        Systemd oneshot service used to generate the certs.

        This option implements the SSL Generator contract.
      '';
      type = lib.types.str;
      default = "my-generator.service";
    };

    # Other options needed for this implementation
  };

  config = {
    # custom implementation goes here
  };
}

You can then create an instance of this generator:

{
  my.generator = ...;
}

And use it whenever a module expects something implementing this SSL generator contract:

{ config, ... }:
{
  my.service.ssl = config.my.generator;
}