dotfiles/terranix/main/modules/nomad_server.nix

263 lines
7.7 KiB
Nix
Raw Normal View History

{
config,
pkgs,
lib,
tflib,
...
}: let
cfg = config.prefab.nomadServer;
inherit
(lib)
mapAttrsToList
foldAttrs
mergeAttrs
fix
flip
mkOption
types
optionalString
optionalAttrs
mkMerge
;
inherit
((a: builtins.break a) tflib)
tf
;
submoduleOptions = {
datacenters = mkOption {
description = ''
'';
type = with types; listOf str;
};
encryptionKey = mkOption {
description = ''
DO NOT hardcode the secret in Nix, generate it with Terraform
and let Terraform substitute it.
'';
type = types.str;
};
paths = {
encryptionKey = mkOption {
description = ''
'';
type = types.str;
};
replicationToken = mkOption {
description = ''
'';
type = with types; nullOr str;
default = null;
};
vaultToken = mkOption {
description = ''
'';
type = types.str;
};
consulToken = mkOption {
description = ''
'';
type = types.str;
};
};
vaultKvMount = mkOption {
description = ''
'';
type = types.str;
};
};
in {
options.prefab.nomadServer = mkOption {
description = ''
'';
type = with types; attrsOf (submodule {options = submoduleOptions;});
default = {};
};
config.resource =
mkMerge
(flip mapAttrsToList cfg (hostname: value:
fix (self: {
"vault_policy"."${hostname}_nomad" = {
name = "${hostname}-nomad-server-agent";
policy = ''
path "${value.vaultKvMount}/data/${value.paths.encryptionKey}" {
capabilities = ["read"]
}
path "${value.vaultKvMount}/data/${value.paths.vaultToken}" {
capabilities = ["read"]
}
path "${value.vaultKvMount}/data/${value.paths.consulToken}" {
capabilities = ["read"]
}
${optionalString (value.paths.replicationToken != null) ''
path "${value.vaultKvMount}/data/${value.paths.replicationToken}" {
capabilities = ["read"]
}
''}
'';
};
"vault_kv_secret_v2"."${hostname}_nomad_encryption_key" = {
mount = value.vaultKvMount;
name = value.paths.encryptionKey;
delete_all_versions = true;
data_json = builtins.toJSON {
key = value.encryptionKey;
};
};
"consul_acl_policy"."${hostname}_nomad_server" = {
name = "${hostname}_nomad_server";
rules = ''
agent_prefix "" {
policy = "read"
}
node_prefix "" {
policy = "read"
}
service_prefix "" {
policy = "write"
}
acl = "write"
'';
};
"consul_acl_token"."${hostname}_nomad_server" = {
description = "Consul token for nomad_server on ${hostname}";
policies = [
(tf "consul_acl_policy.${hostname}_nomad_server.name")
];
local = false;
};
"vault_kv_secret_v2"."${hostname}_nomad_server_consul" = {
mount = value.vaultKvMount;
name = value.paths.consulToken;
delete_all_versions = true;
data_json = builtins.toJSON {
secret = tf "data.consul_acl_token_secret_id.${hostname}_nomad_server.secret_id";
accessor = tf "consul_acl_token.${hostname}_nomad_server.accessor_id";
};
};
"vault_policy"."${hostname}_nomad_server" = {
name = "${hostname}-nomad-server";
policy = ''
# Allow creating tokens under "nomad-cluster" token role. The token role name
# should be updated if "nomad-cluster" is not used.
path "auth/token/create/nomad-cluster" {
capabilities = ["update"]
}
# Allow looking up "nomad-cluster" token role. The token role name should be
# updated if "nomad-cluster" is not used.
path "auth/token/roles/nomad-cluster" {
capabilities = ["read"]
}
# Allow looking up the token passed to Nomad to validate the token has the
# proper capabilities. This is provided by the "default" policy.
path "auth/token/lookup-self" {
capabilities = ["read"]
}
# Allow looking up incoming tokens to validate they have permissions to access
# the tokens they are requesting. This is only required if
# `allow_unauthenticated` is set to false.
path "auth/token/lookup" {
capabilities = ["update"]
}
# Allow revoking tokens that should no longer exist. This allows revoking
# tokens for dead tasks.
path "auth/token/revoke-accessor" {
capabilities = ["update"]
}
# Allow checking the capabilities of our own token. This is used to validate the
# token upon startup. Note this requires update permissions because the Vault API
# is a POST
path "sys/capabilities-self" {
capabilities = ["update"]
}
# Allow our own token to be renewed.
path "auth/token/renew-self" {
capabilities = ["update"]
}
'';
};
"vault_token_auth_backend_role"."${hostname}_nomad_server" = {
role_name = "${hostname}_nomad_server";
allowed_policies = [
(tf "vault_policy.${hostname}_nomad_server.name")
];
orphan = true;
renewable = true;
};
"vault_token"."${hostname}_nomad_server" = {
policies = [
(tf "vault_policy.${hostname}_nomad_server.name")
];
renewable = true;
ttl = "24h";
explicit_max_ttl = 0;
role_name = tf "vault_token_auth_backend_role.${hostname}_nomad_server.role_name";
display_name = "${hostname}-nomad-server-Vault-token";
};
"vault_kv_secret_v2"."${hostname}_nomad_server_vault" = {
mount = value.vaultKvMount;
name = value.paths.vaultToken;
delete_all_versions = true;
data_json = builtins.toJSON {
secret = tf "vault_token.${hostname}_nomad_server.client_token";
};
};
}))
++ (flip mapAttrsToList cfg (
hostname: value: (
optionalAttrs (value.paths.replicationToken != null)
{
"nomad_acl_token"."${hostname}_replication" = {
name = "${hostname} replication token";
type = "management";
};
"vault_kv_secret_v2"."${hostname}_nomad_replication" = {
mount = value.vaultKvMount;
name = value.paths.replicationToken;
delete_all_versions = true;
data_json = builtins.toJSON {
secret = tf "nomad_acl_token.${hostname}_replication.secret_id";
accessor = tf "nomad_acl_token.${hostname}_replication.id";
};
};
}
)
)));
config.data =
mkMerge
(flip mapAttrsToList cfg (hostname: value: {
"consul_acl_token_secret_id"."${hostname}_nomad_server" = {
accessor_id = tf "consul_acl_token.${hostname}_nomad_server.id";
};
}));
}