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 221ce2245..b89120def 100644 --- a/tf/deployment/modules/shared/1password/account/secrets.tf +++ b/tf/deployment/modules/shared/1password/account/secrets.tf @@ -48,13 +48,7 @@ module "manual-secrets" { "GITLAB_OAUTH_APP_FUTO_ZITADEL_ISSUER", "GITHUB_APP_FUTO_ORG_SELFHOSTED_RUNNERS_INSTALLATION_ID" ] - dev = [ - "IMMICH_DISCORD_BOT_TOKEN", - "MONITORING_GRAFANA_TF_AUTH_TOKEN", - "MONITORING_GRAFANA_URL", - "IMMICH_DISCORD_SERVER_ID", - ] - prod = [ + scoped = [ "IMMICH_DISCORD_BOT_TOKEN", "MONITORING_GRAFANA_TF_AUTH_TOKEN", "MONITORING_GRAFANA_URL", @@ -83,12 +77,7 @@ module "generated-secrets" { { name = "IMMICH_GITHUB_ACTION_CHECKS_WEBHOOK_SECRET" }, { name = "OUTLINE_ROLE_SYNC_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..5a172880c --- /dev/null +++ b/tf/deployment/modules/shared/1password/futo-account/.terraform.lock.hcl @@ -0,0 +1,69 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/1password/onepassword" { + version = "2.2.1" + constraints = "~> 2.0" + hashes = [ + "h1:CosIqZ6jkgylvF23rLyNixIecZAAhFyb61sLl6GrEsc=", + "zh:025709a6b5f1b3685d277f2c48f7cb8b53d14b3699c1123d7e9a2135c099c533", + "zh:037fc89d150063a8aacdcab08ba26038b489fe2468d509b842d298ea59096ca6", + "zh:233777182b25faf1658e8ce171b684460983bb41cff79fb243662f3f9dc5ca6c", + "zh:2fb5ca2fc8c37b1d1c54da646ed13bf40897941fe92eece784fba496f677b533", + "zh:4b25b5ce1f694ec265e65234fc85d6bdf3810297ffeaced54ad46a1ba28142de", + "zh:5509d1e4fb7b45c63124ec66fd1f9d6757daa8bf1f7bdd724d5adb2965b61436", + "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", + "zh:a23ba946c629ec912b2fcbf606a2eb8853626ec0e0bee749f2d39146a872c082", + "zh:a3d3024485426237d7b4a4350b12dda4d29d88f3942246a9370be35ec2a51e9e", + "zh:a6ef65544ab8fc26d468b38636407a3d2d902e35c51b648729bf97c31d1937f9", + "zh:afbe9480a0da0ad8dc514b277f1e4be36b8931f045021d05c21665ef1ac0b7c8", + "zh:b2e96e69fa9ff7e179dccdef5b785cd020eb46bb2b3d1d507d009d71be6b0c26", + "zh:ceefaede9e8a3104463523ba267e3e985b27a706f7628a9ddd37330c2ca59d4d", + "zh:ea77786bd6809ff4f8043b84a0212fec4de18b7d51bc420417ba10999ca99887", + "zh:f7d8160c3669c8ab76a2da14ea740d91a08ca23d1fb657669e52a840b2b113d9", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.8.1" + constraints = "3.8.1" + hashes = [ + "h1:EHn3jsqOKhWjbg0X+psk0Ww96yz3N7ASqEKKuFvDFwo=", + "zh:25c458c7c676f15705e872202dad7dcd0982e4a48e7ea1800afa5fc64e77f4c8", + "zh:2edeaf6f1b20435b2f81855ad98a2e70956d473be9e52a5fdf57ccd0098ba476", + "zh:44becb9d5f75d55e36dfed0c5beabaf4c92e0a2bc61a3814d698271c646d48e7", + "zh:7699032612c3b16cc69928add8973de47b10ce81b1141f30644a0e8a895b5cd3", + "zh:86d07aa98d17703de9fbf402c89590dc1e01dbe5671dd6bc5e487eb8fe87eee0", + "zh:8c411c77b8390a49a8a1bc9f176529e6b32369dd33a723606c8533e5ca4d68c1", + "zh:a5ecc8255a612652a56b28149994985e2c4dc046e5d34d416d47fa7767f5c28f", + "zh:aea3fe1a5669b932eda9c5c72e5f327db8da707fe514aaca0d0ef60cb24892f9", + "zh:f56e26e6977f755d7ae56fa6320af96ecf4bb09580d47cb481efbf27f1c5afff", + ] +} + +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..d1a0f92f8 --- /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.8.1" + } + 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" + } +}