[アップデート] EKSでパブリックエンドポイントへのIPアドレスによるアクセス制限が可能になりました

Amazon EKSで、APIサーバーエンドポイントへのパブリックアクセスに対して接続元IPアドレスによる制限ができるようになりました。
2019.12.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさん、こんにちは!
AWS事業本部の青柳@福岡オフィスです。

「Amazon EKS」において、APIサーバーエンドポイントへのパブリックアクセスに対して接続元IPアドレスによる制限ができるようになりました。

Amazon EKS enables network access restrictions to Kubernetes cluster public endpoints

「APIサーバーエンドポイント」「パブリックアクセス」とは?

「APIサーバーエンドポイント」とは、KubernetesのAPIサーバーであるkube-apiserverのエンドポイントです。
Kubernetesのコントロールプレーンを構成する各コンポーネントに対する要求は全てAPIサーバーを通して行われます。
Kubernetesを操作する際の代表的なツールである kubectl も、コマンド実行時にAPIサーバーへアクセスすることで処理を行っています。

EKSにおいて、APIサーバーに対するアクセス方法は二通りあります。

アクセス方法 説明
パブリックアクセス インターネットからアクセス可能
(AWS内部からのアクセスは非VPCネットワーク経由で行われる)
プライベートアクセス インターネットからのアクセスは不可能
VPC内部からのみアクセス可能

EKSでは当初はパブリックアクセスのみ選択可能でしたが、過去のアップデートによりプライベートアクセスが選択可能になりました。

プライベートアクセスが選択可能になったことにより、APIサーバーエンドポイントへのアクセスをセキュアにするために、VPC内に踏み台EC2インスタンスを設置して「インターネット → 踏み台 → APIサーバーエンドポイント」というアクセス経路を実装することが可能になりました。

しかし、いろいろな理由のため、引き続きパブリックアクセスを選択しなければならない場面もあるのではないかと思います。

そのような際に、インターネットからのアクセスを特定IPアドレスからのみに制限できるようになったというのが、今回のアップデート内容です。

アクセス制限を設定する

では、実際にアクセス制限を設定してみます。

設定する方法はいくつかありますが、今回はマネジメントコンソールを使ってクラスターを新規作成する際に設定する方法を説明します。

「クラスターの作成」画面で、「ネットワーキング」の下の方に「API server endpoint access」という項目がありますが、今回のアップデートで「詳細設定」という項目が追加されています。

「詳細設定」を展開すると、「パブリックアクセスエンドポイントへのソースの追加/編集」という項目が現れますので、アクセスを許可したいグローバルIPアドレスを入力します。
(複数設定したい場合は「ソースの追加」をクリックして入力欄を追加します)

あとは、そのままウィザードを続けてクラスターを作成すれば、設定したIPアドレスからのみにアクセスが制限されるようになります。

既存のクラスターに対してアクセス制限を設定することもできます。

クラスターの詳細画面で「ネットワーキング」の「更新」をクリックすると、新規作成の時と同様の設定画面が開きますので、アクセスを許可するIPアドレスを変更したり、追加・削除したりすることができます。

マネジメントコンソール以外にも、AWS CLI (1.16.308以降)、eksctl (0.12.0-rc.0以降) でも設定することができますので、詳しくはリファレンス等を参照してみてください。

アクセス制限が適用されたことを確認する

まず、アクセスを許可するよう設定したIPアドレスからアクセスしてみます。

$ kubectl cluster-info
Kubernetes master is running at https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.sk1.ap-northeast-1.eks.amazonaws.com
CoreDNS is running at https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.sk1.ap-northeast-1.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

問題なくアクセスできました。

次に、アクセスを許可するように設定したIPアドレスではないIPアドレスからアクセスしてみます。

$ kubectl cluster-info dump
Unable to connect to the server: dial tcp XX.XX.XX.XX:443: i/o timeout

このように「APIサーバーへの接続がタイムアウトした」というメッセージが表示されます。

意図した通りにアクセスが制限されていることが確認できました。

なお、EKSコントロールプレーンの「監査ログ」(kube-apiserver-audit) を確認すると、アクセスが許可されていないIPアドレスからのアクセスはログ自体が記録されていませんでした。
よって、APIサーバー自体がアクセス制御しているのではなく、APIサーバーへの到達前にアクセスを遮断しているものと思われます。

・・・実は、これだけではダメなんです

以上で解説を終わります!・・・と言いたいところですが、実はこれだけでは問題が発生します。

ここまでの手順の通りにアクセス制限を設定した場合、「ノードグループが作成できない」あるいは「Fargateプロファイルを使用してPodが起動できない」という問題が発生します。
(前者はノードグループの作成時に「作成に失敗しました」エラーとなり、後者はPodのステータスが「Pending」のままとなります)

何故かと言うと、ノードグループが作成される時およびFargateが起動する時には、ノードグループ/Fargateが自分自身をクラスターに登録するためにAPIサーバーに対してアクセスを行う必要があるためです。

(以下のエラー画面でも、「ヘルスの問題」の「説明」に「Instances failed to join the kubernetes cluster」と表示されていることが分かります)

問題を回避するための設定方法

問題を回避するためには、以下のいずれかの方法を取ります。

  1. ノードグループ/Fargateからのアクセスを許可する設定を追加する
  2. APIサーバーエンドポイントの「プライベートアクセス」を有効にする

「1」の方法では、ノードグループやFargateがVPCの外へアクセスする際に使用するグローバルIPアドレス、具体的にはプライベートサブネットからルーティングされている「NATゲートウェイ」「NATインスタンス」等のグローバルIPアドレスを設定します。

「2」の方法について、何故「プライベートアクセス」を有効にするとノードグループ/FargateからAPIサーバーへのアクセスが行えるようになるのか、理由は下記のドキュメントを読むと分かります。

クラスターエンドポイントのアクセスの変更

上記ドキュメントの表「API サーバーエンドポイントのアクセスオプション」から抜粋して整理すると以下のようになります。

アクセスオプション VPC内部からAPIサーバーへのアクセス経路
「パブリックアクセス」のみ有効 アクセス先:パブリックエンドポイント
(VPCの外に出てからアクセス)
「パブリックアクセス」および
「プライベートアクセス」の両方が有効
アクセス先:プライベートエンドポイント
(VPC内部に閉じたアクセス)
「プライベートアクセス」のみ有効 アクセス先:プライベートエンドポイント
(VPC内部に閉じたアクセス)

グローバルIPアドレスによるアクセス制限は「パブリックアクセス」に対して適用されるため、プライベートアクセスであればアクセス制限の設定に関係なくアクセスすることができるというわけです。

なお、上記「1」「2」いずれの方法でも問題は回避できますが、個人的には「2」の方法を取る方がよろしいのではないかと思います。

「1」の方法ですとアクセスに用いられるグローバルIPアドレスの管理が必要になりますし、セキュリティ観点などを考慮しても「2」の方法を取らない積極的な理由が見当たらないためです。

ということで、アクセス制限を設定する際には、クラスター作成時にAPIサーバーエンドポイントの「パブリックアクセス」と「プライベートアクセス」の両方を有効化しておきましょう。

おわりに

EKSはリリース当初から現在までに、いろいろと機能の追加や新しいトポロジーの導入が行われていますが、ネットワークまわりについては特に様々な変更が行われています。

以前は「できない!」とされていたことも、アップデートによって「できる!」ようになる場合がありますので、アップデートは今後もチェックしていきたいですね。