In an effort to tidy up the infrastructure behind wicknet.dev, new hostnames and tls certificates were configured.

Forge-related services now all run under some combination of .forge.lan, and so a certificate that covered forge.lan and its subdomains was in order.

To do this, two files were created, forge.lan.conf and forge.lan.v3.ext:

[ req ]
default_bits       = 4096
default_md         = sha512
prompt             = no
encrypt_key        = no

# base request
distinguished_name = req_distinguished_name

# extensions
req_extensions     = v3_req

# distinguished_name
[ req_distinguished_name ]
commonName             = "forge.lan"              # CN=
countryName            = "US"                     # C=
organizationName       = "WickNet"                # O=
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = forge.lan
DNS.2 = *.forge.lan

In the wild, certificates issued by let’s encrypt that cover subdomains also include the base domain in the list of alternate names. This practice is mirrored here.

Keys, certificates, and a certificate signing request are generated thusly:

# openssl req -config forge.lan.conf -newkey rsa:4096 -keyout forge.lan.key -out forge.lan.csr

A CA was setup previously to encrypt the docker-registry, so it is reused to sign the new certificate:

# openssl x509 -req -in forge.lan/forge.lan.csr -CA AIDSec.crt -CAkey AIDSec.key -CAcreateserial -out forge.lan/forge.lan.crt -days 730 -sha256 -extfile forge.lan/forge.lan.v3.ext

Finally, a full chain of trust is generated to be served:

# cat forge.lan/forge.lan.crt AIDSec.crt > forge.lan/fullchain.pem

Relevant nginx config were then adjusted to serve forge.lan (forgejo), ci.forge.lan (woodpecker), and cr.forge.lan (docker-registry), terminating tls with the new forge.lan certificate.

server {
    ...
    ssl_certificate /path/to/ca/forge.lan/forge.lan.fullchain.pem;
    ssl_certificate_key /path/to/ca/forge.lan/forge.lan.key;
    ...
}

It is important not to forget to allow large client uploads in the configuration for nginx in front of docker-registry:

server {
...
    # abusing http like this is probably criminal
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
    send_timeout 600s;
    keepalive_timeout 600s;
    client_max_body_size 200G;
...
}

The root certificate (AIDSec.crt) was installed on the dev machine but, unfortunately, firefox was still balking at the certificate, despite other tools such as openssl s_client and curl having no problem verifying the newly added certificate. The quick and dirty solution was to install the certificate directly to firefox through their ui, but this solution is lackluster. For expedience’s sake, no further searching was conducted to find a way to make firefox respect the system’s custom ca config.

useful commands:

Some notes to refer back to:

Install new certificates:

# mv <example>.crt /usr/local/share/ca-certificates && update-ca-certificates

Inspect tls certificates:

$ openssl s_client -connect <host>:<port> < /dev/null  | openssl x509 -text -noout

Setup CA:

# openssl req -x509 -new -nodes -key <example>.key -sha256 -days 1826 -out <example>.crt -config <example.conf>'

Create key, certificate, and signing request

# openssl req -config <example>.conf -newkey rsa:4096 -keyout <example>.key -out <example>.csr