Kubernetes auth method
The kubernetes
auth method can be used to authenticate with Stronghold using a
Kubernetes Service Account Token. This method of authentication makes it easy to
introduce an Stronghold token into a Kubernetes Pod.
You can also use a Kubernetes Service Account Token to log in via JWT auth. See the section on How to work with short-lived Kubernetes tokens for a summary of why you might want to use JWT auth instead and how it compares to Kubernetes auth.
Note: If you are upgrading to Kubernetes v1.21+, ensure the config option
disable_iss_validation
is set to true. Assuming the default mount path, you
can check with d8 stronghold read -field disable_iss_validation auth/kubernetes/config
.
See Kubernetes 1.21 below for more details.
Authentication
Via the CLI
The default path is /kubernetes
. If this auth method was enabled at a
different path, specify -path=/my-path
in the CLI.
d8 stronghold write auth/kubernetes/login role=demo jwt=...
Via the API
The default endpoint is auth/kubernetes/login
. If this auth method was enabled
at a different path, use that value instead of kubernetes
.
$ curl \
--request POST \
--data '{"jwt": "<your service account jwt>", "role": "demo"}' \
http://127.0.0.1:8200/v1/auth/kubernetes/login
The response will contain a token at auth.client_token
:
{
"auth": {
"client_token": "38fe9691-e623-7238-f618-c94d4e7bc674",
"accessor": "78e87a38-84ed-2692-538f-ca8b9f400ab3",
"policies": ["default"],
"metadata": {
"role": "demo",
"service_account_name": "myapp",
"service_account_namespace": "default",
"service_account_secret_name": "myapp-token-pd21c",
"service_account_uid": "aa9aa8ff-98d0-11e7-9bb7-0800276d99bf"
},
"lease_duration": 2764800,
"renewable": true
}
}
Configuration
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.
- Enable the Kubernetes auth method:
d8 stronghold auth enable kubernetes
- Use the
/config
endpoint to configure Stronghold to talk to Kubernetes. Usekubectl cluster-info
to validate the Kubernetes host address and TCP port. For the list of available configuration options, please see the API documentation.
d8 stronghold write auth/kubernetes/config \
token_reviewer_jwt="<your reviewer service account JWT>" \
kubernetes_host=https://192.168.99.100:<your TCP port or blank for 443> \
kubernetes_ca_cert=@ca.crt
Note: The pattern Stronghold uses to authenticate Pods depends on sharing the JWT token over the network. Given the security model of Stronghold, this is allowable because Stronghold is 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.
- Create a named role:
d8 stronghold write auth/kubernetes/role/demo \
bound_service_account_names=myapp \
bound_service_account_namespaces=default \
policies=default \
ttl=1h
This role authorizes the “myapp” service account in the default namespace and it gives it the default policy.
For the complete list of configuration options, please see the API documentation.
Kubernetes 1.21
Starting in version 1.21, the Kubernetes
BoundServiceAccountTokenVolume
feature defaults to enabled. This changes the
JWT token mounted into containers by default in two ways that are important for
Kubernetes auth:
- It has an expiry time and is bound to the lifetime of the pod and service account.
- The value of the JWT’s
"iss"
claim depends on the cluster’s configuration.
The changes to token lifetime are important when configuring the
token_reviewer_jwt
option.
If a short-lived token is used,
Kubernetes will revoke it as soon as the pod or service account are deleted, or
if the expiry time passes, and Stronghold will no longer be able to use the
TokenReview
API. See How to work with short-lived Kubernetes tokens
below for details on handling this change.
In response to the issuer changes, Kubernetes auth has been updated to not
validate the issuer by default. The Kubernetes API does the same validation when
reviewing tokens, so enabling issuer validation on the Stronghold side is
duplicated work. Without disabling Stronghold’s issuer validation, it is not
possible for a single Kubernetes auth configuration to work for default mounted
pod tokens with both Kubernetes 1.20 and 1.21.. See Discovering the service
account issuer
below for guidance if
you wish to enable issuer validation in Stronghold.
How to work with short-lived kubernetes tokens
There are a few different ways to configure auth for Kubernetes pods when default mounted pod tokens are short-lived, each with their own tradeoffs. This table summarizes the options, each of which is explained in more detail below.
Option | All tokens are short-lived | Can revoke tokens early | Other considerations |
---|---|---|---|
Use local token as reviewer JWT | Yes | Yes | Requires Stronghold to be deployed on the Kubernetes cluster |
Use client JWT as reviewer JWT | Yes | Yes | Operational overhead |
Use long-lived token as reviewer JWT | No | Yes | |
Use JWT auth instead | Yes | No |
Note: By default, Kubernetes currently extends the lifetime of admission
injected service account tokens to a year to help smooth the transition to short-lived tokens. If you would like to disable this, set [–service-account-extend-token-expiration=false][k8s-extended-tokens] for kube-apiserver
or specify your own serviceAccountToken
volume mount. See here for an example.
Use local service account token as the reviewer JWT
When running Stronghold in a Kubernetes pod the recommended option is to use the pod’s local
service account token. Stronghold will periodically re-read the file to support
short-lived tokens. To use the local token and CA certificate, omit
token_reviewer_jwt
and kubernetes_ca_cert
when configuring the auth method.
Stronghold will attempt to load them from token
and ca.crt
respectively inside
the default mount folder /var/run/secrets/kubernetes.io/serviceaccount/
.
d8 stronghold write auth/kubernetes/config \
kubernetes_host=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
Use the Stronghold client’s JWT as the reviewer JWT
When configuring Kubernetes auth, you can omit the token_reviewer_jwt
, and Stronghold
will use the Stronghold client’s JWT as its own auth token when communicating with
the Kubernetes TokenReview
API. If Stronghold is running in Kubernetes, you also need
to set disable_local_ca_jwt=true
.
This means Stronghold does not store any JWTs and allows you to use short-lived tokens
everywhere but adds some operational overhead to maintain the cluster role
bindings on the set of service accounts you want to be able to authenticate with
Stronghold. Each client of Stronghold would need the system:auth-delegator
ClusterRole:
kubectl create clusterrolebinding myapp-client-auth-delegator \
--clusterrole=system:auth-delegator \
--group=group1 \
--serviceaccount=default:svcaccount1 \
...
Continue using long-lived tokens
You can create a long-lived secret using the instructions here
and use that as the token_reviewer_jwt
. In this example, the myapp
service
account would need the system:auth-delegator
ClusterRole:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: myapp-k8s-auth-secret
annotations:
kubernetes.io/service-account.name: myapp
type: kubernetes.io/service-account-token
EOF
Using this maintains previous workflows but does not benefit from the improved security posture of short-lived tokens.
Use JWT auth
Kubernetes auth is specialized to use Kubernetes’ TokenReview
API. However, the
JWT tokens Kubernetes generates can also be verified using Kubernetes as an OIDC
provider. The JWT auth method documentation has instructions for
setting up JWT auth with Kubernetes as the OIDC provider.
This solution allows you to use short-lived tokens for all clients and removes the need for a reviewer JWT. However, the client tokens cannot be revoked before their TTL expires, so it is recommended to keep the TTL short with that limitation in mind.
Discovering the service account issuer
Note: disable_iss_validation
and issuer
are deprecated and the
default for disable_iss_validation
has changed to true
for new Kubernetes
auth mounts. The following section only applies if you have set
disable_iss_validation=false
, but disable_iss_validation=true
is the new
recommended value for all versions of Stronghold.
Kubernetes 1.21+ clusters may require setting the service account
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:
echo '{"apiVersion": "authentication.k8s.io/v1", "kind": "TokenRequest"}' \
| kubectl create -f- --raw /api/v1/namespaces/default/serviceaccounts/default/token \
| jq -r '.status.token' \
| cut -d . -f2 \
| base64 -d
Most clusters will also have that information available at the
.well-known/openid-configuration
endpoint:
kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
This value is then used when configuring Kubernetes auth, e.g.:
d8 stronghold write auth/kubernetes/config \
kubernetes_host="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" \
issuer="\"test-aks-cluster-dns-d6cbb78e.hcp.uksouth.azmk8s.io\""
Configuring kubernetes
This auth method accesses the Kubernetes TokenReview API to
validate the provided JWT is still valid. Kubernetes should be running with
--service-account-lookup
. This is defaulted to true from Kubernetes 1.7.
Otherwise deleted tokens in Kubernetes will not be properly revoked and
will be able to authenticate to this auth method.
Service Accounts used in this auth method will need to have access to the TokenReview API. If Kubernetes is configured to use RBAC roles, the Service Account should be granted permissions to access this API. The following example ClusterRoleBinding could be used to grant these permissions:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: myapp-auth
namespace: default
API
The Kubernetes Auth Plugin has a full HTTP API. Please see the API docs for more details.