WIP: feat(infra): introduce Terranix #145
10 changed files with 190 additions and 0 deletions
BIN
.credentials/admin-environment.age
Normal file
BIN
.credentials/admin-environment.age
Normal file
Binary file not shown.
6
.credentials/secrets.nix
Normal file
6
.credentials/secrets.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
let
|
||||||
|
keys = import ../keys;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"admin-environment.age".publicKeys = keys.rootKeys;
|
||||||
|
}
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -9,3 +9,9 @@ result-*
|
||||||
*.qcow2
|
*.qcow2
|
||||||
.gcroots
|
.gcroots
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
|
||||||
|
# Ignore Terraform configuration file
|
||||||
|
config.tf.json
|
||||||
|
|
||||||
|
# Ignore Terraform stuff
|
||||||
|
.terraform
|
||||||
|
|
38
.terraform.lock.hcl
Normal file
38
.terraform.lock.hcl
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# This file is maintained automatically by "tofu init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.opentofu.org/numtide/secret" {
|
||||||
|
version = "1.2.1"
|
||||||
|
constraints = "~> 1.2.1"
|
||||||
|
hashes = [
|
||||||
|
"h1:t2z3CjxVsXjKb3g59WGkLtvDIR4NzLU7UFEcyAgF2C0=",
|
||||||
|
"zh:17cbc7f3b90ee2b3ae5adfc3bd9cb70166a5ffbd8e642e64afa7cb0e32a34bae",
|
||||||
|
"zh:5d66ce2aea25fc3c12cec6fc569b8ff314df6d773b9c3449983a4e9cde8347c7",
|
||||||
|
"zh:67d02e96bf0d07f2fcf16ce9427a7a26f53e695676405d0c2b815808f950411d",
|
||||||
|
"zh:77c3c05681ce199e6b0e2e5a2dfe418f61ae8863d527e7a7d47a9699d912683b",
|
||||||
|
"zh:7f37e633b4f94ba9f347cfe68d44f80fe066188feb954b13ee0f621caae4121d",
|
||||||
|
"zh:ea16bbe494c6ddd0af7bbea9554474c387517db4e7f0d15513bb29ff893871bc",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "registry.opentofu.org/raitobezarius/garage" {
|
||||||
|
version = "1.0.3"
|
||||||
|
constraints = "~> 1.0.3"
|
||||||
|
hashes = [
|
||||||
|
"h1:QKbZcU7u9OG1t/h4S3+pXS3sOUfVMmfLTiYh5L5j1rE=",
|
||||||
|
"zh:04f220a2baf4bd1bae07888a1c311cacd6076c209de83adbe573525fc50f2ea4",
|
||||||
|
"zh:078938d5fa07e024d779c664823427af28935bbeb77e0ff940bac3e7bc41f1e8",
|
||||||
|
"zh:2dd58a2d82094a1b07ff1b6de57e4a0d96e1f20abecd4f70a6469079b46b76d9",
|
||||||
|
"zh:325da7a74b1c84f934b38134d7c419253292aeed6f6836a2fb37f42d13a8ff67",
|
||||||
|
"zh:3ca9230ef87e70691b24fd83d40bb5b6a08f0b91ab26cbb2e692f92155b6d179",
|
||||||
|
"zh:45ef683a18a5053c93c691d08f3903fd4918467dfa056b1c274207de8a6aeb74",
|
||||||
|
"zh:4c9ee6c34b07c209c5daf1e9ff182f828667e54a90a683bc11cdcea86e4f8ef7",
|
||||||
|
"zh:5f0bb6524b2fffa606e0e3585af93dfc31b611c7abf55e4371ae5fc36e85972c",
|
||||||
|
"zh:7a3495dc211164c7d4042769c20d7111c767d0fd5908742e0766281c70d7d184",
|
||||||
|
"zh:7ce79867cdd4b1f7028da811cd5cb271a46820c79c0328a1221dd3bb6215c631",
|
||||||
|
"zh:93278861ee6bcb64e23bd1268f79b02035fba4fca0a98607a98f46abf8dfdf83",
|
||||||
|
"zh:937e681beea8b0dd899557f2a194c8128bd8810417ff04954bc9958ff826e980",
|
||||||
|
"zh:cae6e1598dd32f23f3900c41e50a6ece7d9456dbd033d855bb238ac21539d67b",
|
||||||
|
"zh:f6f7556ba7d5578604290170a709e00140be6d7f8a510a20bce49a9a23d75e5f",
|
||||||
|
]
|
||||||
|
}
|
36
default.nix
36
default.nix
|
@ -67,9 +67,18 @@ let
|
||||||
commitizen.enable = true;
|
commitizen.enable = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
rlahfa marked this conversation as resolved
Outdated
|
|||||||
|
terranixConfig = import "${sources.terranix}/core" {
|
||||||
|
inherit pkgs;
|
||||||
|
strip_nulls = true;
|
||||||
|
terranix_config.imports = [ ./terranix ];
|
||||||
|
};
|
||||||
|
terranixConfigFile = (pkgs.formats.json { }).generate "config.tf.json" terranixConfig.config;
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
rlahfa marked this conversation as resolved
Outdated
thubrecht
commented
Newline also after the inherit Newline also after the inherit
|
|||||||
|
inherit terranixConfigFile terranixConfig;
|
||||||
|
|
||||||
nodes = builtins.mapAttrs (
|
nodes = builtins.mapAttrs (
|
||||||
host: { site, ... }: "${host}.${site}.infra.dgnum.eu"
|
host: { site, ... }: "${host}.${site}.infra.dgnum.eu"
|
||||||
) (import ./meta/nodes.nix);
|
) (import ./meta/nodes.nix);
|
||||||
|
@ -83,11 +92,36 @@ in
|
||||||
name = "dgnum-infra";
|
name = "dgnum-infra";
|
||||||
|
|
||||||
packages = [
|
packages = [
|
||||||
|
(pkgs.writeShellScriptBin "tf" ''
|
||||||
|
set -eo pipefail
|
||||||
|
ln -snf ${terranixConfigFile} config.tf.json
|
||||||
|
exec ${pkgs.lib.getExe pkgs.opentofu} "$@"
|
||||||
|
'')
|
||||||
|
(pkgs.writeShellScriptBin "decryptAndSourceEnvironment" ''
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
# TODO: don't hardcode me.
|
||||||
|
SECRET_FILE=".credentials/admin-environment.age"
|
||||||
|
IDENTITIES=()
|
||||||
|
for identity in [ "$HOME/.ssh/id_ed25519" "$HOME/.ssh/id_rsa" ]; do
|
||||||
|
test -r "$identity" || continue
|
||||||
|
IDENTITIES+=(-i)
|
||||||
|
IDENTITIES+=("$identity")
|
||||||
|
done
|
||||||
|
|
||||||
|
test "''${#IDENTITIES[@]}" -eq 0 && echo "[agenix-shell] WARNING: no readable identities found!"
|
||||||
|
|
||||||
|
test -f "$SECRET_FILE" || echo "[agenix-shell] WARNING: encrypted environment file $SECRET_FILE not found!"
|
||||||
|
export eval $(${pkgs.lib.getExe pkgs.rage} --decrypt "''${IDENTITIES[@]}" -o - $SECRET_FILE)
|
||||||
|
|
||||||
|
echo "[agenix-shell] Repository-wide secrets loaded in the environment."
|
||||||
|
'')
|
||||||
(pkgs.nixos-generators.overrideAttrs (_: {
|
(pkgs.nixos-generators.overrideAttrs (_: {
|
||||||
version = "1.8.0-unstable";
|
version = "1.8.0-unstable";
|
||||||
src = builtins.storePath sources.nixos-generators;
|
src = builtins.storePath sources.nixos-generators;
|
||||||
}))
|
}))
|
||||||
pkgs.npins
|
pkgs.npins
|
||||||
|
pkgs.rage
|
||||||
|
|
||||||
(pkgs.callPackage ./lib/colmena { inherit (nix-pkgs) colmena; })
|
(pkgs.callPackage ./lib/colmena { inherit (nix-pkgs) colmena; })
|
||||||
(pkgs.callPackage "${sources.agenix}/pkgs/agenix.nix" { })
|
(pkgs.callPackage "${sources.agenix}/pkgs/agenix.nix" { })
|
||||||
|
@ -97,6 +131,8 @@ in
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
${git-checks.shellHook}
|
${git-checks.shellHook}
|
||||||
|
# If we want to export these environments, we need to source it, not call it.
|
||||||
|
source $(which decryptAndSourceEnvironment)
|
||||||
'';
|
'';
|
||||||
|
|
||||||
preferLocalBuild = true;
|
preferLocalBuild = true;
|
||||||
|
|
|
@ -294,6 +294,21 @@
|
||||||
"url": null,
|
"url": null,
|
||||||
"hash": "166057469hhxnyqbpd7jjlccdmigzch51616n1d5r617xg0y1mwp"
|
"hash": "166057469hhxnyqbpd7jjlccdmigzch51616n1d5r617xg0y1mwp"
|
||||||
},
|
},
|
||||||
|
"terranix": {
|
||||||
|
"type": "GitRelease",
|
||||||
|
"repository": {
|
||||||
|
"type": "GitHub",
|
||||||
|
"owner": "terranix",
|
||||||
|
"repo": "terranix"
|
||||||
|
},
|
||||||
|
"pre_releases": false,
|
||||||
|
"version_upper_bound": null,
|
||||||
|
"release_prefix": null,
|
||||||
|
"version": "2.7.0",
|
||||||
|
"revision": "00710f39f38a0a654a2c4fd96cbb988b4f4cedfa",
|
||||||
|
"url": "https://api.github.com/repos/terranix/terranix/tarball/2.7.0",
|
||||||
|
"hash": "1wsyhsdsjw6xlhpkhaqvia3x0na3nx2vamcb2rbcbdmb7ra1y9f6"
|
||||||
|
},
|
||||||
"wp4nix": {
|
"wp4nix": {
|
||||||
"type": "Git",
|
"type": "Git",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
7
terranix/common.nix
Normal file
7
terranix/common.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
# Until we get some kind of KMS operational, store secrets in the state file.
|
||||||
|
terraform.required_providers.secret = {
|
||||||
|
version = "~> 1.2.1";
|
||||||
|
source = "numtide/secret";
|
||||||
|
};
|
||||||
|
}
|
7
terranix/default.nix
Normal file
7
terranix/default.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./common.nix
|
||||||
|
./state.nix
|
||||||
|
./s3.nix
|
||||||
|
];
|
||||||
|
}
|
54
terranix/s3.nix
Normal file
54
terranix/s3.nix
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) tf;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# FIXME: add a NixOS module to abstract bucket creation, etc.
|
||||||
|
config = {
|
||||||
|
terraform.required_providers.garage = {
|
||||||
|
version = "~> 1.0.3";
|
||||||
|
source = "registry.opentofu.org/RaitoBezarius/garage";
|
||||||
|
};
|
||||||
|
|
||||||
|
resource = {
|
||||||
|
secret_resource.admin-s3-token.lifecycle.prevent_destroy = true;
|
||||||
|
garage_bucket = {
|
||||||
|
monorepo-terraform-state = { };
|
||||||
|
impress-raito-demo = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
garage_bucket_global_alias = {
|
||||||
|
monorepo-terraform-state = {
|
||||||
|
bucket_id = tf.ref "resource.garage_bucket.monorepo-terraform-state.id";
|
||||||
|
alias = "monorepo-terraform-state";
|
||||||
thubrecht marked this conversation as resolved
Outdated
thubrecht
commented
?? ??
rlahfa
commented
it's just to showcase how to use it it's just to showcase how to use it
rlahfa
commented
terraform won't delete things it doesn't know about FYI terraform won't delete things it doesn't know about FYI
|
|||||||
|
};
|
||||||
|
impress-raito-demo = {
|
||||||
|
bucket_id = tf.ref "resource.garage_bucket.impress-raito-demo.id";
|
||||||
|
alias = "impress-raito-demo";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
garage_key = {
|
||||||
|
raito-dinum-test = {
|
||||||
|
name = "raito-dinum-test";
|
||||||
|
permissions.create_bucket = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
garage_bucket_key = {
|
||||||
|
raito-dinum-test = {
|
||||||
|
bucket_id = tf.ref "resource.garage_bucket.impress-raito-demo.id";
|
||||||
|
access_key_id = tf.ref "resource.garage_key.raito-dinum-test.access_key_id";
|
||||||
|
read = true;
|
||||||
|
write = true;
|
||||||
|
owner = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
provider.garage = {
|
||||||
|
host = "s3-admin.dgnum.eu";
|
||||||
|
scheme = "https";
|
||||||
|
token = tf.ref "resource.secret_resource.admin-s3-token.value";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
21
terranix/state.nix
Normal file
21
terranix/state.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
# We use terraform.backend.s3 directly instead of the type-checked Terranix
|
||||||
|
# backend.s3 options. The latter does not support setting arbitrary s3
|
||||||
|
# endpoints.
|
||||||
|
#
|
||||||
|
# Note: currently requires the user to provide AWS_ACCESS_KEY_ID as well as
|
||||||
|
# AWS_SECRET_ACCESS_KEY in their environment variables.
|
||||||
rlahfa marked this conversation as resolved
Outdated
thubrecht
commented
TODO(one day): Add a .credentials directory, with age encrypted files that can be decrypted when entering the shell TODO(one day): Add a .credentials directory, with age encrypted files that can be decrypted when entering the shell
rlahfa
commented
let's do it now let's do it now
rlahfa
commented
done! done!
|
|||||||
|
|
||||||
|
terraform.backend.s3 = {
|
||||||
|
endpoints.s3 = "s3.dgnum.eu";
|
||||||
|
region = "garage";
|
||||||
|
bucket = "monorepo-terraform-state";
|
||||||
|
key = "state";
|
||||||
|
|
||||||
|
# It's just a dumb Garage server, don't try to be smart.
|
||||||
rlahfa marked this conversation as resolved
Outdated
thubrecht
commented
dumb* dumb*
|
|||||||
|
skip_credentials_validation = true;
|
||||||
|
skip_region_validation = true;
|
||||||
|
skip_requesting_account_id = true;
|
||||||
|
skip_metadata_api_check = true;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue
Please add a newline