Namespace service account token map keys by account
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful

Two service_accounts declaring the same token identifier collapsed into a
single entry under merge(), silently dropping one token. Key the map by
account/identifier the way service_account_permissions already does, and
carry the bare identifier as a field for the authentik_token attribute.
This commit is contained in:
2026-08-29 23:10:38 +10:00
parent 3884a5b21f
commit 0c6a9104c0
+20 -2
View File
@@ -276,9 +276,14 @@ locals {
}
]...)
# Keyed by account/identifier so two accounts reusing an identifier do not
# collapse into one entry under merge().
service_account_tokens = merge([
for k, v in var.service_accounts : {
for identifier, t in v.tokens : identifier => merge(t, { service_account = k })
for identifier, t in v.tokens : "${k}/${identifier}" => merge(t, {
service_account = k
identifier = identifier
})
}
]...)
}
@@ -295,7 +300,7 @@ resource "authentik_rbac_permission_role" "service_account" {
resource "authentik_token" "service_account" {
for_each = local.service_account_tokens
identifier = each.key
identifier = each.value.identifier
user = authentik_user.service_account[each.value.service_account].id
description = each.value.description
intent = "api"
@@ -313,3 +318,16 @@ resource "vault_kv_secret_v2" "service_account_token" {
name = each.value.vault.path
data_json = jsonencode({ (each.value.vault.key) = authentik_token.service_account[each.key].key })
}
# One-off re-address for the tokens that existed before the map was namespaced
# by service account. Without these the rekey reads as destroy+create and the
# published token key rotates. Safe to drop once applied.
moved {
from = authentik_token.service_account["agent-api-token"]
to = authentik_token.service_account["sa-agent-api/agent-api-token"]
}
moved {
from = vault_kv_secret_v2.service_account_token["agent-api-token"]
to = vault_kv_secret_v2.service_account_token["sa-agent-api/agent-api-token"]
}