diff --git a/infra/_modules/tfstate/main.tf b/infra/_modules/tfstate/main.tf new file mode 100644 index 0000000..e69de29 diff --git a/infra/production/root.hcl b/infra/production/root.hcl index 6513a17..f0a23a3 100644 --- a/infra/production/root.hcl +++ b/infra/production/root.hcl @@ -1,6 +1,6 @@ locals { secrets = yamldecode(sops_decrypt_file(find_in_parent_folders("secrets.yaml"))) - env = "production" + env = basename(get_parent_terragrunt_dir()) cloud = split("/", path_relative_to_include())[0] } diff --git a/infra/staging/.sops.yaml b/infra/staging/.sops.yaml new file mode 100644 index 0000000..65ee661 --- /dev/null +++ b/infra/staging/.sops.yaml @@ -0,0 +1,7 @@ +creation_rules: + # TODO auto manage age keys, currently have to: + # - run age-keygen + # - copy public key here + # - copy private key to ~/.config/sops/age/keys.txt + - age: >- + age15c5rpksj0u27sp667525zqh8dhtd70rwrlv7xq2hqhsfaempcdwqu3unel diff --git a/infra/staging/nixos/.terraform.lock.hcl b/infra/staging/nixos/.terraform.lock.hcl new file mode 100644 index 0000000..ba8350e --- /dev/null +++ b/infra/staging/nixos/.terraform.lock.hcl @@ -0,0 +1,53 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/external" { + version = "2.3.5" + hashes = [ + "h1:jcVmeuuz74tdRt2kj0MpUG9AORdlAlRRQ3k61y0r5Vc=", + "zh:1fb9aca1f068374a09d438dba84c9d8ba5915d24934a72b6ef66ef6818329151", + "zh:3eab30e4fcc76369deffb185b4d225999fc82d2eaaa6484d3b3164a4ed0f7c49", + "zh:4f8b7a4832a68080f0bf4f155b56a691832d8a91ce8096dac0f13a90081abc50", + "zh:5ff1935612db62e48e4fe6cfb83dfac401b506a5b7b38342217616fbcab70ce0", + "zh:993192234d327ec86726041eb6d1efb001e41f32e4518ad8b9b162130b65ee9a", + "zh:ce445e68282a2c4b2d1f994a2730406df4ea47914c0932fb4a7eb040a7ec7061", + "zh:e305e17216840c54194141fb852839c2cedd6b41abd70cf8d606d6e88ed40e64", + "zh:edba65fb241d663c09aa2cbf75026c840e963d5195f27000f216829e49811437", + "zh:f306cc6f6ec9beaf75bdcefaadb7b77af320b1f9b56d8f50df5ebd2189a93148", + "zh:fb2ff9e1f86796fda87e1f122d40568912a904da51d477461b850d81a0105f3d", + ] +} + +provider "registry.opentofu.org/hashicorp/local" { + version = "2.5.3" + hashes = [ + "h1:mC9+u1eaUILTjxey6Ivyf/3djm//RNNze9kBVX/trng=", + "zh:32e1d4b0595cea6cda4ca256195c162772ddff25594ab4008731a2ec7be230bf", + "zh:48c390af0c87df994ec9796f04ec2582bcac581fb81ed6bb58e0671da1c17991", + "zh:4be7289c969218a57b40902e2f359914f8d35a7f97b439140cb711aa21e494bd", + "zh:4cf958e631e99ed6c8b522c9b22e1f1b568c0bdadb01dd002ca7dffb1c927764", + "zh:7a0132c0faca4c4c96aa70808effd6817e28712bf5a39881666ac377b4250acf", + "zh:7d60de08fac427fb045e4590d1b921b6778498eee9eb16f78c64d4c577bde096", + "zh:91003bee5981e99ec3925ce2f452a5f743827f9d0e131a86613549c1464796f0", + "zh:9fe2fe75977c8149e2515fb30c6cc6cfd57b225d4ce592c570d81a3831d7ffa3", + "zh:e210e6be54933ce93e03d0994e520ba289aa01b2c1f70e77afb8f2ee796b0fe3", + "zh:e8793e5f9422f2b31a804e51806595f335b827c9a38db18766960464566f21d5", + ] +} + +provider "registry.opentofu.org/hashicorp/null" { + version = "3.2.4" + hashes = [ + "h1:jsKjBiLb+v3OIC3xuDiY4sR0r1OHUMSWPYKult9MhT0=", + "zh:1769783386610bed8bb1e861a119fe25058be41895e3996d9216dd6bb8a7aee3", + "zh:32c62a9387ad0b861b5262b41c5e9ed6e940eda729c2a0e58100e6629af27ddb", + "zh:339bf8c2f9733fce068eb6d5612701144c752425cebeafab36563a16be460fb2", + "zh:36731f23343aee12a7e078067a98644c0126714c4fe9ac930eecb0f2361788c4", + "zh:3d106c7e32a929e2843f732625a582e562ff09120021e510a51a6f5d01175b8d", + "zh:74bcb3567708171ad83b234b92c9d63ab441ef882b770b0210c2b14fdbe3b1b6", + "zh:90b55bdbffa35df9204282251059e62c178b0ac7035958b93a647839643c0072", + "zh:ae24c0e5adc692b8f94cb23a000f91a316070fdc19418578dcf2134ff57cf447", + "zh:b5c10d4ad860c4c21273203d1de6d2f0286845edf1c64319fa2362df526b5f58", + "zh:e05bbd88e82e1d6234988c85db62fd66f11502645838fff594a2ec25352ecd80", + ] +} diff --git a/infra/staging/nixos/terragrunt.hcl b/infra/staging/nixos/terragrunt.hcl new file mode 100644 index 0000000..14070a3 --- /dev/null +++ b/infra/staging/nixos/terragrunt.hcl @@ -0,0 +1,20 @@ +include "root" { + path = find_in_parent_folders("root.hcl") + expose = true +} + +terraform { + source = "${find_in_parent_folders("_modules")}//nixos" +} + +dependency "proxmox" { + config_path = "../proxmox/compute" +} + +inputs = { + flake = "${find_in_parent_folders("_modules")}//nixos" + hosts = merge( + dependency.proxmox.outputs.hosts, + ) + sops_file = find_in_parent_folders("secrets.yaml") +} diff --git a/infra/staging/proxmox/compute/.terraform.lock.hcl b/infra/staging/proxmox/compute/.terraform.lock.hcl new file mode 100644 index 0000000..4987012 --- /dev/null +++ b/infra/staging/proxmox/compute/.terraform.lock.hcl @@ -0,0 +1,42 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/bpg/proxmox" { + version = "0.57.1" + constraints = "~> 0.57.0" + hashes = [ + "h1:F6o5o32V+mE96gHUppHI0U+olrEtxtr23fwUigtQ/Wk=", + "zh:220c75d76e8779970d4e01effdb3073a24139f5065397dae1347710e80b69865", + "zh:271d71cb39225a4efd4b6e0cbb2cba50f89006a353db932969deed5db07cdd9b", + "zh:28c4f33a1b888f488f1a557d21a1383eb9f9bff77d6ed0643b393c02135436bd", + "zh:2c468cb678cdd44f896b531fc09f7a68b16dde298bfded89ee94b792233ddbf1", + "zh:3329ce5f7bd96233cf75a633f9b0927295083cc365a4324294dc8bfbcd4bb2a3", + "zh:5d5c99f763488c30fbab66b6c68adac1f9d41b8439a7201d826351353c452470", + "zh:6a67c621b0bd8c54037ea93273d78308f0a7d2c8b5316def4245c58686639818", + "zh:8d64bbc24008d507608e53d1e9d09705710a07ba5b5fe3b5c5cce51ddd0fa6ac", + "zh:99395ff6c92d49033ba5426c0f3a07c893354883e86d9000692907150a3c096c", + "zh:b03996ae36df1181af784ed57267f8761092400018d40ae2649fa8ec9cabef96", + "zh:be6eb719192e228905a556e59d2814da2d26e512c9b0b2f04b224a7e80d2a017", + "zh:c3c1f9c94ad381a1e1d022f1d02bc446ea47563eb6573c40471c6b0e6293c20c", + "zh:cad37192fb69db274fa053564502077cedc7c8679373a3a8c35da91ed8988a19", + "zh:eabc19a8e0d287bb1abbde3d331fc5ca27943dae24cca8d8812b66fd9c8ed4d3", + "zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597", + ] +} + +provider "registry.opentofu.org/hashicorp/time" { + version = "0.13.1" + hashes = [ + "h1:ueilLAoXlZPufdJYuPFeqznwP39ZwLsRcQtqow+NUiI=", + "zh:10f32af8b544a039f19abd546e345d056a55cb7bdd69d5bbd7322cbc86883848", + "zh:35dd5beb34a9f73de8d0fed332814c69acae69397c9c065ce63ccd8315442bef", + "zh:56545d1dd5f2e7262e0c0c124264974229ec9cc234d0d7a0e36e14b869590f4a", + "zh:8d7259c3f819fd3470ff933c904b6a549502a8351feb1b5c040a4560decaf7e0", + "zh:a40f26878826b142e26fe193f7e3e14fc97f615cd6af140e88ce5bc25f3fcf50", + "zh:b2e82f25fecff172a9a9e24ea37d37e4fc630ee9245617cb40b10e66a6b979c8", + "zh:d4b699850a40ed07ef83c6b827605d24050b2732646ee017bda278e4ddf01c91", + "zh:e4e6a5e5614b6a54557400aabb748ebd57e947cdbd21ad1c7602c51368a80559", + "zh:eb78fb97bca22931e730487a20a90f5a6221ddfb3138aaf070737ea2b7c9c885", + "zh:faba366a1352ee679bba2a5b09c073c6854721db94b191d49b620b60946a065f", + ] +} diff --git a/infra/staging/proxmox/compute/terragrunt.hcl b/infra/staging/proxmox/compute/terragrunt.hcl new file mode 100644 index 0000000..2f76edb --- /dev/null +++ b/infra/staging/proxmox/compute/terragrunt.hcl @@ -0,0 +1,16 @@ +include "root" { + path = find_in_parent_folders("root.hcl") + expose = true +} + +terraform { + source = "${find_in_parent_folders("_modules")}//proxmox-vm" +} + +inputs = { + hosts = { + "kube-1" = { cpu = 4, memory = 12, disk = 128 } + "kube-2" = { cpu = 4, memory = 12, disk = 128 } + "kube-3" = { cpu = 4, memory = 12, disk = 128 } + } +} diff --git a/infra/staging/root.hcl b/infra/staging/root.hcl new file mode 100644 index 0000000..f0a23a3 --- /dev/null +++ b/infra/staging/root.hcl @@ -0,0 +1,70 @@ +locals { + secrets = yamldecode(sops_decrypt_file(find_in_parent_folders("secrets.yaml"))) + env = basename(get_parent_terragrunt_dir()) + cloud = split("/", path_relative_to_include())[0] +} + +generate "backend" { + path = "backend.tf.json" + if_exists = "overwrite" + disable_signature = true + contents = jsonencode({ + terraform = { + backend = { + s3 = { + bucket = "tfstate-${local.env}" + key = "${path_relative_to_include()}/tfstate.json" + region = "auto" + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + skip_requesting_account_id = true + skip_s3_checksum = true + use_path_style = true + access_key = local.secrets.cloudflare_tfstate_access_key + secret_key = local.secrets.cloudflare_tfstate_secret_key + endpoints = { + s3 = "https://${local.secrets.cloudflare_account_id}.r2.cloudflarestorage.com" + } + } + } + } + }) +} + +generate "provider" { + path = "provider.tf.json" + if_exists = "overwrite" + disable_signature = true + + contents = jsonencode(lookup( + { + oracle = { + provider = { + oci = { + tenancy_ocid = local.secrets.oracle_tenancy_ocid + user_ocid = local.secrets.oracle_user_ocid + fingerprint = local.secrets.oracle_fingerprint + private_key = local.secrets.oracle_private_key + region = local.secrets.oracle_region + } + } + } + hetzner = { + provider = { + hcloud = {} + } + } + proxmox = { + provider = { + proxmox = { + endpoint = "https://proxmox:8006" + insecure = true + } + } + } + }, + local.cloud, + {} + )) +} diff --git a/infra/staging/secrets.yaml b/infra/staging/secrets.yaml new file mode 100644 index 0000000..38f76ae --- /dev/null +++ b/infra/staging/secrets.yaml @@ -0,0 +1,20 @@ +age_key: ENC[AES256_GCM,data:Q5n2nohubYGddLVghlUMUyaL5rgc8sy7fygzkw1Z+7Fk8HSl6nn7IC46OGx3nSu6ypStg1anvjOkTTZWvoL/ETL+pGeRgETdf7Y=,iv:AdSB/+HwVWFD0GQ5kNoybXvGVBLla9CmQ8pAOkf6tow=,tag:ZILB6vg8dXHjptDLtkqTAg==,type:str] +cloudflare_tfstate_api_token: ENC[AES256_GCM,data:ZNK2qzaiXV93txbV73sSnvxicazxY8uzxf/0yLe/NwQYZKc+t2AVkA==,iv:6gNRl8Kr2xYfwKDVefKP+Fe7/NOf1zKftnBqzoWo5N0=,tag:pjCsHKYL4wbyGGZ63ERvDQ==,type:str] +cloudflare_tfstate_access_key: ENC[AES256_GCM,data:1N7/YeqYBLaPD0u9EMzQA9nZDpAAk/cb70pF+EwlPMM=,iv:BJ4x220lnXcle3MiDnlj3mY1Wl56z0Fc1bgyA7p294o=,tag:5HcspXjzggy2aQnnR4q71A==,type:str] +cloudflare_tfstate_secret_key: ENC[AES256_GCM,data:/EEAKxDwtEgMdDNPVXJ5pu8Xzx20ZZwRqMR+90M8KkQwbBRxk67IHP4LeY7Sm6BEQOfjim+tvAdjABfSMpzl4w==,iv:Kj2RP5EDGPkJp5VN7qE6tmCao/QBSxHMRk9VC0up7D4=,tag:fM9oYGx9NpVepSJctp2Y8w==,type:str] +cloudflare_account_id: ENC[AES256_GCM,data:zj6mfdohnYRlptkdPThaOVkUV9cSQn0Q9Lq9m4T+e9g=,iv:orAlN13bR1Vni7aZ3iNWx5tfjODX/oKrhZijSnAWu4Y=,tag:Qsq6K3K2uDBeossojArCxg==,type:str] +sops: + age: + - recipient: age15c5rpksj0u27sp667525zqh8dhtd70rwrlv7xq2hqhsfaempcdwqu3unel + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzRUNOT2pDaDJneCs4RzdL + VDRHV29Dc21Bd1ovNXJWR1U4UmYvd0kxUlFrCjdpcFlvVnRWakljQ05FVFNqRUpC + Y1Fpc2c3RENCemUxWUVLamRKOFRLbDgKLS0tIGRoT29NNkp3V3pvSFhmb0tRalMy + bzdTeVZWYVIwM1VyUm5UM0pQZW5KYlUKWw7Fq17anbkfY6U3HCr00OKEfffRL/TM + zvtvDaWLg2ZilP7kWM7YbqyTi4XqjLXKldOblwIcF7qA5E/OfbbzXw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-08-31T03:08:10Z" + mac: ENC[AES256_GCM,data:rvbD+/1nsZLMe9AN6O9I8nl6G5Miu9DtV72KOfC/91C/f9vY26fE3EmD4MF56dQuQzmWZ/1lQai7srqLOx5V0FUUgBTFLJkwgb9CBXFfNBrcSUOqKkn5LdSilAzyz0j5L2YmQAfUVWIFjXUfr1Mw/0kborxDM4IKIfWLBNQ5sFs=,iv:YA53/iagS9hRvw2HWMLHHxI+9Cy/HWKi58+9cpXrg6s=,tag:g2q0Au6PvAaBisCBecQ5bg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/infra/staging/tfstate/terragrunt.hcl b/infra/staging/tfstate/terragrunt.hcl new file mode 100644 index 0000000..29ee54a --- /dev/null +++ b/infra/staging/tfstate/terragrunt.hcl @@ -0,0 +1,18 @@ +include "root" { + path = find_in_parent_folders("root.hcl") + expose = true +} + +terraform { + source = "${find_in_parent_folders("_modules")}//tfstate" + + before_hook "bootstrap_tfstate" { + commands = ["init", "plan", "apply"] + execute = [ + "go", "run", ".", + "--api-token=${include.root.locals.secrets.cloudflare_tfstate_api_token}", + "--account-id=${include.root.locals.secrets.cloudflare_account_id}", + "--bucket=tfstate-${include.root.locals.env}", + ] + } +}