---
title: KindでAzure ADのOpenID Connectと連携してRBACを設定するメモ
tags: ["Kubernetes", "Kind", "Azure AD", "OIDC", "OpenID Connect"]
categories: ["Dev", "CaaS", "Kubernetes", "kind"]
date: 2023-08-03T07:01:10Z
updated: 2023-08-04T01:43:51Z
---

Kindで作るK8sクラスタに対してOIDCを設定したく、OIDC ProviderとしてAzure ADを使用するメモです。

RBACの検証をローカルで行いたい場合や、任意のk8sクラスタでOIDC連携したい場合に使えます。

> * EKSでOIDC連携する方法 https://docs.aws.amazon.com/eks/latest/userguide/authenticate-oidc-identity-provider.html
> * GKEでOIDC連携する方法 https://cloud.google.com/kubernetes-engine/docs/how-to/oidc

**目次**
<!-- toc -->

### Azure ADでアプリケーションの登録

https://azure.github.io/kubelogin/topics/k8s-oidc-aad.html を参考に以下の手順でAzure AD上でアプリケーション (OIDCクライアント) を登録します。ここでは`kind-oidc`という名前で作成します。

> ℹ️ Azure ADのアプリケーション作成に関しては https://www.pomerium.com/docs/identity-providers/azure も参考にしました。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/7cee7035-eb09-4587-9ea4-8779781b6cca">

"Allow public client flows"を"Yes"にします。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/b3b0407d-a661-4c66-8118-6c43ed88c205">

"Microsoft Graph"でpermissionを追加します。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/ac57e721-fd67-4eb3-980d-1b4b2783e164">

`Directory.Read.All`、`Group.Read.All`、`User.Read.All`のpermissionを追加します。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/c720489f-a8b3-4325-b0d1-1d7228ffc36b">

"Grant admin content for xxxx"を有効にします。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/4eb6bafa-f9fa-498d-bb95-494edc5548cb">

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/1b14f71d-470f-4e6e-ab1a-747a33e3c92e">

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/ef51b5e2-68ec-4462-ab62-a782432e1820">

`groups` claimを追加します。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/4eee7c90-3698-4d32-bb62-1ec755ed42b9">

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/62cd4c92-07c5-43a7-a8ed-2c794258ead3">

OverviewからApplication (client) IDとDirectory (tenant) IDをコピーします。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/41e31117-05d1-4503-8558-4d8727158594">


```
AAD_CLIENT_ID=*****
AAD_TENANT_ID=*****
```

`https://sts.windows.net/$AAD_TENANT_ID` がOIDCのissuer urlになるので、次のURLでメタデータを取得できます。

```
curl -s https://sts.windows.net/$AAD_TENANT_ID/.well-known/openid-configuration
```

### kubeloginのインストール

Azure ADから`kubectl`用のアクセストークンを取得するために、[`kubelogin`](https://github.com/Azure/kubelogin)を使用します。

以下のドキュメントに従ってインストールします。

https://azure.github.io/kubelogin/install.html

```
brew install Azure/kubelogin/kubelogin
```

次のコマンドを実行してトークンを取得できます。

```
$ kubelogin get-token --environment AzurePublicCloud --server-id $AAD_CLIENT_ID --client-id $AAD_CLIENT_ID --tenant-id $AAD_TENANT_ID
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code IU3PMB29G to authenticate.
```

出力されたメッセージにしたがって、ブラウザでログインします。

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/b680c746-b3c5-4c62-9500-4a6ec5e819d6">


ログインが成功するとトークンが出力されます。

このトークンは`~/.kube/cache/kubelogin`以下にキャッシュされています。`kubelogin remove-tokens`でキャッシュを削除できます。

以下のコマンドでアクセストークンの中身をデコードしてclaimをみることが出来ます。

```
$ cat ~/.kube/cache/kubelogin/*.json | jq -r .access_token | jq -R 'split(".") | .[1] | @base64d | fromjson'

{
  "aud": "*****",
  "iss": "https://sts.windows.net/*****/",
  "iat": 1691042264,
  "nbf": 1691042264,
  "exp": 1691047580,
  "acr": "1",
  "aio": "*****",
  "amr": [
    "pwd",
    "mfa"
  ],
  "appid": "*****",
  "appidacr": "0",
  "email": "*****",
  "family_name": "*****",
  "given_name": "*****",
  "groups": [
    "*****",
    "*****"
  ],
  "idp": "*****",
  "ipaddr": "*****",
  "name": "*****",
  "oid": "*****",
  "rh": "*****",
  "scp": "User.Read",
  "sub": "*****",
  "tid": "*****",
  "unique_name": "*****",
  "uti": "*****",
  "ver": "1.0",
  "wids": [
    "*****",
    "*****"
  ]
}
```

### Kind Clusterの作成

作成したOIDCクライアントを使った認可を行うためにAPI Serverにオプションを追加してkindでクラスタを作成します。

API Serverの設定に関するドキュメントは https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuring-the-api-server です。

```yaml
cat <<EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
kubeadmConfigPatches:
- |-
  kind: ClusterConfiguration
  apiServer:
    extraArgs:
      oidc-client-id: $AAD_CLIENT_ID
      oidc-issuer-url: https://sts.windows.net/$AAD_TENANT_ID/
      oidc-username-claim: email
      oidc-groups-claim: groups
nodes:
- role: control-plane
EOF
```

```
kind create cluster --config kind-config.yaml --image kindest/node:v1.26.6
```

`kubectl`で`kubelogin`を使ったuserを設定します。

```
kubectl config set-credentials "azure-user" \
  --exec-api-version=client.authentication.k8s.io/v1beta1 \
  --exec-command=kubelogin \
  --exec-arg=get-token \
  --exec-arg=--environment \
  --exec-arg=AzurePublicCloud \
  --exec-arg=--server-id \
  --exec-arg=$AAD_CLIENT_ID \
  --exec-arg=--client-id \
  --exec-arg=$AAD_CLIENT_ID \
  --exec-arg=--tenant-id \
  --exec-arg=$AAD_TENANT_ID
```

上記のuserを使用するcontextをkindクラスタに対して設定して、contextを切り替えます。

```
kubectl config set-context kind-oidc --cluster=kind-kind --user=azure-user
kubectl config use-context kind-oidc
```

このcontextで次のコマンドを実行すると次のようなエラーメッセージが出力されるはずです。

```
$ kubectl get pod   
Error from server (Forbidden): pods is forbidden: User "****" cannot list resource "pods" in API group "" in the namespace "default"
```

Azure ADでログインしたユーザーはまだなんの権限もないので、K8sに対して何もできません。

### ADグループの作成とメンバー追加

Developer用のADグループを作成します。

```
GROUP_ID=$(az ad group create --display-name demo-developer --mail-nickname demo-developer --query id -o tsv)
```

`az login`でログインしたの自分のアカウントをこのグループに追加します。

```
az login

UPN=$(az ad signed-in-user show --query userPrincipalName -o tsv)
OID=$(az ad user show --id ${UPN} --query id -o tsv)

az ad group member add --group demo-developer --member-id ${OID}
```

groupに追加されていることを確認します。

```
$ az ad group member list --group demo-developer
[
  {
    "@odata.type": "#microsoft.graph.user",
    "businessPhones": [],
    "displayName": "****",
    "givenName": "****",
    "id": "****",
    "jobTitle": null,
    "mail": "****",
    "mobilePhone": null,
    "officeLocation": null,
    "preferredLanguage": null,
    "surname": "****",
    "userPrincipalName": "****"
  }
]
```

`GROUP_ID`は次のコマンドでも取得できます。

```
GROUP_ID=$(az ad group list --filter "displayname eq 'demo-developer'" --query '[0].id' -o tsv)
```

ユーザーをグループに追加したら、トークンを取得し直します。

```
kubelogin remove-tokens
kubelogin get-token --environment AzurePublicCloud --server-id $AAD_CLIENT_ID --client-id $AAD_CLIENT_ID --tenant-id $AAD_TENANT_ID
```

以下のコマンドを実行し、`groups` claimに`$GROUP_ID`が追加されていることを確認してください。

```
cat ~/.kube/cache/kubelogin/*.json | jq -r .access_token | jq -R 'split(".") | .[1] | @base64d | fromjson'
```


### グループに対するRoleBindingの作成

cluster-admin権限で作成したグループに対して`dev` namespaceの`admin` clusterroleをbindします。

```
kubectl create ns dev --context kind-kind
kubectl create rolebinding -n dev --clusterrole=admin --group=${GROUP_ID} demo-admin --context kind-kind
```

```
$ kubectl get rolebinding -n dev -owide
NAME         ROLE                AGE   USERS   GROUPS                                 SERVICEACCOUNTS
demo-admin   ClusterRole/admin   14s           7afc7680-534d-46aa-9c95-0195655caf57  
```

これで`dev` namespaceにはadminとして操作が可能になりますが、他のnamespaceでは引き続き操作が制限されています。

```
$ kubectl get pod -n dev
No resources found in dev namespace.
$ kubectl get pod -n default
Error from server (Forbidden): pods is forbidden: User "****" cannot list resource "pods" in API group "" in the namespace "default"
```
