Mint the netbox user-management credential dynamically from the single admin token #119
Reference in New Issue
Block a user
Delete Branch "benvin/netbox-user-mgmt-token-decouple"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
netbox_user_management authenticates to NetBox to reconcile service users + permissions on every apply. It must not depend on a second static admin token, and it must not break when the engine rotates its admin seed (
netbox/config/rotatemints a fresh admin token and deletes the old one). The durable shape: keep exactly ONE static admin token, and have the netbox engine mint an ephemeral, user-admin-capable token that the e-breuninger provider uses to manage users.How
module.netbox_user_mgmt_rolecreatesnetbox/roles/vault-user-mgmt, a write-enabled role for a pre-existing NetBox superuser named byuser_mgmt_username. Minted tokens authenticate AS that superuser (NetBox tokens carry no scope beyondwrite_enabled; the user's permissions apply), so they can create users.netbox_user_managementreadsnetbox/creds/vault-user-mgmtand configures the netbox provider with the minted token. Whenuser_mgmt_usernameis unset it falls back to the single staticadmin_token(acheckblock warns that rotation would then break it) - a bootstrap/degraded path, never a second static token.readonnetbox/creds/vault-user-mgmt(the one deliberate exception to the admin policy'snetbox/creds/*exclusion).token_version-match postconditions on the single static admin token.Feasibility constraints (worked through, documented in-module)
write_enabledgate (vault-plugin-secrets-netboxpath_roles.go,client.goMintToken); point it at a superuser and minted tokens can manage users.vault_generic_secretDATA source: the short-lived token is written to state (sensitive, lease-revoked) and re-minted each plan. Migrate to an ephemeral resource once the vault provider ships a dynamic-secret one.config/netbox_secret_backend/netbox.yaml.Operator follow-up
vault write netbox/config token=<BARE>(the mount usesignore_changes=[token]), keeptoken_version=2.user_mgmt_usernameto the pre-existing superuser, apply the deployer creds policy, then bootstrap once:tofu apply -target=...netbox_secret_backend -target=...netbox_user_mgmt_role, then apply normally. Until then user management stays on the static token (non-breaking, with a warning).Follow-up from live re-test (pipeline 162):
Repair the live mount (immediate). The mount uses
ignore_changes=[token], so re-seeding KV did not reach it - it still holds the old scheme-prefixedBearer nbt_..., which the plugin double-mangles intoToken Bearer nbt_...(the 403 onGET /api/users/users/?username=terraform-infra). Push the bare token straight into the running mount (agents AppRole, not root):netbox_url/token_versionare preserved on a partial update. Do NOT-replacethe mount to force a KV re-read - that recreates the mount and drops all roles.token_version verdict: keep 2. It does not affect how the plugin authenticates its own calls -
authHeaderFor(cfg.Token)derives the scheme from the token value'snbt_prefix (Bearer=v2, Token=v1), not fromtoken_version, which only sets the version of the per-user tokens the engine mints. The original mount valueBearer nbt_...is unambiguously v2; strippingBearerleaves a barenbt_...(still v2), sotoken_version=2is correct. user-management succeeding under the provider'sToken <token>scheme does NOT imply a v1 token - NetBox 4.6.5 infers the version from thenbt_value prefix, so a bare v2 token authenticates under either keyword.Latest commit adds a postcondition asserting
token_versionmatches the admin-token kind (nbt_ v2 <-> 2; bare v1 <-> 1) so a mismatch fails at plan time instead of 403ing at runtime.Decouple netbox user management from the rotating engine seedto Mint the netbox user-management credential dynamically from the single admin token