246 lines
8.0 KiB
Nix
246 lines
8.0 KiB
Nix
{ ... }:
|
|
{
|
|
_class = "clan.service";
|
|
manifest.name = "certificates";
|
|
manifest.description = "Sets up a certificates internal to your Clan";
|
|
manifest.categories = [ "Network" ];
|
|
manifest.readme = builtins.readFile ./README.md;
|
|
|
|
roles.ca = {
|
|
|
|
interface =
|
|
{ lib, ... }:
|
|
{
|
|
|
|
options.acmeEmail = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "none@none.tld";
|
|
description = ''
|
|
Email address for account creation and correspondence from the CA.
|
|
It is recommended to use the same email for all certs to avoid account
|
|
creation limits.
|
|
'';
|
|
};
|
|
|
|
options.tlds = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
description = "Top level domain for this CA. Certificates will be issued and trusted for *.<tld>";
|
|
};
|
|
|
|
options.expire = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
description = "When the certificate should expire.";
|
|
default = "8760h";
|
|
example = "8760h";
|
|
};
|
|
};
|
|
|
|
perInstance =
|
|
{ settings, ... }:
|
|
{
|
|
nixosModule =
|
|
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}:
|
|
let
|
|
domains = map (tld: "ca.${tld}") settings.tlds;
|
|
in
|
|
{
|
|
security.acme.defaults.email = settings.acmeEmail;
|
|
security.acme = {
|
|
certs = builtins.listToAttrs (
|
|
map (domain: {
|
|
name = domain;
|
|
value = {
|
|
server = "https://${domain}:1443/acme/acme/directory";
|
|
};
|
|
}) domains
|
|
);
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = [
|
|
80
|
|
443
|
|
];
|
|
|
|
services.nginx = {
|
|
enable = true;
|
|
recommendedProxySettings = true;
|
|
virtualHosts = builtins.listToAttrs (
|
|
map (domain: {
|
|
name = domain;
|
|
value = {
|
|
addSSL = true;
|
|
enableACME = true;
|
|
locations."/".proxyPass = "https://localhost:1443";
|
|
locations."= /ca.crt".alias =
|
|
config.clan.core.vars.generators.step-intermediate-cert.files."intermediate.crt".path;
|
|
};
|
|
}) domains
|
|
);
|
|
};
|
|
|
|
clan.core.vars.generators = {
|
|
|
|
# Intermediate key generator
|
|
"step-intermediate-key" = {
|
|
files."intermediate.key" = {
|
|
secret = true;
|
|
deploy = true;
|
|
owner = "step-ca";
|
|
group = "step-ca";
|
|
};
|
|
runtimeInputs = [ pkgs.step-cli ];
|
|
script = ''
|
|
step crypto keypair --kty EC --curve P-256 --no-password --insecure $out/intermediate.pub $out/intermediate.key
|
|
'';
|
|
};
|
|
|
|
# Intermediate certificate generator
|
|
"step-intermediate-cert" = {
|
|
files."intermediate.crt".secret = false;
|
|
dependencies = [
|
|
"step-ca"
|
|
"step-intermediate-key"
|
|
];
|
|
runtimeInputs = [ pkgs.step-cli ];
|
|
script = ''
|
|
# Create intermediate certificate
|
|
step certificate create \
|
|
--ca $in/step-ca/ca.crt \
|
|
--ca-key $in/step-ca/ca.key \
|
|
--ca-password-file /dev/null \
|
|
--key $in/step-intermediate-key/intermediate.key \
|
|
--template ${pkgs.writeText "intermediate.tmpl" ''
|
|
{
|
|
"subject": {{ toJson .Subject }},
|
|
"keyUsage": ["certSign", "crlSign"],
|
|
"basicConstraints": {
|
|
"isCA": true,
|
|
"maxPathLen": 0
|
|
},
|
|
"nameConstraints": {
|
|
"critical": true,
|
|
"permittedDNSDomains": [${
|
|
(lib.strings.concatStringsSep "," (map (tld: ''"${tld}"'') settings.tlds))
|
|
}]
|
|
}
|
|
}
|
|
''} ${lib.optionalString (settings.expire != null) "--not-after ${settings.expire}"} \
|
|
--not-before=-12h \
|
|
--no-password --insecure \
|
|
"Clan Intermediate CA" \
|
|
$out/intermediate.crt
|
|
'';
|
|
};
|
|
};
|
|
|
|
services.step-ca = {
|
|
enable = true;
|
|
intermediatePasswordFile = "/dev/null";
|
|
address = "0.0.0.0";
|
|
port = 1443;
|
|
settings = {
|
|
root = config.clan.core.vars.generators.step-ca.files."ca.crt".path;
|
|
crt = config.clan.core.vars.generators.step-intermediate-cert.files."intermediate.crt".path;
|
|
key = config.clan.core.vars.generators.step-intermediate-key.files."intermediate.key".path;
|
|
dnsNames = domains;
|
|
logger.format = "text";
|
|
db = {
|
|
type = "badger";
|
|
dataSource = "/var/lib/step-ca/db";
|
|
};
|
|
authority = {
|
|
provisioners = [
|
|
{
|
|
type = "ACME";
|
|
name = "acme";
|
|
forceCN = true;
|
|
}
|
|
];
|
|
claims = {
|
|
maxTLSCertDuration = "2160h";
|
|
defaultTLSCertDuration = "2160h";
|
|
};
|
|
backdate = "1m0s";
|
|
};
|
|
tls = {
|
|
cipherSuites = [
|
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
|
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
|
];
|
|
minVersion = 1.2;
|
|
maxVersion = 1.3;
|
|
renegotiation = false;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
# Empty role, so we can add non-ca machins to the instance to trust the CA
|
|
roles.default = {
|
|
interface =
|
|
{ lib, ... }:
|
|
{
|
|
options.acmeEmail = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "none@none.tld";
|
|
description = ''
|
|
Email address for account creation and correspondence from the CA.
|
|
It is recommended to use the same email for all certs to avoid account
|
|
creation limits.
|
|
'';
|
|
};
|
|
};
|
|
|
|
perInstance =
|
|
{ settings, ... }:
|
|
{
|
|
nixosModule.security.acme.defaults.email = settings.acmeEmail;
|
|
};
|
|
};
|
|
|
|
# All machines (independent of role) will trust the CA
|
|
perMachine.nixosModule =
|
|
{ pkgs, config, ... }:
|
|
{
|
|
# Root CA generator
|
|
clan.core.vars.generators = {
|
|
"step-ca" = {
|
|
share = true;
|
|
files."ca.key" = {
|
|
secret = true;
|
|
deploy = false;
|
|
};
|
|
files."ca.crt".secret = false;
|
|
runtimeInputs = [ pkgs.step-cli ];
|
|
script = ''
|
|
step certificate create --template ${pkgs.writeText "root.tmpl" ''
|
|
{
|
|
"subject": {{ toJson .Subject }},
|
|
"issuer": {{ toJson .Subject }},
|
|
"keyUsage": ["certSign", "crlSign"],
|
|
"basicConstraints": {
|
|
"isCA": true,
|
|
"maxPathLen": 1
|
|
}
|
|
}
|
|
''} "Clan Root CA" $out/ca.crt $out/ca.key \
|
|
--kty EC --curve P-256 \
|
|
--not-after=8760h \
|
|
--not-before=-12h \
|
|
--no-password --insecure
|
|
'';
|
|
};
|
|
};
|
|
security.pki.certificateFiles = [ config.clan.core.vars.generators."step-ca".files."ca.crt".path ];
|
|
environment.systemPackages = [ pkgs.openssl ];
|
|
security.acme.acceptTerms = true;
|
|
};
|
|
}
|