mirror of
https://git.sr.ht/~magic_rb/dotfiles
synced 2024-11-25 09:36:14 +01:00
Base terranix configuration
Signed-off-by: Magic_RB <magic_rb@redalder.org>
This commit is contained in:
parent
fd68d0e485
commit
9b1c305c3b
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,6 +7,6 @@
|
|||
result
|
||||
result-*
|
||||
|
||||
|
||||
/.terraform/
|
||||
|
||||
|
||||
|
|
44
.terraform.lock.hcl
Normal file
44
.terraform.lock.hcl
Normal 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=",
|
||||
]
|
||||
}
|
|
@ -878,8 +878,8 @@
|
|||
"terranix": "terranix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680122738,
|
||||
"narHash": "sha256-Dvb6ZpRSPt5G6VkHzNOqCNRyHD7J9AdFYgPfHEHi7BU=",
|
||||
"lastModified": 1686862391,
|
||||
"narHash": "sha256-U7q2iwNNdB0A7GHyLjNYLWluOVJO+K0LtiOV0Y3/vuY=",
|
||||
"path": "/home/main/uterranix",
|
||||
"type": "path"
|
||||
},
|
||||
|
|
31
flake.nix
31
flake.nix
|
@ -79,8 +79,39 @@
|
|||
overlays/terraform-provider-vault.nix
|
||||
overlays/terraform-provider-influxdb-v2.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 = {
|
||||
hashicorp = nixos/modules/hashicorp.nix;
|
||||
hashicorp-envoy = nixos/modules/hashicorp-envoy.nix;
|
||||
|
|
105
terranix/blowhole.nix
Normal file
105
terranix/blowhole.nix
Normal 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
203
terranix/default.nix
Normal 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
18
terranix/lib/default.nix
Normal 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 {};
|
||||
};
|
||||
};
|
||||
}
|
30
terranix/lib/nfs_volume.nix
Normal file
30
terranix/lib/nfs_volume.nix
Normal 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;
|
||||
};
|
||||
}
|
11
terranix/lib/nomad_job.nix
Normal file
11
terranix/lib/nomad_job.nix
Normal file
|
@ -0,0 +1,11 @@
|
|||
{}:
|
||||
{ jobspec
|
||||
, vars ? {}
|
||||
}:
|
||||
{
|
||||
jobspec = "\${file(\"${jobspec}\")}";
|
||||
hcl2 = {
|
||||
enabled = true;
|
||||
inherit vars;
|
||||
};
|
||||
}
|
27
terranix/lib/terraform-module.nix
Normal file
27
terranix/lib/terraform-module.nix
Normal 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
|
||||
'';
|
||||
}
|
228
terranix/modules/consul_agent.nix
Normal file
228
terranix/modules/consul_agent.nix
Normal 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";
|
||||
};
|
||||
})
|
||||
));
|
||||
}
|
256
terranix/modules/nomad_server.nix
Normal file
256
terranix/modules/nomad_server.nix
Normal 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";
|
||||
};
|
||||
}));
|
||||
|
||||
}
|
109
terranix/modules/push_approles.nix
Normal file
109
terranix/modules/push_approles.nix
Normal 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
41
terranix/pki.nix
Normal 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
73
terranix/toothpick.nix
Normal 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";
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue