Raito Bezarius
27e17b3f34
It's impossible to recover the path resource IDs from the Terraform resource IDs form. Let's just add the path component and do the right thing. Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
199 lines
7.8 KiB
Nix
199 lines
7.8 KiB
Nix
{ config, lib, ... }:
|
|
let
|
|
toplevelConfig = config;
|
|
inherit (lib) tf filterAttrs mapAttrs replaceChars addErrorContext concatMapAttrs mapAttrs';
|
|
# Create a Vault path for a certificate.
|
|
mkPath = { enableVersioning, name, version, certVersion, id }:
|
|
if enableVersioning then
|
|
"${id}/v${toString version}/${name}/v${toString certVersion}"
|
|
else
|
|
"${id}/unversioned/${name}";
|
|
mkCommonName = { enableVersioning, certVersion, prefix }:
|
|
if enableVersioning then
|
|
"${prefix} v${toString certVersion} "
|
|
else
|
|
"${prefix} unversioned ";
|
|
mkCsrCommonName = { parentConfig, chainVersion, enableVersioning, certVersion, prefix, name }:
|
|
if enableVersioning then
|
|
assert lib.assertMsg (parentConfig.enableVersioning) "Versioning requires all the chain to be versioned. You forgot to enable versioning on the parent of '${name}'!";
|
|
"${prefix} v${chainVersion}"
|
|
else
|
|
if parentConfig.enableVersioning then
|
|
"${prefix} v${toString parentConfig.chainVersion}.unversioned"
|
|
else
|
|
"${prefix} unversioned";
|
|
mkDescription = { enableVersioning, certVersion, version, name, displayName }:
|
|
if enableVersioning then
|
|
"PKI engine hosting v${toString version} ${name} v${toString certVersion} for ${displayName}"
|
|
else
|
|
"Unversioned PKI engine hosting ${name} for ${displayName}";
|
|
mkSignId = { parentConfig, enableVersioning, certVersion, resourceId }:
|
|
if enableVersioning then
|
|
"${resourceId}_by_${parentConfig.name}_v${toString certVersion}"
|
|
else
|
|
"${resourceId}_by_${parentConfig.name}_unversioned";
|
|
hour_in_secs = 1 * 60 * 60;
|
|
hour_in_days = 24;
|
|
day_in_secs = hour_in_days * hour_in_secs;
|
|
resourceIdAsPath = resourceId: replaceChars [ "_" ] [ "/" ] resourceId;
|
|
|
|
# Explore the subCA tree fragment and emit
|
|
bfs = f: parentCA: initialState:
|
|
let
|
|
immediateChildren = mapAttrs (name: _:
|
|
addErrorContext "while evaluating sub-CA configuration `${name}` in `${parentCA.name}`:"
|
|
(parentCA.subCA.${name} or { })
|
|
) parentCA.subCA;
|
|
in
|
|
concatMapAttrs (name: value:
|
|
let pairWithMore = f parentCA name value initialState;
|
|
in
|
|
(if builtins.length (builtins.attrValues pairWithMore.value) > 0 then { ${pairWithMore.name} = pairWithMore.value; } else { }) // bfs f value (pairWithMore.state or initialState))
|
|
(filterAttrs (_: subCA: subCA.enable) immediateChildren);
|
|
|
|
concatBfs = f: parentCA:
|
|
let
|
|
immediateChildren = mapAttrs (name: _:
|
|
addErrorContext "while evaluating sub-CA configuration `${name}` in `${parentCA.name}`:"
|
|
(parentCA.subCA.${name} or { })
|
|
) parentCA.subCA;
|
|
in
|
|
concatMapAttrs (name: value:
|
|
let attrs = f parentCA name value;
|
|
in
|
|
attrs // concatBfs f value)
|
|
(filterAttrs (_: subCA: subCA.enable) immediateChildren);
|
|
in
|
|
{
|
|
resource.vault_mount = bfs (parent: name: config: _:
|
|
{
|
|
name = "${toplevelConfig.infra.pki.org.id}_${config.partialResourceId}";
|
|
value = {
|
|
inherit (toplevelConfig.infra.pki) provider;
|
|
path = mkPath {
|
|
inherit (config) enableVersioning version certVersion name;
|
|
inherit (toplevelConfig.infra.pki.org) id;
|
|
};
|
|
type = "pki";
|
|
description = mkDescription {
|
|
inherit (config) enableVersioning version certVersion name;
|
|
displayName = config.cn;
|
|
};
|
|
default_lease_ttl_seconds = 1 * hour_in_secs;
|
|
max_lease_ttl_seconds = 365 * day_in_secs;
|
|
};
|
|
}) config.infra.pki.ica2 { };
|
|
|
|
resource.vault_pki_secret_backend_intermediate_cert_request = bfs (parentConfig: name: config: _:
|
|
let
|
|
resourceId = "${toplevelConfig.infra.pki.org.id}_${config.partialResourceId}";
|
|
in
|
|
{
|
|
name = resourceId;
|
|
value = {
|
|
inherit (toplevelConfig.infra.pki) provider;
|
|
depends_on = [ "vault_mount.${resourceId}" ];
|
|
backend = tf.ref "vault_mount.${resourceId}.path";
|
|
type = "internal";
|
|
common_name = mkCommonName {
|
|
inherit (config) enableVersioning certVersion;
|
|
prefix = config.cn;
|
|
};
|
|
key_type = config.keyType;
|
|
};
|
|
}) config.infra.pki.ica2 { };
|
|
|
|
resource.vault_pki_secret_backend_root_sign_intermediate = bfs (parentConfig: name: config: state:
|
|
let
|
|
parentResourceId = "${toplevelConfig.infra.pki.org.id}_${parentConfig.partialResourceId}";
|
|
resourceId = "${toplevelConfig.infra.pki.org.id}_${config.partialResourceId}";
|
|
chainVersion = "${toString config.certVersion}.${state.chainVersion}";
|
|
in
|
|
{
|
|
state = {
|
|
inherit chainVersion;
|
|
};
|
|
name = mkSignId {
|
|
inherit parentConfig resourceId;
|
|
inherit (config) enableVersioning certVersion;
|
|
};
|
|
value = {
|
|
inherit (toplevelConfig.infra.pki) provider;
|
|
depends_on = [
|
|
"vault_mount.${resourceId}"
|
|
"vault_pki_secret_backend_intermediate_cert_request.${resourceId}"
|
|
];
|
|
backend = tf.ref "vault_mount.${parentResourceId}.path";
|
|
csr = tf.ref "vault_pki_secret_backend_intermediate_cert_request.${resourceId}.csr";
|
|
common_name = mkCsrCommonName {
|
|
inherit parentConfig chainVersion;
|
|
inherit (config) enableVersioning certVersion name;
|
|
prefix = config.cn;
|
|
};
|
|
exclude_cn_from_sans = true;
|
|
inherit (toplevelConfig.infra.pki.org) ou organization country locality province;
|
|
max_path_length = config.extensions.pathlen;
|
|
ttl = config.expiry.days * day_in_secs;
|
|
};
|
|
}) config.infra.pki.ica2 {
|
|
chainVersion = "${toString config.infra.pki.ica2.certVersion}";
|
|
};
|
|
|
|
resource.vault_pki_secret_backend_intermediate_set_signed = bfs (parentConfig: name: config: _:
|
|
let
|
|
# We cannot inline it in the submodule as it depends `config.infra.pki.org.id`.
|
|
resourceId = "${toplevelConfig.infra.pki.org.id}_${config.partialResourceId}";
|
|
signId = mkSignId {
|
|
inherit parentConfig resourceId;
|
|
inherit (config) enableVersioning certVersion;
|
|
};
|
|
parentResourceId = "${toplevelConfig.infra.pki.org.id}_${parentConfig.partialResourceId}";
|
|
in
|
|
{
|
|
name = "${resourceId}_signed_cert";
|
|
value = {
|
|
inherit (toplevelConfig.infra.pki) provider;
|
|
|
|
# Here we wait upon the parent configuration to have its final chain ready.
|
|
# We wait for our own signature.
|
|
depends_on = [
|
|
"vault_pki_secret_backend_root_sign_intermediate.${signId}"
|
|
"vault_pki_secret_backend_intermediate_set_signed.${parentResourceId}_signed_cert"
|
|
];
|
|
backend = tf.ref "vault_mount.${resourceId}.path";
|
|
|
|
# The final chain is the concatenation of the previous chain plus our certificate.
|
|
certificate = ''
|
|
${tf.ref "vault_pki_secret_backend_root_sign_intermediate.${signId}.certificate"}
|
|
${tf.ref "vault_pki_secret_backend_intermediate_set_signed.${parentResourceId}_signed_cert.certificate"}
|
|
'';
|
|
};
|
|
}) config.infra.pki.ica2 { };
|
|
|
|
resource.vault_pki_secret_backend_role = concatBfs (parentConfig: name: config:
|
|
let
|
|
resourceId = "${toplevelConfig.infra.pki.org.id}_${config.partialResourceId}";
|
|
in
|
|
mapAttrs' (name: role:
|
|
{
|
|
name = "${resourceId}_${name}";
|
|
value = role // {
|
|
inherit (toplevelConfig.infra.pki) provider;
|
|
# Default issuer for this backend, i.e. the sub CA.
|
|
# TODO: make this the exact issuer ref we are using.
|
|
issuer_ref = "default";
|
|
backend = tf.ref "vault_mount.${resourceId}.path";
|
|
};
|
|
}
|
|
) config.roles) config.infra.pki.ica2;
|
|
|
|
# Generate the empty policy if there's nothing.
|
|
infra.vault.policies = concatBfs (parentConfig: name: config:
|
|
mapAttrs (name: value:
|
|
mapAttrs' (rulePath: value: {
|
|
name = "${toplevelConfig.infra.pki.org.id}/${config.partialResourceIdPath}/${rulePath}";
|
|
inherit value;
|
|
}) value
|
|
) config.policies)
|
|
config.infra.pki.ica2;
|
|
}
|