AKS の Active Directory インテグレーションを触ってみる


本ブログは自分の学習のメモとしての内容で、実際にやっている内容は、次のオフィシャルドキュメントの内容である。
https://docs.microsoft.com/en-us/azure/aks/managed-aad

Azure AD 認証の概要

Azure AD 認証は、AKSに対して OpenID Connect と共に提供される。OpenID Connectは、OAuth 2.0 protocol の上に作られた Identity Layer である。

Kubernetes クラスタの内部から、 Webhook Token Authentication が認証トークンを Verify するのに使われる。Webhook Token Authentication はAKSクラスターの一部として構成される。

前提条件

az コマンドの 2.11.0 以上インストールは必須ですが、それ以外にも、テナントのAdminである必要があります。例えば私は自社のAdminではないですが、旧MSDNのメンバーシップはあるので、そちらの方だと私はAdminの権限を持っているのでそちらのSubscriptionで実施する必要がありました。

AD グループの作成

AD のグループを作成します。下記の2つのパラメータは必須なので記述していますが、他にもパラメータはあります。--description などは後々便利かも。まだ、グループという概念が正確に理解できていませんが、こののちわかるのでしょう。

$ az ad group create --display-name tsushiAksGroup --mail-nickname tsushiAksGroup

AD enabled の AKS クラスタを作成する

ちなみに、aks を japanwest にデプロイしようとしましたが、私の Subscription (旧MSDN) ではだめなようでした。 先ほどのコマンドで、取得した、objectId--aad-admin-group-object-ids に引き渡してあげれば良いようです。

$ az aks create -g $resourceGroup -n $aksName --enable-aad --aad-admin-group-object-ids <<objectId>>

先ほど設定したobjectId が、adminGroupObjectIdsにセットされており、tenantId が正しければデプロイ成功。

{                                                                     
  "aadProfile": {
    "adminGroupObjectIds": [
      "<<objectId>>"
    ],
    "clientAppId": null,
    "enableAzureRbac": false,
    "managed": true,
    "serverAppId": null,
    "serverAppSecret": null,
    "tenantId": "<<tenantId>>"
  },

Kubernetes のクレデンシャルの取得

$ az aks get-credentials --resource-group $resourceGroup --name $aksName

普通にkubectl get nodes を実施すると思いっきり失敗するがな。

kubectl get nodes
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code <<CODE>> to authenticate.
E0606 21:21:29.761965    1809 round_trippers.go:174] CancelRequest not implemented by *azure.azureRoundTripper
error: You must be logged in to the server (Unauthorized)

いろいろ試したがダメだったので、質問を投げて次に進む
https://github.com/MicrosoftDocs/azure-docs/issues/76479

Root Cause

最初の手順を怠っていたため。自分は、kubectl を持っているので必要ないと思ってスキップしたが、今のバージョンでは、kubectlに加えて、kubeloginというのが含まれており、これが、AD 連携を行ってくれる。これは、kubectlのプラグインなので、これ無しでは、当然 ADのインテグレーションは使えないということ。

$ sudo az aks install-cli

admin でログインする

先ほどは失敗したので、admin でログインして Control access to cluster resources using Kubernetes role-based access control and Azure Active Directory identities in Azure Kubernetes Service のページに進んでみよう。

$ az aks get-credentials --resource-group $resourceGroup --name ${aksName} --admin

AD のアカウントを作成

DevとSREのアカウントを作成してみる。ADD_DEV_UPN, ADD_DEV_PWADD_SRE_UPNADD_SRE_PW にそれぞれ、User Principal Name (あなたのドメインのユーザ名。ドメインをつけて、[email protected] の形式で作成する。パスワードはルールが厳しいので、大文字小文字、英数、記号を交えて作成。 その後次のようなスクリプトを作成して流してみる。

とても単純なのですが、AD のグループを作成して

$ APPDEV_ID=$(az ad group create --display-name appdev --mail-nickname appdev --query objectId -o tsv)
$ OPSSRE_ID=$(az ad group create --display-name opssre --mail-nickname opssre --query objectId -o tsv)

その後、ADのグループにユーザを作成して、追加していきます。

AKS_ID=$(az aks show --resource-group $resourceGroup --name ${aksName} --query id -o tsv)

AKSDEV_ID=$(az ad user create \
  --display-name "AKS Dev" \
  --user-principal-name $AAD_DEV_UPN \
  --password $AAD_DEV_PW \
  --query objectId -o tsv)

az ad group member add --group appdev --member-id $AKSDEV_ID


AKSSRE_ID=$(az ad user create \
  --display-name "AKS SRE" \
  --user-principal-name $AAD_SRE_UPN \
  --password $AAD_SRE_PW \
  --query objectId -o tsv)

az ad group member add --group opssre --member-id $AKSSRE_ID

Kubernetes のリソースの作成

Namespace の作成

Kubernetes 側の作業として、ネームスペースをそれぞれ dev sre と作成します。作成ししたネームスペースに対して、RoleRoleBindings を作成していきます。ポイントは、ServiceAccount を使う代わりに、Group を定義して、ADのグループのobjectIdを引き渡します。

Role の作成

Dev, SRE それぞれの Role を定義します。それぞれの Namespace を使えるようにします。

role-dev-namespace.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dev-user-full-access
  namespace: dev
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]
role-sre-namespace.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: sre-user-full-access
  namespace: sre
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]

Role Bindings

Role Bindings の方で、AD の Group の objectId を渡します。これだけ!

kubectl create namespace dev 

kubectl apply -f role-dev-namespace.yaml

groupObjectId=$(az ad group show --group appdev --query objectId -o tsv)

cat << EOF > rolebinding-dev-namespace.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dev-user-access
  namespace: dev
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: dev-user-full-access
subjects:
- kind: Group
  namespace: dev
  name: ${groupObjectId}
EOF

kubectl apply -f rolebinding-dev-namespace.yaml

kubectl create namespace sre 
kubectl apply -f role-sre-namespace.yaml

groupObjectId=$(az ad group show --group opssre --query objectId -o tsv)

cat << EOY > rolebinding-sre-namespace.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: sre-user-access
  namespace: sre
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: sre-user-full-access
subjects:
- kind: Group
  namespace: sre
  name: ${groupObjectId}
EOY

kubectl apply -f rolebinding-sre-namespace.yaml 

テスト実行

クレデンシャルをクリアしておきます。

az aks get-credentials --resource-group $resourceGroup --name $aksName --overwrite-existing

次に、対象のオペレーションを行うと、AD のログインが要求されます。今回はdevでログインしたので、devにはデプロイ可能です。

kubectl run nginx-dev-01 --image=mcr.microsoft.com/oss/nginx/nginx:1.15.5-alpine --namespace dev
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code SVXPBTST3 to authenticate.
pod/nginx-dev-01 created

SREのネームスペースにデプロイすると当然はじかれます。

kubectl run nginx-sre-01 --image=mcr.microsoft.com/oss/nginx/nginx:1.15.5-alpine --namespace sre
Error from server (Forbidden): pods is forbidden: User "[email protected]" cannot create resource "pods" in API group "" in the namespace "sre"

自分が試したときには、なぜか、dev は、正しい動きだけど、sre はなぜか devにもデプロイできました。上記の k8s のオブジェクトを見直しましたが、正しくコンフィグレーションされています。では何だったか?というと、AD の設定ミスでした。両方登録されとるがな。

az ad group member list --group appdev --query '[].userPrincipalName'
[
  "[email protected]",
  "[email protected]"
]

内部的には

Service Account と default secrets が作られているようですね

 kubectl get sa default -n sre -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2021-06-07T05:51:57Z"
  name: default
  namespace: sre
  resourceVersion: "9761"
  selfLink: /api/v1/namespaces/sre/serviceaccounts/default
  uid: 4059160d-a83d-4a89-a7ec-fc08cda977c5
secrets:
- name: default-token-z5sng

終わりに

自分のしょーもない2つのミスで時間をロスしました。

  • kubelogin の手順を飛ばしていた
  • AD のグループの登録をミスしていた

多分スピーディにやろうとし過ぎて失敗していると思うので、確認しながら実施したほうが結局の早く物事が進みそうです。反省。しかし、大体インテグレーションのイメージはつくようになりました。