nixos/taskserver: Allow to specify expiration/bits

At least this should allow for some customisation of how the
certificates and keys are created. We now have two sub-namespaces within
PKI so it should be more clear which options you have to set if you want
to either manage your own CA or let the module create it automatically.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
This commit is contained in:
aszlig 2016-04-12 04:14:33 +02:00
parent a41b109bc1
commit 9f1e536948
No known key found for this signature in database
GPG key ID: D0EBD0EC8C2DC961
2 changed files with 63 additions and 14 deletions

View file

@ -17,7 +17,7 @@ let
result = "${key} = ${mkVal val}"; result = "${key} = ${mkVal val}";
in optionalString (val != null && val != []) result; in optionalString (val != null && val != []) result;
mkPkiOption = desc: mkOption { mkManualPkiOption = desc: mkOption {
type = types.nullOr types.path; type = types.nullOr types.path;
default = null; default = null;
description = desc + '' description = desc + ''
@ -27,24 +27,60 @@ let
''; '';
}; };
pkiOptions = { manualPkiOptions = {
ca.cert = mkPkiOption '' ca.cert = mkManualPkiOption ''
Fully qualified path to the CA certificate. Fully qualified path to the CA certificate.
''; '';
server.cert = mkPkiOption '' server.cert = mkManualPkiOption ''
Fully qualified path to the server certificate. Fully qualified path to the server certificate.
''; '';
server.crl = mkPkiOption '' server.crl = mkManualPkiOption ''
Fully qualified path to the server certificate revocation list. Fully qualified path to the server certificate revocation list.
''; '';
server.key = mkPkiOption '' server.key = mkManualPkiOption ''
Fully qualified path to the server key. Fully qualified path to the server key.
''; '';
}; };
mkAutoDesc = preamble: ''
${preamble}
<note><para>
This option is for the automatically handled CA and will be ignored if any
of the <option>services.taskserver.pki.manual.*</option> options are set.
</para></note>
'';
mkExpireOption = desc: mkOption {
type = types.nullOr types.int;
default = null;
example = 365;
apply = val: if isNull val then -1 else val;
description = mkAutoDesc ''
The expiration time of ${desc} in days or <literal>null</literal> for no
expiration time.
'';
};
autoPkiOptions = {
bits = mkOption {
type = types.int;
default = 4096;
example = 2048;
description = mkAutoDesc "The bit size for generated keys.";
};
expiration = {
ca = mkExpireOption "the CA certificate";
server = mkExpireOption "the server certificate";
client = mkExpireOption "client certificates";
crl = mkExpireOption "the certificate revocation list (CRL)";
};
};
needToCreateCA = let needToCreateCA = let
notFound = path: let notFound = path: let
dotted = concatStringsSep "." path; dotted = concatStringsSep "." path;
@ -53,10 +89,10 @@ let
mkSublist = key: val: let mkSublist = key: val: let
newPath = path ++ singleton key; newPath = path ++ singleton key;
in if isOption val in if isOption val
then attrByPath newPath (notFound newPath) cfg.pki then attrByPath newPath (notFound newPath) cfg.pki.manual
else findPkiDefinitions newPath val; else findPkiDefinitions newPath val;
in flatten (mapAttrsToList mkSublist attrs); in flatten (mapAttrsToList mkSublist attrs);
in all isNull (findPkiDefinitions [] pkiOptions); in all isNull (findPkiDefinitions [] manualPkiOptions);
configFile = pkgs.writeText "taskdrc" '' configFile = pkgs.writeText "taskdrc" ''
# systemd related # systemd related
@ -130,6 +166,9 @@ let
src = ./helper-tool.py; src = ./helper-tool.py;
inherit taskd certtool; inherit taskd certtool;
inherit (cfg) dataDir user group fqdn; inherit (cfg) dataDir user group fqdn;
certBits = cfg.pki.auto.bits;
clientExpiration = cfg.pki.auto.expiration.client;
crlExpiration = cfg.pki.auto.expiration.crl;
}}" > "$out/main.py" }}" > "$out/main.py"
cat > "$out/setup.py" <<EOF cat > "$out/setup.py" <<EOF
from setuptools import setup from setuptools import setup
@ -322,7 +361,8 @@ in {
''; '';
}; };
pki = pkiOptions; pki.manual = manualPkiOptions;
pki.auto = autoPkiOptions;
}; };
}; };
@ -364,11 +404,12 @@ in {
if [ ! -e "${cfg.dataDir}/keys/ca.key" ]; then if [ ! -e "${cfg.dataDir}/keys/ca.key" ]; then
silent_certtool -p \ silent_certtool -p \
--bits 2048 \ --bits ${toString cfg.pki.auto.bits} \
--outfile "${cfg.dataDir}/keys/ca.key" --outfile "${cfg.dataDir}/keys/ca.key"
silent_certtool -s \ silent_certtool -s \
--template "${pkgs.writeText "taskserver-ca.template" '' --template "${pkgs.writeText "taskserver-ca.template" ''
cn = ${cfg.fqdn} cn = ${cfg.fqdn}
expiration_days = ${toString cfg.pki.auto.expiration.ca}
cert_signing_key cert_signing_key
ca ca
''}" \ ''}" \
@ -381,12 +422,13 @@ in {
if [ ! -e "${cfg.dataDir}/keys/server.key" ]; then if [ ! -e "${cfg.dataDir}/keys/server.key" ]; then
silent_certtool -p \ silent_certtool -p \
--bits 2048 \ --bits ${toString cfg.pki.auto.bits} \
--outfile "${cfg.dataDir}/keys/server.key" --outfile "${cfg.dataDir}/keys/server.key"
silent_certtool -c \ silent_certtool -c \
--template "${pkgs.writeText "taskserver-cert.template" '' --template "${pkgs.writeText "taskserver-cert.template" ''
cn = ${cfg.fqdn} cn = ${cfg.fqdn}
expiration_days = ${toString cfg.pki.auto.expiration.server}
tls_www_server tls_www_server
encryption_key encryption_key
signing_key signing_key
@ -408,7 +450,7 @@ in {
if [ ! -e "${cfg.dataDir}/keys/server.crl" ]; then if [ ! -e "${cfg.dataDir}/keys/server.crl" ]; then
silent_certtool --generate-crl \ silent_certtool --generate-crl \
--template "${pkgs.writeText "taskserver-crl.template" '' --template "${pkgs.writeText "taskserver-crl.template" ''
expiration_days = 3650 expiration_days = ${toString cfg.pki.auto.expiration.crl}
''}" \ ''}" \
--load-ca-privkey "${cfg.dataDir}/keys/ca.key" \ --load-ca-privkey "${cfg.dataDir}/keys/ca.key" \
--load-ca-certificate "${cfg.dataDir}/keys/ca.cert" \ --load-ca-certificate "${cfg.dataDir}/keys/ca.cert" \

View file

@ -14,6 +14,10 @@ from tempfile import NamedTemporaryFile
import click import click
CERTTOOL_COMMAND = "@certtool@" CERTTOOL_COMMAND = "@certtool@"
CERT_BITS = "@certBits@"
CLIENT_EXPIRATION = "@clientExpiration@"
CRL_EXPIRATION = "@crlExpiration@"
TASKD_COMMAND = "@taskd@" TASKD_COMMAND = "@taskd@"
TASKD_DATA_DIR = "@dataDir@" TASKD_DATA_DIR = "@dataDir@"
TASKD_USER = "@user@" TASKD_USER = "@user@"
@ -153,11 +157,12 @@ def generate_key(org, user):
try: try:
os.makedirs(basedir, mode=0700) os.makedirs(basedir, mode=0700)
certtool_cmd("-p", "--bits", "2048", "--outfile", privkey) certtool_cmd("-p", "--bits", CERT_BITS, "--outfile", privkey)
template_data = [ template_data = [
"organization = {0}".format(org), "organization = {0}".format(org),
"cn = {}".format(FQDN), "cn = {}".format(FQDN),
"expiration_days = {}".format(CLIENT_EXPIRATION),
"tls_www_client", "tls_www_client",
"encryption_key", "encryption_key",
"signing_key" "signing_key"
@ -188,7 +193,9 @@ def revoke_key(org, user):
pubcert = os.path.join(basedir, "public.cert") pubcert = os.path.join(basedir, "public.cert")
with create_template(["expiration_days = 3650"]) as template: expiration = "expiration_days = {}".format(CRL_EXPIRATION)
with create_template([expiration]) as template:
oldcrl = NamedTemporaryFile(mode="wb", prefix="old-crl") oldcrl = NamedTemporaryFile(mode="wb", prefix="old-crl")
oldcrl.write(open(crl, "rb").read()) oldcrl.write(open(crl, "rb").read())
oldcrl.flush() oldcrl.flush()