Impersonating kube service accounts
clux March 31, 2019 [software] #bash #kubernetesAuthenticating with large kubernetes clusters often risks you dealing with complicated provider logic and sometimes policies outside your control.
While controllers and operators authenticate with service accounts directly, this is only true inside the cluster. That is, unless you can impersonate the service account from outside.
EDIT: as of Kubernetes 1.24 the bypass method no longer works.
..but why would you need to do this?
1. Testing service account access
If you have a way to quickly impersonate a service account you can tell if your rbac verbs, resources are correct and were slash separated in the way kube expects.
As an example, to allow shell access into pods, you must grant create
on pods/exec
in the empty api group (""
)
- apiGroups:
resources:
- pods/exec
verbs:
It's safe to say that the groups and resource names are often less than intuitive, and it doesn't help that there is very lackluster errors when applying policies.
2. kubectl is better than your language-x client
Having your app deal with oidc providers is an unnecessary pain point / code path when your app is meant to live in the cluster and authenticate with a service account anyway.
Even if the language you're writing in is one of the supposedly supported languages, your mileage may vary if it's not Go. Even post 1.11, it's still beta in go.
3. service accounts can function as group auth
Not saying you shouldn't have single sign on hooked up to kube, but if you are lacking a good solution at the moment, a few targetted developer accounts with actual rbac policies attached to them is an actual, revokeable solution (as opposed to handing over admin tokens).
It does not provide as clean of an audit trail, but if you just want to give read only access to pods, logs, deployments, you might not care.
Impersonation
There are currently two main ways of doing this. The new, limited-use-case way, and the old yaml wrangling method.
Rbac controlled
These days, kubectl supports user-impersonation, so if you're just testing access you can use kubectl <verb> <resource> --as=jenkins
, provided your user has the impersonate
verb set where you need it to:
- apiGroups:
resources:
verbs:
However, this doesn't solve problem 2 or 3 listed above.
Manual impersonation
This method extracts the credentials from a service account and adds them as extra entries in your ~/.kube/config
. This way most language clients should be able to handle them, and you can have an unobtrusive new context to test.
The following implementation requires kubectl
, yq
, plus the existing rbac access to read service accounts and secrets in the namespace you want to impersonate.
#!/usr/bin/env bash
# usage: impersonate jenkins kube-system
# shellcheck disable=SC2068
Make it an executable impersonate.sh
file and run ./impersonate account namespace
. Note that this implementation requires that your context has a namespace.
For a budget solution to 3; take the token
+ secret
, store it in a secured vault
that you probably already use policies for correctly. People can now elevate themselves from vault
to kubectl
while you bang your head against the oidc providers.