Configuring the thing that makes tokens needs a token
The GitLab secrets engine needs a GitLab token to start, which makes provisioning it from terraform more awkward than it looks.
Somebody opened an issue saying the plugin was difficult to provision from terraform, and they were right.
The engine needs a GitLab token before it can do anything, because it checks the token is valid when you configure it.
So the first apply has to carry a real token, which is fine, you can pass it in from the environment.
The problem is what happens on the second apply.
The plugin rotates its own configuration token, so the token in terraform state is not the token the plugin is using any more.
Terraform sees a difference and puts the original one back, which quietly replaces a rotated credential with an expiring one.
You’d normally reach for ignore_changes here, and you can’t, because with the Vault provider the token lives inside a JSON blob along with every other setting.
Ignoring the field means ignoring all of them, so you lose the ability to change anything else about the config.
So we fixed it on the plugin side instead, because there was nothing left to try on the terraform side.
Every config property became individually patchable, so we write the token once and then manage everything else without ever sending the token again.
vault patch gitlab/config/default auto_rotate_before=72hThe Vault terraform provider’s generic endpoint resource doesn’t support PATCH, which I checked before suggesting any of this, so there are two working shapes in the repository rather than one.
The first writes the config once and then gets out of the way, with ignore_changes on the blob and write_fields listing the properties it’s still allowed to read back.
resource "vault_generic_endpoint" "config" { path = "gitlab/config/default" disable_delete = true write_fields = ["base_url", "auto_rotate_token", "auto_rotate_before", "type", "scopes"] data_json = jsonencode(local.config)
lifecycle { ignore_changes = [data_json] }}Vault owns the token after that, rotation included, and terraform stops having an opinion about it.
The second drives vault patch from a null_resource per property, which is uglier and is what you want if the settings themselves need to be managed.
The shape of this is familiar once you’ve seen it a few times.
A component that manages credentials needs a credential, and the bootstrap is always the awkward part, because the thing that would normally hold it securely is the thing you are trying to set up.