APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

Amazon EKSのアクセス管理をAccess Entryでシンプルにする

こんにちは、クラウド事業部の山路です。

昨年12月のアップデートにより、Amazon EKSへのアクセス制御方法を Access Entry というリソース/APIで実現できるようになりました。今回はこの新機能を簡単に検証してみます。

aws.amazon.com

背景

Amazon EKSへのアクセスを制御する場合、これまではAWS、KubernetesのそれぞれのAPIに対するアクセス制御を設定する必要がありました。

※参考:

repost.aws

これによる課題はいくつかあります。

まず、アクセス制御を実現するための手順が複雑になります。クラスター管理者はAWS APIとKubernetes APIを行き来しながら設定変更を行うため、作業ミスの可能性も高くなります。例えば誤って aws-auth ConfigMapを削除してしまうと、最悪の場合そのクラスターには誰もアクセスできなくなってしまいます。

また、クラスター作成者に付与される cluster-admin 権限が残り続けることも課題でした。たとえクラスター作成者がその後そのクラスターを操作しないとしてもroot権限が付与され続けることになり、強力な権限が関係のないアカウントに付与され続ける状態は、セキュリティ的にも大きな問題となりえます。

これを改善するため、Amazon EKS APIがAmazon EKSとKubernetesオブジェクトに対しAWS IAM principalを直接付与できるようになりました。これはつまりAWS側のリソースだけでEKSに対するアクセス制御を完結できるようになったことを意味します。

この仕組みを実現するため、Access Policy Access Entry という2つのリソースを利用します。Access Policy は特定のクラスターアクションを実行するための権限を、 Access Entry は Access Policy とそのポリシーを利用するIAMロール・ユーザーとの紐づけを管理します。

https://d2908q01vomqb2.cloudfront.net/fe2ef495a1152561572949784c16bf23abb28057/2023/11/16/Workflow.png

※画像: AWSブログより引用

Access Policy Access Entry を利用することで、EKSへのアクセス制御をAWS APIで完結できるようになります。これにより、例えばAWS CloudFormation / Terraform / AWS CDKといったIaCツールを使用して、クラスターのアクセス管理を実現できました。また、クラスター作成者に付与された cluster-admin 権限も取り除けるので、不必要に強い権限の付与を避けることができます。さらに設定ミスでクラスターへのアクセス権限を削除してしまった場合も、新しいAPIから権限を付与しなおすことで復旧できます。

なお、新しいAPI追加後も、従来通り aws-auth ConfigMapによる権限管理は可能です。現在EKSへのアクセスには以下の3つの認証モードを利用できます。

  • CONFIG_MAP: 従来通り aws-auth ConfigMapによる認証
  • API_AND_CONFIG_MAP: 新しいAPIと従来のConfigMapによる認証をどちらも利用できる
  • API: 新しいAPIによる認証

2つ目の認証モードは新旧の認証モードを利用できるので、利用者は既存のConfigMapベースの認証からAPIベースの認証への移行がやりやすくなります。認証モードの切り替えは既存のクラスターに対する設定変更で実現可能であり、従来のConfigMapベースの認証とAPI認証を並行して利用することで、従来の権限を損なうことなくAPI認証モードへの移行を進めることができます。

なお、新しいAPIを利用する際はいくつか注意事項があります。

  • 認証モードの切り替えは一方向です。切り替えは CONFIG_MAPAPI_AND_CONFIG_MAPAPI の方向に切り替え可能で、切り替え後は元のモードに戻すことはできません。
  • API認証を利用するには、 ver 1.23以降のクラスターが必要です。また、指定のバージョン以上のPlatform versionを利用している必要もあります。

利用時の条件などは AWS公式ドキュメント もご確認ください。

検証

ここから実際に新しいアクセスコントロールを試します。以降の作業ではAWS CLIを利用するため、必要に応じてAWS CLIのバージョンを更新し、 list-access-policies などの新しいコマンドを実行可能にします。

AWS CLIを更新後に list-access-policies コマンドを実行すると、利用できるAccess Policyが出力されます。

$ aws eks list-access-policies
{
    "accessPolicies": [
        {
            "name": "AmazonEKSAdminPolicy",
            "arn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy"
        },
        {
            "name": "AmazonEKSClusterAdminPolicy",
            "arn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
        },
        {
            "name": "AmazonEKSEditPolicy",
            "arn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSEditPolicy"
        },
        {
            "name": "AmazonEKSViewPolicy",
            "arn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy"
        }
    ]
}

なお、ここで出力されるポリシーの権限は、Kubernetesに用意されたユーザー向けのロールに対応しています。

  • AmazonEKSClusterAdminPolicy: cluster-admin
  • AmazonEKSAdminPolicy: admin
  • AmazonEKSEditPolicy: edit
  • AmazonEKSViewPolicy: view

kubernetes.io

またAmazon EKSを作成済みの場合、 describe-cluster コマンドを実行すると authenticationMode というパラメータも確認できます。

$ aws eks describe-cluster --name eks-cluster --query 'cluster.accessConfig'
{
    "authenticationMode": "CONFIG_MAP"
}

認証モードの変更

API認証を利用するため、まずは authenticationMode の変更を行います。クラスターを新規に作成する場合、AWS CLIでは以下のようなコマンドで指定できます。

$ aws eks create-cluster \
      --name <CLUSTER_NAME> \
      --role-arn <CLUSTER_ROLE_ARN> \
      --resources-vpc-config subnetIds=<value>,endpointPublicAccess=true,endpointPrivateAccess=true \
      --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}' \
      --access-config authenticationMode=API

またAWS CloudFormationを利用する場合、 AWS::EKS::ClusterAccessConfig というパラメータで指定します。

Type: AWS::EKS::Cluster
Properties:
  AccessConfig: 
    AuthenticationMode: String
    BootstrapClusterCreatorAdminPermissions: Boolean

docs.aws.amazon.com

既存のクラスターの設定を変更する場合、AWS CLIでは update-cluster-config コマンドを使用します。

$ aws eks update-cluster-config \
      --name <CLUSTER_NAME> \
      --access-config authenticationMode=<Select auth mode>

今回はAWS CloudFormationでクラスターを作成していたので、ファイルに AccessConfig を設定し、更新しました。

更新後、修正されていることを確認します。

$ aws cloudformation deploy --template-file eks-cluster.yaml \
      --stack-name eks-cluster \
      --capabilities CAPABILITY_IAM

$ aws eks describe-cluster --name eks-cluster --query 'cluster.accessConfig'
{
    "authenticationMode": "API_AND_CONFIG_MAP"
}

なお、今回は BootstrapClusterCreatorAdminPermissions というパラメータは特に指定しなかったため、作成したユーザーに対するアクセス権限が付与されています。CloudFormationで指定する場合はリソースのReplaceを必要とするのでご注意ください。

$ aws eks list-access-entries --cluster-name eks-cluster
{
    "accessEntries": [
        "arn:aws:iam::<AWS Account ID>:user/yamaji"
    ]
}

EKSへのアクセスユーザーを追加

ここで、別のユーザーに対してクラスターへのアクセス権を付与します。

AWS CLIの場合、アクセス権を付与するため、まずは新しいアクセスエントリーを作成します。

$ aws eks create-access-entry \
      --cluster-name <CLUSTER_NAME> \
      --principal-arn <IAM_PRINCIPAL_ARN>

その後、作成したアクセスエントリーとアクセスポリシーを紐づけることで、権限付与は完了します。

$ aws eks associate-access-policy \
      --cluster-name <CLUSTER_NAME> \
      --principal-arn <IAM_PRINCIPAL_ARN> \
      --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy
      --access-scope type=cluster

今回はCloudFormationで以下のようなテンプレートを使用します。

AWSTemplateFormatVersion: 2010-09-09
Description: 'Access entries for EKS cluster'
Parameters:
  ClusterName:
    Type: String
  
Resources:
  AccessEntry:
    Type: 'AWS::EKS::AccessEntry'
    Properties:
      AccessPolicies: 
        - AccessScope:
            Type: 'cluster'
          PolicyArn: 'arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy'
      ClusterName: !Ref ClusterName
      PrincipalArn: !Sub 'arn:aws:iam::${AWS::AccountId}:user/test-user'

上記テンプレートファイルを使用してアクセス権の付与を行います。

$ aws cloudformation deploy --stack-name eks-accessentry \
      --template-file eks-accessentry.yaml \
      --parameter-overrides ClusterName=eks-cluster 

$ aws eks list-access-entries --cluster-name eks-cluster
{
    "accessEntries": [
        "arn:aws:iam::<AWS Account ID>:user/test-user",
        "arn:aws:iam::<AWS Account ID>:user/yamaji"
    ]
}

あとは追加したユーザーでアクセスできるようkubeconfigを更新すれば、EKSにアクセスし、クラスター上のリソースも見れるようになります。

$ aws eks update-kubeconfig --name eks-cluster

# kubectlは定期的にアップデートしておきましょう
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.0", GitCommit:"c2b5237ccd9c0f1d600d3072634ca66cefdf272f", GitTreeState:"clean", BuildDate:"2021-08-04T18:03:20Z", GoVersion:"go1.16.6", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"27+", GitVersion:"v1.27.8-eks-8cb36c9", GitCommit:"fca3a8722c88c4dba573a903712a6feaf3c40a51", GitTreeState:"clean", BuildDate:"2023-11-22T21:52:13Z", GoVersion:"go1.20.11", Compiler:"gc", Platform:"linux/amd64"}
WARNING: version difference between client (1.22) and server (1.27) exceeds the supported minor version skew of +/-1

# 今回はクラスターだけ作成しておりNodeがないためPodは作れない状態です
$ kubectl get pods -A
NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE
kube-system   coredns-8496bbc677-2hkgr   0/1     Pending   0          35m
kube-system   coredns-8496bbc677-zmwvh   0/1     Pending   0          35m

Namespaceレベルの権限コントロール

新しいアクセス管理を利用すると、Kubernetes Namespaceレベルの権限コントロールも可能となります。先ほど使用したCloudFormationには AccessScope というパラメーターがありましたが、ここで namespace を指定することも可能です。

AWSTemplateFormatVersion: 2010-09-09
Description: 'Access entries for EKS cluster'
Parameters:
  ClusterName:
    Type: String
  
Resources:
  AccessEntry:
    Type: 'AWS::EKS::AccessEntry'
    Properties:
      AccessPolicies: 
        - AccessScope:
            Type: 'namespace'
            Namespaces: # 対象のNamespaceを指定
              - 'default'
          PolicyArn: 'arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy'
      ClusterName: !Ref ClusterName
      PrincipalArn: !Sub 'arn:aws:iam::${AWS::AccountId}:user/test-user'

このファイルを使用してAccess Entryを更新すると、 test-user からは default Namespaceにしかアクセスできず、それ以外 (ここでは kube-system ) にはアクセスできません。

$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   46m


$ kubectl get all -n kube-system
Error from server (Forbidden): pods is forbidden: User "arn:aws:iam::<AWS Account ID>:user/test-user" cannot list resource "pods" in API group "" in the namespace "kube-system"
Error from server (Forbidden): replicationcontrollers is forbidden: User "arn:aws:iam::<AWS Account ID>:user/test-user" cannot list resource "replicationcontrollers" in API group "" in the namespace "kube-system"
Error from server (Forbidden): services is forbidden: User "arn:aws:iam::<AWS Account ID>:user/test-user" cannot list resource "services" in API group "" in the namespace "kube-system"

(以降割愛)

なお、Access EntryはKubernetes RBACと組み合わせることも可能です。例えばAccess EntryはKubernetes Groupを指定することもできるので、Cluster Role BindingでKubernetes GroupとCluster Roleを紐づければ、Kubernetes RBACベースでの制御を実現できます。

さいごに

Amazon EKSへの新しいアクセス制御方法の紹介でした。従来のConfigMapベースの認証にこだわりがない場合は、基本的にAPI認証のほうが使いやすそうな印象です。

設定変更も簡単にできるので、EKSへのアクセス管理に苦労している人は検討してみるのはいかがでしょうか。

弊社はAWSアドバンスドティアサービスパートナー認定を受けております。また以下のようにAWSの活用を支援するサービスも行っているので、何かご相談したいことがあればお気軽にご連絡ください。

www.ap-com.co.jp