2017-09-19 14:27:26 +00:00
---
2020-01-18 00:18:09 +00:00
layout: docs
page_title: Kubernetes - Auth Methods
2017-09-19 14:27:26 +00:00
description: |-
2017-09-20 20:47:13 +00:00
The Kubernetes auth method allows automated authentication of Kubernetes
2017-09-29 15:52:42 +00:00
Service Accounts.
2017-09-19 14:27:26 +00:00
---
2017-09-20 20:47:13 +00:00
# Kubernetes Auth Method
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
The `kubernetes` auth method can be used to authenticate with Vault using a
2017-09-19 14:27:26 +00:00
Kubernetes Service Account Token. This method of authentication makes it easy to
2017-09-20 20:47:13 +00:00
introduce a Vault token into a Kubernetes Pod.
2017-09-19 14:27:26 +00:00
## Authentication
2017-09-20 20:47:13 +00:00
### Via the CLI
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
The default path is `/kubernetes`. If this auth method was enabled at a
different path, specify `-path=/my-path` in the CLI.
2017-09-19 14:27:26 +00:00
2020-05-21 17:18:17 +00:00
```shell-session
2017-09-20 20:47:13 +00:00
$ vault write auth/kubernetes/login role=demo jwt=...
```
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
### Via the API
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
The default endpoint is `auth/kubernetes/login`. If this auth method was enabled
at a different path, use that value instead of `kubernetes`.
2017-09-19 14:27:26 +00:00
2020-05-21 17:18:17 +00:00
```shell-session
2017-09-20 20:47:13 +00:00
$ curl \
--request POST \
2020-11-16 23:45:12 +00:00
--data '{"jwt": "<your service account jwt>", "role": "demo"}' \
2018-03-23 15:41:51 +00:00
http://127.0.0.1:8200/v1/auth/kubernetes/login
2017-09-19 14:27:26 +00:00
```
2017-09-20 20:47:13 +00:00
The response will contain a token at `auth.client_token`:
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
```json
2017-09-19 14:27:26 +00:00
{
2017-09-20 20:47:13 +00:00
"auth": {
"client_token": "38fe9691-e623-7238-f618-c94d4e7bc674",
"accessor": "78e87a38-84ed-2692-538f-ca8b9f400ab3",
2020-01-18 00:18:09 +00:00
"policies": ["default"],
2017-09-20 20:47:13 +00:00
"metadata": {
2018-05-01 22:04:53 +00:00
"role": "demo",
2017-09-20 20:47:13 +00:00
"service_account_name": "vault-auth",
"service_account_namespace": "default",
"service_account_secret_name": "vault-auth-token-pd21c",
"service_account_uid": "aa9aa8ff-98d0-11e7-9bb7-0800276d99bf"
},
"lease_duration": 2764800,
"renewable": true
}
2017-09-19 14:27:26 +00:00
}
```
## Configuration
2017-09-20 20:47:13 +00:00
Auth methods must be configured in advance before users or machines can
authenticate. These steps are usually completed by an operator or configuration
management tool.
2017-09-19 14:27:26 +00:00
2020-01-18 00:18:09 +00:00
1. Enable the Kubernetes auth method:
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
```text
$ vault auth enable kubernetes
```
2017-09-19 14:27:26 +00:00
2021-09-09 15:39:21 +00:00
1. Use the `/config` endpoint to configure Vault to talk to Kubernetes. Use `kubectl cluster-info` to validate the Kubernetes host address and TCP port. Kubernetes 1.21+ clusters may require setting the service account `issuer`, [as described here](/docs/auth/kubernetes#discovering-the-service-account-issuer). For the list of available configuration options, please see the [API documentation](/api/auth/kubernetes).
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
```text
$ vault write auth/kubernetes/config \
2020-11-16 23:45:12 +00:00
token_reviewer_jwt="<your reviewer service account JWT>" \
2021-02-09 19:50:31 +00:00
kubernetes_host=https://192.168.99.100:<your TCP port or blank for 443> \
2017-09-20 20:47:13 +00:00
kubernetes_ca_cert=@ca.crt
```
2017-09-19 14:27:26 +00:00
2019-06-18 19:36:51 +00:00
!> **NOTE:** The pattern Vault uses to authenticate Pods depends on sharing
the JWT token over the network. Given the [security model of
2020-01-22 20:05:41 +00:00
Vault](/docs/internals/security), this is allowable because Vault is
2019-06-18 19:36:51 +00:00
part of the trusted compute base. In general, Kubernetes applications should
**not** share this JWT with other applications, as it allows API calls to be
made on behalf of the Pod and can result in unintended access being granted
to 3rd parties.
2020-01-18 00:18:09 +00:00
1. Create a named role:
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
```text
vault write auth/kubernetes/role/demo \
bound_service_account_names=vault-auth \
bound_service_account_namespaces=default \
policies=default \
ttl=1h
```
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
This role authorizes the "vault-auth" service account in the default
namespace and it gives it the default policy.
2017-09-19 14:27:26 +00:00
2021-09-09 15:39:21 +00:00
For the complete list of configuration options, please see the [API
documentation](/api/auth/kubernetes).
### Discovering the service account `issuer`
2021-11-18 23:16:54 +00:00
-> **Deprecated:** The `issuer` parameter has been deprecated as of Vault 1.9 and will be removed in a future release.
2021-09-09 15:39:21 +00:00
Kubernetes 1.21+ clusters may require setting the service account
[`issuer`](/api-docs/auth/kubernetes#issuer) to the same value as
`kube-apiserver`'s `--service-account-issuer` flag. This is because the service
account JWTs for these clusters may have an issuer specific to the cluster
itself, instead of the old default of `kubernetes/serviceaccount`. If you are
unable to check this value directly, you can run the following and look for the
`"iss"` field to find the required value:
```bash
kubectl proxy &
curl --silent http://127.0.0.1:8001/api/v1/namespaces/default/serviceaccounts/default/token \
-H "Content-Type: application/json" \
-X POST \
-d '{"apiVersion": "authentication.k8s.io/v1", "kind": "TokenRequest"}' \
| jq -r '.status.token' \
2021-09-27 19:37:03 +00:00
| cut -d . -f2 \
2021-09-09 15:39:21 +00:00
| base64 -D
```
Most clusters will also have that information available at the
`.well-known/openid-configuration` endpoint:
```bash
kubectl proxy &
curl --silent http://127.0.0.1:8001/.well-known/openid-configuration | jq -r .issuer
```
This value is then used when configuring Kubernetes auth, e.g.:
```bash
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
issuer="\"test-aks-cluster-dns-d6cbb78e.hcp.uksouth.azmk8s.io\""
```
2017-09-19 14:27:26 +00:00
## Configuring Kubernetes
2017-09-20 20:47:13 +00:00
This auth method accesses the [Kubernetes TokenReview API][k8s-tokenreview] to
validate the provided JWT is still valid. Kubernetes should be running with
2017-09-19 14:27:26 +00:00
`--service-account-lookup`. This is defaulted to true in Kubernetes 1.7, but any
2018-04-22 02:24:10 +00:00
versions prior should ensure the Kubernetes API server is started with this
2017-09-19 14:27:26 +00:00
setting. Otherwise deleted tokens in Kubernetes will not be properly revoked and
2017-09-20 20:47:13 +00:00
will be able to authenticate to this auth method.
2017-09-27 21:02:18 +00:00
2017-09-20 20:47:13 +00:00
Service Accounts used in this auth method will need to have access to the
2018-12-12 14:23:20 +00:00
TokenReview API. If Kubernetes is configured to use RBAC roles, the Service
2017-09-20 20:47:13 +00:00
Account should be granted permissions to access this API. The following
example ClusterRoleBinding could be used to grant these permissions:
2017-09-19 14:27:26 +00:00
2017-09-20 20:47:13 +00:00
```yaml
2017-09-19 14:27:26 +00:00
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
2020-01-18 00:18:09 +00:00
- kind: ServiceAccount
name: vault-auth
namespace: default
2017-09-19 14:27:26 +00:00
```
## API
The Kubernetes Auth Plugin has a full HTTP API. Please see the
2020-01-22 20:05:41 +00:00
[API docs](/api/auth/kubernetes) for more details.
2017-09-19 14:27:26 +00:00
2020-12-03 21:24:37 +00:00
[k8s-tokenreview]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#tokenreview-v1beta1-authentication-k8s-io
2021-10-08 21:57:53 +00:00
## Code Example
The following code snippet demonstrates the Kubernetes auth method to authenticate
with Vault.
<CodeTabs heading="kubernetes auth example">
<CodeBlockConfig lineNumbers>
```go
package main
import (
"fmt"
"os"
vault "github.com/hashicorp/vault/api"
2021-11-17 19:52:38 +00:00
auth "github.com/hashicorp/vault/api/auth/kubernetes"
2021-10-08 21:57:53 +00:00
)
// Fetches a key-value secret (kv-v2) after authenticating to Vault with a Kubernetes service account.
//
// As the client, all we need to do is pass along the JWT token representing our application's Kubernetes Service Account in our login request to Vault.
//
// For a more in-depth setup explanation, please see the full version of this code in the hashicorp/vault-examples repo.
func getSecretWithKubernetesAuth() (string, error) {
2021-11-17 19:52:38 +00:00
// If set, the VAULT_ADDR environment variable will be the address that
// your pod uses to communicate with Vault.
2021-10-08 21:57:53 +00:00
config := vault.DefaultConfig() // modify for more granular configuration
client, err := vault.NewClient(config)
if err != nil {
return "", fmt.Errorf("unable to initialize Vault client: %w", err)
}
2021-11-17 19:52:38 +00:00
// The service-account token will be read from the path where the token's
// Kubernetes Secret is mounted. By default, Kubernetes will mount it to
// /var/run/secrets/kubernetes.io/serviceaccount/token, but an administrator
// may have configured it to be mounted elsewhere.
// In that case, we'll use the option WithServiceAccountTokenPath to look
// for the token there.
k8sAuth, err := auth.NewKubernetesAuth(
"dev-role-k8s",
auth.WithServiceAccountTokenPath("path/to/service-account-token"),
)
2021-10-08 21:57:53 +00:00
if err != nil {
2021-11-17 19:52:38 +00:00
return "", fmt.Errorf("unable to initialize Kubernetes auth method: %w", err)
2021-10-08 21:57:53 +00:00
}
2021-11-17 19:52:38 +00:00
authInfo, err := client.Auth().Login(context.TODO(), k8sAuth)
2021-10-08 21:57:53 +00:00
if err != nil {
return "", fmt.Errorf("unable to log in with Kubernetes auth: %w", err)
}
2021-11-17 19:52:38 +00:00
if authInfo == nil {
return "", fmt.Errorf("no auth info was returned after login")
2021-10-08 21:57:53 +00:00
}
// get secret from Vault
secret, err := client.Logical().Read("kv-v2/data/creds")
if err != nil {
return "", fmt.Errorf("unable to read secret: %w", err)
}
data, ok := secret.Data["data"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("data type assertion failed: %T %#v", secret.Data["data"], secret.Data["data"])
}
2021-11-17 19:52:38 +00:00
// data map can contain more than one key-value pair,
// in this case we're just grabbing one of them
2021-10-08 21:57:53 +00:00
key := "password"
value, ok := data[key].(string)
if !ok {
return "", fmt.Errorf("value type assertion failed: %T %#v", data[key], data[key])
}
return value, nil
}
```
</CodeBlockConfig>
2021-11-03 17:10:28 +00:00
<CodeBlockConfig lineNumbers>
```cs
using System;
using System.IO;
using VaultSharp;
using VaultSharp.V1.AuthMethods;
using VaultSharp.V1.AuthMethods.Kubernetes;
using VaultSharp.V1.Commons;
namespace Examples
{
public class KubernetesAuthExample
{
const string DefaultTokenPath = "path/to/service-account-token";
// Fetches a key-value secret (kv-v2) after authenticating to Vault with a Kubernetes service account.
//
// As the client, all we need to do is pass along the JWT token representing our application's Kubernetes Service Account in our login request to Vault.
// This token is automatically mounted to your application's container by Kubernetes. Read more at https://www.vaultproject.io/docs/auth/kubernetes
//
// SETUP NOTES: If an operator has not already set up Kubernetes auth in Vault for you, then you must also first configure the Vault server with its own Service Account token to be able to communicate with the Kubernetes API
// so it can verify that the client's service-account token is valid. The service account that will be performing that verification needs the ClusterRole system:auth-delegator.
//
// export TOKEN_REVIEW_JWT=$(kubectl get secret $TOKEN_REVIEWER_SECRET --output='go-template={{ .data.token }}' | base64 --decode)
// export KUBE_HOST=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.server}')
// kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.certificate-authority-data}' | base64 --decode > path/to/kube_ca_cert
//
// vault write auth/kubernetes/config \
// token_reviewer_jwt=${TOKEN_REVIEW_JWT} \
// kubernetes_host=${KUBE_HOST} \
// kubernetes_ca_cert=@path/to/kube_ca_cert \
// issuer="kubernetes/serviceaccount"
//
// The "issuer" field is normally only required when running Kubernetes 1.21 or above, and may differ from the default value above:
// https://www.vaultproject.io/docs/auth/kubernetes#discovering-the-service-account-issuer.
//
// Finally, make sure to create a role in Vault bound to your pod's service account:
//
// vault write auth/kubernetes/role/dev-role-k8s \
// policies="dev-policy" \
// bound_service_account_names="my-app" \
// bound_service_account_namespaces="default"
public string GetSecretWithK8s()
{
var vaultAddr = Environment.GetEnvironmentVariable("VAULT_ADDR");
if(String.IsNullOrEmpty(vaultAddr))
{
throw new System.ArgumentNullException("Vault Address");
}
var roleName = Environment.GetEnvironmentVariable("VAULT_ROLE");
if(String.IsNullOrEmpty(roleName))
{
throw new System.ArgumentNullException("Vault Role Name");
}
// Get the path to service account token or fall back on default path
string pathToToken = String.IsNullOrEmpty(Environment.GetEnvironmentVariable("SA_TOKEN_PATH")) ? DefaultTokenPath : Environment.GetEnvironmentVariable("SA_TOKEN_PATH");
string jwt = File.ReadAllText(pathToToken);
IAuthMethodInfo authMethod = new KubernetesAuthMethodInfo(roleName, jwt);
var vaultClientSettings = new VaultClientSettings(vaultAddr, authMethod);
IVaultClient vaultClient = new VaultClient(vaultClientSettings);
// We can retrieve the secret after creating our VaultClient object
Secret<SecretData> kv2Secret = null;
kv2Secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(path: "/creds").Result;
var password = kv2Secret.Data.Data["password"];
return password.ToString();
}
}
}
```
</CodeBlockConfig>
2021-10-08 21:57:53 +00:00
</CodeTabs>