summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaïm Favier <n@monade.li>2023-02-15 13:15:09 +0100
committerlewo <lewo@abesis.fr>2023-05-24 21:10:02 +0000
commita948c49ca7e484636f618cf3933f193092370906 (patch)
tree564d8d1657eea16eeea5a1beae2cf152197fb0fb
parent42c55647910820eae41586c9ff08443a1cd46ac5 (diff)
Allow using existing ACME certificates
Add a certificate scheme for using an existing ACME certificate without setting up Nginx. Also use names instead of magic numbers for certificate schemes.
-rw-r--r--default.nix52
-rw-r--r--docs/setup-guide.rst2
-rw-r--r--mail-server/common.nix16
-rw-r--r--mail-server/environment.nix2
-rw-r--r--mail-server/networking.nix4
-rw-r--r--mail-server/nginx.nix4
-rw-r--r--mail-server/systemd.nix6
7 files changed, 50 insertions, 36 deletions
diff --git a/default.nix b/default.nix
index ef27f43..49103f3 100644
--- a/default.nix
+++ b/default.nix
@@ -48,7 +48,11 @@ in
type = types.listOf types.str;
example = [ "imap.example.com" "pop3.example.com" ];
default = [];
- description = "Secondary domains and subdomains for which it is necessary to generate a certificate.";
+ description = ''
+ ({option}`mailserver.certificateScheme` == `acme-nginx`)
+
+ Secondary domains and subdomains for which it is necessary to generate a certificate.
+ '';
};
messageSizeLimit = mkOption {
@@ -448,19 +452,26 @@ in
};
};
- certificateScheme = mkOption {
- type = types.enum [ 1 2 3 ];
- default = 2;
+ certificateScheme = let
+ schemes = [ "manual" "selfsigned" "acme-nginx" "acme" ];
+ translate = i: warn "setting mailserver.certificateScheme by number is deprecated, please use names instead"
+ (builtins.elemAt schemes (i - 1));
+ in mkOption {
+ type = with types; coercedTo (enum [ 1 2 3 ]) translate (enum schemes);
+ default = "selfsigned";
description = ''
- Certificate Files. There are three options for these.
-
- 1) You specify locations and manually copy certificates there.
- 2) You let the server create new (self signed) certificates on the fly.
- 3) You let the server create a certificate via `Let's Encrypt`. Note that
- this implies that a stripped down webserver has to be started. This also
- implies that the FQDN must be set as an `A` record to point to the IP of
- the server. In particular port 80 on the server will be opened. For details
- on how to set up the domain records, see the guide in the readme.
+ The scheme to use for managing TLS certificates:
+
+ 1. `manual`: you specify locations via {option}`mailserver.certificateFile` and
+ {option}`mailserver.keyFile` and manually copy certificates there.
+ 2. `selfsigned`: you let the server create new (self-signed) certificates on the fly.
+ 3. `acme-nginx`: you let the server request certificates from [Let's Encrypt](https://letsencrypt.org)
+ via NixOS' ACME module. By default, this will set up a stripped-down Nginx server for
+ {option}`mailserver.fqdn` and open port 80. For this to work, the FQDN must be properly
+ configured to point to your server (see the [setup guide](setup-guide.rst) for more information).
+ 4. `acme`: you already have an ACME certificate set up (for example, you're already running a TLS-enabled
+ Nginx server on the FQDN). This is better than `manual` because the appropriate services will be reloaded
+ when the certificate is renewed.
'';
};
@@ -468,8 +479,9 @@ in
type = types.path;
example = "/root/mail-server.crt";
description = ''
- Scheme 1)
- Location of the certificate
+ ({option}`mailserver.certificateScheme` == `manual`)
+
+ Location of the certificate.
'';
};
@@ -477,8 +489,9 @@ in
type = types.path;
example = "/root/mail-server.key";
description = ''
- Scheme 1)
- Location of the key file
+ ({option}`mailserver.certificateScheme` == `manual`)
+
+ Location of the key file.
'';
};
@@ -486,8 +499,9 @@ in
type = types.path;
default = "/var/certs";
description = ''
- Scheme 2)
- This is the folder where the certificate will be created. The name is
+ ({option}`mailserver.certificateScheme` == `selfsigned`)
+
+ This is the folder where the self-signed certificate will be created. The name is
hardcoded to "cert-DOMAIN.pem" and "key-DOMAIN.pem" and the
certificate is valid for 10 years.
'';
diff --git a/docs/setup-guide.rst b/docs/setup-guide.rst
index 8127734..c74a53d 100644
--- a/docs/setup-guide.rst
+++ b/docs/setup-guide.rst
@@ -81,7 +81,7 @@ these should be the most common ones.
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
- certificateScheme = 3;
+ certificateScheme = "acme-nginx";
};
}
diff --git a/mail-server/common.nix b/mail-server/common.nix
index 2a264a7..e8beb7a 100644
--- a/mail-server/common.nix
+++ b/mail-server/common.nix
@@ -21,22 +21,22 @@ let
in
{
# cert :: PATH
- certificatePath = if cfg.certificateScheme == 1
+ certificatePath = if cfg.certificateScheme == "manual"
then cfg.certificateFile
- else if cfg.certificateScheme == 2
+ else if cfg.certificateScheme == "selfsigned"
then "${cfg.certificateDirectory}/cert-${cfg.fqdn}.pem"
- else if cfg.certificateScheme == 3
+ else if cfg.certificateScheme == "acme" || cfg.certificateScheme == "acme-nginx"
then "${config.security.acme.certs.${cfg.fqdn}.directory}/fullchain.pem"
- else throw "Error: Certificate Scheme must be in { 1, 2, 3 }";
+ else throw "unknown certificate scheme";
# key :: PATH
- keyPath = if cfg.certificateScheme == 1
+ keyPath = if cfg.certificateScheme == "manual"
then cfg.keyFile
- else if cfg.certificateScheme == 2
+ else if cfg.certificateScheme == "selfsigned"
then "${cfg.certificateDirectory}/key-${cfg.fqdn}.pem"
- else if cfg.certificateScheme == 3
+ else if cfg.certificateScheme == "acme" || cfg.certificateScheme == "acme-nginx"
then "${config.security.acme.certs.${cfg.fqdn}.directory}/key.pem"
- else throw "Error: Certificate Scheme must be in { 1, 2, 3 }";
+ else throw "unknown certificate scheme";
passwordFiles = let
mkHashFile = name: hash: pkgs.writeText "${builtins.hashString "sha256" name}-password-hash" hash;
diff --git a/mail-server/environment.nix b/mail-server/environment.nix
index cc85202..e509ea6 100644
--- a/mail-server/environment.nix
+++ b/mail-server/environment.nix
@@ -23,6 +23,6 @@ in
config = with cfg; lib.mkIf enable {
environment.systemPackages = with pkgs; [
dovecot opendkim openssh postfix rspamd
- ] ++ (if certificateScheme == 2 then [ openssl ] else []);
+ ] ++ (if certificateScheme == "selfsigned" then [ openssl ] else []);
};
}
diff --git a/mail-server/networking.nix b/mail-server/networking.nix
index e8a222e..6af186a 100644
--- a/mail-server/networking.nix
+++ b/mail-server/networking.nix
@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
-{ config, pkgs, lib, ... }:
+{ config, lib, ... }:
let
cfg = config.mailserver;
@@ -31,7 +31,7 @@ in
++ lib.optional enablePop3 110
++ lib.optional enablePop3Ssl 995
++ lib.optional enableManageSieve 4190
- ++ lib.optional (certificateScheme == 3) 80;
+ ++ lib.optional (certificateScheme == "acme-nginx") 80;
};
};
}
diff --git a/mail-server/nginx.nix b/mail-server/nginx.nix
index abc6421..e5fa597 100644
--- a/mail-server/nginx.nix
+++ b/mail-server/nginx.nix
@@ -24,8 +24,8 @@ let
acmeRoot = "/var/lib/acme/acme-challenge";
in
{
- config = lib.mkIf (cfg.enable && cfg.certificateScheme == 3) {
- services.nginx = {
+ config = lib.mkIf (cfg.enable && (cfg.certificateScheme == "acme" || cfg.certificateScheme == "acme-nginx")) {
+ services.nginx = lib.mkIf (cfg.certificateScheme == "acme-nginx") {
enable = true;
virtualHosts."${cfg.fqdn}" = {
serverName = cfg.fqdn;
diff --git a/mail-server/systemd.nix b/mail-server/systemd.nix
index 36e48d6..0fdcf90 100644
--- a/mail-server/systemd.nix
+++ b/mail-server/systemd.nix
@@ -19,9 +19,9 @@
let
cfg = config.mailserver;
certificatesDeps =
- if cfg.certificateScheme == 1 then
+ if cfg.certificateScheme == "manual" then
[]
- else if cfg.certificateScheme == 2 then
+ else if cfg.certificateScheme == "selfsigned" then
[ "mailserver-selfsigned-certificate.service" ]
else
[ "acme-finished-${cfg.fqdn}.target" ];
@@ -29,7 +29,7 @@ in
{
config = with cfg; lib.mkIf enable {
# Create self signed certificate
- systemd.services.mailserver-selfsigned-certificate = lib.mkIf (cfg.certificateScheme == 2) {
+ systemd.services.mailserver-selfsigned-certificate = lib.mkIf (cfg.certificateScheme == "selfsigned") {
after = [ "local-fs.target" ];
script = ''
# Create certificates if they do not exist yet