Base terranix configuration

Signed-off-by: Magic_RB <magic_rb@redalder.org>
This commit is contained in:
Magic_RB 2023-06-15 23:04:14 +02:00
parent fd68d0e485
commit 9b1c305c3b
15 changed files with 1179 additions and 3 deletions

2
.gitignore vendored
View file

@ -7,6 +7,6 @@
result result
result-* result-*
/.terraform/

44
.terraform.lock.hcl Normal file
View file

@ -0,0 +1,44 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/consul" {
version = "2.17.0"
hashes = [
"h1:tiKb9pAW5/dl1Y0HUeUdl+/leNQpaPXwpnbo1AJPR6k=",
]
}
provider "registry.terraform.io/hashicorp/nomad" {
version = "1.4.20"
hashes = [
"h1:SCMAWGssM1bSbLNlrS8GdZuJ4MWpb3X4AXO/jLDYfXA=",
]
}
provider "registry.terraform.io/hashicorp/null" {
version = "3.2.1"
hashes = [
"h1:tXn3DUW3RQLZERTKY85/iMGh1MYpp8ZK9dKJDExY888=",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "3.5.1"
hashes = [
"h1:8ccmyrDBWfKr/qY7gQoAriinamltIC/LLvz53ar4a4k=",
]
}
provider "registry.terraform.io/hashicorp/vault" {
version = "3.15.2"
hashes = [
"h1:uiBosZpSRpOArbzoiKpqhwp0bmf6vUA1kYJOgerydaw=",
]
}
provider "registry.terraform.io/magicrb/influxdb-v2" {
version = "0.4.6"
hashes = [
"h1:0atGQr/mtBBm6IsHdZ+r+9H2rCCfzI/ZMYrPNsAkzNU=",
]
}

View file

@ -878,8 +878,8 @@
"terranix": "terranix" "terranix": "terranix"
}, },
"locked": { "locked": {
"lastModified": 1680122738, "lastModified": 1686862391,
"narHash": "sha256-Dvb6ZpRSPt5G6VkHzNOqCNRyHD7J9AdFYgPfHEHi7BU=", "narHash": "sha256-U7q2iwNNdB0A7GHyLjNYLWluOVJO+K0LtiOV0Y3/vuY=",
"path": "/home/main/uterranix", "path": "/home/main/uterranix",
"type": "path" "type": "path"
}, },

View file

@ -79,8 +79,39 @@
overlays/terraform-provider-vault.nix overlays/terraform-provider-vault.nix
overlays/terraform-provider-influxdb-v2.nix overlays/terraform-provider-influxdb-v2.nix
overlays/bootloadHID.nix overlays/bootloadHID.nix
inputs.uterranix.flakeModule
]; ];
uterranix.config = [
./terranix/default.nix
{
_module.args.vars = {
flake_rev = self.rev or null;
flake_sha = self.sha or null;
flake_ref = self.ref or null;
flake_host = "git+https://git.sr.ht/~magic_rb/cluster";
};
}
];
uterranix.terraform = pkgs:
let
hpkgs = inputs.nixpkgs.legacyPackages.${pkgs.stdenv.system}.appendOverlays (with config.flake.overlays; [
terraform-provider-vault
terraform-provider-influxdb-v2
]);
in
hpkgs.terraform.withPlugins (p: [
p.consul
p.nomad
p.local
p.vault
p.random
p.null
p.influxdb-v2
] );
flake.nixosModules = { flake.nixosModules = {
hashicorp = nixos/modules/hashicorp.nix; hashicorp = nixos/modules/hashicorp.nix;
hashicorp-envoy = nixos/modules/hashicorp-envoy.nix; hashicorp-envoy = nixos/modules/hashicorp-envoy.nix;

105
terranix/blowhole.nix Normal file
View file

@ -0,0 +1,105 @@
{ tflib, config, secret, ... }:
let
inherit (tflib)
tf;
paths.consul = {
encryption_key = "homelab-1/blowhole/consul/encryption_key";
agent_token = "homelab-1/blowhole/consul/agent_token";
anonymous_token = "homelab-1/blowhole/consul/anonymous_token";
};
paths.nomad = {
encryption_key = "homelab-1/blowhole/nomad/encryption_key";
vault_token = "homelab-1/blowhole/nomad/vault_token";
consul_token = "homelab-1/blowhole/nomad/consul_token";
};
vaultKvMount = config.resource."vault_mount"."kv".path;
vaultConsulMount = config.resource."vault_consul_secret_backend"."consul".path;
in
{
prefab.consulAgent."blowhole" = {
datacenter = "homelab-1";
inherit vaultKvMount;
paths = {
encryptionKey = paths.consul.encryption_key;
agentToken = paths.consul.agent_token;
anonymousToken = paths.consul.anonymous_token;
};
encryptionKey = tf "random_id.homelab-1_consul_encryption_key.b64_std";
anonymousToken = {
secret = tf "data.consul_acl_token_secret_id.anonymous.secret_id";
accessor = tf "consul_acl_token.anonymous.id";
};
};
prefab.nomadServer."blowhole" = {
datacenters = [ "homelab-1" ];
inherit vaultKvMount;
encryptionKey = tf "random_id.nomad_encryption_key.b64_std";
paths = {
encryptionKey = paths.nomad.encryption_key;
vaultToken = paths.nomad.vault_token;
consulToken = paths.nomad.consul_token;
};
};
resource."vault_policy"."vault-agent-blowhole" = {
name = "blowhole-id_ed_camera";
policy = ''
path "${vaultKvMount}/data/homelab-1/blowhole/id_ed_camera" {
capabilities = ["read"]
}
path "${vaultKvMount}/data/homelab-1/blowhole/hostapd/wpa_psk" {
capabilities = ["read"]
}
path "${vaultConsulMount}/creds/${tf "module.blowhole.envoy_grafana.name"}" {
capabilities = ["read"]
}
path "${vaultConsulMount}/creds/${tf "module.blowhole.envoy_blowhole.name"}" {
capabilities = ["read"]
}
path "${vaultConsulMount}/creds/${tf "module.blowhole.envoy_klipper.name"}" {
capabilities = ["read"]
}
path "${vaultKvMount}/data/homelab-1/blowhole/monitor/telegraf" {
capabilities = ["read"]
}
path "${vaultKvMount}/data/homelab-1/blowhole/monitor/grafana" {
capabilities = ["read"]
}
'';
};
prefab.pushApproles."blowhole" = {
host = secret.network.ips.blowhole.ip or "";
user = "main";
policies = [
config.resource."vault_policy"."blowhole_consul".name
config.resource."vault_policy"."blowhole_nomad".name
config.resource."vault_policy"."pki_inra_update".name
config.resource."vault_policy"."vault-agent-blowhole".name
];
metadata = {
"ip_address" = "blowhole.in.redalder.org";
};
approlePath = tf "vault_auth_backend.approle.path";
};
}

203
terranix/default.nix Normal file
View file

@ -0,0 +1,203 @@
{ config, elib, tflib, lib, pkgs, ... }:
let
paths.toothpick.consul = {
encryption_key = "do-1/toothpick/consul/encryption_key";
agent_token = "do-1/toothpick/consul/agent_token";
anonymous_token = "do-1/toothpick/consul/anonymous_token";
replication_token = "do-1/toothpick/consul/replication_token";
};
paths.toothpick.nomad = {
encryption_key = "do-1/toothpick/nomad/encryption_key";
vault_token = "do-1/toothpick/nomad/vault_token";
consul_token = "do-1/toothpick/nomad/consul_token";
replication_token = "do-1/toothpick/nomad/replication_token";
};
inherit (tflib)
tf
;
inherit (lib)
singleton
;
in
{
provider."vault" = {
address = "https://vault.in.redalder.org:8200";
};
provider."consul" = {
address = "http://consul.in.redalder.org:8500";
};
provider."nomad" = {
address = "http://nomad.in.redalder.org:4646";
};
provider."influxdb-v2" = {
url = "http://influx.in.redalder.org";
};
module."syncthing" = elib.terraformModule {
name = "syncthing";
source = ./containers/syncthing;
};
module."website" = elib.terraformModule {
name = "website";
source = ./containers/website;
};
module."hydra" = elib.terraformModule {
name = "hydra";
source = ./containers/hydra;
};
module."matrix" = elib.terraformModule {
name = "matrix";
source = ./containers/matrix;
};
module."jellyfin" = elib.terraformModule {
name = "jellyfin";
source = ./containers/jellyfin;
};
module."gitea" = elib.terraformModule {
name = "gitea";
source = ./containers/gitea;
};
module."home-assistant" = elib.terraformModule {
name = "home-assistant";
source = ./containers/home-assistant;
};
module."ingress-blowhole" = elib.terraformModule {
name = "ingress-blowhole";
source = ./containers/ingress-blowhole;
};
module."ingress-toothpick" = elib.terraformModule {
name = "ingress-toothpick";
source = ./containers/ingress-toothpick;
};
module."gateway-mesh" = elib.terraformModule {
name = "gateway-mesh";
source = ./containers/gateway-mesh;
};
module."nfs-csi" = elib.terraformModule {
name = "nfs-csi";
source = ./containers/nfs-csi;
};
imports = [
./lib
./modules/push_approles.nix
./modules/consul_agent.nix
./modules/nomad_server.nix
./pki.nix
./blowhole.nix
./toothpick.nix
];
terraform.backend."consul" = {
address = "consul.in.redalder.org:8500";
scheme = "http";
path = "terraform/dotfiles";
};
terraform.required_providers = {
influxdb-v2 = {
source = "MagicRB/influxdb-v2";
};
};
resource."vault_auth_backend"."approle" = {
type = "approle";
tune = singleton {
max_lease_ttl = "90000s";
listing_visibility = "unauth";
allowed_response_headers = null;
audit_non_hmac_request_keys = null;
audit_non_hmac_response_keys = null;
default_lease_ttl = null;
passthrough_request_headers = null;
token_type = null;
};
};
resource."vault_mount"."kv" = {
path = "kv";
type = "kv";
options.version = "2";
description = "KV Version 2 secret engine mount";
};
resource."vault_kv_secret_backend_v2"."config" = {
mount = config.resource."vault_mount"."kv".path;
max_versions = 5;
};
resource."consul_acl_token"."vault_management_token" = {
description = "Vault management token";
policies = ["global-management"];
local = false;
};
data."consul_acl_token_secret_id"."vault_management_token" = {
accessor_id = tf "consul_acl_token.vault_management_token.id";
};
resource."vault_consul_secret_backend"."consul" = {
path = "consul";
description = "Manages the Consul backend";
address = "consul.in.redalder.org:8500";
token = tf "data.consul_acl_token_secret_id.vault_management_token.secret_id";
};
resource."vault_token_auth_backend_role"."nomad_cluster" = {
role_name = "nomad-cluster";
disallowed_policies = ["nomad-server"];
orphan = true;
token_period = "259200";
renewable = true;
token_explicit_max_ttl = "0";
};
resource."random_id"."nomad_encryption_key" = {
byte_length = 32;
};
resource."random_id"."homelab-1_consul_encryption_key" = {
byte_length = 32;
};
resource."random_id"."do-1_consul_encryption_key" = {
byte_length = 32;
};
resource."consul_acl_policy"."anonymous" = {
name = "consul-anonymous";
rules = ''
service_prefix "" { policy = "read" }
node_prefix "" { policy = "read" }
'';
};
resource."consul_acl_token"."anonymous" = {
description = "Consul anonymous token";
policies = [
config.resource.consul_acl_policy.anonymous.name
];
local = false;
};
data."consul_acl_token_secret_id"."anonymous" = {
accessor_id = tf "consul_acl_token.anonymous.id";
};
}

18
terranix/lib/default.nix Normal file
View file

@ -0,0 +1,18 @@
{ elib, lib, pkgs, tflib, config, ... }:
let
inherit (lib)
callPackageWith;
callPackage = callPackageWith {
inherit lib elib pkgs tflib config;
};
in
{
_module.args = {
elib = {
nfsVolume = callPackage ./nfs_volume.nix {};
terraformModule = callPackage ./terraform-module.nix {};
nomadJob = callPackage ./nomad_job.nix {};
};
};
}

View file

@ -0,0 +1,30 @@
{}:
{ volume_name
, access_mode
, server
, share
, mount_flags ? []
}:
{
type = "csi";
plugin_id = "org.democratic-csi.nfs";
volume_id = volume_name;
name = volume_name;
external_id = volume_name;
capability = {
inherit access_mode;
attachment_mode = "file-system";
};
context = {
inherit server share;
node_attach_driver = "nfs";
provisioner_driver = "node-manual";
};
mount_options = {
fs_type = "nfs";
inherit mount_flags;
};
}

View file

@ -0,0 +1,11 @@
{}:
{ jobspec
, vars ? {}
}:
{
jobspec = "\${file(\"${jobspec}\")}";
hcl2 = {
enabled = true;
inherit vars;
};
}

View file

@ -0,0 +1,27 @@
{ tflib
, pkgs
, config
}:
{
name
, source
}:
{
source =
let
module = (tflib.mkTerranixConfiguration {
inherit pkgs;
modules = [
source
{
_file = "terraform-module.nix";
_module.args = builtins.removeAttrs config._module.args [ "pkgs" ];
}
];
} ).config.build.json;
in
pkgs.runCommandNoCC "${name}-module" {} ''
mkdir -p $out/
ln -s ${module} $out/main.tf.json
'';
}

View file

@ -0,0 +1,228 @@
{ config, pkgs, lib, tflib, ... }:
let
cfg = config.prefab.consulAgent;
inherit (lib)
mkOption
types
mapAttrsToList
fix
optionalString
optionalAttrs
singleton
mkMerge
flip
;
inherit (tflib)
tf;
submoduleOptions = {
datacenter = mkOption {
description = ''
'';
type = types.str;
};
replicationDatacenters = 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;
};
anonymousToken = mkOption {
description = ''
DO NOT hardcode the secret in Nix, generate it with Terraform
and let Terraform substitute it.
'';
type = types.submodule {
options.secret = mkOption {
description = '''';
type = types.str;
};
options.accessor = mkOption {
description = '''';
type = types.str;
};
};
};
paths = {
encryptionKey = mkOption {
description = ''
'';
type = types.str;
};
agentToken = mkOption {
description = ''
'';
type = types.str;
};
replicationToken = mkOption {
description = ''
'';
type = with types; nullOr str;
default = null;
};
anonymousToken = mkOption {
description = ''
'';
type = types.str;
};
};
vaultKvMount = mkOption {
description = ''
'';
type = types.str;
};
};
in
{
options.prefab.consulAgent = mkOption {
description = ''
'';
type = with types; attrsOf (submodule { options = submoduleOptions; });
default = {};
};
config.resource = mkMerge
(flip mapAttrsToList cfg (hostname: value:
fix (self: {
"consul_acl_policy"."${hostname}_agent" = {
name = "${hostname}-consul-agent";
rules = ''
node "${hostname}" {
policy = "write"
}
agent "${hostname}" {
policy = "write"
}
service_prefix "" {
policy = "write"
}
'';
};
"consul_acl_token"."${hostname}_consul_agent" = {
description = "Consul agent token on ${hostname}";
node_identities = singleton {
node_name = hostname;
datacenter = value.datacenter;
};
local = false;
};
"vault_kv_secret_v2"."${hostname}_consul_encryption_key" = {
mount = value.vaultKvMount;
name = value.paths.encryptionKey;
delete_all_versions = true;
data_json = builtins.toJSON {
key = value.encryptionKey;
};
};
"vault_kv_secret_v2"."${hostname}_consul_anonymous_token" = {
mount = value.vaultKvMount;
name = value.paths.anonymousToken;
delete_all_versions = true;
data_json = builtins.toJSON {
secret = value.anonymousToken.secret;
accessor = value.anonymousToken.accessor;
};
};
"vault_kv_secret_v2"."${hostname}_consul_agent" = {
mount = value.vaultKvMount;
name = value.paths.agentToken;
delete_all_versions = true;
data_json = builtins.toJSON {
secret = tf "data.consul_acl_token_secret_id.${hostname}_consul_agent.secret_id";
accessor = tf "consul_acl_token.${hostname}_consul_agent.id";
};
};
"vault_policy"."${hostname}_consul" = {
name = "${hostname}_consul_agent";
policy = ''
path "${value.vaultKvMount}/data/${value.paths.encryptionKey}" {
capabilities = ["read"]
}
path "${value.vaultKvMount}/data/${value.paths.agentToken}" {
capabilities = ["read"]
}
${optionalString (value.paths.replicationToken != null) ''
path "${value.vaultKvMount}/data/${value.paths.replicationToken}" {
capabilities = ["read"]
}
''}
path "${value.vaultKvMount}/data/${value.paths.anonymousToken}" {
capabilities = ["read"]
}
'';
};
})) ++
(flip mapAttrsToList cfg (hostname: value:
(optionalAttrs (value.paths.replicationToken != null) {
"consul_acl_policy"."${hostname}_replication" = {
name = "${hostname}_consul_replication";
datacenters = value.replicationDatacenters;
rules = ''
acl = "write"
operator = "write"
service_prefix "" {
policy = "read"
intentions = "read"
}
'';
};
"consul_acl_token"."${hostname}_consul_replication" = {
description = "Consul replication token on ${hostname}";
policies = [
(tf "consul_acl_policy.${hostname}_replication.name")
];
local = false;
};
"vault_kv_secret_v2"."${hostname}_consul_replication" = {
mount = value.vaultKvMount;
name = value.paths.replicationToken;
delete_all_versions = true;
data_json = builtins.toJSON {
secret = tf "data.consul_acl_token_secret_id.${hostname}_consul_replication.secret_id";
accessor = tf "consul_acl_token.${hostname}_consul_replication.id";
};
};
})
)));
config.data = mkMerge
(flip mapAttrsToList cfg (hostname: value:
{
"consul_acl_token_secret_id"."${hostname}_consul_agent" = {
accessor_id = tf "consul_acl_token.${hostname}_consul_agent.id";
};
}
) ++
flip mapAttrsToList cfg (hostname: value:
(optionalAttrs (value.paths.replicationToken != null) {
"consul_acl_token_secret_id"."${hostname}_consul_replication" = {
accessor_id = tf "consul_acl_token.${hostname}_consul_replication.id";
};
})
));
}

View file

@ -0,0 +1,256 @@
{ 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";
};
}));
}

View file

@ -0,0 +1,109 @@
{ config, pkgs, lib, tflib, ... }:
let
cfg = config.prefab.pushApproles;
inherit (lib)
mkOption
mdDoc
types
mapAttrsToList
mkMerge
flip
;
inherit (tflib)
tf
;
metadataType = pkgs.formats.json {};
submoduleOptions = {
policies = mkOption {
description = mdDoc ''
Vault policies added to the approle generated.
'';
type = with types; listOf str;
default = [];
};
host = mkOption {
description = mdDoc ''
The address of the machine, either IP address, domain name or any other identificator accepted by `ssh`.
'';
type = types.str;
};
user = mkOption {
description = mdDoc ''
The user to connect as.
'';
type = types.str;
};
metadata = mkOption {
description = mdDoc ''
'';
type = metadataType.type;
default = {};
};
approlePath = mkOption {
description = mdDoc ''
'';
type = types.str;
};
};
in
{
options.prefab.pushApproles = mkOption {
description = ''
'';
type = with types; attrsOf (submodule { options = submoduleOptions; });
default = {};
};
config.resource = mkMerge
(flip mapAttrsToList cfg (hostname: value:
{
"vault_approle_auth_backend_role"."system-${hostname}" = {
backend = value.approlePath;
role_name = hostname;
token_policies = value.policies;
};
"vault_approle_auth_backend_role_secret_id"."system-${hostname}" = {
backend = value.approlePath;
role_name = tf "vault_approle_auth_backend_role.system-${hostname}.role_name";
metadata = builtins.toJSON value.metadata;
};
"null_resource"."approles-${hostname}" = {
triggers = {
secret_id = tf "vault_approle_auth_backend_role_secret_id.system-${hostname}.secret_id";
role_id = tf "data.vault_approle_auth_backend_role_id.system-${hostname}.role_id";
};
connection = {
inherit (value)
host
user;
};
provisioner = {
"remote-exec" = {
inline = [
"echo \${vault_approle_auth_backend_role_secret_id.system-${hostname}.secret_id} > /var/secrets/approle.secretid"
"echo \${data.vault_approle_auth_backend_role_id.system-${hostname}.role_id} > /var/secrets/approle.roleid"
];
};
};
};
}));
config.data = mkMerge
(flip mapAttrsToList cfg (hostname: value:
{
"vault_approle_auth_backend_role_id"."system-${hostname}" = {
backend = value.approlePath;
role_name = tf "vault_approle_auth_backend_role.system-${hostname}.role_name";
};
}));
}

41
terranix/pki.nix Normal file
View file

@ -0,0 +1,41 @@
{ config, ... }:
{
resource."vault_mount"."pki_inra" = {
path = "pki-inra";
type = "pki";
description = "in.redalder.org";
default_lease_ttl_seconds = 8640000;
max_lease_ttl_seconds = 8640000;
};
resource."vault_policy"."pki_inra_update" = {
name = "pki-inra-update";
policy = ''
path "${config.resource."vault_mount"."pki_inra".path}/config/ca" {
capabilities = ["update"]
}
'';
};
resource."vault_pki_secret_backend_config_urls"."example" = {
backend = config.resource."vault_mount"."pki_inra".path;
issuing_certificates = [
"https://vault.in.redalder.org:8200/v1/pki/ca"
];
crl_distribution_points = [
"https://vault.in.redalder.org:8200/v1/pki_int/crl"
];
};
resource."vault_pki_secret_backend_role"."test_role" = {
backend = config.resource."vault_mount"."pki_inra".path;
name = "test_role";
ttl = 3600;
allow_ip_sans = true;
key_type = "rsa";
key_bits = 4096;
allowed_domains = ["test.in.redalder.org"];
allow_subdomains = false;
};
}

73
terranix/toothpick.nix Normal file
View file

@ -0,0 +1,73 @@
{ tflib, config, ... }:
let
inherit (tflib)
tf;
paths.consul = {
encryption_key = "do-1/toothpick/consul/encryption_key";
agent_token = "do-1/toothpick/consul/agent_token";
anonymous_token = "do-1/toothpick/consul/anonymous_token";
replication_token = "do-1/toothpick/consul/replication_token";
};
paths.nomad = {
encryption_key = "do-1/toothpick/nomad/encryption_key";
vault_token = "do-1/toothpick/nomad/vault_token";
consul_token = "do-1/toothpick/nomad/consul_token";
replication_token = "do-1/toothpick/nomad/replication_token";
};
vaultKvMount = config.resource."vault_mount"."kv".path;
in
{
prefab.consulAgent."toothpick" = {
datacenter = "do-1";
replicationDatacenters = [ "homelab-1" ];
inherit vaultKvMount;
paths = {
encryptionKey = paths.consul.encryption_key;
agentToken = paths.consul.agent_token;
anonymousToken = paths.consul.anonymous_token;
replicationToken = paths.consul.replication_token;
};
encryptionKey = tf "random_id.do-1_consul_encryption_key.b64_std";
anonymousToken = {
secret = tf "data.consul_acl_token_secret_id.anonymous.secret_id";
accessor = tf "consul_acl_token.anonymous.id";
};
};
prefab.nomadServer."toothpick" = {
datacenters = [ "do-1" ];
inherit vaultKvMount;
encryptionKey = tf "random_id.nomad_encryption_key.b64_std";
paths = {
encryptionKey = paths.nomad.encryption_key;
vaultToken = paths.nomad.vault_token;
consulToken = paths.nomad.consul_token;
replicationToken = paths.nomad.replication_token;
};
};
prefab.pushApproles."toothpick" = {
host = "10.64.0.1";
user = "main";
policies = [
(tf "vault_policy.toothpick_consul.name")
(tf "vault_policy.toothpick_nomad.name")
];
metadata = {
"ip_address" = "redalder.org";
};
approlePath = tf "vault_auth_backend.approle.path";
};
}