Azure RBAC を使用した Azure AD Authentication を有効にした Azure Kubernetes Service のクラスタを C# で操作する

C# で KubernetesClient を使って AKSクラスタを操作するとき、認証情報はローカルに保存されたものを使っていたけど、本番ではそうはいかない。

AKS では認可に Azure RBAC が使えるので、例えば Azure AD でアプリを登録し、Azure RBAC で AKSクラスタを操作する権限を付与したら良さそう。

learn.microsoft.com

Azure のサービスプリンシパルを使うように、サンプルを書き変えてみたら上手くいった。

using Azure.Identity;
using k8s;
using k8s.KubeConfigModels;
using k8s.Models;

const string clusterName = "your-cluster-name";
const string apiServerAddress = "https://your-aks-server-address:443";
const string namespaceParameter = "your-namespace";

// 環境変数 AZURE_CLIENT_ID・AZURE_CLIENT_SECRET・AZURE_TENANT_ID
// をセットして、サービスプリンシパルを使うようにしておく
var creds = new DefaultAzureCredential();

var token = await creds.GetTokenAsync(
    new Azure.Core.TokenRequestContext(
        scopes: new string[]
        {
            // このスコープは、Microsoft社の「Azure Kubernetes Service AAD Server」アプリ
            "6dae42f8-4368-4678-94ff-3960e28e3630/.default"
        }));

var k8sConfig = new K8SConfiguration()
{
    Clusters = new List<Cluster>()
    {
        new Cluster()
        {
            Name = clusterName,
            ClusterEndpoint = new ClusterEndpoint()
            {
                Server = apiServerAddress,
            }
        }
    },
    Contexts = new List<Context>()
    {
        new Context()
        {
            Name = clusterName,
            ContextDetails = new ContextDetails()
            {
                Cluster = clusterName,
            },
        },
    },
};

var config = KubernetesClientConfiguration.BuildConfigFromConfigObject(k8sConfig, currentContext: clusterName);
config.AccessToken = token.Token;

// AKS が HTTP/2 をサポートしていないのか、ハンドシェイクで失敗する。
// HTTP/2 を使わないようにしておく。
config.DisableHttp2 = true;

// Kubernetes は独自の証明書を使っているので、
// そのままでは接続できない。
// 本来なら接続用の証明書を用意する必要があるみたいだが、
// 今回は手抜きして証明書の検証をスキップ。
config.SkipTlsVerify = true;

var client = new Kubernetes(config);

var deployments = await client.ListNamespacedDeploymentAsync(namespaceParameter);
foreach (var deployment in deployments)
{
    Console.WriteLine(deployment.Name());
}

Console.WriteLine("Enter で終了");
Console.ReadLine();