Azure Kubernetes Service (AKS) クラスター上の Windows Server ノードでグループ管理サービス アカウント (GMSA) を有効にする

グループ管理サービス アカウント (GMSA) は、パスワードの自動管理、簡略化されたサービス プリンシパル名 (SPN) の管理、および管理を他の管理者に委任する機能を提供する複数のサーバーのマネージド ドメイン アカウントです。 AKS では、Windows Server ノードで GMSA を有効にする機能が提供されます。これにより、Windows Server ノード上で実行されているコンテナーを GMSA と統合して GMSA で管理できます。

前提条件

AKS 上の Windows Server ノードで GMSA を有効にするには、次のものが必要となります。

  • Kubernetes 1.19 以上。
  • Azure CLI バージョン 2.35.0 以降
  • AKS クラスターのマネージド ID
  • Azure Key Vault を作成または更新するためのアクセス許可。
  • Active Directory Domain Services またはオンプレミスの Active Directory で GMSA を構成するためのアクセス許可。
  • ドメイン コントローラーで Active Directory Web サービスが有効になっている必要があります。また、AKS クラスターからポート 9389 に到達できる必要があります。

Active Directory ドメイン コントローラーに GMSA を構成する

AKS で GMSA を使用するには、ドメイン コントローラーに構成されている GMSA 資格情報にアクセスするために、GMSA と標準のドメイン ユーザーの資格情報の両方が必要です。 ドメイン コントローラーに GMSA を構成するには、グループ管理サービス アカウントの概要に関する記事を参照してください。 標準のドメイン ユーザーの資格情報の場合は、GMSA の資格情報にアクセスできる限り、既存のユーザーを使用するか、新しいユーザーを作成できます。

重要

Active Directory Domain Services またはオンプレミスの Active Directory を使用する必要があります。 現時点では、Azure Active Directory を使用して AKS クラスターで GMSA を構成することはできません。

標準のドメイン ユーザーの資格情報を Azure Key Vault に格納する

AKS クラスターでは、標準のドメイン ユーザーの資格情報を使用して、ドメイン コントローラーから GMSA の資格情報にアクセスします。 AKS クラスターにそれらの資格情報への安全なアクセスを提供するには、それらの資格情報を Azure Key Vault に格納する必要があります。 新しいキー コンテナーを作成するか、既存のキー コンテナーを使用できます。

標準のドメイン ユーザーの資格情報をシークレットとしてキー コンテナーに格納するには、az keyvault secret set を使用します。 次の例では、ドメイン ユーザーの資格情報を MyAKSGMSAVault キー コンテナーにキー GMSADomainUserCred で格納します。 パラメーターを独自のキー コンテナー、キー、ドメイン ユーザーの資格情報に置き換える必要があります。

az keyvault secret set --vault-name MyAKSGMSAVault --name "GMSADomainUserCred" --value "$Domain\\$DomainUsername:$DomainUserPassword"

注意

内部ネットワークで使用できる部分修飾ドメイン名ではなく、ドメインの完全修飾ドメイン名を使用します。

上記のコマンドを使用すると、Linux シェルで Azure CLI を実行するための value パラメーターがエスケープされます。 Windows PowerShell で Azure CLI コマンドを実行する場合、value パラメーター内の文字をエスケープする必要はありません。

オプション: カスタム DNS を持つカスタム VNET を使用する

ドメイン コントローラーは、AKS クラスターから到達できるように、DNS を使用して構成する必要があります。 AKS クラスターの外部にネットワークと DNS を構成して、クラスターからドメイン コントローラーにアクセスできるようすることができます。 または、AKS クラスターで Azure CNI を使用してカスタム DNS を持つカスタム VNET を構成し、ドメイン コントローラーへのアクセスを提供することもできます。 詳細については、「Azure Kubernetes Service (AKS) で Azure CNI ネットワークを構成する」を参照してください。

オプション: クラスターに独自の kubelet ID を使用する

AKS クラスターからキー コンテナーにアクセスできるようにするには、クラスターの kubelet ID でキー コンテナーにアクセスする必要があります。 既定では、マネージド ID が有効になっているクラスターを作成すると、kubelet ID が自動的に作成されます。 後の手順でクラスターを作成した後に、キー コンテナーへのアクセス権をこの ID に付与できます。

または、独自の ID を作成し、後の手順でクラスターを作成するときにこの ID を使用することもできます。 提供されるマネージド ID の詳細については、「マネージド ID の概要」を参照してください。

独自の ID を作成するには、az identity create を使用して ID を作成します。 次の例では、リソース グループ myResourceGroupmyIdentity という ID を作成します。

az identity create --name myIdentity --resource-group myResourceGroup

クラスターの作成前または作成後に、キー コンテナーへのアクセス権を kubelet ID に付与できます。 次の例では、az identity list を使用して ID を取得し、それを az identity list に設定してから、az keyvault set-policy を使用して az keyvault set-policy キー コンテナーへのアクセス権をその ID に付与します。

MANAGED_ID=$(az identity list --query "[].id" -o tsv)
az keyvault set-policy --name "MyAKSGMSAVault" --object-id $MANAGED_ID --secret-permissions get

AKS クラスターの作成

AKS クラスターで GMSA を使用するには、enable-windows-gmsagmsa-dns-servergmsa-root-domain-nameenable-managed-identity パラメーターを使用します。

Note

Windows Server ノード プールを使用してクラスターを作成する場合は、クラスターの作成時に管理者の資格情報を指定する必要があります。 次のコマンドを実行すると、ユーザー名の入力が求められ、後のコマンドで使用できるように WINDOWS_USERNAME と設定されます (この記事に示すコマンドは BASH シェルで入力されます)。

echo "Please enter the username to use as administrator credentials for Windows Server nodes on your cluster: " && read WINDOWS_USERNAME

az aks create を使用して AKS クラスターを作成してから、az aks nodepool add を使用して Windows Server ノード プールを追加します。 次の例では、MyResourceGroup リソース グループに MyAKS クラスターを作成し、GMSA を有効にして、npwin という新しいノード プールを追加します。

Note

カスタム VNet を使用している場合は、vnet-subnet-id を使用して VNet の ID を指定する必要があります。また、構成に応じて、docker-bridge-addressdns-service-ipservice-cidr も追加する必要がある場合があります。

kubelet ID 用に独自の ID を作成した場合は、assign-kubelet-identity パラメーターを使用して ID を指定します。

DNS_SERVER=<IP address of DNS server>
ROOT_DOMAIN_NAME="contoso.com"

az aks create \
    --resource-group MyResourceGroup \
    --name MyAKS \
    --vm-set-type VirtualMachineScaleSets \
    --network-plugin azure \
    --load-balancer-sku standard \
    --windows-admin-username $WINDOWS_USERNAME \
    --enable-managed-identity \
    --enable-windows-gmsa \
    --gmsa-dns-server $DNS_SERVER \
    --gmsa-root-domain-name $ROOT_DOMAIN_NAME

az aks nodepool add \
    --resource-group myResourceGroup \
    --cluster-name myAKS \
    --os-type Windows \
    --name npwin \
    --node-count 1    

az aks update を使用して、Windows Server ノードとマネージド ID が既にある既存のクラスターで GMSA を有効にすることもできます。 次に例を示します。

az aks update \
    --resource-group MyResourceGroup \
    --name MyAKS \
    --enable-windows-gmsa \
    --gmsa-dns-server $DNS_SERVER \
    --gmsa-root-domain-name $ROOT_DOMAIN_NAME

クラスターを作成または更新した後に、az keyvault set-policy を使用して、キー コンテナーへのアクセス権を ID に付与します。 次の例では、クラスターによって作成された kubelet ID に MyAKSGMSAVault キー コンテナーへのアクセスを許可します。

Note

kubelet ID に独自の ID を指定した場合は、このステップをスキップします。

MANAGED_ID=$(az aks show -g MyResourceGroup -n MyAKS --query "identityProfile.kubeletidentity.objectId" -o tsv)

az keyvault set-policy --name "MyAKSGMSAVault" --object-id $MANAGED_ID --secret-permissions get

GMSA の資格情報の仕様をインストールする

Kubernetes クラスターに接続するように kubectl を構成するには、az aks get-credentials コマンドを使用します。 次の例では、MyResourceGroupMyAKS という名前の AKS クラスター用の資格情報が取得されます。

az aks get-credentials --resource-group MyResourceGroup --name MyAKS

以下の内容で gmsa-spec.yaml を作成し、プレースホルダーを独自の値に置き換えます。

apiVersion: windows.k8s.io/v1alpha1
kind: GMSACredentialSpec
metadata:
  name: aks-gmsa-spec  # This name can be changed, but it will be used as a reference in the pod spec
credspec:
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: $GMSA_ACCOUNT_USERNAME
      Scope: $NETBIOS_DOMAIN_NAME
    - Name: $GMSA_ACCOUNT_USERNAME
      Scope: $DNS_DOMAIN_NAME
    HostAccountConfig:
      PluginGUID: '{CCC2A336-D7F3-4818-A213-272B7924213E}'
      PortableCcgVersion: "1"
      PluginInput: ObjectId=$MANAGED_ID;SecretUri=$SECRET_URI  # SECRET_URI takes the form https://$akvName.vault.azure.net/secrets/$akvSecretName
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    DnsName: $DNS_DOMAIN_NAME
    DnsTreeName: $DNS_ROOT_DOMAIN_NAME
    Guid:  $AD_DOMAIN_OBJECT_GUID
    MachineAccountName: $GMSA_ACCOUNT_USERNAME
    NetBiosName: $NETBIOS_DOMAIN_NAME
    Sid: $GMSA_SID

次の内容で gmsa-role.yaml を作成します。

#Create the Role to read the credspec
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: aks-gmsa-role
rules:
- apiGroups: ["windows.k8s.io"]
  resources: ["gmsacredentialspecs"]
  verbs: ["use"]
  resourceNames: ["aks-gmsa-spec"]

次の内容で gmsa-role-binding.yaml を作成します。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: allow-default-svc-account-read-on-aks-gmsa-spec
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: aks-gmsa-role
  apiGroup: rbac.authorization.k8s.io

kubectl apply を使用して、kubectl applygmsa-role.yamlgmsa-role-binding.yaml から変更を適用します。

kubectl apply -f gmsa-spec.yaml
kubectl apply -f gmsa-role.yaml
kubectl apply -f gmsa-role-binding.yaml

GMSA がインストールされて動作していることを確認する

次の内容で gmsa-demo.yaml を作成します。

---
kind: ConfigMap
apiVersion: v1
metadata:
  labels:
   app: gmsa-demo
  name: gmsa-demo
  namespace: default
data:
  run.ps1: |
   $ErrorActionPreference = "Stop"

   Write-Output "Configuring IIS with authentication."

   # Add required Windows features, since they are not installed by default.
   Install-WindowsFeature "Web-Windows-Auth", "Web-Asp-Net45"

   # Create simple ASP.Net page.
   New-Item -Force -ItemType Directory -Path 'C:\inetpub\wwwroot\app'
   Set-Content -Path 'C:\inetpub\wwwroot\app\default.aspx' -Value 'Authenticated as <B><%=User.Identity.Name%></B>, Type of Authentication: <B><%=User.Identity.AuthenticationType%></B>'

   # Configure IIS with authentication.
   Import-Module IISAdministration
   Start-IISCommitDelay
   (Get-IISConfigSection -SectionPath 'system.webServer/security/authentication/windowsAuthentication').Attributes['enabled'].value = $true
   (Get-IISConfigSection -SectionPath 'system.webServer/security/authentication/anonymousAuthentication').Attributes['enabled'].value = $false
   (Get-IISServerManager).Sites[0].Applications[0].VirtualDirectories[0].PhysicalPath = 'C:\inetpub\wwwroot\app'
   Stop-IISCommitDelay

   Write-Output "IIS with authentication is ready."

   C:\ServiceMonitor.exe w3svc
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: gmsa-demo
  name: gmsa-demo
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gmsa-demo
  template:
    metadata:
      labels:
        app: gmsa-demo
    spec:
      securityContext:
        windowsOptions:
          gmsaCredentialSpecName: aks-gmsa-spec
      containers:
      - name: iis
        image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: IfNotPresent
        command:
         - powershell
        args:
          - -File
          - /gmsa-demo/run.ps1
        volumeMounts:
          - name: gmsa-demo
            mountPath: /gmsa-demo
      volumes:
      - configMap:
          defaultMode: 420
          name: gmsa-demo
        name: gmsa-demo
      nodeSelector:
        kubernetes.io/os: windows
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: gmsa-demo
  name: gmsa-demo
  namespace: default
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: gmsa-demo
  type: LoadBalancer

kubectl apply を使用して、kubectl apply から変更を適用します

kubectl apply -f gmsa-demo.yaml

kubectl get service を使用して、サンプル アプリケーションの IP アドレスを表示します。

kubectl get service gmsa-demo --watch

最初は、gmsa-demo サービスの EXTERNAL-IP が "保留中" として表示されます。

NAME               TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
gmsa-demo          LoadBalancer   10.0.37.27   <pending>     80:30572/TCP   6s

EXTERNAL-IP アドレスが "保留中" から実際のパブリック IP アドレスに変わったら、CTRL-C を使用して kubectl ウォッチ プロセスを停止します。 次の出力例は、サービスに割り当てられている有効なパブリック IP アドレスを示しています。

gmsa-demo  LoadBalancer   10.0.37.27   EXTERNAL-IP   80:30572/TCP   2m

GMSA が動作していて正しく構成されていることを確認するには、gmsa-demo サービスの外部 IP アドレスを指定して Web ブラウザーを開きます。 $NETBIOS_DOMAIN_NAME\$AD_USERNAME とパスワードを使用して認証し、Authenticated as $NETBIOS_DOMAIN_NAME\$AD_USERNAME, Type of Authentication: Negotiate が表示されることを確認します。

トラブルシューティング

ページを読み込むときに認証を求められない

ページを読み込んでも認証を求めるメッセージが表示されない場合は、kubelet logs POD_NAME を使用してポッドのログを表示し、"kubelet logs POD_NAME" と表示されていることを確認します。

ページの読み込み時に接続がタイムアウトする

ページを読み込もうとしたときに接続タイムアウトが発生した場合は、kubectl get pods --watch を使用してサンプル アプリが実行されていることを確認します。 サンプル アプリ ポッドが実行される前に、サンプル アプリ サービスの外部 IP アドレスが使用できる場合があります。

ポッドの起動に失敗し、ポッド イベントに "winapi エラー" が表示される

kubectl get pods --watch を実行して数分待った後に、ポッドが起動しない場合は kubectl describe pod POD_NAME を実行します。 ポッド イベントに "winapi エラー" が表示される場合は、GMSA 資格情報の仕様の構成でエラーが発生している可能性があります。 gmsa-spec.yaml で置き換えたすべての値が正しいことを確認し、 を再実行して、サンプル アプリケーションを再デプロイします。