This article outlines the configuration needed to help fix the
permission denied
error in
k8s auth
Introduction
The
kubernetes
auth method can be used to authenticate with Vault using a Kubernetes Service Account Token. This method of authentication makes it easy to introduce a Vault token into a Kubernetes Pod.
Problem
When a pod attempts to authenticate to vault via the configured kubernetes auth method; it gets
Permission Denied
error
Cause
{"time":"2020-05-23T00:16:35.5749466Z","type":"response","auth":{"token_type":"default"},"request":{"id":"6f594d4c-40b2-dbfc-d4ba-ef53d1ba03f9","operation":"update","mount_type":"kubernetes","namespace":{"id":"root"},"path":"auth/k8s-auth/login","data":{"jwt":"---BLAH---","role":"test"},"remote_address":"10.121.22.67"},"response":{"mount_type":"kubernetes"},"error":"permission denied"}
This error message is usually caused by one of five reasons:
The
JWT
used for authenticating to vault does not have the right role associated to it specified during the login
The
JWT
does not belong to the right service account
The role in k8s auth is not configured properly
Overview of possible solutions (if applicable)
Solutions:
Decode your
JWT
being used for login using
jwt.io
and examine the payload data to make sure the service account and namespace look right
Below is an example configuration of a working k8s auth. In this below example:
vault-auth
is the service account with which k8s auth is configured.
test-cloud
is the service account used to login to vault using the k8s auth method
test
is the namespace of the service account test-cloud
role-tokenreview-binding
is the name of the cluster role binding the service accounts (vault-auth and test-cloud) need to be associated with
# Create k8s namespace test
$ kubectl create namespace test
namespace/test created
# Create a service account, secret and ClusterRoleBinding with the necessary permissions to allow the service account test-cloud to perform token reviews with k8s
cat <<EOF | kubectl create -f -
---
apiVersion: v1 kind: ServiceAccount
metadata:
name: test-cloud
namespace: test
---
apiVersion: v1
kind: Secret
metadata:
name: test-cloud
namespace: test
annotations:
kubernetes.io/service-account.name: test-cloud
type: kubernetes.io/service-account-token
EOF
serviceaccount/test-cloud created
secret/test-cloud created
# Create a service account, secret and ClusterRoleBinding with the necessary permissions to allow vault to perform token reviews with k8s (Make note that clusterRoleBinding has been created associating serviceaccount test-cloud as well)
cat <<EOF | kubectl create -f -
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault-auth
---
apiVersion: v1
kind: Secret
metadata:
name: vault-auth
annotations:
kubernetes.io/service-account.name: vault-auth
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: vault-auth
namespace: default
- kind: ServiceAccount
name: test-cloud
namespace: test
EOF
serviceaccount/vault-auth created
secret/vault-auth created
clusterrolebinding.rbac.authorization.k8s.io/role-tokenreview-binding created
# Enable k8s auth method in vault
$ vault auth enable kubernetes
Success! Enabled kubernetes auth method at: kubernetes/
# Get the JSON web token (JWT) for vault-auth service account in default namespace to be used by vault k8s config
$ TOKEN_REVIEW_JWT=$(kubectl get secret vault-auth -o go-template='{{ .data.token }}' | base64 --decode)
# Retrieve the k8s CA certificate
$ KUBE_CA_CERT=$(kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 --decode)# Retrieve the k8s host URL
$ KUBE_HOST=$(kubectl config view --raw --minify --flatten --output='jsonpath={.clusters[].cluster.server}')
# Configure the k8s auth method to use the above sa token, location of the k8s host and its certificate from above
$ vault write auth/kubernetes/config token_reviewer_jwt="$TOKEN_REVIEW_JWT" kubernetes_host="$KUBE_HOST" kubernetes_ca_cert="$KUBE_CA_CERT" disable_local_ca_jwt="true"
Success! Data written to: auth/kubernetes/config# Read the k8s config
$ vault read auth/kubernetes/config
Key Value
--- -----
disable_iss_validation false
disable_local_ca_jwt true
issuer n/a
kubernetes_ca_cert -----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
a3ViZUNBMB4XDTIxMDYyMDE0MzA1OVoXDTMxMDYxOTE0MzA1OVowFTETMBEGA1UE
AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZV
jjkUtgyFX/rodABD7SqRPuygBpSik4u2wHLm5Wr101+1aZ+nO7L63ykqAbOL89Nm
-----END CERTIFICATE-----
kubernetes_host https://172.17.0.61:8443
pem_keys []# Write a policy to associate with the devweb-app role used for login by test-cloud service account
vault policy write devwebapp - <<EOF
path "secret/data/devwebapp/config" {
capabilities = ["read”]
}
EOF
Success! Uploaded policy: devwebapp# Associate the role to the serviceaccount and the policy:
vault write auth/kubernetes/role/devweb-app \
bound_service_account_names=test-cloud \
bound_service_account_namespaces=test \
policies=devwebapp \
ttl=24h
Success! Data written to: auth/kubernetes/role/devweb-app# Retrieve the JWT for test-cloud sa to login
TOKEN_REVIEW_SJWT=$(kubectl get secret test-cloud -n test -o go-template='{{ .data.token }}' | base64 --decode)
# Perform a k8s login using test-cloud serviceaccount's JWT and the role
$ curl \
> --request POST \
> --data '{"jwt": "'$TOKEN_REVIEW_SJWT'", "role": "devweb-app"}' \
> http://127.0.0.1:8200/v1/auth/kubernetes/login
{"request_id":"80cac595-c206-348f-2da5-29fe029eddd7","lease_id":"","renewable":false,"lease_duration":0,"data":null,"wrap_info":null,"warnings":null,"auth":{"client_token":"s.mBUJCVNNFKtUVuWVVgfPi9Sj","accessor":"4NoXtX7F9bcu19RZ7TAbtcjT","policies":["default","devwebapp"],"token_policies":["default","devwebapp"],"metadata":{"role":"devweb-app","service_account_name":"test-cloud","service_account_namespace":"test","service_account_secret_name":"test-cloud","service_account_uid":"6d475e37-0288-4070-ad8a-e44abc87b496"},"lease_duration":86400,"renewable":true,"entity_id":"841af42c-87ff-8441-b2d5-0c02ea062384","token_type":"service","orphan":true}}
The login is successful.If the login is successful, that indicates everything is set up right.
Additional Information
Kubernetes auth with external vault