Authenticate to Kubernetes API Server with an external Identity Provider
With this post I will be going through how you can authenticate to your kubernetes API server through WSO2 Identity Server. Well, with this method you don’t need to have separate users in your kubernetes cluster. You can manage users through your cooperate Identity Provider itself. (Any IDP which supports OpenID connect). [1]
At the end of this, you can authenticate your kubctl using the tokens retrieved from your Identity Provider. The IDP has to have below important characteristics in order to use it as the OIDC IDP for kubernetes. Well these were there in WSO2 Identity Server from way back !!.
- Support OpenID connect discovery; not all do.
- Run in TLS with non-obsolete ciphers
To start with you need to have a CA signed a Self Signed certificates for WSO2 Identity Server which has proper domains. At least you need to add your domain or IP as SANs while creating certificate. Unless we won’t be able to continue. Whatever the host/IP you are using for calls to WSO2 Identity server, it has to have that host/ip as CN or a SAN. Keep the public certificate somewhere as you need it later. I will refer it as yay.pem.
Well one more thing. Before starting WSO2 Identity Server, do the following config changes
- Remove authentication enforcement to /.well-known configuration endpoint. By default this endpoint requires basic authentication in order to retrieve information. In order to remove it, comment out the below part in repository/conf/identity/identity.xml
<!--Resource context="(.*)/.well-known(.*)" secured="true" http-method="all"/-->
2. Change the issuer of the IssuerID in the same file to below
<IDTokenIssuerID>${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/oidcdiscovery</IDTokenIssuerID>
Please note that keep the place holders starting with ${ as they are. Those will be replace runtime.
3. Add the correct hostname or the IP which you are running your IS in repository/conf carbon.xml. I have this IP as a SAN in my self signed certificate.
<HostName>10.100.5.78</HostName><MgtHostName>10.100.5.78</MgtHostName>
Start your Identity Server !!. Do the following.
- Create a user and a role. Lets say our user is hasintha and role is cluster-admin.
- Add the user hasintha to cluster-admin role
- Add a service provider and configure it for OIDC. (Just a matter of getting client ID and Secret). Keep the client id and secret as we need it in future.
- Add role claim as a mandatory claim under Claim Configurations. Below is an image of what your SP configurations should look like.
- Go to resident IDP configurations and change the spEntityId under OAuth2/OpenID Connect Configuration to below
https://10.100.5.78:9443/oauth2/oidcdiscovery
Well, you need replace your host / IP , port while adding this.
Configuring API Server to trust WSO2 Identity Server
Pass following additional arguments when starting kube API executable in order to trust WSO2 Identity Server. You need to have your IDPs public certificate in place.
In my case I have kubeadmin. My kube-apiserver.yaml looks like the below [1]. In this I had copied the certificate to my machine and mounted it to container using a host mount.
Client ID should be the one which you generated while creating a service provider in WSO2 Identity Server.
Create a cluster role binding.
What we expect from this step is to map the external IDP role cluster-admin to kubernetes cluster-admin role. Below is the yaml for creating the cluster binding role
Configuring Kubectl to retrieve tokens
As the first step get a token from WSO2 Identity Server using password grant type.
curl -u H1Vt_n8eRyKzu1EBzwfXVirQIfga:XE5CEn6ke9drWwDHH_cI52hfB7Ea -k -d "grant_type=password&username=hasintha&password=hasintha&scope=openid" -H "Content-Type:application/x-www-form-urlencoded" https://10.100.5.78:9443/oauth2/token
The token has to have scope openid. Because the ID token will be using for user assertion. In response to the above request you will receive a toke, ID token and a refresh token. Below will authenticate your user to kube API server.
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )
This will produce the below configuration
Now you are successfully authenticated as a federated user. Note that username which you configure above is not so important. You can authenticate as any user and the user which is denoted in ID token will be the ultimate authenticated user. You can keep using this since, kubectl refreshes token using refresh grant.
References
[1] https://kubernetes.io/docs/reference/access-authn-authz/authentication/
[2] kube-apiserver.yaml