Amazon EKSがプライベートアクセス専用で使えるようにアップデートされました

はじめに

おはようございます、加藤です。Amazon EKSにアップデートが行われました。
Amazon EKS Cluster Endpoint Access Control - Amazon EKS
従来、kubectlでアクセスするエンドポイントは必ずパブリックに公開され、AWS IAMとk8sのRBACによって保護されていました。
今回のアップデートによってプライベートにのみエンドポイントを公開するといった設計が可能になります。

アップデートの内容

最初に、この機能はAWS PrivateLinkエンドポイントではありません、Amazon VPCのコンソールから操作はできずEKSに対して操作する必要があります。

EKSのコンソールにアクセスし、クラスターのネットワーキングの項目を確認してみるとAPI server endpoint accessという項目が存在します。 普段私が触っている検証用のEKSではPrivate: Disabled, Public: Enabled と設定されていました。

ドキュメントを元にこれらの設定がどういう意味か確認していきます。

パブリックアクセス プライベートアクセス 動作
有効 無効 Amazon EKSクラスターのデフォルトの状態
クラスターの存在するVPC内からのAPIアクセスは、VPC外に出るがAmazonのネットワーク内のみを通る(Worker Nodes→Controll Planeの通信など)
インターネットからAPIアクセスが可能
有効 有効 クラスターの存在するVPC内からのAPIアクセスは、プライベートVPCエンドポイントにアクセスする
インターネットからAPIアクセスが可能
無効 有効 クラスターの存在するVPC内からのAPIアクセスする必要がある
インターネットからAPIアクセスが不可能

上記でクラスターの存在するVPCと記載していますが、VPNやDirect Connectなどによって継っている範囲も含みます。

プライベートアクセスの制限事項

EKSクラスターが存在するVPCで下記の設定を有効にする必要があります。

  • enableDnsHostnames: true
  • enableDnsSupport: true

設定方法(パブリック無効/プライベート有効)

踏み台サーバーを立てる

インスタンスプロファイルを作成します。 AWS管理ポリシーのAmazonEC2RoleforSSMと下記のインラインポリシーを関連付けしておきます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "eks:UpdateClusterConfig",
                "eks:DescribeUpdate",
                "eks:DescribeCluster",
                "eks:ListClusters"
            ],
            "Resource": "*"
        }
    ]
}

EC2インスタンスを1台立ち上げて、先程作成したインスタンスプロファイルを関連付けます。

Controll PlaneのSecurity Groupの設定

踏み台サーバーからControll Planeに対して、HTTPS(TCP/443)アクセスを許可します。

アクセス権限の付与

踏み台サーバー(のIAMロール)にアクセス権限を付与します。下記ドキュメントを参考に設定してください。system:mastersに所属させました。

      groups:
        - system:masters

クラスターのユーザーまたは IAM ロールの管理 - Amazon EKS

踏み台をサーバーのセットアップ

踏み台サーバーに接続し作業を行います。

最新のAWS CLIをインストール

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli

kubectlのインストール

curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.11.5/2018-12-06/bin/linux/amd64/kubectl
chmod +x ./kubectl
mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc

aws-iam-authenticatorのインストール

curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.11.5/2018-12-06/bin/linux/amd64/aws-iam-authenticator
chmod +x ./aws-iam-authenticator
mkdir -p $HOME/bin && cp ./aws-iam-authenticator $HOME/bin/aws-iam-authenticator && export PATH=$HOME/bin:$PATH
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc

kubeconfigの取得

aws eks --region ap-northeast-1 update-kubeconfig --name shared-cluster

動作確認

kubectl version

クラスターの設定を変更

現在が、インターネット経由でAPIアクセスできる事を確認しておきます。kubectl versionで確認しました。

踏み台サーバーに接続し作業を行います。

APIアクセスの設置をパブリック無効/プライベート有効に変更します。

cluster_name=YOUR_CLUSTER_NAME
public_access=false
private_access=true
aws eks --region ap-northeast-1 update-cluster-config \
    --name ${cluster_name} \
    --resources-vpc-config endpointPublicAccess=${public_access},endpointPrivateAccess=${private_access}

下記のようなレスポンスがコンソールに表示され、クラスター設定の変更が始まります。

{
    "update": {
        "status": "InProgress",
        "errors": [],
        "params": [
            {
                "type": "EndpointPublicAccess",
                "value": "false"
            },
            {
                "type": "EndpointPrivateAccess",
                "value": "true"
            }
        ],
        "type": "EndpointAccessUpdate",
        "id": "YOUR_UPDATE_ID",
        "createdAt": 1553058197.196
    }
}

進行状況は下記のコマンドで確認ができます。

aws eks --region ap-northeast-1 describe-update --name ${cluster_name} --update-id YOUR_UPDATE_ID

動作確認

踏み台からはAPIアクセスが可能なままですが、インターネット経由だと不可能になりました。
kubectl versionの結果を見るとXXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.comがAPIのアドレスで、これが名前解決ができていない様です。

kubectl version
Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.5", GitCommit:"753b2dbc622f5cc417845f0ff8a77f539a4213ea", GitTreeState:"clean", BuildDate:"2018-12-06T01:33:57Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: dial tcp: lookup XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com on 10.63.200.10:53: no such host

踏み台で名前解決してみました。プライベートIPアドレスで解決ができています。

dig XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com

; <<>> DiG 9.9.4-RedHat-9.9.4-73.amzn2.1.1 <<>> XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15661
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 4, ADDITIONAL: 0

;; QUESTION SECTION:
;XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. IN A

;; ANSWER SECTION:
XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. 60 IN A 192.168.131.209
XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. 60 IN A 192.168.104.190

;; AUTHORITY SECTION:
XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. 172800 IN NS ns-XXXX.awsdns-00.org.
XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. 172800 IN NS ns-XXXX.awsdns-00.co.uk.
XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. 172800 IN NS ns-XXXX.awsdns-00.net.
XXXXXXXXXXXX.yl4.ap-northeast-1.eks.amazonaws.com. 172800 IN NS ns-XXXX.awsdns-00.com.

;; Query time: 4 msec
;; SERVER: 192.168.0.2#53(192.168.0.2)
;; WHEN: Wed Mar 20 05:15:00 UTC 2019
;; MSG SIZE  rcvd: 254

ドキュメントを確認するとこの名前解決を行うためにバックエンド(ユーザーからは見えない)でAmazon EKSがRoute53 プライベートホストゾーンを作成し名前解決を提供してくれているようです。
ドキュメントによるとVPNやDirect Connect経由でもプライベートアクセスが可能ですが、Route53 Resolverを使うなど名前解決はしっかりと検討すべきですね。(パブリック無効の時はVPC外から基本的にプライベートIPアドレスも解決できない)

あとがき

従来のVPCエンドポイントは、VPC内から出ないでAWSサービスにアクセスできるという仕組みでパブリックからのアクセスを禁止するものではありません。しかし、このEKS独自の仕組みはパブリックアクセスの禁止が可能という事が大きな特徴です。
個人的な見解としては、この設定を行ってしまうとVPC外からアクセスができなくなり、例えばCodeBuildからkubectlを叩く事が出来なくなってしまいます。思わぬ落とし穴を作ってしまうかなと感じています。使うのは明確にやむを得ない理由がある場合に留めた方が良いでしょう。