Last modified March 6, 2022

Authenticating with Microsoft Azure Active Directory

The Kubernetes API of workload clusters, by default, uses key pairs (X.509 private key and certificate) for authentication.

In order to use Microsoft Azure Active Directory (AAD) for authentication instead, Giant Swarm can configure your management cluster(s) so that all workload clusters use the same settings and users can authenticate kubectl using their common identity (single sign-on, SSO) via OpenID Connect (OIDC).

Setting up kubectl for Azure auth

1. Set up a user

kubectl config \
  set-credentials "<username>" \
  --auth-provider=azure \
  --auth-provider-arg=environment=AzurePublicCloud \
  --auth-provider-arg=client-id=<kubectl-app-id> \
  --auth-provider-arg=tenant-id=<tenant-id> \
  --auth-provider-arg=apiserver-id=<apiserver-app-id>
  • username can be freely chosen, but must be unique within your local kubeconfig.
  • The 3 IDs are global settings that are set by your company. You should be able to obtain those internally.

2. Set up a cluster

kubectl config \
  set-cluster <clustername> \
  --server=https://<api-server-endpoint> \
  --certificate-authority=/path/to/ca.crt
  • clustername can be freely chosen, but must be unique within your local kubeconfig.
  • Kubernetes API Server endpoint and CA you can get from the web UI (Happa) or using gsctl.

3. Set up a context

kubectl config \
  set-context <contextname> \
  --cluster=<clustername> \
  --user=<username>
  • contextname can be freely chosen, but must be unique within your local kubeconfig.
  • clustername and username are the names chosen in step 1 and 2.

4. Authenticate on your first command

When you run your first kubectl command you will see something like the following:

$ kubectl get node
To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code DEHTRY693 to authenticate.

This step needs to be done only once and will register your kubectl as an authenticated device. From then on you can freely run commands against the cluster (limited only by the roles given to you on said cluster).

Note that in some cases (depending on AD settings) the device authentication can only be done in a Browser running on a Windows machine.

Creating a kubeconfig for general usage

If you are a Cluster Admin and want to create kubeconfig files to give out to your users you can use following template:

apiVersion: v1
kind: Config
clusters:
- cluster:
  name: <clustername>
    certificate-authority: /path/to/ca.crt
    server: https://<api-server-endpoint>
users:
- name: <username>
  user:
    auth-provider:
      name: azure
      config:
        apiserver-id: <apiserver-app-id>
        client-id: <kubectl-app-id>
        tenant-id: <tenant-id>
contexts:
- context:
    cluster: <clustername>
    user: <username>
  name: <contextname>
current-context: <contextname>

If you set all the above names to something generic, you can send the same file to all your users. The actual identification of each user will happen through the device authentication request done with their first kubectl command.

Furthermore, to make the kubeconfig self-contained, you can replace /path/to/ca.crt with an inline representation of the file. For that you need to base64-encode the contents of ca.crt and paste them into the kubeconfig.

Binding roles to users and groups coming from AAD

When authenticating with AAD your user identifies to Kubernetes with a username and the groups you are a member of in AAD. A Cluster Admin can bind roles to these to grant access on a specific cluster.

As explained in Securing your Cluster with RBAC and PSP you can either use the default roles or define custom Role or ClusterRole resources to bind to subjects.

In the following examples we’ll use one of the default cluster roles.

Note that you can only bind roles if your own role is wider defined than the role you want to bind for others. When in doubt use cluster-admin to apply bindings.

Binding a single user

AAD prefixes usernames so that they look like the following:

https://sts.windows.net/<tenant-id>/#<username>

Note: Here, username is not the freely chosen username you set in kubectl, but the username claim set to a specific attribute of your AAD user. Usually this will be set to your username attribute in AAD.

Based on that, we bind the user like the following:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: username-global-admin
subjects:
  - kind: User
    name: https://sts.windows.net/<tenant-id>/#<username>
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

Binding a group of users

Unlike usernames, groups are not prefixed. You can identify them by the Object ID of the group in AAD.

Based on that, we bind a group like the following:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: username-global-admin
subjects:
  - kind: Group
    name: <group-oid>
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

Revoking access

Access is revoked as soon as the user has either been removed from a bound group or completely from the AAD tenant.

Further reading