diff --git a/config/netbox_secret_backend/netbox.yaml b/config/netbox_secret_backend/netbox.yaml index cc877e4..993b9c3 100644 --- a/config/netbox_secret_backend/netbox.yaml +++ b/config/netbox_secret_backend/netbox.yaml @@ -22,7 +22,16 @@ # # token_version 2 is the NetBox 4.6.5 default and requires API_TOKEN_PEPPERS to # be configured on the NetBox server; set token_version: 1 here if the server -# has no peppers. +# has no peppers. token_version does NOT change how the plugin authenticates its +# own calls (that scheme comes from the admin_token value's nbt_ prefix); it only +# sets the version of the per-user tokens the engine mints. It must still MATCH +# the admin_token kind: nbt_ v2 token -> token_version 2; bare v1 token -> 1. +# +# The mount uses ignore_changes=[token], so editing KV alone does NOT reach the +# live mount. To push a corrected/rotated admin token into a running mount: +# vault write netbox/config token= +# (netbox_url/token_version are preserved on a partial update). Do NOT -replace +# the mount to force a re-read - that recreates it and drops all roles/config. description: "NetBox ephemeral scoped API token engine" netbox_url: "https://netbox.k8s.syd1.au.unkin.net" token_version: 2 diff --git a/modules/vault_cluster/modules/netbox_secret_backend/main.tf b/modules/vault_cluster/modules/netbox_secret_backend/main.tf index 48dbfb5..585d6d9 100644 --- a/modules/vault_cluster/modules/netbox_secret_backend/main.tf +++ b/modules/vault_cluster/modules/netbox_secret_backend/main.tf @@ -10,15 +10,23 @@ data "vault_kv_secret_v2" "config" { name = "service/vault/${var.country}/${var.region}/secret_backend/${var.path}/config" lifecycle { - # The plugin adds the Authorization scheme itself (Bearer for v2 nbt_ tokens, - # Token for v1), so admin_token must be the BARE token. A literal `Bearer `/ - # `Token ` prefix in the seed yields a malformed header and 403s on mint/rotate. + # The plugin builds its own Authorization header from the token VALUE, not + # token_version: a value starting with the nbt_ prefix is sent as + # "Bearer " (v2), otherwise "Token " (v1). So admin_token must + # be the BARE token - a literal `Bearer `/`Token ` scheme prefix yields a + # malformed three-part header and 403s on the plugin's own NetBox calls. + # + # token_version does NOT change that header; it only selects the version of + # the per-user tokens the engine mints for roles. It must still MATCH the + # admin token's kind so the mount and its minted creds line up: an nbt_ v2 + # admin token pairs with token_version=2, a bare v1 token with token_version=1. postcondition { condition = nonsensitive( !startswith(self.data["admin_token"], "Bearer ") && - !startswith(self.data["admin_token"], "Token ") + !startswith(self.data["admin_token"], "Token ") && + startswith(self.data["admin_token"], "nbt_") == (var.token_version == 2) ) - error_message = "KV admin_token for netbox backend '${var.path}' must be a BARE NetBox token with no 'Bearer '/'Token ' scheme prefix (v2: nbt_.; v1: the 40-char value)." + error_message = "KV admin_token for netbox backend '${var.path}' must be a BARE NetBox token with no 'Bearer '/'Token ' scheme prefix, AND its version must match token_version: a v2 token (nbt_.) requires token_version=2; a v1 token (bare 40-char value) requires token_version=1." } } }