Configure Vault access for the Consul feature-gate job
The Consul on Kubernetes Helm chart runs a feature-gate job after each install and upgrade. The job waits for a Consul leader, then sets Consul feature gates. The job sets only the gates that your Helm values enable. When your values enable no gates, the job exits without changes, but it still runs and still needs Vault access.
When Vault is your secrets backend, the
job reads its access control list (ACL) token from Vault. Set
global.secretsBackend.vault.featureGateSetRole to a Vault Kubernetes auth role
that can read the token, and bind that role to the job's ServiceAccount.
Refer to Feature gates to learn about feature gates and how to enable them in Consul.
When you must set featureGateSetRole
The job authenticates to Vault with the role in featureGateSetRole.
You must set featureGateSetRole when global.secretsBackend.vault.enabled is true and you also set either of the following values:
When you omit featureGateSetRole in these cases, the chart fails to render with the error global.secretsBackend.vault.featureGateSetRole is required when the feature-gate-set job reads a Vault ACL token.
The roles in manageSystemACLsRole, adminPartitionsRole, and connectInjectRole serve other components. They do not replace featureGateSetRole.
When the job reads only the Consul certificate authority (CA) certificate from Vault and no ACL token, it uses global.secretsBackend.vault.consulCARole instead. This page does not apply to that case.
Requirements
- Complete the systems integration, including Vault Kubernetes authentication.
- Authenticate to Vault with permission to manage roles and policies.
- Store the ACL token in Vault. The job reads the bootstrap token from
global.acls.bootstrapToken.secretName. In a secondary datacenter without a bootstrap token, it reads the replication token fromglobal.acls.replicationToken.secretName. - Note the Vault API path of that token. For the key/value (KV) v2 secrets engine, include
/data/in the path, as insecret/data/consul/bootstrap-token. - Confirm that the Consul token has
operator:writepermissions. Vault read access only lets the job retrieve the token. It does not grant Consul ACL permissions. Refer to Feature gates.
Find the feature-gate ServiceAccount name
The ServiceAccount name depends on the Helm release name and chart configuration. The examples on this page use the namespace consul and the ServiceAccount consul-consul-feature-gate-set.
Set your Helm release name. Replace
consulwith your release name.$ RELEASE_NAME=consulRender the ServiceAccount and check
metadata.name.$ helm template hashicorp/consul \ --release-name ${RELEASE_NAME} \ --show-only templates/feature-gate-set-serviceaccount.yaml \ --values values.yaml
Choose a role configuration
Choose one of the following options:
- Reuse the ACL-init role. Use this option to avoid creating a new role. The feature-gate job gets every policy already attached to that role.
- Create a dedicated role. Use this option when you need narrower permissions.
Reuse the ACL-init role
Add the feature-gate ServiceAccount to the role named in global.secretsBackend.vault.manageSystemACLsRole. The existing ServiceAccount bindings stay in place. This option requires jq.
Set the Kubernetes auth mount path, the existing role name, and the feature-gate ServiceAccount. Replace
<manage-system-acls-role>with the role name frommanageSystemACLsRole.$ VAULT_AUTH_PATH=kubernetes $ ROLE=<manage-system-acls-role> $ FEATURE_GATE_SA=consul-consul-feature-gate-setRead the role and add the ServiceAccount to its bindings. The command keeps the role's other settings. It writes only after the read and the JSON transformation both succeed.
$ ROLE_JSON=$(vault read -format=json \ "auth/${VAULT_AUTH_PATH}/role/${ROLE}") && UPDATED_ROLE_JSON=$(printf '%s\n' "$ROLE_JSON" \ | jq --arg sa "$FEATURE_GATE_SA" \ '.data | .bound_service_account_names = ((.bound_service_account_names + [$sa]) | unique)') && printf '%s\n' "$UPDATED_ROLE_JSON" \ | vault write "auth/${VAULT_AUTH_PATH}/role/${ROLE}" -Read the updated role.
$ vault read "auth/${VAULT_AUTH_PATH}/role/${ROLE}"Confirm the following in the output:
bound_service_account_namesincludes the feature-gate ServiceAccount.bound_service_account_namespacesincludes the Helm release namespace.- The attached policies permit reading the ACL token path.
- When you enable TLS, the attached policies also permit reading the
global.tls.caCert.secretNamepath.
When you enable TLS and no attached policy permits reading the CA certificate path, add that path to one of the role's policies. That policy change also applies to the ACL-init job. To keep the jobs separate, create a dedicated role instead.
Create a dedicated role
Set the Kubernetes auth mount path, role, policy, namespace, and ServiceAccount. Choose unused role and policy names so you do not replace an existing configuration.
$ VAULT_AUTH_PATH=kubernetes $ ROLE=feature-gate-set $ POLICY=consul-feature-gate-set $ NAMESPACE=consul $ SERVICE_ACCOUNT=consul-consul-feature-gate-setCreate a policy file that permits reading the ACL token. Replace the example path with the API path of your token.
feature-gate-set-policy.hcl
path "secret/data/consul/bootstrap-token" { capabilities = ["read"] }When you enable TLS, add read access to the CA certificate in the same file. Replace the example path with your
global.tls.caCert.secretNamepath.feature-gate-set-policy.hcl
path "secret/data/consul/ca-cert" { capabilities = ["read"] }Write the policy to Vault.
$ vault policy write "$POLICY" feature-gate-set-policy.hclCreate a Kubernetes auth role that binds the policy to the job's ServiceAccount and namespace.
$ vault write "auth/${VAULT_AUTH_PATH}/role/${ROLE}" \ bound_service_account_names="$SERVICE_ACCOUNT" \ bound_service_account_namespaces="$NAMESPACE" \ token_policies="$POLICY" \ token_ttl=15m \ token_max_ttl=1hVerify the policy.
$ vault policy read "$POLICY"Verify the role's ServiceAccount, namespace, and policy bindings.
$ vault read "auth/${VAULT_AUTH_PATH}/role/${ROLE}"
Update the Consul on Kubernetes Helm chart
Add the role name to your existing Helm values. Replace
<feature-gate-role>with the role you configured.values.yaml
global: secretsBackend: vault: enabled: true featureGateSetRole: <feature-gate-role>Reapply your Helm configuration with the same release, namespace, chart version, and existing values. You can also pass
--set global.secretsBackend.vault.featureGateSetRole="$ROLE"to that Helm command instead of editingvalues.yaml.Confirm that the Helm command finishes without a hook error. Helm waits for the feature-gate job to complete and fails the release when the job fails. The chart deletes the job after it succeeds. When the job fails, it stays in the cluster so you can check its logs.
$ kubectl logs job/${RELEASE_NAME}-consul-feature-gate-set --namespace <namespace>Verify that the feature gates your Helm values enable have the expected state.
$ consul operator feature list