diff --git a/tf/deployment/.env b/tf/deployment/.env index 68cc2e4e2..abdd0ed49 100644 --- a/tf/deployment/.env +++ b/tf/deployment/.env @@ -7,6 +7,7 @@ export TF_VAR_github_app_id="op://tf/GITHUB_APP_IMMICH_TOFU/app_id" export TF_VAR_github_app_pem_file="op://tf/GITHUB_APP_IMMICH_TOFU/pkcs1" export TF_VAR_github_owner="op://tf/GITHUB_APP_IMMICH_TOFU/owner" export TF_VAR_op_service_account_token="op://tf/1pass_service_account/superuser_token" +export TF_VAR_futo_op_service_account_token="op://tf_$ENVIRONMENT/yucca_futo_1pass_superuser_service_account/password" export TF_VAR_discord_token="op://tf/IMMICH_TF_DISCORD_BOT_TOKEN/password" export TF_VAR_zitadel_profile_json="op://tf/ZITADEL_PROFILE_JSON/password" export TF_VAR_zitadel_github_client_id="op://tf/GITHUB_OAUTH_APP_IMMICH_ZITADEL_CLIENT_ID/password" diff --git a/tf/deployment/modules/shared/1password/account/secrets.tf b/tf/deployment/modules/shared/1password/account/secrets.tf index 0b5a4f6fa..b422411e3 100644 --- a/tf/deployment/modules/shared/1password/account/secrets.tf +++ b/tf/deployment/modules/shared/1password/account/secrets.tf @@ -43,12 +43,7 @@ module "manual-secrets" { "IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION", "IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION" ] - dev = [ - "MONITORING_GRAFANA_TF_AUTH_TOKEN", - "MONITORING_GRAFANA_URL", - "IMMICH_DISCORD_SERVER_ID", - ] - prod = [ + scoped = [ "MONITORING_GRAFANA_TF_AUTH_TOKEN", "MONITORING_GRAFANA_URL", "IMMICH_DISCORD_SERVER_ID", @@ -75,12 +70,7 @@ module "generated-secrets" { { name = "OAUTH2_PROXY_COOKIE_SECRET", length = 32 }, { name = "IMMICH_GITHUB_ACTION_CHECKS_WEBHOOK_SECRET" } ] - dev = [ - { name = "METRICS_READ_TOKEN" }, - { name = "METRICS_WRITE_TOKEN" }, - { name = "METRICS_ADMIN_TOKEN" } - ] - prod = [ + scoped = [ { name = "METRICS_READ_TOKEN" }, { name = "METRICS_WRITE_TOKEN" }, { name = "METRICS_ADMIN_TOKEN" }, diff --git a/tf/deployment/modules/shared/1password/futo-account/.terraform.lock.hcl b/tf/deployment/modules/shared/1password/futo-account/.terraform.lock.hcl new file mode 100644 index 000000000..3cbebc0b2 --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/.terraform.lock.hcl @@ -0,0 +1,79 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/1password/onepassword" { + version = "2.1.0" + constraints = "~> 2.0" + hashes = [ + "h1:B3G7M02HxGCgT4S1+d4ITPR0vj7ZXDzGx+vqkKtk81c=", + "zh:0d6f803760aa7cae0e841cfca17ef04411231170b2844cc0b30556d5476d9dff", + "zh:17badbffb56309f28aee1893a6b93d1cd87ed5157704fb17b93889f0ccf8cc2d", + "zh:185e0c7c66cc159769d7b91c37ab51a546efc13fb99eb206481739a521f75236", + "zh:19e213f8265445a29d8bb7c7b1f0d4e3c1fdfd538178704f8e8378db2dcdf359", + "zh:49929666304f97301f44ee0fdd39f40f63e35ccfb4c81588439bdab6d5bafde0", + "zh:4de33f5630350d6a561d5d62994d525beb8849c94287c2658f39242fe3170cf8", + "zh:4f212a8fbbbaa7a47f1b31857be3bad2d590f92be845c6b252c9716bb70076d9", + "zh:596cc2bd9aaafd2e649aabcff0125afa9d4270f702813c935fbd5694eed002e7", + "zh:618e703a43608c502066c5b909ead45b1f4202f7cebc993f447278477d32cda2", + "zh:61fde3651bcb2e691ee9d82ce1de03588d006f53b2e8e2516910321da8627228", + "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", + "zh:db05022113841a00174bba5e24cfc77195bbc03d24339c5e8ac4346069901e45", + "zh:dcc7792a24c74890081a96ba2bc360d90ab71a4d25232ca18046d9868c835e21", + "zh:f2e67a298d20bf52cb208611767b420962d3f0d518e89cf41cc432551b1faf63", + "zh:f7e587814506c7e74fc1d80b29465c8e4b7bdbf803f7f8c0a8bb498968cdd58d", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.7.2" + constraints = "3.7.2" + hashes = [ + "h1:5wxrQQTchfk/2S1wSi9lx/fmiscVLGI3kL2v/+LccHU=", + "h1:C1D2Vo445WXAeLwSpovebSDR97ohiGvXVixcXJneQTg=", + "h1:KvLLxlMi6iNdlZS+vQAwovIeL2r5Q2s/EXXF+oypKHI=", + "h1:Q1EQQw7icbHSYUSYMlgi4qSXPuJDySuMjXcC0WqzgP8=", + "h1:cFGCdxTlsrteTiaOV/iOQdql7eJkD3F/vtJxenkj9IE=", + "h1:o15Kr/27vFN5AD9YkF48tDrHLSAshEq4Q7sAxIViZHM=", + "h1:rdpkD+Rzr+KCPqOvb1ckzupjWCOum/boRX4FqVboAHQ=", + "h1:ttMGebt31P1FZCEWptLTMpmx1aeDvkJ9nBDivtCCkyM=", + "h1:wz31hqWhHTq9bgIM/3+VNqy89JAICMXSwCmG8A70w0A=", + "h1:yHMBbZOIHlXUuBQ8Mhioe0hwmhermuboq2eNNoCJaf8=", + "zh:2ffeb1058bd7b21a9e15a5301abb863053a2d42dffa3f6cf654a1667e10f4727", + "zh:519319ed8f4312ed76519652ad6cd9f98bc75cf4ec7990a5684c072cf5dd0a5d", + "zh:7371c2cc28c94deb9dba62fbac2685f7dde47f93019273a758dd5a2794f72919", + "zh:9b0ac4c1d8e36a86b59ced94fa517ae9b015b1d044b3455465cc6f0eab70915d", + "zh:c6336d7196f1318e1cbb120b3de8426ce43d4cacd2c75f45dba2dbdba666ce00", + "zh:c71f18b0cb5d55a103ea81e346fb56db15b144459123f1be1b0209cffc1deb4e", + "zh:d2dc49a6cac2d156e91b0506d6d756809e36bf390844a187f305094336d3e8d8", + "zh:d5b5fc881ccc41b268f952dae303501d6ec9f9d24ee11fe2fa56eed7478e15d0", + "zh:db9723eaca26d58c930e13fde221d93501529a5cd036b1f167ef8cff6f1a03cc", + "zh:fe3359f733f3ab518c6f85f3a9cd89322a7143463263f30321de0973a52d4ad8", + ] +} + +provider "registry.opentofu.org/hashicorp/tls" { + version = "4.1.0" + constraints = "4.1.0" + hashes = [ + "h1:E9RjaL6cn8U/IkzfNcmrf/9EtMGjJnwUeXpx85sOGRg=", + "h1:M2wp0tzlf2SDIxQbN5Sxc8o5HCGYZFfyfPwM9MJI3PE=", + "h1:MByilNnYPdjPTlb/qcNgR0DErA6550hI6wd8OJYB1vw=", + "h1:RBhHxjVu41XdAnM4WxxGTz2nYaccHNLalqx4031L8rE=", + "h1:Scu4v7p3hVi6JmyWN4e1KkR31MX48T65dfA3Nfaeb/E=", + "h1:Xb4aKDd/LTy9kSpauyTIe/Y4py2xK2sbImV1LdgMc/Q=", + "h1:m4r9DvgYoUdf1ZeJMd2NGs3b6+8/RPhXUrEex554eQw=", + "h1:p4jzSJLVx9DHkNZ1ax2/bMPTirjZxxN9nmiVx0aFQjA=", + "h1:ujNwtB97C/kEt12+S3mUTWkGaJO8LNbqWoRg1FZ5a80=", + "h1:yNZuPWUgw6Ik2huf9lhsuCGONWo2rsY1MfeceT0BQpw=", + "zh:187a99f0d236fd92da224e2f026c4ca8f1dcbf2b5cddc8e6896801bacfab0d73", + "zh:61a32a01cc46f382014dcf7aff5bcac61fe97bd69d3ccb51c801e9437ecdb9ce", + "zh:683ba18baa2cc336ff83f061b5e4569e2cd7c4a097b53a2d80bb0a26be2fc59a", + "zh:85c7640ea13dcf5ae5f7f3abbf2f21e4b93ce7f333ffee5b4a6acd6b5fe71223", + "zh:882f2c5214fd6d280a500acfd560925a71030ef70e10d11fa2b94815b58ae9b6", + "zh:97cb5e0b81b8687870a6b8a16e9a9cfe546e2fdb7534bdd8302eda0d66393f78", + "zh:c0a0110b15ce45140036fe5bf5a44cb822c2f55b30ff2770faf37d7c3cae3b5e", + "zh:d98c1c63fd0c76704fd7be38c316c305a2c95f3215330f2fb1e6b0b7081bf8e9", + "zh:e703a7adf220ac436f8ebfd06529de865b965fcfc461c7ef7b71afa0de04c8e9", + "zh:e93e241150cd438a0708679cb4aa7976742fde02f4c1725cfdefc405c4eeca1a", + ] +} diff --git a/tf/deployment/modules/shared/1password/futo-account/config.tf b/tf/deployment/modules/shared/1password/futo-account/config.tf new file mode 100644 index 000000000..63f0eb561 --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/config.tf @@ -0,0 +1,21 @@ +terraform { + backend "pg" { + schema_name = "prod_1password_futo_account" + } + required_version = "~> 1.7" + + required_providers { + onepassword = { + source = "1Password/onepassword" + version = "~> 2.0" + } + random = { + source = "hashicorp/random" + version = "3.7.2" + } + tls = { + source = "hashicorp/tls" + version = "4.1.0" + } + } +} diff --git a/tf/deployment/modules/shared/1password/futo-account/providers.tf b/tf/deployment/modules/shared/1password/futo-account/providers.tf new file mode 100644 index 000000000..507429683 --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/providers.tf @@ -0,0 +1,3 @@ +provider "onepassword" { + service_account_token = var.futo_op_service_account_token +} diff --git a/tf/deployment/modules/shared/1password/futo-account/terragrunt.hcl b/tf/deployment/modules/shared/1password/futo-account/terragrunt.hcl new file mode 100644 index 000000000..c63229bc5 --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/terragrunt.hcl @@ -0,0 +1,11 @@ +terraform { + source = "../../../../../" + + extra_arguments custom_vars { + commands = get_terraform_commands_that_need_vars() + } +} + +include "root" { + path = find_in_parent_folders("root.hcl") +} diff --git a/tf/deployment/modules/shared/1password/futo-account/variables.tf b/tf/deployment/modules/shared/1password/futo-account/variables.tf new file mode 100644 index 000000000..2ba1f9318 --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/variables.tf @@ -0,0 +1 @@ +variable "futo_op_service_account_token" {} diff --git a/tf/deployment/modules/shared/1password/futo-account/yucca-secrets.tf b/tf/deployment/modules/shared/1password/futo-account/yucca-secrets.tf new file mode 100644 index 000000000..bfdcfd305 --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/yucca-secrets.tf @@ -0,0 +1,42 @@ +module "yucca-manual-secrets" { + source = "./shared/modules/secrets/manual" + + secrets = { + global = [ + "TF_STATE_S3_ENDPOINT", + "TF_STATE_S3_BUCKET", + "TF_STATE_S3_REGION", + "TF_STATE_S3_ACCESS_KEY", + "TF_STATE_S3_SECRET_KEY", + "OVH_APPLICATION_KEY", + "OVH_APPLICATION_SECRET", + "OVH_CONSUMER_KEY", + "TAILSCALE_API_KEY", + "TAILSCALE_TAILNET_ID" + ] + scoped = [] + } + global_vault = "yucca_tf_manual" + copy_global_vault = "yucca_tf" + scoped_vaults = { + "yucca_tf_prod_manual" = "yucca_tf_prod" + "yucca_tf_staging_manual" = "yucca_tf_staging" + "yucca_tf_dev_manual" = "yucca_tf_dev" + } +} + +module "generated-secrets" { + source = "./shared/modules/secrets/generated" + + secrets = { + global = [] + scoped = [] + } + + global_vault = "yucca_tf" + scoped_vaults = toset([ + "yucca_tf_prod", + "yucca_tf_staging", + "yucca_tf_dev", + ]) +} diff --git a/tf/shared/modules/secrets/generated/data.tf b/tf/shared/modules/secrets/generated/data.tf index 932a3f9a3..fdd21bef5 100644 --- a/tf/shared/modules/secrets/generated/data.tf +++ b/tf/shared/modules/secrets/generated/data.tf @@ -1,11 +1,8 @@ -data "onepassword_vault" "tf" { - name = "tf" +data "onepassword_vault" "global" { + name = var.global_vault } -data "onepassword_vault" "tf_dev" { - name = "tf_dev" -} - -data "onepassword_vault" "tf_prod" { - name = "tf_prod" +data "onepassword_vault" "scoped" { + for_each = var.scoped_vaults + name = each.value } diff --git a/tf/shared/modules/secrets/generated/secrets.tf b/tf/shared/modules/secrets/generated/secrets.tf index ea9b7d754..f899294c0 100644 --- a/tf/shared/modules/secrets/generated/secrets.tf +++ b/tf/shared/modules/secrets/generated/secrets.tf @@ -2,28 +2,22 @@ locals { secrets = concat( var.secrets.global != null ? [ for secret_obj in var.secrets.global : { - vault = data.onepassword_vault.tf + vault = data.onepassword_vault.global name = secret_obj.name length = secret_obj.length type = secret_obj.type } ] : [], - var.secrets.dev != null ? [ - for secret_obj in var.secrets.dev : { - vault = data.onepassword_vault.tf_dev - name = secret_obj.name - length = secret_obj.length - type = secret_obj.type - } - ] : [], - var.secrets.prod != null ? [ - for secret_obj in var.secrets.prod : { - vault = data.onepassword_vault.tf_prod - name = secret_obj.name - length = secret_obj.length - type = secret_obj.type - } - ] : [] + var.secrets.scoped != null ? flatten([ + for vault_name in var.scoped_vaults : [ + for secret_obj in var.secrets.scoped : { + vault = data.onepassword_vault.scoped[vault_name] + name = secret_obj.name + length = secret_obj.length + type = secret_obj.type + } + ] + ]) : [] ) } diff --git a/tf/shared/modules/secrets/generated/variables.tf b/tf/shared/modules/secrets/generated/variables.tf index ebe69b2df..6d52679d5 100644 --- a/tf/shared/modules/secrets/generated/variables.tf +++ b/tf/shared/modules/secrets/generated/variables.tf @@ -5,12 +5,7 @@ variable "secrets" { length = optional(number) type = optional(string, "alphanumeric") }))) - dev = optional(list(object({ - name = string - length = optional(number) - type = optional(string, "alphanumeric") - }))) - prod = optional(list(object({ + scoped = optional(list(object({ name = string length = optional(number) type = optional(string, "alphanumeric") @@ -18,6 +13,18 @@ variable "secrets" { }) } +variable "global_vault" { + type = string + description = "Name of the vault for storing global secrets" + default = "tf" +} + +variable "scoped_vaults" { + type = set(string) + description = "Names of the vaults for storing scoped secrets" + default = ["tf_prod", "tf_dev"] +} + variable "default_secret_length" { type = number description = "The default length for generated secrets if not specified per secret." diff --git a/tf/shared/modules/secrets/manual/data.tf b/tf/shared/modules/secrets/manual/data.tf index 287188776..5e32e343f 100644 --- a/tf/shared/modules/secrets/manual/data.tf +++ b/tf/shared/modules/secrets/manual/data.tf @@ -1,23 +1,17 @@ -data "onepassword_vault" "manual" { - name = "tf_manual" +data "onepassword_vault" "manual_global" { + name = var.global_vault } -data "onepassword_vault" "manual_dev" { - name = "tf_dev_manual" +data "onepassword_vault" "manual_scoped" { + for_each = var.scoped_vaults + name = each.key } -data "onepassword_vault" "manual_prod" { - name = "tf_prod_manual" +data "onepassword_vault" "copy_global" { + name = var.copy_global_vault } -data "onepassword_vault" "tf" { - name = "tf" -} - -data "onepassword_vault" "tf_dev" { - name = "tf_dev" -} - -data "onepassword_vault" "tf_prod" { - name = "tf_prod" +data "onepassword_vault" "copy_scoped" { + for_each = var.scoped_vaults + name = each.value } diff --git a/tf/shared/modules/secrets/manual/secrets.tf b/tf/shared/modules/secrets/manual/secrets.tf index 84cebc251..bce70c5fb 100644 --- a/tf/shared/modules/secrets/manual/secrets.tf +++ b/tf/shared/modules/secrets/manual/secrets.tf @@ -2,25 +2,20 @@ locals { secrets = concat( var.secrets.global != null ? [ for name in var.secrets.global : { - manual_vault = data.onepassword_vault.manual - vault = data.onepassword_vault.tf + manual_vault = data.onepassword_vault.manual_global + vault = data.onepassword_vault.copy_global name = name } ] : [], - var.secrets.dev != null ? [ - for name in var.secrets.dev : { - manual_vault = data.onepassword_vault.manual_dev - vault = data.onepassword_vault.tf_dev - name = name - } - ] : [], - var.secrets.prod != null ? [ - for name in var.secrets.prod : { - manual_vault = data.onepassword_vault.manual_prod - vault = data.onepassword_vault.tf_prod - name = name - } - ] : [] + var.secrets.scoped != null ? flatten([ + for manual_vault, copy_vault in var.scoped_vaults : [ + for name in var.secrets.scoped : { + manual_vault = data.onepassword_vault.manual_scoped[manual_vault] + vault = data.onepassword_vault.copy_scoped[manual_vault] + name = name + } + ] + ]) : [] ) } diff --git a/tf/shared/modules/secrets/manual/variables.tf b/tf/shared/modules/secrets/manual/variables.tf index ec5f05c6a..8757512fb 100644 --- a/tf/shared/modules/secrets/manual/variables.tf +++ b/tf/shared/modules/secrets/manual/variables.tf @@ -1,7 +1,27 @@ variable "secrets" { type = object({ global = optional(list(string)) - dev = optional(list(string)) - prod = optional(list(string)) + scoped = optional(list(string)) }) } + +variable "global_vault" { + type = string + description = "Name of the vault for storing global manual secrets" + default = "tf_manual" +} + +variable "copy_global_vault" { + type = string + description = "Name of the vault for copying global secrets to" + default = "tf" +} + +variable "scoped_vaults" { + type = map(string) + description = "Map of manual vault names to copy vault names for scoped secrets" + default = { + "tf_prod_manual" = "tf_prod" + "tf_dev_manual" = "tf_dev" + } +}