Manage Kubernetes service tokens
Challenge
Some CI/CD pipelines require the ability to manage applications running on a Kubernetes cluster. Granting access to a Kubernetes cluster is a risky scenario, and require special care. Kubernetes Secrets Engine provides a secure token with temporary access to the cluster.
When authenticating a process in Kubernetes, the Kubernetes APII requires a proof of identity. For machine users, this is a JSON Web Token (JWT) owned by a Kubernetes service account. Kubernetes manages authorization by binding roles to identities. The roles describe the actions an entity is able to perform with the Kubernetes API.
An secure continuous integration pipeline requires an automated creation of the service role, bindings, and short lived tokens. Creation of service accounts is simple enough but the manual process of binding and unbinding is tedious, and becomes a lot to manage.
Solution
Vault's Kubernetes secrets engine manages credentials for customer applications. It generates and manages service account tokens, which in turn have specific capabilities assigned to them. With a configurable TTL, the tokens are automatically revoked once the Vault lease expires. This offers the advantage of granting what access is needed, when it is needed.
Prerequisites
- Vault CLI version 1.11+
- Kubernetes command-line interface (CLI)
- Minikube
- Helm CLI
- jwt-cli version 6.0+ - optional, allows you examine fields in JSON Web Tokens.
Set up Vault on Kubernetes
Clone the Learn Vault Kubernetes repo.
Navigate to
secrets-engine
, and run the rest of this lab in that directory.Start a minikube cluster.
Initialization of minikube can take a few minutes.
Use Helm to install Vault on minikube.
Make sure Vault is running.
Allow access to the Vault instance running in your minikube cluster.
This command will forward calls through your local 8200 to port 8200 on the Kubernetes Cluster.
Set up local environment variables.
Create a new namespace in Kubernetes.
Now create the role, service accounts and bindings that are used by the Kubernetes secrets engine.
Start up an nginx server.
This server will mostly be used to demonstrate the access you will be given through the secretes engine.
Set up Kubernetes Secrets Engine
You will now use the Vault CLI to set up the Kubernetes Secrets Engine.
It will provide a short lived token, that gives you access to the Kubernetes cluster.
Create and initialize Kubernetes secrets engine on vault
This endpoint configures and initializes the plugin with the necessary information to reach the Kubernetes API and authenticate with it.
Create a role for the sample app.
Notice that the only allowed namespace is "demo". This roles abilities should be limited to that one namespace.
Create credentials for the sample application in the demo namespace, and receive a service account token in return.
Create an environment variable to store the generated service account token.
The export should resemble the following:
Demonstrate token use
Using that token allows you access to the demo namespace.
First, look at the token a bit closer and then use it to list pods in the demo namespace.
Optional Step This will generate another token, but directly return the
service_account_token
field, and run it throughjwt-cli
, allowing you to examine the JWT in a bit more detail.Run this command to examine the payload of the JWT.
The output is similar too:
Notice how the namespace, and app are specified in this token along with timestamps.
Now use cURL, and include the token in the authorization header. This will access the Kubernetes cluster and get a list of pods.
The output is long so only a truncated version is given.
Now, that token should not have access to other namespaces. Try the same command but change the
demo
todefault
.You can create roles as needed. Go ahead and create a new role.
Create a new token and specify the ttl on the command line.
Earlier this was broken into two parts, but now getting the token into the en variable is one command.
Tip
If you are getting the error:
The JWT provided is invalid because Error(Base64(InvalidByte(0, 34)))
and haveVAULT_FORMAT=json
then unset theVAULT_FORMAT
environment variable.List pods in the demo namespace.
Response is truncated for brevity's sake.
Revoke those credentials.
You can do the same with
kubernetes/creds/sample-app
if you like, but it had a ttl of 3 hours and will expire soon enough anyways.
Create a cluster role
A Cluster role is not limited to a specific namespace and will have access to the whole Kubernetes cluster. In this section you will create and bind a cluster role, and use it to get details on the Minikube cluster.
Create a new cluster role.
The
kubernetes_role_type=ClusterRole
specifies that this is a cluster role.Next, create some credentials for the cluster role.
Test out the token by listing the pods in the demo namspace.
Check out a different namespace - default. Using a cluster role should give you access to all namspaces.
You also can look at the Vault namespace.
Output should be similar to the two examples above.
Switch off the cluster role status.
No access to view Vault namespace anymore.
Try the demo namespace again.
Go ahead and revoke these credentials.
Verify the credentials are revoked.
Rewrite the rules to give it a bit more power.
Get a new token. This new command will put the token into
TEST_TOKEN
for you.Using that token, delete a pod.
Verify pod deleted.
With Vault Kubernetes Secrets Engine you can grant temporary access to make major changes to the cluster.
Clean up
The fastest way to ckean up this lab is just to delete Minikube.
Review
You created a Kubernets Cluster locally using minikube, and added Vault and Nginx to it. Using the Kubernetes Secrets Engine on Vault, recieved an JSON Web Token (JWT) and used it git the API and examine pods in the cluster. These were initially using roles, which are limited to specific namespaces.
Then you created a cluster role, which allows you access the whole cluster. You looked at the pods in a few namespaces and after changing some of the caabilities of the cluster role deleted the Nginx pod.