From 6906baae5c8686ac8d859b3af6083d8210c57d80 Mon Sep 17 00:00:00 2001 From: Nikolay Amiantov Date: Tue, 8 Dec 2015 21:09:19 +0300 Subject: [PATCH] nixos/simp_le: improve configuration options --- nixos/modules/services/security/simp_le.nix | 101 +++++++++++++++----- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/nixos/modules/services/security/simp_le.nix b/nixos/modules/services/security/simp_le.nix index d578d5bb679b..927359da0d31 100644 --- a/nixos/modules/services/security/simp_le.nix +++ b/nixos/modules/services/security/simp_le.nix @@ -9,9 +9,14 @@ let certOpts = { ... }: { options = { webroot = mkOption { - type = types.nullOr types.str; - default = null; - description = "Where the webroot of the HTTP vhost is located."; + type = types.str; + description = '' + Where the webroot of the HTTP vhost is located. + .well-known/acme-challenge/ directory + will be created automatically if it doesn't exist. + http://example.org/.well-known/acme-challenge/ must also + be available (notice unencrypted HTTP). + ''; }; validMin = mkOption { @@ -32,20 +37,53 @@ let description = "Contact email address for the CA to be able to reach you."; }; + user = mkOption { + type = types.str; + default = "root"; + description = "User under which simp_le would run."; + }; + + group = mkOption { + type = types.str; + default = "root"; + description = "Group under which simp_le would run."; + }; + + postRun = mkOption { + type = types.lines; + default = ""; + example = "systemctl reload nginx.service"; + description = '' + Commands to run after certificates are re-issued. Typically + the web server and other servers using certificates need to + be reloaded. + ''; + }; + plugins = mkOption { type = types.listOf (types.enum [ "cert.der" "cert.pem" "chain.der" "chain.pem" "external_pem.sh" - "fullchain.der" "fullchain.pem" "key.der" "key.pem" + "fullchain.der" "fullchain.pem" "key.der" "key.pem" "account_key.json" ]); - default = [ "fullchain.pem" "key.pem" ]; - description = "Plugins to enable."; + default = [ "fullchain.pem" "key.pem" "account_key.json" ]; + description = '' + Plugins to enable. With default settings simp_le will + store public certificate bundle in fullchain.pem + and private key in key.pem in its state directory. + ''; }; extraDomains = mkOption { - default = [ ]; - type = types.listOf types.str; - description = "More domains to include in the certificate."; - example = [ "example.com" "foo.example.com:/var/www/foo" ]; + type = types.attrsOf (types.nullOr types.str); + default = {}; + example = { + "example.org" = "/srv/http/nginx"; + "mydomain.org" = null; + }; + description = '' + Extra domain names for which certificates are to be issued, with their + own server roots if needed. + ''; }; }; }; @@ -62,7 +100,7 @@ in default = "/etc/ssl"; type = types.str; description = '' - Directory where certs will be stored by default. + Directory where certs and other state will be stored by default. ''; }; @@ -74,10 +112,10 @@ in ''; options = [ certOpts ]; example = { - "foo.example.com" = { + "example.com" = { webroot = "/var/www/challenges/"; email = "foo@example.com"; - extraDomains = [ "www.example.com" "example.com" ]; + extraDomains = { "www.example.com" = null; "foo.example.com" = "/var/www/foo/"; }; }; "bar.example.com" = { webroot = "/var/www/challenges/"; @@ -91,27 +129,42 @@ in ###### implementation config = mkIf (cfg.certs != { }) { - systemd.services = flip mapAttrs' cfg.certs (cert: data: nameValuePair + systemd.services = flip mapAttrs' cfg.certs (cert: data: + let + cpath = "${cfg.directory}/${cert}"; + cmdline = [ "-v" "-d" cert "--default_root" data.webroot "--valid_min" data.validMin ] + ++ optionals (data.email != null) [ "--email" data.email ] + ++ concatMap (p: [ "-f" p ]) data.plugins + ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains); + + in nameValuePair ("simp_le-${cert}") ({ description = "simp_le cert renewal for ${cert}"; after = [ "network.target" ]; serviceConfig = { Type = "oneshot"; - SuccessExitStatus = "0 1"; + SuccessExitStatus = [ "0" "1" ]; }; + path = [ pkgs.simp_le pkgs.sudo ]; preStart = '' - mkdir -p "${cfg.directory}/${cert}" + mkdir -p '${cfg.directory}' + if [ ! -d '${cpath}' ]; then + mkdir -m 700 '${cpath}' + chown '${data.user}:${data.group}' '${cpath}' + fi ''; script = '' - WEBROOT="${optionalString (data.webroot == null) data.webroot}" - cd "${cfg.directory}/${cert}" - ${pkgs.simp_le}/bin/simp_le -v \ - ${concatMapStringsSep " " (p: "-f ${p}") data.plugins} \ - -d ${cert} --default_root "$WEBROOT" \ - ${concatMapStringsSep " " (p: "-d ${p}") data.extraDomains} \ - ${optionalString (data.email != null) "--email ${data.email}"} \ - --valid_min ${toString data.validMin} + cd '${cpath}' + set +e + sudo -u '${data.user}' -- simp_le ${concatMapStringsSep " " (arg: escapeShellArg (toString arg)) cmdline} + EXITCODE=$? + set -e + if [ "$EXITCODE" = "0" ]; then + ${data.postRun} + else + exit "$EXITCODE" + fi ''; }) );