@@ -1061,7 +1061,8 @@ The `.spec.decryption` field has the following subfields:
10611061- `.secretRef.name` : The name of the secret that contains the keys or cloud provider
10621062 static credentials for KMS services to be used for decryption.
10631063- `.serviceAccountName` : The name of the service account used for
1064- secret-less authentication with KMS services from cloud providers.
1064+ secret-less authentication with KMS services from cloud providers, and
1065+ with Hashicorp Vault/OpenBao via the [Kubernetes auth method](#kubernetes-auth).
10651066
10661067To make a Kustomization react immediately to changes in the referenced Secret
10671068see [this](#reacting-immediately-to-configuration-dependencies) section.
@@ -1310,6 +1311,10 @@ data:
13101311 sops.vault-token: <BASE64>
13111312` ` `
13121313
1314+ Alternatively, for secret-less authentication to Hashicorp Vault/OpenBao using a
1315+ Kubernetes ServiceAccount instead of a static token, see
1316+ [Kubernetes auth](#kubernetes-auth).
1317+
13131318# ### Controlling the decryption behavior of resources
13141319
13151320To change the decryption behaviour for specific Kubernetes resources, you can annotate them with :
@@ -1673,8 +1678,13 @@ permissions, and controller configuration for each cloud provider.
16731678
16741679# ### Hashicorp Vault
16751680
1676- To configure a global default for Hashicorp Vault, patch the controller's
1677- Deployment with a `VAULT_TOKEN` environment variable.
1681+ There are two ways to configure controller-level authentication to Hashicorp
1682+ Vault/OpenBao for SOPS decryption : a static token, or the Kubernetes auth method.
1683+
1684+ # #### Static token
1685+
1686+ To configure a global default token, patch the controller's Deployment with a
1687+ ` VAULT_TOKEN` environment variable.
16781688
16791689` ` ` yaml
16801690---
@@ -1693,6 +1703,91 @@ spec:
16931703 value: <token>
16941704` ` `
16951705
1706+ # #### Kubernetes auth
1707+
1708+ Instead of a static token, the controller can authenticate to Hashicorp
1709+ Vault/OpenBao by exchanging a Kubernetes ServiceAccount token for a short-lived
1710+ Vault token via a JWT-backed auth method (e.g. the
1711+ [Kubernetes auth method](https://openbao.org/docs/auth/kubernetes/) or the
1712+ [JWT auth method](https://openbao.org/docs/auth/jwt/)). This is enabled with the
1713+ ` --sops-vault-configmap` flag, which names a ConfigMap in the controller's
1714+ namespace that maps each Vault address to the login path to authenticate at. The
1715+ ConfigMap also acts as an **allowlist** : only addresses listed in it can be
1716+ authenticated to this way. This does not affect the static token paths below —
1717+ the `sops.vault-token` Secret entry and the `VAULT_TOKEN` environment variable
1718+ continue to work for any address. When the flag is empty, this authentication is
1719+ disabled and decryption falls back to those static token paths.
1720+
1721+ The mapping is stored under the `config.yaml` key as a list of instances, each
1722+ with an `address` and the `loginPath` to authenticate at. The login path is used
1723+ verbatim, so it supports any JWT-backed auth method and namespace-prefixed paths
1724+ (e.g. `ns1/ns2/auth/kubernetes/login`). The ConfigMap must be in the same
1725+ namespace as the kustomize-controller Deployment.
1726+
1727+ ` ` ` yaml
1728+ ---
1729+ apiVersion: v1
1730+ kind: ConfigMap
1731+ metadata:
1732+ name: sops-vault-config
1733+ namespace: flux-system
1734+ data:
1735+ config.yaml: |
1736+ instances:
1737+ - address: https://vault-a.example.com:8200
1738+ loginPath: auth/kubernetes/login
1739+ - address: https://vault-b.example.com:8200
1740+ loginPath: ns1/ns2/auth/kubernetes/login
1741+ ` ` `
1742+
1743+ Then, patch the kustomize-controller Deployment to add the flag :
1744+
1745+ ` ` ` yaml
1746+ ---
1747+ apiVersion: apps/v1
1748+ kind: Deployment
1749+ metadata:
1750+ name: kustomize-controller
1751+ namespace: flux-system
1752+ spec:
1753+ template:
1754+ spec:
1755+ containers:
1756+ - name: manager
1757+ args:
1758+ - --sops-vault-configmap=sops-vault-config
1759+ ` ` `
1760+
1761+ When enabled, a Kustomization whose decryption Secret does **not** contain a
1762+ ` sops.vault-token` authenticates to the Vault address found in the SOPS metadata
1763+ of each encrypted data key as follows :
1764+
1765+ - The Kubernetes ServiceAccount token is issued for
1766+ [`.spec.decryption.serviceAccountName`](#decryption) when set (object-level
1767+ workload identity), otherwise for the controller's own ServiceAccount
1768+ (controller-level workload identity). Object-level workload identity requires
1769+ the `ObjectLevelWorkloadIdentity` feature gate to be enabled.
1770+ - The token audience is set to the Vault address.
1771+ - The Vault role is derived from the ServiceAccount as `{namespace}_{name}`
1772+ (e.g. a ServiceAccount `sops` in namespace `apps` maps to the role `apps_sops`).
1773+
1774+ On the Vault server, the operator must enable and configure the auth method
1775+ behind the configured login path (for the Kubernetes auth method, with the
1776+ cluster's API server address, CA certificate and a token reviewer JWT), and
1777+ create a role `{namespace}_{name}` bound to the ServiceAccount and namespace,
1778+ with its audience set to the Vault address and a policy granting `update` on the
1779+ relevant `transit/decrypt/<key>` paths. See the
1780+ [OpenBao Kubernetes auth docs](https://openbao.org/docs/auth/kubernetes/) for the
1781+ auth method and role configuration. When several clusters share one Vault, enable
1782+ a separate auth mount per cluster (each configured with that cluster's API
1783+ server, CA and reviewer JWT) and set each cluster's login path in its own
1784+ ConfigMap.
1785+
1786+ The authentication methods are tried in order of precedence : a static
1787+ ` sops.vault-token` in the Secret referenced by
1788+ [`.spec.decryption.secretRef`](#decryption) takes priority over Kubernetes auth,
1789+ which in turn takes priority over the global `VAULT_TOKEN` environment variable.
1790+
16961791# ### SOPS Age Keys
16971792
16981793To configure global decryption for SOPS Age keys, use the `--sops-age-secret`
0 commit comments