160 lines
4.6 KiB
Markdown
160 lines
4.6 KiB
Markdown
|
# 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.<implementation>.<name>.paths.cert
|
||
|
config.shb.certs.<implementation>.<name>.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@
|
||
|
```
|