Have nix auto-generate a sslCertificate for nginx virtual host

Say I don’t care about the certificate and its security because it’s only meant for local testing. Is there an easy way have nix auto-generate a certificate key pair for me, when configuring services.nginx?

 services.nginx = {
    enable = true;
    recommendedGzipSettings = true;
    recommendedOptimisation = true;
    virtualHosts = {
      somehost = {
        serverName = "someserver";
        sslCertificate = ???;
        sslCertificateKey = ???;
        forceSSL = true;
        locations."/".[proxyPass = "http://127.0.0.1:8080/";
      };
    };
  };

This would be nice to have for services like SMTP as well, were a certificate is better nothing but verification can’t be enforced.

If you enable ACME (with enableACME = true; at the same level of serverName) you get by default a self-signed certificate, until you get a real certificate from Let’s Encrypt, which can as well be never.
If you don’t like having failed units you can have a look at the tests under nixos/tests in nixpkgs, there are many that create test certs and keys with openssl

1 Like

I ended up writing this function:

  tls-cert = {alt ? []}: (pkgs.runCommand "selfSignedCert" { buildInputs = [ pkgs.openssl ]; } ''
    mkdir -p $out
    openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -days 365 -nodes \
      -keyout $out/cert.key -out $out/cert.crt \
      -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,${builtins.concatStringsSep "," (["IP:127.0.0.1"] ++ alt)}"
  '');

and then:

  services.nginx = {
    enable = true;
    recommendedGzipSettings = true;
    recommendedOptimisation = true;
    virtualHosts = {
      somehost = let
        cert = tls-cert { alt = [ "IP:192.168.0.10" ] };
      in
      {
        serverName = "someserver";
        sslCertificate = "${cert}/cert.crt";
        sslCertificateKey = "${cert}/cert.key";
        forceSSL = true;
        locations."/".proxyPass = "http://127.0.0.1:8080/";
      };
    };
  };

but hoped somebody had already added a function like that to nixpkgs.lib or there’d be an option in the nginx selfsignedLocalhost = true;.

There are a number of parameters that people would like to tune and adjust according to their needs, I feel that a function like these would either be useful only to a small number of people or a monster of a function if we wanted to parameterize everything, but I may be mistaken.
Also, that would need to emit a warning or some sort of “please don’t shoot yourself in the foot by putting a secret in a world-readable store” opt-in mechanism

Oh no, you do not want to do it this way. This is, fundamentally, a non-reproducible derivation, with private information stored in the nix store. That’s two problems.

  1. You have one derivation that will produce randomized outputs. As your system is updated, this derivation will be rebuilt, and every time that happens, the keys are going to change.
  2. Files stored in the nix store are readable by all users on the system, which is highly recommended against for secret key material like this.
  3. A consequence of the combination of these two problems is that this derivation can be copied around as a Nix derivation, which makes no sense. Randomly generated keys shouldn’t be substitute-able with nix substitution, and in fact the mere possibility of that opens you up to accidentally substituting third-party provided keys, which is a massive security risk.

The correct way to handle keys like this is to generate them at runtime, not at build time, and store them in local (non-nix-store) storage. You should use a systemd service to run the code to do this at the right time during boot.

1 Like

Please read the premise, Jerricco. The word security is meaningless without a threat-model.

I gave the nixos tests that generate certificates for https a quick look-over, to me it seems that more than half of them would be served by something like my simple function.

It’s still wrong because of point #1. When the derivation is rebuilt, your keys will change and break things.