The OpenID Connect Webhook Authenticator allows Kubernetes cluster administrators to dynamically register new OpenID Connect providers in their clusters to use for kube-apiserver authentication.
Note: This repository still in
alphastage and in active development. It should not be used in production. The API can change without any backwards compatibility.
In Kubernetes, only a single OpenID Connect authenticator can be used for end-users to authenticate.
To workaround this limitations, a Webhook Token Authentication can be configured. The Kube APIServer then sends the Bearer Tokens (id_token) to an external webhook for validation:
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"spec": {
"token": "(BEARERTOKEN)"
}
}Where upon verification, the remote webhook returns the identity of the user (if authentication succeeds):
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
"username": "[email protected]",
"uid": "42",
"groups": [
"developers",
"qa"
],
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
}
}
}This repository is the out-of tree implementation of Dynamic Authentication KEP.
- Establish trust relationship between different Kubernetes clusters using Service Account Token Volume Projection and Service Account Issuer Discovery.
- Offer cluster admins the option to dynamically allow users from other OIDC IDPs to authenticate against their
kube-apiserver.
This webhook is a Kubernetes controller that acts on OpenIDConnect resources e.g:
apiVersion: authentication.gardener.cloud/v1alpha1
kind: OpenIDConnect
metadata:
name: foo
spec:
issuerURL: https://foo.bar
audiences:
- some-client-id
usernameClaim: email
usernamePrefix: "test-"
groupsClaim: groups
groupsPrefix: "baz-"
supportedSigningAlgs:
- RS256
requiredClaims:
baz: bar
caBundle: LS0tLS1CRUdJTiBDRVJU...base64-encoded CA certs for issuerURL.Note: The fields in the specification corresponds to the kube-apiserver OIDC flags.
The flow is following:
- Admin adds a new
OpenIDConnectto the cluster. - The webhook controller watches for changes on this resource and does OIDC discovery. The OIDC provider's configuration has to be accessible under the
spec.issuerURLwith a well-known path (.well-known/openid-configuration). - The webhook controller uses the
jwks_uriobtained from the OIDC providers configuration, to fetch the OIDC provider's public keys from that endpoint. - The webhook controller uses those keys, issuer, client_id and other settings to add OIDC authenticator to a in-memory list of Token Authenticators.
An overview of the controller:
When a user wants to authenticate to the kube-apiserver via this new Custom OpenIDConnect IDP:
-
The user authenticates in Custom IDP.
-
id_tokenis obtained from Custom IDP (e.g.ddeewfwef...). -
The user uses
id_tokento perform an API call to Kube APIServer. -
As the
id_tokenis not matched by any build-in or configured authenticators in the Kube APIServer, it is send to OpenID Connect Webhook Authenticator for validation.{ "TokenReview": { "kind": "TokenReview", "apiVersion": "authentication.k8s.io/v1", "spec": { "token": "ddeewfwef..." } } } -
The webhook then iterates over all registered
OpenIDConnectToken authenticators and tries to validate the token. -
Upon a successful validation it returns the
TokenReviewwith user, groups and extra parameters:{ "TokenReview": { "kind": "TokenReview", "apiVersion": "authentication.k8s.io/v1", "spec": { "token": "ddeewfwef..." }, "status": { "authenticated": true, "user": { "username": "[email protected]", "groups": [ "test-some-group" ], "extra": { "gardener.cloud/authenticator/name": [ "gardener" ], "gardener.cloud/authenticator/uid": [ "e5062528-e5a4-4b97-ad83-614d015b0979" ] } } } } }
It adds the following extra information, that can be used by custom authorizers later on:
gardener.cloud/authenticator/namecontains the name of theOpenIDConnectauthenticator which was used.gardener.cloud/authenticator/uidcontains the UID of theOpenIDConnectauthenticator which was used.
Docker images are available here or you can choose to pull the latest pre-release version with the following command:
docker pull europe-docker.pkg.dev/gardener-project/public/gardener/oidc-webhook-authenticator:latest
For this setup the following components are needed:
The API server is started with --authentication-token-webhook-config-file with kubeconfig file pointing to the Webhook.
mkdir -p ~/.minikube/files/var/lib/minikube/certs
cp config/samples/minikube-webhook-kubeconfig.yaml ~/.minikube/files/var/lib/minikube/certs/minikube-webhook-kubeconfig.yaml
minikube start \
--extra-config=apiserver.authentication-token-webhook-config-file=/var/lib/minikube/certs/minikube-webhook-kubeconfig.yaml \
--extra-config=apiserver.authentication-token-webhook-cache-ttl=10sTo allow easy communication between the kube-apiserver and the oidc-webhook-authenticator minikube IP is added as control-plane.minikube.internal in /etc/hosts
sudo sed -ie '/control-plane.minikube.internal/d' /etc/hosts
echo "$(minikube ip) control-plane.minikube.internal" | sudo tee -a /etc/hostsAdd the CRD:
kubectl apply -f config/crd/bases/authentication.gardener.cloud_openidconnects.yamlBuild the image, so it's accessible by minikube:
minikube image build -t oidc-webhook-authenticator .Deploy the oidc webhook authenticator.
kubectl apply -f config/samples/deployment.yamlCreate an OpenIDConnect resource configured with your identity provider's settings (see an example here). Get a token from your identity provider. You can now authenticate against the minikube cluster.
curl -k -H "Authorization: Bearer $MY_TOKEN" $(k config view -o=jsonpath="{.clusters[?(@.name=='minikube')].cluster.server}")Alternatively you can also use a token kubeconfig or the kubelogin plugin and configure an OIDC kubeconfig.