EKSのAPIサーバーエンドポイントの設定の違いをまとめた

## 背景

普段は現場のクローズドなEKSしか触っていなかったため、APIサーバのエンドポイントのパブリックアクセスなるものを知らなかった。
[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cluster-endpoint.html)を読んでなんとなく理解したものの、実際の挙動が気になってしまったので動作検証してまとめてみた。

## 概要

|マネジメントコンソール上での名称|パブリックアクセス|プライベートアクセス|同一VPCからのアクセス|インターネット経由でのアクセス|
|---|---|---|---|---|
|パブリック|有効|無効|-|◯|
|パブリックおよびプライベート|有効|有効|◯|◯|
|プライベート|無効|有効|◯|-|

### 「パブリック」設定時の挙動

- EKSクラスターの作成時のデフォルトの設定
- VPC内の踏み台サーバやワーカノードからのコントロールプレーンへのアクセスはVPC外の通信となる
- 必要に応じてパブリックエンドポイントへのアクセスできるCIDRを設定可能

![chart-ページ2.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389171/c05df3b7-755e-dc1e-1bd6-314b3c0f8e5f.png)

#### 同じVPC上のサーバからアクセス

__名前解決__  
EKSクラスターと同じVPCに立てたEKS管理サーバから、APIサーバのエンドポイントの名前解決をするとグローバルIPアドレスが返ってくる。つまり、コントロールプレーンへのリクエストはVPCを離れることになる。

```bash
[root@ip-192-168-0-50 ~]# nslookup XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: グローバルIPアドレス①
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: グローバルIPアドレス②
```

__接続確認__

```bash
[root@ip-192-168-0-50 ~]# k get ns
NAME              STATUS   AGE
default           Active   18h
kube-node-lease   Active   18h
kube-public       Active   18h
kube-system       Active   18h
```

#### CIDRブロックでアクセス制御

APIサーバのエンドポイントをパブリックにした場合、CIDRブロックでアクセス制御を設定する事ができる。デフォルトは「0.0.0.0/0」だが、任意のCIDRブロックからのアクセスだけを許可することも可能。 CIDRブロックのアクセス制御をした場合、範囲外のIPアドレスからAPIサーバへアクセスすると設定どおりブロックされる。

```bash
[root@ip-10-1-1-102 ~]# k get ns
E1229 02:55:17.693490    2657 memcache.go:265] couldn't get current server API group list: Get "https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com/api?timeout=32s": dial tcp XX.XX.XX.XX:443: i/o timeout
^C
```

なお、EKSクラスターに設定したセキュリティグループはVPC内の通信にのみ適用されるため、インバウンドルールに許可設定がなくともAPIサーバにアクセスする事ができる。

### 「パブリックおよびプライベート」設定時の挙動

- VPC内の踏み台サーバやワーカノードからのコントロールプレーンへのアクセスはVPC内の通信となる
- つまり、VPC内からAPIサーバへのアクセスはVPC内で完結するけど、インターネットからもアクセスできるよって設定
- こちらも必要に応じてパブリックエンドポイントへのアクセスできるCIDRを設定可能


![chart-ページ2のコピー.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389171/9963f323-8211-e0d0-df22-58b17d516a7c.png)

#### 同じVPC上のサーバからアクセス

__名前解決__  
EKSクラスターと同じVPCに立てたEKS管理サーバから、APIサーバのエンドポイントの名前解決をするとクラスターを構築したVPC上のプライベートIPアドレスが解決される。

```bash
[root@ip-192-168-0-50 ~]# nslookup XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: 192.168.0.110
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: 192.168.2.137
```

__接続確認__

```bash
[root@ip-192-168-0-50 ~]# k get ns
NAME              STATUS   AGE
default           Active   18h
kube-node-lease   Active   18h
kube-public       Active   18h
kube-system       Active   18h
```

EKS管理サーバの通信はVPC間の通信となるため、EKSクラスターのセキュリティグループのインバウンドルールで許可をしないとタイムアウトとなってしまうので注意。

```bash
[root@ip-192-168-0-50 ~]# k get ns
Unable to connect to the server: dial tcp 192.168.0.110:443: i/o timeout
```

#### VPC外のEC2インスタンスからアクセス

__名前解決__
「パブリック」設定時と同じグローバルIPアドレスが返ってくる。  
アクセスが許可されたCIDRブロック内のIPアドレスであれば、このインスタンスからもAPIサーバへアクセスすることができる。

```bash
[root@ip-10-1-1-102 ~]# nslookup XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Server:         10.1.1.2
Address:        10.1.1.2#53

Non-authoritative answer:
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: グローバルIPアドレス①
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: グローバルIPアドレス②
```

__接続確認__

```bash
[root@ip-10-1-1-102 ~]# k get ns
NAME              STATUS   AGE
default           Active   18h
kube-node-lease   Active   18h
kube-public       Active   18h
kube-system       Active   18h
```

この通信はVPC外からのアクセスになるので、EKSクラスターのセキュリティグループで許可されいなくても、アクセスが許可されたCIDRブロック内のIPアドレスであれば接続することができる。

### 「プライベート」設定時の挙動

- Kubernetes APIサーバへのアクセスはすべてVPC経由のアクセスに限定される。

![chart-ページ2のコピーのコピー.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389171/ea6f96d8-756d-0f01-2c04-a74611fd112a.png)

#### 同じVPC上のサーバからアクセス

__名前解決__  
クラスターを構築したVPC上のプライベートIPアドレスが解決される。

```bash
[root@ip-192-168-0-50 ~]# nslookup XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: 192.168.0.110
Name:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.gr7.ap-northeast-1.eks.amazonaws.com
Address: 192.168.2.137
```

__接続確認__

```bash
[root@ip-192-168-0-50 ~]# k get ns
NAME              STATUS   AGE
default           Active   18h
kube-node-lease   Active   18h
kube-public       Active   18h
kube-system       Active   18h
```

ちなみに、どの環境でこのエンドポイントの名前解決をした場合でも同じ回答が返ってきた。従って、別のVPC（相互接続していない）やインターネット経由でAPIサーバへアクセスすることは出来ない。

## まとめ

- クローズドな環境であれば「プライベート」の設定で良さそう
- どうしても別のVPCやインターネット越しにコントロールプレーン(APIサーバ)へアクセスする必要がある場合は「パブリック」を設定する
  - ただし、その場合は接続元のIPアドレスを限定するのが良さそう
- VPCの中からのリクエストなのか外からのリクエストなのかによって送信元を制御する方法が異なるので注意