parent
229e29d1eb
commit
0bfa15fd3c
2 changed files with 91 additions and 32 deletions
|
@ -73,6 +73,20 @@ in
|
||||||
example = "example.com";
|
example = "example.com";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extraDomains = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Other domains to generate a certificate for.
|
||||||
|
'';
|
||||||
|
default = [];
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
[
|
||||||
|
"sub1.example.com"
|
||||||
|
"sub2.example.com"
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
paths = lib.mkOption {
|
paths = lib.mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Paths where certs will be located.
|
Paths where certs will be located.
|
||||||
|
@ -109,6 +123,20 @@ in
|
||||||
example = "example.com";
|
example = "example.com";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extraDomains = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Other domains to generate a certificate for.
|
||||||
|
'';
|
||||||
|
default = [];
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
[
|
||||||
|
"sub1.example.com"
|
||||||
|
"sub2.example.com"
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
paths = lib.mkOption {
|
paths = lib.mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Paths where certs will be located.
|
Paths where certs will be located.
|
||||||
|
@ -278,7 +306,11 @@ in
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
serviceConfig.RuntimeDirectory = serviceName certCfg.systemdService;
|
serviceConfig.RuntimeDirectory = serviceName certCfg.systemdService;
|
||||||
# Taken from https://github.com/NixOS/nixpkgs/blob/7f311dd9226bbd568a43632c977f4992cfb2b5c8/nixos/tests/custom-ca.nix
|
# Taken from https://github.com/NixOS/nixpkgs/blob/7f311dd9226bbd568a43632c977f4992cfb2b5c8/nixos/tests/custom-ca.nix
|
||||||
script = ''
|
script =
|
||||||
|
let
|
||||||
|
extraDnsNames = lib.strings.concatStringsSep "\n" (map (n: "dns_name = ${n}") certCfg.extraDomains);
|
||||||
|
in
|
||||||
|
''
|
||||||
cd $RUNTIME_DIRECTORY
|
cd $RUNTIME_DIRECTORY
|
||||||
|
|
||||||
# server cert template
|
# server cert template
|
||||||
|
@ -287,6 +319,7 @@ in
|
||||||
cn = "${certCfg.domain}"
|
cn = "${certCfg.domain}"
|
||||||
expiration_days = 30
|
expiration_days = 30
|
||||||
dns_name = "${certCfg.domain}"
|
dns_name = "${certCfg.domain}"
|
||||||
|
${extraDnsNames}
|
||||||
encryption_key
|
encryption_key
|
||||||
signing_key
|
signing_key
|
||||||
EOF
|
EOF
|
||||||
|
@ -327,7 +360,7 @@ in
|
||||||
|
|
||||||
security.acme.certs = lib.mkMerge (lib.mapAttrsToList (name: certCfg: {
|
security.acme.certs = lib.mkMerge (lib.mapAttrsToList (name: certCfg: {
|
||||||
"${name}" = {
|
"${name}" = {
|
||||||
extraDomainNames = [ certCfg.domain ];
|
extraDomainNames = [ certCfg.domain ] ++ certCfg.extraDomains;
|
||||||
email = certCfg.adminEmail;
|
email = certCfg.adminEmail;
|
||||||
inherit (certCfg) dnsProvider dnsResolver;
|
inherit (certCfg) dnsProvider dnsResolver;
|
||||||
credentialsFile = certCfg.credentialsFile;
|
credentialsFile = certCfg.credentialsFile;
|
||||||
|
|
|
@ -28,33 +28,45 @@
|
||||||
|
|
||||||
domain = "subdomain.example.com";
|
domain = "subdomain.example.com";
|
||||||
};
|
};
|
||||||
|
multi = {
|
||||||
|
ca = config.shb.certs.cas.selfsigned.myca;
|
||||||
|
|
||||||
|
domain = "multi1.example.com";
|
||||||
|
extraDomains = [ "multi2.example.com" "multi3.example.com" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# The configuration below is to create a webserver that uses the server certificate.
|
# The configuration below is to create a webserver that uses the server certificate.
|
||||||
networking.hosts."127.0.0.1" = [ "example.com" "subdomain.example.com" "wrong.example.com" ];
|
networking.hosts."127.0.0.1" = [
|
||||||
|
"example.com"
|
||||||
|
"subdomain.example.com"
|
||||||
|
"wrong.example.com"
|
||||||
|
"multi1.example.com"
|
||||||
|
"multi2.example.com"
|
||||||
|
"multi3.example.com"
|
||||||
|
];
|
||||||
|
|
||||||
services.nginx.enable = true;
|
services.nginx.enable = true;
|
||||||
services.nginx.virtualHosts."example.com" =
|
services.nginx.virtualHosts =
|
||||||
{
|
let
|
||||||
onlySSL = true;
|
mkVirtualHost = response: cert: {
|
||||||
sslCertificate = config.shb.certs.certs.selfsigned.top.paths.cert;
|
onlySSL = true;
|
||||||
sslCertificateKey = config.shb.certs.certs.selfsigned.top.paths.key;
|
sslCertificate = cert.paths.cert;
|
||||||
locations."/".extraConfig = ''
|
sslCertificateKey = cert.paths.key;
|
||||||
add_header Content-Type text/plain;
|
locations."/".extraConfig = ''
|
||||||
return 200 'Top domain';
|
add_header Content-Type text/plain;
|
||||||
'';
|
return 200 '${response}';
|
||||||
};
|
'';
|
||||||
services.nginx.virtualHosts."subdomain.example.com" =
|
};
|
||||||
{
|
in
|
||||||
onlySSL = true;
|
{
|
||||||
sslCertificate = config.shb.certs.certs.selfsigned.subdomain.paths.cert;
|
"example.com" = mkVirtualHost "Top domain" config.shb.certs.certs.selfsigned.top;
|
||||||
sslCertificateKey = config.shb.certs.certs.selfsigned.subdomain.paths.key;
|
"subdomain.example.com" = mkVirtualHost "Subdomain" config.shb.certs.certs.selfsigned.subdomain;
|
||||||
locations."/".extraConfig = ''
|
"multi1.example.com" = mkVirtualHost "multi1" config.shb.certs.certs.selfsigned.multi;
|
||||||
add_header Content-Type text/plain;
|
"multi2.example.com" = mkVirtualHost "multi2" config.shb.certs.certs.selfsigned.multi;
|
||||||
return 200 'Subdomain';
|
"multi3.example.com" = mkVirtualHost "multi3" config.shb.certs.certs.selfsigned.multi;
|
||||||
'';
|
};
|
||||||
};
|
|
||||||
systemd.services.nginx = {
|
systemd.services.nginx = {
|
||||||
after = [ config.shb.certs.certs.selfsigned.top.systemdService config.shb.certs.certs.selfsigned.subdomain.systemdService ];
|
after = [ config.shb.certs.certs.selfsigned.top.systemdService config.shb.certs.certs.selfsigned.subdomain.systemdService ];
|
||||||
requires = [ config.shb.certs.certs.selfsigned.top.systemdService config.shb.certs.certs.selfsigned.subdomain.systemdService ];
|
requires = [ config.shb.certs.certs.selfsigned.top.systemdService config.shb.certs.certs.selfsigned.subdomain.systemdService ];
|
||||||
|
@ -68,6 +80,7 @@
|
||||||
myotherca = nodes.server.shb.certs.cas.selfsigned.myotherca;
|
myotherca = nodes.server.shb.certs.cas.selfsigned.myotherca;
|
||||||
top = nodes.server.shb.certs.certs.selfsigned.top;
|
top = nodes.server.shb.certs.certs.selfsigned.top;
|
||||||
subdomain = nodes.server.shb.certs.certs.selfsigned.subdomain;
|
subdomain = nodes.server.shb.certs.certs.selfsigned.subdomain;
|
||||||
|
multi = nodes.server.shb.certs.certs.selfsigned.multi;
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
start_all()
|
start_all()
|
||||||
|
@ -81,27 +94,40 @@
|
||||||
server.wait_for_file("${top.paths.cert}")
|
server.wait_for_file("${top.paths.cert}")
|
||||||
server.wait_for_file("${subdomain.paths.key}")
|
server.wait_for_file("${subdomain.paths.key}")
|
||||||
server.wait_for_file("${subdomain.paths.cert}")
|
server.wait_for_file("${subdomain.paths.cert}")
|
||||||
|
server.wait_for_file("${multi.paths.key}")
|
||||||
|
server.wait_for_file("${multi.paths.cert}")
|
||||||
|
|
||||||
# Wait for jkkk
|
|
||||||
server.require_unit_state("${nodes.server.shb.certs.systemdService}", "inactive")
|
server.require_unit_state("${nodes.server.shb.certs.systemdService}", "inactive")
|
||||||
|
|
||||||
machine.wait_for_unit("nginx")
|
server.wait_for_unit("nginx")
|
||||||
machine.wait_for_open_port(443)
|
server.wait_for_open_port(443)
|
||||||
|
|
||||||
with subtest("Certificate is trusted in curl"):
|
with subtest("Certificate is trusted in curl"):
|
||||||
resp = machine.succeed("curl --fail-with-body -v https://example.com")
|
resp = server.succeed("curl --fail-with-body -v https://example.com")
|
||||||
if resp != "Top domain":
|
if resp != "Top domain":
|
||||||
raise Exception('Unexpected response, got: {}'.format(resp))
|
raise Exception('Unexpected response, got: {}'.format(resp))
|
||||||
|
|
||||||
resp = machine.succeed("curl --fail-with-body -v https://subdomain.example.com")
|
resp = server.succeed("curl --fail-with-body -v https://subdomain.example.com")
|
||||||
if resp != "Subdomain":
|
if resp != "Subdomain":
|
||||||
raise Exception('Unexpected response, got: {}'.format(resp))
|
raise Exception('Unexpected response, got: {}'.format(resp))
|
||||||
|
|
||||||
|
resp = server.succeed("curl --fail-with-body -v https://multi1.example.com")
|
||||||
|
if resp != "multi1":
|
||||||
|
raise Exception('Unexpected response, got: {}'.format(resp))
|
||||||
|
|
||||||
|
resp = server.succeed("curl --fail-with-body -v https://multi2.example.com")
|
||||||
|
if resp != "multi2":
|
||||||
|
raise Exception('Unexpected response, got: {}'.format(resp))
|
||||||
|
|
||||||
|
resp = server.succeed("curl --fail-with-body -v https://multi3.example.com")
|
||||||
|
if resp != "multi3":
|
||||||
|
raise Exception('Unexpected response, got: {}'.format(resp))
|
||||||
|
|
||||||
with subtest("Fail if certificate is not in CA bundle"):
|
with subtest("Fail if certificate is not in CA bundle"):
|
||||||
machine.fail("curl --cacert /etc/static/ssl/certs/ca-bundle.crt --fail-with-body -v https://example.com")
|
server.fail("curl --cacert /etc/static/ssl/certs/ca-bundle.crt --fail-with-body -v https://example.com")
|
||||||
machine.fail("curl --cacert /etc/static/ssl/certs/ca-bundle.crt --fail-with-body -v https://subdomain.example.com")
|
server.fail("curl --cacert /etc/static/ssl/certs/ca-bundle.crt --fail-with-body -v https://subdomain.example.com")
|
||||||
machine.fail("curl --cacert /etc/static/ssl/certs/ca-certificates.crt --fail-with-body -v https://example.com")
|
server.fail("curl --cacert /etc/static/ssl/certs/ca-certificates.crt --fail-with-body -v https://example.com")
|
||||||
machine.fail("curl --cacert /etc/static/ssl/certs/ca-certificates.crt --fail-with-body -v https://subdomain.example.com")
|
server.fail("curl --cacert /etc/static/ssl/certs/ca-certificates.crt --fail-with-body -v https://subdomain.example.com")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue