diff --git a/.sops.yaml b/.sops.yaml index 2fd0efc3e..b36d340ad 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -75,7 +75,6 @@ creation_rules: - age: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMm3/o1HguyRL1z/nZxLBY9j/YUNXeNuDoiBLZAyt88Z - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFiozp1A1+SUfJQPa5DZUQcVc6CZK2ZxL6FJtNdh+2TP - - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILAkBZMRNgsJ/IbLtjMHqBw/9+4tyn9nT+5B5RFiV0vJ - age1dzvjjum2p240qtdt2qcxpm7pl2s5w36mh4fs3q9dhhq0uezvdqaq9vrgfy - age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz - age1d87z3zqlv6ullnzyng8l722xzxwqr677csacf3zf3l28dau7avfs6pc7ay diff --git a/dev/terraform.nix b/dev/terraform.nix index b09f6b638..d545d6244 100644 --- a/dev/terraform.nix +++ b/dev/terraform.nix @@ -7,6 +7,7 @@ terraform = pkgs.opentofu.withPlugins (p: [ p.carlpett_sops p.determinatesystems_hydra + p.hashicorp_tfe p.integrations_github ]); terraform-validate = diff --git a/devdoc/onboarding.md b/devdoc/onboarding.md index 84ea87796..7537aace8 100644 --- a/devdoc/onboarding.md +++ b/devdoc/onboarding.md @@ -4,10 +4,12 @@ - Add their user and ssh key to [users](../users) as member of the `trusted` and `wheel` groups. - - `wheel` will give them access to the terraform state storage. - - Add their age key to [sops.json](../sops.json) and run `inv update-sops-files`. +- Add their email in [terraform/locals.tf](../terraform/locals.tf), this will give them access to: + + - [Terraform Cloud](https://app.terraform.io) + - Add their user to the list of `admins` in [modules/nixos/buildbot.nix](../modules/nixos/buildbot.nix). - Add their user to the list of `hydra-github-users` in [modules/nixos/hydra.nix](../modules/nixos/hydra.nix). diff --git a/hosts/web01/default.nix b/hosts/web01/default.nix index 5e65e6f1e..f43eb7bce 100644 --- a/hosts/web01/default.nix +++ b/hosts/web01/default.nix @@ -3,8 +3,6 @@ imports = [ ./gandi.nix ./landscape.nix - ./postgresql.nix - ./postgresql-tf.nix inputs.self.nixosModules.monitoring inputs.self.nixosModules.nginx inputs.self.nixosModules.nur-update diff --git a/hosts/web01/postgresql-tf.nix b/hosts/web01/postgresql-tf.nix deleted file mode 100644 index 2f0a37ed7..000000000 --- a/hosts/web01/postgresql-tf.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, ... }: -{ - services.postgresql = { - authentication = '' - local terraform terraform peer map=tf_map - ''; - - identMap = lib.pipe config.users.users [ - (lib.filterAttrs (_: user: lib.elem "wheel" (user.extraGroups or [ ]))) - lib.attrNames - (map (user: "tf_map ${user} terraform")) - (lib.concatStringsSep "\n") - ]; - - ensureDatabases = [ "terraform" ]; - ensureUsers = [ - { - name = "terraform"; - ensureDBOwnership = true; - } - ]; - }; -} diff --git a/hosts/web01/postgresql.nix b/hosts/web01/postgresql.nix deleted file mode 100644 index dd39f3553..000000000 --- a/hosts/web01/postgresql.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ - config, - inputs, - pkgs, - ... -}: -{ - imports = [ - inputs.self.nixosModules.backup - ]; - - services.postgresqlBackup = { - enable = true; - compression = "none"; - startAt = "daily"; - }; - - nixCommunity.backup = [ - { - name = "postgresql"; - after = [ config.systemd.services.postgresqlBackup.name ]; - paths = [ config.services.postgresqlBackup.location ]; - startAt = "daily"; - } - ]; - - services.postgresql = { - enable = true; - package = pkgs.postgresql_18; - }; -} diff --git a/modules/secrets/backup.yaml b/modules/secrets/backup.yaml index 7693aa220..896fd4ce4 100644 --- a/modules/secrets/backup.yaml +++ b/modules/secrets/backup.yaml @@ -4,77 +4,67 @@ sops: - recipient: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMm3/o1HguyRL1z/nZxLBY9j/YUNXeNuDoiBLZAyt88Z enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEVTL3RrUSBoY0ln - TFBwZDFTSEE0NGZ4cFkzSmdHUDJsQVl3RFBNeGRwS2QyT2lzRWtjCkYxUm9TMHVN - K0dILzhjTXV6QlNXQ3ZGRHZuSlZKMXlHQU4xSDlyMFUvL2cKLS0tIGI1WFpzcjE3 - c2o5eXBPajlHSm5ZQzVrS2ttNnN0MzMyTjQ1c1NYZVI1RUkKKFynY+lX9YDcAk1G - bj2tajvc35EyrkQy5+ULhy3VI+udPrTCZ5g/xOtcNd+fh6UGLjggTw86EHHlK5rP - j7K47Q== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEVTL3RrUSB0cjNP + cHA0THc4L3BJRktJWFBrWitWMHdzbXA5ZkUzV0lpMnk2K2gzU0VRCm9GMmtYSWxm + NnpLVERpUkRRcW5DcVhSeU1RVG1lUXFYcjhBdGdlL1ZtQ0UKLS0tIGIvdzIzUml5 + NEVOZXdvNk5MMGNKVm9Janc5UjZpZjJOZWJsTTBCUmZNdUEKsrtXQE/a/H1uR0le + DVZpA8S4KykeCEHZHPnsjvShvDuHWEN80is9yA62j6zhirVRdEibr/M0BmQ8pgH+ + Cm7lIA== -----END AGE ENCRYPTED FILE----- - recipient: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFiozp1A1+SUfJQPa5DZUQcVc6CZK2ZxL6FJtNdh+2TP enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHczV0xmQSAydmhZ - eXVRVkN5VklTRGE1K1M2b1V3d1NobWpid2tOd3ZvK0tTS0hHMlVNCjY0YWVVYlp0 - Y0NZTFY3N3pyTXhxcU1RckhreHplQ3p4WWhpbXYwS3RBb1EKLS0tIDRFWk1FMFlt - bnlILzRKbDk4VFRTSUFONUEvZXF0L2I4M3JHVWlmdTcyWEEKrzHkszyWQW9YotgO - bMGoNpk9XE49Jh5UjAQOk2lcss8PIgxLCSODz+kTrCDTg8J5iXygy0FGSzrwQ62k - OZqEVg== - -----END AGE ENCRYPTED FILE----- - - recipient: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILAkBZMRNgsJ/IbLtjMHqBw/9+4tyn9nT+5B5RFiV0vJ - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG1lemEyZyBONWVj - UUF4YUJoTlpyeTcrY0V0WDlVTlFrWTN0TGI1WnB2OGdVNkJZWVNZCnNxYW9SMUZV - UCttVExLU2RMN0x5MlZkZkZPeG5MV2FKTk5qMEVIbWY2ckEKLS0tIDBqb1VoVmh4 - dk9oOGtxaGlkdDZZMTdxZm5vemtsVm1QenlpSktjQUF1SXMKgUzVGmjFBYueQfgY - ITN1xcBWEVZ+u0CE/mIPPIM1QJfinUj9iYiINr9lR6+edcK6ZIx5O5VUzf98lUjs - fXzCxA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHczV0xmQSBQK1Va + cFVFdmk2bjJKMjUvZDhpeWpVVHM5SFpicXRsbUpRYStpUDlibWdJCm9TR0lEajNz + U0dUdmhjcjBUODJBRk02WU4yMjQ5QnJPL2tTTGFCbUNSencKLS0tIFNQYkpkaVRF + cGdNV3crNG15Rm9zMWJidkV4enlYY2ZpQzlTaSt1K3ZqTHMKNsRxY950e/GoDuyI + nnNi22UwmyHXPMZAh2Pp9DuhOvtE42cLKqSboaUrjryXvnSDpDwCoh8krcsCIbZ/ + 4orT1g== -----END AGE ENCRYPTED FILE----- - recipient: age1dzvjjum2p240qtdt2qcxpm7pl2s5w36mh4fs3q9dhhq0uezvdqaq9vrgfy enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0VllRS3c3N2FkTGdzM1FO - emxJVWNFSUM1YXFQT0VWREJ2RURkT0drSWlJCmttVHpSNXdlWHBxTUpETjJRZ1hH - a1gyeVppQWZKTTQxb2E2ZnZ1L2cweUEKLS0tIG95RDR2NDJPTkFuNGM3VTFGcHpL - dXhRd00yMmd6TisveXhOUFd4QXBneVEKAbcO+quUvT41nOhtzNNf/AOsxMEzfk0E - dzmHkHWJUVCSLe5C9ZfJ+qhTJ3iw/hPX+dkueDKvI7GdbjjamSc0Pw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWUnQ5U3MrRFlKVzFwWXgy + QVB3bjVRdk4rODh5b0ZFR2FJdUJsc21JVlNvCkYvV2g3M2tkeUFsM1d4RkNvVWRj + NkhQajJZRy9IemtVK0RMTDY2czk1NkkKLS0tIGxVaG1ZSHBvRy9MNzJ2by9tUEQy + RGpkZldaemZhQThNZ3MrdEFaMGExWGMKmMZp0KU7ffYa7gxVDTp3AJO8RvAyURTH + 3x/aP0NaXHN9QO7NuSCVKvqJP6W0OwvCZKDAqlhqoyzzMz+r0GQeBA== -----END AGE ENCRYPTED FILE----- - recipient: age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwcktXMDVFY2lXOVRhajBN - c2cwTmxvZDE5U1lYTzhBM2lTRE1QNldyUDJFCitlWXAzMDArTzBsaHZOTjBSZi8x - aW5rSVpKSTMvR3VKa0FyRVVYL3VkYUUKLS0tIFAxb0FsSzJrYTNVTFVyV1Z4NGlB - dHpxNXRpU215Nk9HUEpwYXlkVHlxS0kKfafZemR234vGtthLGdQBZFNcdFoT77h8 - j9Shmn+HS31IBcyiCKTHggBbjHIvuUnLvVcY3bL7ZjIk3A34sbjLQQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIUTJabElHc3Z3MGhrcjJB + Z2RvSFNNL0xWTTlPTTJoN3FJc1Z5aDRUL3pNCmRvTUw1cW9vRjExcUR6bDNIRkhq + Vk1lcCt1KytYcVEwL3gwdllLRUlwM2MKLS0tIE1WMnIrL1VTZVdhRzlpK3I1VUVi + cXladTZJRjdla09MQWlnTnpVOENBVW8KDrnWjXCeVzcJaChk5EpF+OkjQTDH4R5j + +HaVIkXoEXQqfA5+/w5/xTe7D+6S5pakGUMDs+CAmSgOxnDtq364Og== -----END AGE ENCRYPTED FILE----- - recipient: age1d87z3zqlv6ullnzyng8l722xzxwqr677csacf3zf3l28dau7avfs6pc7ay enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOdDdKenhHM2s4bnArWTZX - UmwvZncvMnM1M1FqZHJXY2xtU2o2endmMnlrCmo4aGNBSU4xWHlYbS9iYjFKTzl2 - TWNQTkM1WWV2Uk5RaUdBb3JMRHRVOG8KLS0tIHNha08xRG55d0l5ZGR6UTVmS3Bz - QWNxSWJ0UEMwK1BpR2kyRWJYRnBjcmMKnTiCEplbZAJDKVsgIcHCtkvNhnUbR6bk - bbepRca2aH8S9JI1h5iCacalr7607UuGT1vTKSjH1EtnvErJbDz68g== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiRkZzdVJENzlGRXJIT3Rr + blo4LzdVcXJXdDN1WUw5T2NSMStlTDFIL1VJCmtJWUxWOEZ6SDRXV0FqOGJQNU1J + czFXWTlueDRCU0ZndWZhbitFR2ZzM0EKLS0tIHBseWw5ekNZSEIrbEhuWkgxN29O + K24wY3REM1J3Q1d3Qlc5Y0RMaGszOVEKa8QCuX9wYb3vWIM97AOUn/zdz051NqaU + ajtwDDciQ8F4GuW9U5+AjSf0Mb3z4JdiB21p2jA9yIgrBECCFxQIKA== -----END AGE ENCRYPTED FILE----- - recipient: age1jrh8yyq3swjru09s75s4mspu0mphh7h6z54z946raa9wx3pcdegq0x8t4h enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWMmFRYmRMY3J4Sm82UEx3 - WHZEM1ZjUTJHSXhVTGkxcFcxV1hDZnBFREYwCkxhMXl4cUl3cnUvckQ3R3JuRlF6 - VENGblV4dDZ6Z1ZUKzQvZGVDVGRRSzgKLS0tIGF5dWw3enBLa1JVcFBORFZYTkZV - dnlxOFdzdWpoK3pNeGlkWlY2c1ZTdk0KNxgTztzxxMJZBBHPzKxx9ChVpuNnzixK - TYJR8OuKNwByB/vLee3Fgslx2LOv6Akl09brxxRjeM5TbTvoojZ3YQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUZkRJa0FLdG5YSjMyUW9j + SVVzckhNcUhYWG9nWS9Cb0JFYW1BUGREM1NRCk9pSGt6QSsvMW9zakhlZndwdGc1 + aVJ0MkhLVjVkRVZpWFREbkl1eHpxS2MKLS0tIFExODJJQVc5M2tDYjRSK1VSVndz + M1dueFFrcHpPWURVUjhwTCtDUnE1TkEK894JR6dlzQueyIZRAiQbvnmtXw6VjScK + J5BgZmnGRoqX2qEAYj+DOSbUzh+VIgg89HLye9qCV2Zn2ANUivHSxQ== -----END AGE ENCRYPTED FILE----- - recipient: age1m7xhem3qll35d539f364pm6txexvnp6k0tk34d8jxu4ry3pptv7smm0k5n enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLNXhwL1BnN3E4QW9sTFJT - SitEQk5MRW9rMGJacFI2TE5VNFdtTVpTOWpjCnJUemlweVJXbGZOb1FJS0JNR2VR - cjFhL21ScDQvd1FIZ3p1Zy9ndnpaSE0KLS0tIFF5M0djbEhUUDRVSkRhQ0dGK29m - UjlOdHUwVzZqdGRWUGZhbmpaa0l2UzgKkAmCAeyi91yJJWLO8jJglxmb+mIvo0gi - LcvzAJCpkq2474ohnQmHNTgJpZ1cevpkgiQTZUg4rZEwqMmvXYy2jA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5aVRMMUxlTGNOc1hVOHVm + OHpjbkRTelBvT3c0NVRLem5VRjA5QTZCblRZCmNBeFBNaWRha3NDa2Nzc0dFT2Vn + YTBxQWZwNlplOVk2aWgxY0Y5eit2OVkKLS0tIG5jSjIyWjZhdGJ0NnZCTlpUMzhq + RGZ6Mmwrd08wN3lMYVE5V1lGS3hZbHcKY6Us+t+7vRhGLWkb8kS84/+2L9umcX0q + smQALmDMDO+LtkNCW5CZNReSUeCX6FHCFoh/BsuI6E+5/YL15IwyOw== -----END AGE ENCRYPTED FILE----- lastmodified: "2024-12-19T00:28:56Z" mac: ENC[AES256_GCM,data:jc/oaE8thHZzrCkHfcD40YiyZczKoltvxU9DkX8VUsCkLaEIHjoPyyo82EA4DH3GH4Nk4f6+AN84MFzBjh4k/2PVctUukpB5uqQyTtluhMxA7MhIaIquDA44qmYU3tg3jTaTJwaWzUf1UdFxjOG489U7coqWzPtSw4yMLLK6KEk=,iv:fymEmLFZGHWpoNbUYZuqydF1ssGCqKVYqOOVtkLbVbQ=,tag:ZXFZI24XBCLqUaNAUlW7gA==,type:str] diff --git a/sops.nix b/sops.nix index e9e04725a..b3380aef5 100644 --- a/sops.nix +++ b/sops.nix @@ -29,7 +29,6 @@ let "modules/secrets/backup.yaml" = [ "build02" "build03" - "web01" ]; "modules/secrets/community-builder.yaml" = [ "build01" diff --git a/terraform/.envrc b/terraform/.envrc index 38c33f44a..d8cc365f8 100644 --- a/terraform/.envrc +++ b/terraform/.envrc @@ -1,8 +1,8 @@ # shellcheck shell=bash -env_vars_required GITHUB_TOKEN +env_vars_required GITHUB_TOKEN TF_TOKEN_app_terraform_io TFE_TOKEN use flake .#terraform TF_VAR_passphrase="$(sops -d --extract '["passphrase"]' secrets.yaml)" -export PGPORT=5433 TF_VAR_passphrase +export TF_VAR_passphrase diff --git a/terraform/locals.tf b/terraform/locals.tf new file mode 100644 index 000000000..42695489e --- /dev/null +++ b/terraform/locals.tf @@ -0,0 +1,10 @@ +locals { + # The set of admins + admins = { + adisbladis = "adisbladis@gmail.com" + mic92 = "joerg@thalheim.io" + ryantm = "ryan@ryantm.com" + zimbatm = "zimbatm@zimbatm.com" + zowoq = "zowoq.gh@gmail.com" + } +} diff --git a/terraform/terraform_backend.tf b/terraform/terraform_backend.tf index f74456abb..1956c2b67 100644 --- a/terraform/terraform_backend.tf +++ b/terraform/terraform_backend.tf @@ -1,6 +1,8 @@ terraform { - backend "pg" { - conn_str = "postgres://terraform@localhost/terraform?sslmode=disable" + cloud { + hostname = "app.terraform.io" + organization = "nix-community" + workspaces { name = "infra" } } encryption { @@ -25,5 +27,6 @@ terraform { } variable "passphrase" { + ephemeral = true sensitive = true } diff --git a/terraform/terraform_cloud.tf b/terraform/terraform_cloud.tf new file mode 100644 index 000000000..d750d9df4 --- /dev/null +++ b/terraform/terraform_cloud.tf @@ -0,0 +1,66 @@ +# Configure Terraform Cloud, with Terraform +# +# Terraform Cloud is used only for one thing: to store the terraform state. +# +locals { + # NOTE: there is a limit of 5 members in the free plan + tfe_owners = local.admins +} + +# Org setup + +resource "tfe_organization" "nix-community" { + name = "nix-community" + email = "admin@nix-community.org" + allow_force_delete_workspaces = true + speculative_plan_management_enabled = false +} + +# Members setup + +resource "tfe_team" "owners" { + name = "owners" + organization = tfe_organization.nix-community.name +} + +resource "tfe_organization_membership" "owners" { + for_each = local.tfe_owners + organization = tfe_organization.nix-community.name + email = each.value +} + +resource "tfe_team_organization_member" "owners" { + for_each = local.tfe_owners + team_id = tfe_team.owners.id + organization_membership_id = tfe_organization_membership.owners[each.key].id +} + +# Project setup + +resource "tfe_project" "default" { + organization = tfe_organization.nix-community.name + name = "Default Project" +} + +resource "tfe_project_settings" "default-settings" { + project_id = tfe_project.default.id + # workspaces in this project will use local execution mode by default + default_execution_mode = "local" # only use it to hold state +} + +# Workspaces setup + +# For new we only have one workspace that contains everything +resource "tfe_workspace" "infra" { + name = "infra" + organization = tfe_organization.nix-community.name + + file_triggers_enabled = false + force_delete = false + queue_all_runs = false +} + +resource "tfe_workspace_settings" "infra-settings" { + workspace_id = tfe_workspace.infra.id + execution_mode = "local" # only use it to hold state +} diff --git a/terraform/terraform_providers.tf b/terraform/terraform_providers.tf index 53afdabb3..7b6a009b0 100644 --- a/terraform/terraform_providers.tf +++ b/terraform/terraform_providers.tf @@ -9,6 +9,9 @@ terraform { sops = { source = "carlpett/sops" } + tfe = { + source = "hashicorp/tfe" + } } } diff --git a/terraform/tf-tunnel b/terraform/tf-tunnel deleted file mode 100755 index eb3c1e033..000000000 --- a/terraform/tf-tunnel +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -eu - -pushd "$(dirname "$0")" >/dev/null - -ssh -f -N -L "$PGPORT":/var/run/postgresql/.s.PGSQL.5432 web01.nix-community.org - -popd