feat: yucca secrets and secret module improvements (#1121)

This commit is contained in:
Zack Pollard
2026-03-19 16:39:04 +00:00
committed by GitHub
parent 6b628c37b3
commit 838151963c
14 changed files with 222 additions and 78 deletions
+1
View File
@@ -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"
@@ -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" },
@@ -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",
]
}
@@ -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"
}
}
}
@@ -0,0 +1,3 @@
provider "onepassword" {
service_account_token = var.futo_op_service_account_token
}
@@ -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")
}
@@ -0,0 +1 @@
variable "futo_op_service_account_token" {}
@@ -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",
])
}
+5 -8
View File
@@ -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
}
+11 -17
View File
@@ -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
}
]
]) : []
)
}
@@ -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."
+10 -16
View File
@@ -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
}
+11 -16
View File
@@ -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
}
]
]) : []
)
}
+22 -2
View File
@@ -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"
}
}