343 lines
12 KiB
Plaintext
343 lines
12 KiB
Plaintext
|
---
|
|||
|
layout: docs
|
|||
|
page_title: Kubernetes - Secrets Engines
|
|||
|
description: >-
|
|||
|
The Kubernetes secrets engine for Vault generates Kubernetes service account
|
|||
|
tokens, service accounts, role bindings, and roles dynamically.
|
|||
|
---
|
|||
|
|
|||
|
# Kubernetes Secrets Engine
|
|||
|
|
|||
|
The Kubernetes Secrets Engine for Vault generates Kubernetes service account tokens, and
|
|||
|
optionally service accounts, role bindings, and roles. The created service account tokens have
|
|||
|
a configurable TTL and any objects created are automatically deleted when the Vault lease expires.
|
|||
|
|
|||
|
For each lease, Vault will create a service account token attached to the
|
|||
|
defined service account. The service account token is returned to the caller.
|
|||
|
|
|||
|
To learn more about service accounts in Kubernetes, visit the
|
|||
|
[Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)
|
|||
|
and [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
|
|||
|
documentation.
|
|||
|
|
|||
|
~> **Note:** We do not recommend using tokens created by the Kubernetes Secrets Engine to
|
|||
|
authenticate with the [Vault Kuberenetes Auth Method](/docs/auth/kubernetes). This will
|
|||
|
generate many unique identities in Vault that will be hard to manage.
|
|||
|
|
|||
|
## Setup
|
|||
|
|
|||
|
The Kubernetes Secrets Engine must be configured in advance before it
|
|||
|
can perform its functions. These steps are usually completed by an operator or configuration
|
|||
|
management tool.
|
|||
|
|
|||
|
1. By default, Vault will connect to Kubernetes using its own service account.
|
|||
|
If using the [standard Helm chart](https://github.com/hashicorp/vault-helm), this service account
|
|||
|
is created automatically by default and named after the Helm release (often `vault`, but this can be
|
|||
|
configured via the Helm value `server.serviceAccount.name`).
|
|||
|
|
|||
|
It's necessary to ensure that the service account Vault uses will have permissions to manage
|
|||
|
service account tokens, and optionally manage service accounts, roles, and role bindings. These
|
|||
|
permissions can be managed using a Kuberentes role or cluster role. The role is attached to the
|
|||
|
Vault service account with a role binding or cluster role binding.
|
|||
|
|
|||
|
For example, a minimal cluster role to create service account tokens is:
|
|||
|
```yaml
|
|||
|
apiVersion: rbac.authorization.k8s.io/v1
|
|||
|
kind: ClusterRole
|
|||
|
metadata:
|
|||
|
name: k8s-minimal-secrets-abilities
|
|||
|
rules:
|
|||
|
- apiGroups: [""]
|
|||
|
resources: ["serviceaccounts/token"]
|
|||
|
verbs: ["create"]
|
|||
|
```
|
|||
|
|
|||
|
Similarly, you can create a more permissive cluster role with full permissions to manage tokens,
|
|||
|
service accounts, bindings, and roles.
|
|||
|
|
|||
|
```yaml
|
|||
|
apiVersion: rbac.authorization.k8s.io/v1
|
|||
|
kind: ClusterRole
|
|||
|
metadata:
|
|||
|
name: k8s-full-secrets-abilities
|
|||
|
rules:
|
|||
|
- apiGroups: [""]
|
|||
|
resources: ["serviceaccounts", "serviceaccounts/token"]
|
|||
|
verbs: ["create", "update", "delete"]
|
|||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
|||
|
resources: ["rolebindings", "clusterrolebindings"]
|
|||
|
verbs: ["create", "update", "delete"]
|
|||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
|||
|
resources: ["roles", "clusterroles"]
|
|||
|
verbs: ["bind", "escalate", "create", "update", "delete"]
|
|||
|
```
|
|||
|
|
|||
|
Create this role in Kubernetes (e.g., with `kubectl apply -f`).
|
|||
|
|
|||
|
~> **Note:** Getting the right permissions for Vault will require some trial and error most
|
|||
|
likely since Kubernetes has strict protections against privilege escalation. You can read more
|
|||
|
in the
|
|||
|
[Kubernetes RBAC documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping).
|
|||
|
|
|||
|
~> **Note:** Protect the Vault service account, especially if you use broader permissions for it,
|
|||
|
as it is essentially a cluster administrator account.
|
|||
|
|
|||
|
1. Create a role binding to bind the role to Vault's service account and grant Vault permission
|
|||
|
to manage tokens.
|
|||
|
|
|||
|
```yaml
|
|||
|
apiVersion: rbac.authorization.k8s.io/v1
|
|||
|
kind: ClusterRoleBinding
|
|||
|
metadata:
|
|||
|
name: vault-token-creator-binding
|
|||
|
roleRef:
|
|||
|
apiGroup: rbac.authorization.k8s.io
|
|||
|
kind: ClusterRole
|
|||
|
name: k8s-minimal-secrets-abilities
|
|||
|
subjects:
|
|||
|
- kind: ServiceAccount
|
|||
|
name: vault
|
|||
|
namespace: vault
|
|||
|
```
|
|||
|
|
|||
|
For more information on Kubernetes roles, service accounts, bindings, and tokens, visit the
|
|||
|
[Kubernetes RBAC documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/).
|
|||
|
|
|||
|
1. If Vault will not be automatically managing roles or service accounts (see
|
|||
|
[Automatically Managing Roles and Service Accounts](#automatically-managing-roles-and-service-accounts)),
|
|||
|
then you will need to set up a service account that Vault will issue tokens for.
|
|||
|
|
|||
|
~> **Note**: It is highly recommended that the service account that Vault issues tokens for
|
|||
|
is **NOT** the same service account that Vault itself uses.
|
|||
|
|
|||
|
The examples we will use will under the namespace `test`, which you can create if it does not
|
|||
|
already exist.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ kubectl create namespace test
|
|||
|
namespace/test created
|
|||
|
```
|
|||
|
|
|||
|
Here is a simple set up of a service account, role, and role binding in the Kubernetes `test`
|
|||
|
namespace with basic permissions we will use for this document:
|
|||
|
```yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: ServiceAccount
|
|||
|
metadata:
|
|||
|
name: test-service-account-with-generated-token
|
|||
|
namespace: test
|
|||
|
---
|
|||
|
apiVersion: rbac.authorization.k8s.io/v1
|
|||
|
kind: Role
|
|||
|
metadata:
|
|||
|
name: test-role-list-pods
|
|||
|
namespace: test
|
|||
|
rules:
|
|||
|
- apiGroups: [""]
|
|||
|
resources: ["pods"]
|
|||
|
verbs: ["list"]
|
|||
|
---
|
|||
|
apiVersion: rbac.authorization.k8s.io/v1
|
|||
|
kind: RoleBinding
|
|||
|
metadata:
|
|||
|
name: test-role-abilities
|
|||
|
namespace: test
|
|||
|
roleRef:
|
|||
|
apiGroup: rbac.authorization.k8s.io
|
|||
|
kind: Role
|
|||
|
name: test-role-list-pods
|
|||
|
subjects:
|
|||
|
- kind: ServiceAccount
|
|||
|
name: test-service-account-with-generated-token
|
|||
|
namespace: test
|
|||
|
```
|
|||
|
|
|||
|
You can create these objects with `kubectl apply -f`.
|
|||
|
|
|||
|
1. Enable the Kubernetes Secrets Engine:
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault secrets enable kubernetes
|
|||
|
Success! Enabled the kubernetes Secrets Engine at: kubernetes/
|
|||
|
```
|
|||
|
|
|||
|
By default, the secrets engine will mount at the same name as the engine, i.e.,
|
|||
|
`kubernetes/` here. This can be changed by passing the `-path` argument when enabling.
|
|||
|
|
|||
|
1. Configure the mount point. An empty config is allowed.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write -f kubernetes/config
|
|||
|
```
|
|||
|
|
|||
|
Configuration options are available as specified in the
|
|||
|
[API docs](/api-docs/secret/kubernetes).
|
|||
|
|
|||
|
1. You can now configure Kubernetes Secrets Engine to create a Vault role (**not** the same as a
|
|||
|
Kubernetes role) that can generate service account tokens for the given service account:
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/roles/my-role \
|
|||
|
allowed_kubernetes_namespaces="*" \
|
|||
|
service_account_name="test-service-account-with-generated-token" \
|
|||
|
token_default_ttl="10m"
|
|||
|
```
|
|||
|
|
|||
|
## Generating Credentials
|
|||
|
|
|||
|
After a user has authenticated to Vault and has sufficient permissions, a write to the
|
|||
|
`creds` endpoint for the Vault role will generate and return a new service account token.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/creds/my-role \
|
|||
|
kubernetes_namespace=test
|
|||
|
|
|||
|
Key Value
|
|||
|
–-- -----
|
|||
|
lease_id kubernetes/creds/my-role/31d771a6-...
|
|||
|
lease_duration 10m0s
|
|||
|
lease_renwable false
|
|||
|
service_account_name test-service-account-with-generated-token
|
|||
|
service_account_namespace test
|
|||
|
service_account_token eyJHbGci0iJSUzI1NiIsImtpZCI6ImlrUEE...
|
|||
|
```
|
|||
|
|
|||
|
You can use the service account token above (`eyJHbG...`) with any Kubernetes API request that
|
|||
|
its service account is authorized for (through role bindings).
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ curl -sk $(kubectl config view --minify -o 'jsonpath={.clusters[].cluster.server}')/api/v1/namespaces/test/pods \
|
|||
|
--header "Authorization: Bearer eyJHbGci0iJSUzI1Ni..."
|
|||
|
{
|
|||
|
"kind": "PodList",
|
|||
|
"apiVersion": "v1",
|
|||
|
"metadata": {
|
|||
|
"resourceVersion": "1624"
|
|||
|
},
|
|||
|
"items": []
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
When the lease expires, you can verify that the token has been revoked.
|
|||
|
```shell-session
|
|||
|
$ curl -sk $(kubectl config view --minify -o 'jsonpath={.clusters[].cluster.server}')/api/v1/namespaces/test/pods \
|
|||
|
--header "Authorization: Bearer eyJHbGci0iJSUzI1Ni..."
|
|||
|
{
|
|||
|
"kind": "Status",
|
|||
|
"apiVersion": "v1",
|
|||
|
"metadata": {},
|
|||
|
"status": "Failure",
|
|||
|
"message": "Unauthorized",
|
|||
|
"reason": "Unauthorized",
|
|||
|
"code": 401
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## TTL
|
|||
|
|
|||
|
Kubernetes service account tokens have a time-to-live (TTL). When a token expires it is
|
|||
|
automatically revoked.
|
|||
|
|
|||
|
You can set a default (`token_default_ttl`) and a maximum TTL (`token_max_ttl`) when
|
|||
|
creating or tuning the Vault role.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/roles/my-role \
|
|||
|
allowed_kubernetes_namespaces="*" \
|
|||
|
service_account_name="new-service-account-with-generated-token" \
|
|||
|
token_default_ttl="10m" \
|
|||
|
token_max_ttl="2h"
|
|||
|
```
|
|||
|
|
|||
|
You can also set a TTL (`ttl`) when you generate the token from the credentials endpoint.
|
|||
|
The TTL of the token will be given the default if not specified (and cannot exceed the
|
|||
|
maximum TTL of the role, if present).
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/creds/my-role \
|
|||
|
kubernetes_namespace=test \
|
|||
|
ttl=20m
|
|||
|
|
|||
|
Key Value
|
|||
|
–-- -----
|
|||
|
lease_id kubernetes/creds/my-role/31d771a6-...
|
|||
|
lease_duration 20m0s
|
|||
|
lease_renwable false
|
|||
|
service_account_name new-service-account-with-generated-token
|
|||
|
service_account_namespace test
|
|||
|
service_account_token eyJHbGci0iJSUzI1NiIsImtpZCI6ImlrUEE...
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
You can verify the token's TTL by decoding the JWT token and extracting the `iat`
|
|||
|
(issued at) and `exp` (expiration time) claims.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ echo 'eyJhbGc...' | cut -d'.' -f2 | base64 -d | jq -r '.iat,.exp|todate'
|
|||
|
2022-05-20T17:14:50Z
|
|||
|
2022-05-20T17:34:50Z
|
|||
|
```
|
|||
|
|
|||
|
## Automatically Managing Roles and Service Accounts
|
|||
|
|
|||
|
When configuring the Vault role, you can pass in parameters to specify that you want to
|
|||
|
automatically generate the Kubernetes service account and role binding,
|
|||
|
and optionally generate the Kubernetes role itself.
|
|||
|
|
|||
|
If you want to configure the Vault role to use a pre-existing Kubernetes role, but generate
|
|||
|
the service account and role binding automatically, you can set the `kubernetes_role_name`
|
|||
|
parameter.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/roles/auto-managed-sa-role \
|
|||
|
allowed_kubernetes_namespaces="test" \
|
|||
|
kubernetes_role_name="test-role-list-pods"
|
|||
|
```
|
|||
|
|
|||
|
~> **Note**: Vault's service account will also need access to the resources it is granting
|
|||
|
access to. This can be done for the examples above with `kubectl -n test create rolebinding --role test-role-list-pods --serviceaccount=vault:vault vault-test-role-abilities`.
|
|||
|
This is how Kuberentes prevents privilege escalation.
|
|||
|
You can read more in the
|
|||
|
[Kubernetes RBAC documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping).
|
|||
|
|
|||
|
You can then get credentials with the automatically generated service account.
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/creds/auto-managed-sa-role \
|
|||
|
kubernetes_namespace=test
|
|||
|
Key Value
|
|||
|
--- -----
|
|||
|
lease_id kubernetes/creds/auto-managed-sa-role/cujRLYjKZUMQk6dkHBGGWm67
|
|||
|
lease_duration 768h
|
|||
|
lease_renewable false
|
|||
|
service_account_name v-token-auto-man-1653001548-5z6hrgsxnmzncxejztml4arz
|
|||
|
service_account_namespace test
|
|||
|
service_account_token eyJHbGci0iJSUzI1Ni...
|
|||
|
```
|
|||
|
|
|||
|
Furthermore, Vault can also automatically create the role in addition to the service account and
|
|||
|
role binding by specifying the `generated_role_rules` parameter, which accepts a set of JSON or YAML
|
|||
|
rules for the generated role.
|
|||
|
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/roles/auto-managed-sa-and-role \
|
|||
|
allowed_kubernetes_namespaces="test" \
|
|||
|
generated_role_rules='{"rules":[{"apiGroups":[""],"resources":["pods"],"verbs":["list"]}]}'
|
|||
|
```
|
|||
|
You can then get credentials in the same way as before.
|
|||
|
```shell-session
|
|||
|
$ vault write kubernetes/creds/auto-managed-sa-and-role \
|
|||
|
kubernetes_namespace=test
|
|||
|
Key Value
|
|||
|
--- -----
|
|||
|
lease_id kubernetes/creds/auto-managed-sa-and-role/pehLtegoTP8vCkcaQozUqOHf
|
|||
|
lease_duration 768h
|
|||
|
lease_renewable false
|
|||
|
service_account_name v-token-auto-man-1653002096-4imxf3ytjh5hbyro9s1oqdo3
|
|||
|
service_account_namespace test
|
|||
|
service_account_token eyJHbGci0iJSUzI1Ni...
|
|||
|
```
|
|||
|
|
|||
|
## API
|
|||
|
|
|||
|
The Kubernetes Secrets Engine has a full HTTP API. Please see the
|
|||
|
[Kubernetes Secrets Engine API docs](/api-docs/secret/kubernetes) for more details.
|