EKSでランタイムデフォルトのseccompプロファイルを使用する

EKSでランタイムデフォルトのseccompプロファイルが使用できるかを確認する。

Dockerのデフォルトで適用されるプロファイルは以下に記載がある。

1.19

1.19のEKSクラスターを起動する。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: mycluster19
  region: ap-northeast-1
  version: "1.19"
vpc:
  cidr: "10.0.0.0/16"

availabilityZones:
  - ap-northeast-1a
  - ap-northeast-1c

managedNodeGroups:
  - name: managed-ng-1
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    ssh:
      allow: true
      publicKeyName: default
      enableSsm: true

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true
eksctl create cluster -f cluster19.yaml

確認

NginxのPodを普通に起動する。

$ k run pod1 --image=nginx
pod/pod1 created

コンテナにログインし、プロセスのステータスを見る。Seccomp: 0となっている。

$ k exec -it pod1 -- bash
root@pod1:/# cat /proc/1/status 
Name:   nginx
Umask:  0022
State:  S (sleeping)
Tgid:   1
Ngid:   0
Pid:    1
PPid:   0
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 64
Groups:  
NStgid: 1
NSpid:  1
NSpgid: 1
NSsid:  1
VmPeak:    10676 kB
VmSize:    10648 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      5972 kB
VmRSS:      5972 kB
RssAnon:             804 kB
RssFile:            5168 kB
RssShmem:              0 kB
VmData:      988 kB
VmStk:       132 kB
VmExe:       988 kB
VmLib:      3792 kB
VmPTE:        56 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
CoreDumping:    0
THP_enabled:    1
Threads:        1
SigQ:   0/30446
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000040001000
SigCgt: 0000000198016a07
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
Speculation_Store_Bypass:       vulnerable
Cpus_allowed:   3
Cpus_allowed_list:      0-1
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        23
nonvoluntary_ctxt_switches:     62
root@pod1:/#

seccompプロファイルを指定してPodを起動する。

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod2
  name: pod2
spec:
  containers:
  - image: nginx
    name: pod2
    securityContext:
      seccompProfile:
        type: RuntimeDefault
$ k apply -f pod2.yaml
pod/pod2 created

コンテナにログインし、プロセスのステータスを見る。Seccomp: 2となったので、プロファイルが適用されている。

$ k exec -it pod2 -- bash
root@pod2:/# cat /proc/1/status
Name:   nginx
Umask:  0022
State:  S (sleeping)
Tgid:   1
Ngid:   0
Pid:    1
PPid:   0
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 64
Groups:  
NStgid: 1
NSpid:  1
NSpgid: 1
NSsid:  1
VmPeak:    10676 kB
VmSize:    10648 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      6076 kB
VmRSS:      6076 kB
RssAnon:             812 kB
RssFile:            5264 kB
RssShmem:              0 kB
VmData:      988 kB
VmStk:       132 kB
VmExe:       988 kB
VmLib:      3792 kB
VmPTE:        56 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
CoreDumping:    0
THP_enabled:    1
Threads:        1
SigQ:   0/30446
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000040001000
SigCgt: 0000000198016a07
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        2
Speculation_Store_Bypass:       vulnerable
Cpus_allowed:   3
Cpus_allowed_list:      0-1
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        65
nonvoluntary_ctxt_switches:     16
root@pod2:/# 

1.18

1.18以前はアノテーションで指定することになっているが、ランタイムデフォルトの使用であればkubeletの起動引数のカスタマイズなしでも大丈夫なのかを確認する。

1.18のEKSクラスターを起動する。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: mycluster18
  region: ap-northeast-1
  version: "1.18"
vpc:
  cidr: "10.0.0.0/16"

availabilityZones:
  - ap-northeast-1a
  - ap-northeast-1c

managedNodeGroups:
  - name: managed-ng-1
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    ssh:
      allow: true
      publicKeyName: default
      enableSsm: true

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true
eksctl create cluster -f cluster18.yaml

確認

NginxのPodを普通に起動する。

$ k run pod1 --image=nginx
pod/pod1 created

コンテナにログインし、プロセスのステータスを見る。Seccomp: 0となっている。

$ k exec -it pod1 -- bash
root@pod1:/# cat /proc/1/status
Name:   nginx
Umask:  0022
State:  S (sleeping)
Tgid:   1
Ngid:   0
Pid:    1
PPid:   0
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 64
Groups:  
NStgid: 1
NSpid:  1
NSpgid: 1
NSsid:  1
VmPeak:    10680 kB
VmSize:    10652 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      6008 kB
VmRSS:      6008 kB
RssAnon:             812 kB
RssFile:            5196 kB
RssShmem:              0 kB
VmData:      988 kB
VmStk:       132 kB
VmExe:       988 kB
VmLib:      3796 kB
VmPTE:        40 kB
VmPMD:        12 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
Threads:        1
SigQ:   0/30446
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000040001000
SigCgt: 0000000198016a07
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
Speculation_Store_Bypass:       vulnerable
Cpus_allowed:   3
Cpus_allowed_list:      0-1
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        55
nonvoluntary_ctxt_switches:     7
root@pod1:/# 

seccompプロファイルを指定してPodを起動する。

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod3
  name: pod3
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: "runtime/default"
spec:
  containers:
  - image: nginx
    name: pod3
$ k apply -f pod3.yaml
pod/pod3 created

コンテナにログインし、プロセスのステータスを見る。Seccomp: 2となったので、プロファイルが適用されている。

$ k exec -it pod3 -- bash
root@pod3:/# cat /proc/1/status
Name:   nginx
Umask:  0022
State:  S (sleeping)
Tgid:   1
Ngid:   0
Pid:    1
PPid:   0
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 64
Groups:  
NStgid: 1
NSpid:  1
NSpgid: 1
NSsid:  1
VmPeak:    10680 kB
VmSize:    10652 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      5980 kB
VmRSS:      5980 kB
RssAnon:             808 kB
RssFile:            5172 kB
RssShmem:              0 kB
VmData:      988 kB
VmStk:       132 kB
VmExe:       988 kB
VmLib:      3796 kB
VmPTE:        40 kB
VmPMD:        12 kB
VmSwap:        0 kB
HugetlbPages:          0 kB
Threads:        1
SigQ:   0/30446
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000040001000
SigCgt: 0000000198016a07
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        2
Speculation_Store_Bypass:       vulnerable
Cpus_allowed:   3
Cpus_allowed_list:      0-1
Mems_allowed:   00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        72
nonvoluntary_ctxt_switches:     37
root@pod3:/# 

参考リンク

SPIFFEのチュートリアルを試したメモ

以下ブログを翻訳しようとしたが、SPIFFEが全然わからなかったので、SPIFFEのチュートリアルを試したメモ。

参考リンク

手順

クラスターの作成

今回はMinikubeでやってみる。注意点として記載があるとおり、いくつかフラグをつけて起動する。

$ minikube start \
>     --extra-config=apiserver.service-account-signing-key-file=/var/lib/minikube/certs/sa.key \
>     --extra-config=apiserver.service-account-key-file=/var/lib/minikube/certs/sa.pub \
>     --extra-config=apiserver.service-account-issuer=api \
>     --extra-config=apiserver.service-account-api-audiences=api,spire-server \
>     --extra-config=apiserver.authorization-mode=Node,RBAC
😄  Darwin 10.14.6 上の minikube v1.18.1
✨  dockerドライバーが自動的に選択されました。他の選択肢:  hyperkit, virtualbox, ssh
👍  コントロールプレーンのノード minikube を minikube 上で起動しています
🚜  Pulling base image ...
💾  Kubernetes v1.20.2 のダウンロードの準備をしています
    > preloaded-images-k8s-v9-v1....: 491.22 MiB / 491.22 MiB  100.00% 25.98 Mi
🔥  docker container (CPUs=2, Memory=3890MB) を作成しています...
🐳  Docker 20.10.3 で Kubernetes v1.20.2 を準備しています...
    ▪ apiserver.service-account-signing-key-file=/var/lib/minikube/certs/sa.key
    ▪ apiserver.service-account-key-file=/var/lib/minikube/certs/sa.pub
    ▪ apiserver.service-account-issuer=api
    ▪ apiserver.service-account-api-audiences=api,spire-server
    ▪ apiserver.authorization-mode=Node,RBAC
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Kubernetes コンポーネントを検証しています...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v4
🌟  有効なアドオン: default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

リポジトリのクローン

リポジトリをクローンする。

git clone https://github.com/spiffe/spire-tutorials
cd spire-tutorials/k8s/quickstart

サーバーの構成

Namespaceを作成する。

$ kubectl apply -f spire-namespace.yaml
namespace/spire created
$ k get ns
NAME              STATUS   AGE
default           Active   9m14s
kube-node-lease   Active   9m15s
kube-public       Active   9m16s
kube-system       Active   9m16s
spire             Active   8s

SPIREサーバー用のServiceAccountCondfigMapClusterRole/ClusterRoleBindingを作成する。

$ kubectl apply \
>     -f server-account.yaml \
>     -f spire-bundle-configmap.yaml \
>     -f server-cluster-role.yaml
serviceaccount/spire-server created
configmap/spire-bundle created
clusterrole.rbac.authorization.k8s.io/spire-server-trust-role created
clusterrolebinding.rbac.authorization.k8s.io/spire-server-trust-role-binding created

SPIREサーバーのConfigMapStatefulSetServiceを作成する。

$ kubectl apply \
>     -f server-configmap.yaml \
>     -f server-statefulset.yaml \
>     -f server-service.yaml
configmap/spire-server created
statefulset.apps/spire-server created
service/spire-server created

確認する。

$  kubectl get statefulset --namespace spire
NAME           READY   AGE
spire-server   1/1     20s
$ kubectl get pods --namespace spire
NAME             READY   STATUS    RESTARTS   AGE
spire-server-0   1/1     Running   0          30s
$ kubectl get services --namespace spire
NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
spire-server   NodePort   10.106.188.29   <none>        8081:31210/TCP   37s

エージェントの構成

SPIREエージェント用のServiceAccountClusterRole/ClusterRoleBindingを作成する。

$ kubectl apply \
>     -f agent-account.yaml \
>     -f agent-cluster-role.yaml
serviceaccount/spire-agent created
clusterrole.rbac.authorization.k8s.io/spire-agent-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/spire-agent-cluster-role-binding created

SPIREエージェントのConfigMapDaemonSetを作成する。

$ kubectl apply \
>     -f agent-configmap.yaml \
>     -f agent-daemonset.yaml
configmap/spire-agent created
daemonset.apps/spire-agent created

確認する。

$ kubectl get daemonset --namespace spire
NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
spire-agent   1         1         1       1            1           <none>          114s
$ kubectl get pods --namespace spire
NAME                READY   STATUS    RESTARTS   AGE
spire-agent-fx88v   1/1     Running   0          2m
spire-server-0      1/1     Running   0          7m39s

ワークロードの登録

最初にワークロードをサーバーに登録する必要がある。

ノードに割り当てるSPIFFEIDを指定して、ノードの新しい登録エントリーを作成する。

$ kubectl exec -n spire spire-server-0 -- \
>     /opt/spire/bin/spire-server entry create \
>     -spiffeID spiffe://example.org/ns/spire/sa/spire-agent \
>     -selector k8s_sat:cluster:demo-cluster \
>     -selector k8s_sat:agent_ns:spire \
>     -selector k8s_sat:agent_sa:spire-agent \
>     -node
Entry ID         : dbd74f07-f3ce-4dcf-b6c1-1a78f062dfe1
SPIFFE ID        : spiffe://example.org/ns/spire/sa/spire-agent
Parent ID        : spiffe://example.org/spire/server
Revision         : 0
TTL              : default
Selector         : k8s_sat:agent_ns:spire
Selector         : k8s_sat:agent_sa:spire-agent
Selector         : k8s_sat:cluster:demo-cluster

ワークロードに割り当てるSPIFFEIDを指定して、ワークロードの新しい登録エントリを作成する。

$ kubectl exec -n spire spire-server-0 -- \
>     /opt/spire/bin/spire-server entry create \
>     -spiffeID spiffe://example.org/ns/default/sa/default \
>     -parentID spiffe://example.org/ns/spire/sa/spire-agent \
>     -selector k8s:ns:default \
>     -selector k8s:sa:default
Entry ID         : f5ef86a6-9b8f-4a0a-b503-2c9a3e2dd476
SPIFFE ID        : spiffe://example.org/ns/default/sa/default
Parent ID        : spiffe://example.org/ns/spire/sa/spire-agent
Revision         : 0
TTL              : default
Selector         : k8s:ns:default
Selector         : k8s:sa:default

ワークロードコンテナの構成

SPIREにアクセスするようにワークロードコンテナを構成する。

クライアントのDeploymentを作成する。

$ kubectl apply -f client-deployment.yaml
deployment.apps/client created

マニフェストを見ると、ホストの/run/spire/socketsをマウントしていて、hostPID: truehostNetwork: trueが設定されている。

Podに接続する。

kubectl exec -it $(kubectl get pods -o=jsonpath='{.items[0].metadata.name}' \
   -l app=client)  -- /bin/sh

ソケットにアクセスしSVIDが取得できることを確認する。

/opt/spire # /opt/spire/bin/spire-agent api fetch -socketPath /run/spire/sockets/agent.sock
Received 1 svid after 10.535ms

SPIFFE ID:              spiffe://example.org/ns/default/sa/default
SVID Valid After:       2021-03-24 13:42:52 +0000 UTC
SVID Valid Until:       2021-03-24 14:43:02 +0000 UTC
CA #1 Valid After:      2021-03-24 13:30:48 +0000 UTC
CA #1 Valid Until:      2021-03-25 13:30:58 +0000 UTC

/opt/spire # 

以上でチュートリアルは終了。

-writeで証明書を保存できる。

/opt/spire # /opt/spire/bin/spire-agent api fetch x509 -socketPath /run/spire/sockets/agent.sock -write /tmp/
Received 1 svid after 16.7911ms

SPIFFE ID:              spiffe://example.org/ns/default/sa/default
SVID Valid After:       2021-03-24 13:42:52 +0000 UTC
SVID Valid Until:       2021-03-24 14:43:02 +0000 UTC
CA #1 Valid After:      2021-03-24 13:30:48 +0000 UTC
CA #1 Valid Until:      2021-03-25 13:30:58 +0000 UTC

Writing SVID #0 to file /tmp/svid.0.pem.
Writing key #0 to file /tmp/svid.0.key.
Writing bundle #0 to file /tmp/bundle.0.pem.
/opt/spire # 

Cloud9からMySQLやPostgreSQLに接続する

Cloud9からAurora MySQLやAurora PostgreSQLに接続してバージョンを確認したメモ。

MySQL

mysqlクライアントはインストール済み。

接続する。SSL が必要な時は、--ssl を付与する。

ENDPOINT=<エンドポイント>
mysql -h ${ENDPOINT} -P 3306 -u admin -p

バージョンを確認する。

MySQL [(none)]> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.12    |
+-----------+
1 row in set (0.00 sec)

MySQL [(none)]> SELECT AURORA_VERSION();                                                                                                                                                                                       
+------------------+
| AURORA_VERSION() |
+------------------+
| 2.09.2           |
+------------------+
1 row in set (0.01 sec)

切断する。

MySQL [(none)]> exit
Bye

PostgreSQL

psqlをインストールする。

# sudo yum install postgresql
sudo amazon-linux-extras install -y postgresql14

なお、古いバージョンだと、接続時に psql: SCRAM authentication requires libpq version 10 or above というエラーになる。

接続する。

ENDPOINT=<エンドポイント>
psql -h ${ENDPOINT} -p 5432 -U postgres

バージョン確認する。

postgres=> SHOW SERVER_VERSION;
 server_version 
----------------
 11.9
(1 row)

postgres=> SELECT AURORA_VERSION();
 aurora_version 
----------------
 3.4.1
(1 row)

切断する。

postgres-> \q

EKSでKubeFedを試す

EKSでKubeFedを試してみたメモ。

コンポーネント バージョン
Kubernetesバージョン 1.18.9
プラットフォームバージョン eks.3
kubefedctl 0.6.1
kubefed 0.6.1
kubefedチャート 0.6.1

参考リンク

準備

ローカル端末にkubefedctlコマンドを導入する。リリースページからダウンロードして配置する。

$ kubefedctl version
kubefedctl version: version.Info{Version:"v0.6.1-1-g1eae3323", GitCommit:"1eae3323499765ee3f7a59e9fb7b6e7f214759c0", GitTreeState:"clean", BuildDate:"2021-01-25T16:45:24Z", GoVersion:"go1.15.3", Compiler:"gc", Platform:"darwin/amd64"}

クラスターを3つ、managementmember1member2を同じVPCに作成する。VPCやリージョンを分けてもよいが、VPCピアリングを作成するかどうかの違いだけと思われるので省略。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: management
  region: ap-northeast-1
  version: "1.18"
vpc:
  cidr: "10.0.0.0/16"

availabilityZones:
  - ap-northeast-1a
  - ap-northeast-1c

managedNodeGroups:
  - name: managed-ng-1
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    ssh:
      allow: true
      publicKeyName: default

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: member1
  region: ap-northeast-1
  version: "1.18"

vpc:
  id: "vpc-069df5f127c927d4b"
  subnets:
    public:
      ap-northeast-1a:
          id: "subnet-09885490580d35e8b"
      ap-northeast-1c:
          id: "subnet-04a6c3c9d5475f527"
    private:
      ap-northeast-1a:
          id: "subnet-0d9342027be0bfba4"
      ap-northeast-1c:
          id: "subnet-02897ae1574ed897a"

managedNodeGroups:
  - name: managed-ng-1
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    ssh:
      allow: true
      publicKeyName: default

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: member2
  region: ap-northeast-1
  version: "1.18"

vpc:
  id: "vpc-069df5f127c927d4b"
  subnets:
    public:
      ap-northeast-1a:
          id: "subnet-09885490580d35e8b"
      ap-northeast-1c:
          id: "subnet-04a6c3c9d5475f527"
    private:
      ap-northeast-1a:
          id: "subnet-0d9342027be0bfba4"
      ap-northeast-1c:
          id: "subnet-02897ae1574ed897a"

managedNodeGroups:
  - name: managed-ng-1
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    ssh:
      allow: true
      publicKeyName: default

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true
eksctl create cluster -f management.yaml
eksctl create cluster -f member1.yaml
eksctl create cluster -f member2.yaml

KubeFedの導入

HelmチャートでKubeFedを導入する。

helm repo add kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts
helm repo update

チャートを確認する。

$ helm search repo kubefed
NAME                    CHART VERSION   APP VERSION     DESCRIPTION       
kubefed-charts/kubefed  0.6.1                           KubeFed helm chart

チャートからインストールする。

$ helm --namespace kube-federation-system upgrade -i kubefed kubefed-charts/kubefed --version=0.6.1 --create-namespace
Release "kubefed" does not exist. Installing it now.
NAME: kubefed
LAST DEPLOYED: Mon Mar 15 17:52:23 2021
NAMESPACE: kube-federation-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

確認する。

$ k get all -n kube-federation-system
NAME                                              READY   STATUS    RESTARTS   AGE
pod/kubefed-admission-webhook-7dff5dfcd4-bvcz2    1/1     Running   0          64s
pod/kubefed-controller-manager-7f8997d65f-hvjxq   1/1     Running   0          43s
pod/kubefed-controller-manager-7f8997d65f-w9q9v   1/1     Running   0          41s

NAME                                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/kubefed-admission-webhook                    ClusterIP   172.20.0.4       <none>        443/TCP    64s
service/kubefed-controller-manager-metrics-service   ClusterIP   172.20.224.221   <none>        9090/TCP   64s

NAME                                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kubefed-admission-webhook    1/1     1            1           64s
deployment.apps/kubefed-controller-manager   2/2     2            2           64s

NAME                                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/kubefed-admission-webhook-7dff5dfcd4    1         1         1       64s
replicaset.apps/kubefed-controller-manager-7f8997d65f   2         2         2       43s
replicaset.apps/kubefed-controller-manager-84fdcb4bf8   0         0         0       64s

このネームスペースにはNameラベルが必要。チャートからデプロイ時に付与される。

$ k get ns --show-labels
NAME                     STATUS   AGE     LABELS
default                  Active   41m     <none>
kube-federation-system   Active   5m25s   name=kube-federation-system
kube-node-lease          Active   41m     <none>
kube-public              Active   41m     <none>
kube-system              Active   41m     <none>

アドミッションウェブフックが登録されている。

$ k get mutatingwebhookconfigurations.admissionregistration.k8s.io
NAME                            WEBHOOKS   AGE
mutation.core.kubefed.io        1          72m
pod-identity-webhook            1          108m
vpc-resource-mutating-webhook   1          108m
$ k get validatingwebhookconfigurations.admissionregistration.k8s.io
NAME                              WEBHOOKS   AGE
validations.core.kubefed.io       3          72m
vpc-resource-validating-webhook   1          108m

クラスターの登録

クラスターに接続する。コンテキストを確認する。

$ k config get-contexts
CURRENT   NAME                                           CLUSTER                               AUTHINFO                                       NAMESPACE
          kind-kind                                      kind-kind                             kind-kind                                      
*         sotosugi@management.ap-northeast-1.eksctl.io   management.ap-northeast-1.eksctl.io   sotosugi@management.ap-northeast-1.eksctl.io   
          sotosugi@member1.ap-northeast-1.eksctl.io      member1.ap-northeast-1.eksctl.io      sotosugi@member1.ap-northeast-1.eksctl.io      
          sotosugi@production.ap-northeast-1.eksctl.io   production.ap-northeast-1.eksctl.io   sotosugi@production.ap-northeast-1.eksctl.io   
          sotosugi@staging.ap-northeast-1.eksctl.io      staging.ap-northeast-1.eksctl.io      sotosugi@staging.ap-northeast-1.eksctl.io      kube-system

以下のようなコマンドでクラスターを登録するが、eksctlが作成したコンテキストを上手く解釈できずエラーとなる。

kubefedctl join member1 \
  --cluster-context sotosugi@member1.ap-northeast-1.eksctl.io \
  --host-cluster-context sotosugi@management.ap-northeast-1.eksctl.io
$ kubefedctl join member1 \
>   --cluster-context sotosugi@member1.ap-northeast-1.eksctl.io \
>   --host-cluster-context sotosugi@management.ap-northeast-1.eksctl.io
F0315 18:06:17.087427   50344 join.go:127] Error: ServiceAccount "member1-sotosugi@management.ap-northeast-1.eksctl.io" is invalid: metadata.name: Invalid value: "member1-sotosugi@management.ap-northeast-1.eksctl.io": a DNS-1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')

.kube/configを手動で調整する。

- context:
    cluster: management.ap-northeast-1.eksctl.io
    user: sotosugi@management.ap-northeast-1.eksctl.io
  name: sotosugi@management.ap-northeast-1.eksctl.io
- context:
    cluster: member1.ap-northeast-1.eksctl.io
    user: sotosugi@member1.ap-northeast-1.eksctl.io
  name: sotosugi@member1.ap-northeast-1.eksctl.io
- context:
    cluster: member2.ap-northeast-1.eksctl.io
    user: sotosugi@member2.ap-northeast-1.eksctl.io
  name: sotosugi@member2.ap-northeast-1.eksctl.io

上記のコンテキストを以下に直し、他の場所を整合性がとれるように直す。

- context:
    cluster: management
    user: sotosugi-management
  name: sotosugi-management
- context:
    cluster: member1
    user: sotosugi-member1
  name: sotosugi-member1
- context:
    cluster: member2
    user: sotosugi-member2
  name: sotosugi-member2

コンテキストを再確認する。

$ k config get-contexts
CURRENT   NAME                                           CLUSTER                               AUTHINFO                                       NAMESPACE
          kind-kind                                      kind-kind                             kind-kind                                      
          sotosugi-management                            management                            sotosugi-management                            
          sotosugi-member1                               member1                               sotosugi-member1                               
          sotosugi-member2                               member2                               sotosugi-member2                               
          sotosugi@production.ap-northeast-1.eksctl.io   production.ap-northeast-1.eksctl.io   sotosugi@production.ap-northeast-1.eksctl.io   
          sotosugi@staging.ap-northeast-1.eksctl.io      staging.ap-northeast-1.eksctl.io      sotosugi@staging.ap-northeast-1.eksctl.io      kube-system

これで再チャレンジする。ログ出力を追加する。

kubefedctl join member1 \
  --cluster-context sotosugi-member1 \
  --host-cluster-context sotosugi-management \
  --v=2
$ kubefedctl join member1 \
>   --cluster-context sotosugi-member1 \
>   --host-cluster-context sotosugi-management \
>   --v=2
I0315 18:22:33.415339   53014 join.go:160] Args and flags: name member1, host: sotosugi-management, host-system-namespace: kube-federation-system, kubeconfig: , cluster-context: sotosugi-member1, secret-name: , dry-run: false
I0315 18:22:33.789387   53014 join.go:241] Performing preflight checks.
I0315 18:22:33.900167   53014 join.go:247] Creating kube-federation-system namespace in joining cluster
I0315 18:22:33.947034   53014 join.go:254] Created kube-federation-system namespace in joining cluster
I0315 18:22:33.947065   53014 join.go:408] Creating service account in joining cluster: member1
I0315 18:22:33.968599   53014 join.go:418] Created service account: member1-sotosugi-management in joining cluster: member1
I0315 18:22:33.968658   53014 join.go:445] Creating cluster role and binding for service account: member1-sotosugi-management in joining cluster: member1
I0315 18:22:34.052268   53014 join.go:454] Created cluster role and binding for service account: member1-sotosugi-management in joining cluster: member1
I0315 18:22:34.052286   53014 join.go:814] Creating cluster credentials secret in host cluster
I0315 18:22:34.090902   53014 join.go:842] Using secret named: member1-sotosugi-management-token-5qd76
I0315 18:22:34.119917   53014 join.go:887] Created secret in host cluster named: member1-sp98w
I0315 18:22:34.173581   53014 join.go:282] Created federated cluster resource
kubefedctl join member2 \
  --cluster-context sotosugi-member2 \
  --host-cluster-context sotosugi-management \
  --v=2
$ kubefedctl join member2 \
>   --cluster-context sotosugi-member2 \
>   --host-cluster-context sotosugi-management \
>   --v=2
I0315 18:23:16.870401   53200 join.go:160] Args and flags: name member2, host: sotosugi-management, host-system-namespace: kube-federation-system, kubeconfig: , cluster-context: sotosugi-member2, secret-name: , dry-run: false
I0315 18:23:17.239271   53200 join.go:241] Performing preflight checks.
I0315 18:23:17.376232   53200 join.go:247] Creating kube-federation-system namespace in joining cluster
I0315 18:23:17.433407   53200 join.go:254] Created kube-federation-system namespace in joining cluster
I0315 18:23:17.433441   53200 join.go:408] Creating service account in joining cluster: member2
I0315 18:23:17.451068   53200 join.go:418] Created service account: member2-sotosugi-management in joining cluster: member2
I0315 18:23:17.451109   53200 join.go:445] Creating cluster role and binding for service account: member2-sotosugi-management in joining cluster: member2
I0315 18:23:17.523683   53200 join.go:454] Created cluster role and binding for service account: member2-sotosugi-management in joining cluster: member2
I0315 18:23:17.523701   53200 join.go:814] Creating cluster credentials secret in host cluster
I0315 18:23:17.551803   53200 join.go:842] Using secret named: member2-sotosugi-management-token-sdl8j
I0315 18:23:17.580312   53200 join.go:887] Created secret in host cluster named: member2-h7txt
I0315 18:23:17.637979   53200 join.go:282] Created federated cluster resource

登録されたクラスターを確認する。

$ kubectl -n kube-federation-system get kubefedclusters
NAME      AGE     READY
member1   2m38s   True
member2   115s    True

先ほどのログを見ると、ターゲットクラスターにもkube-federation-system Namespaceを作成し、ServiceAccountを作成して権限を与えている。

$ kubectx sotosugi-member1
Switched to context "sotosugi-member1".
$ k get sa -n kube-federation-system
NAME                          SECRETS   AGE
default                       1         9m4s
member1-sotosugi-management   1         9m4s

与えられている権限を確認すると、何でもできる権限を持っている。

$ k get clusterrolebinding | grep -e kubefed -e NAME
NAME                                                     ROLE                                                                 AGE
kubefed-controller-manager:member1-sotosugi-management   ClusterRole/kubefed-controller-manager:member1-sotosugi-management   20m
$ k get clusterrole kubefed-controller-manager:member1-sotosugi-management -o yaml | k neat
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubefed-controller-manager:member1-sotosugi-management
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs:
  - '*'
  verbs:
  - get

ホストクラスターにはターゲットクラスターに作成されたServiceAccountのトークンが保存されている(トークンの中身を確認すると一致する)。

$ k get secret -n kube-federation-system
NAME                                     TYPE                                  DATA   AGE
default-token-52kmm                      kubernetes.io/service-account-token   3      45m
kubefed-admission-webhook-serving-cert   kubernetes.io/tls                     2      45m
kubefed-admission-webhook-token-5n8jj    kubernetes.io/service-account-token   3      45m
kubefed-controller-token-2529v           kubernetes.io/service-account-token   3      45m
member1-sp98w                            Opaque                                1      15m
member2-h7txt                            Opaque                                1      14m
sh.helm.release.v1.kubefed.v1            helm.sh/release.v1                    1      45m

KubeFedClusterリソースはこのSecretやAPIサーバーのエンドポイントや証明書などの情報が入っている。kubefedctlを使わなくても可能だと思われるが面倒そう。

$ kubectl -n kube-federation-system get kubefedclusters member1 -o yaml | k neat
apiVersion: core.kubefed.io/v1beta1
kind: KubeFedCluster
metadata:
  name: member1
  namespace: kube-federation-system
spec:
  apiEndpoint: https://XXXX.gr7.ap-northeast-1.eks.amazonaws.com
  caBundle: XXXX
  secretRef:
    name: member1-sp98w

動作確認

ホストクラスターにローカルNamespaceを作成する。

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: test
EOF

ホストクラスターにFederatedNamespaceを作成する。このときローカルNamespaceとFederatedNamespaceの名前は一致する必要がある。

cat <<EOF | kubectl apply -f -
apiVersion: types.kubefed.io/v1beta1
kind: FederatedNamespace
metadata:
  name: test
  namespace: test
spec:
  placement:
    clusters:
    - name: member1
    - name: member2
EOF

ターゲットクラスターで作成されたネームスペースを確認する。

$ k --context sotosugi-member1 get ns
NAME                     STATUS   AGE
default                  Active   71m
kube-federation-system   Active   27m
kube-node-lease          Active   71m
kube-public              Active   71m
kube-system              Active   71m
test                     Active   19s
$ k --context sotosugi-member1 get ns
NAME                     STATUS   AGE
default                  Active   52m
kube-federation-system   Active   26m
kube-node-lease          Active   52m
kube-public              Active   52m
kube-system              Active   52m
test                     Active   29s

FederatedDeploymentを作成する。

cat <<EOF | kubectl apply -f -
apiVersion: types.kubefed.io/v1beta1
kind: FederatedDeployment
metadata:
  name: test
  namespace: test
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
  placement:
    clusters:
    - name: member2
    - name: member1
  overrides:
  - clusterName: member2
    clusterOverrides:
    - path: "/spec/replicas"
      value: 5
    - path: "/spec/template/spec/containers/0/image"
      value: "nginx:1.17.0-alpine"
    - path: "/metadata/annotations"
      op: "add"
      value:
        foo: bar
EOF

確認する。

$ k --context sotosugi-member1 -n test get deploy -o wide
NAME   READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES   SELECTOR
test   3/3     3            3           112s   nginx        nginx    app=nginx
$ k --context sotosugi-member2 -n test get deploy -o wide
NAME   READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES                SELECTOR
test   5/5     5            5           116s   nginx        nginx:1.17.0-alpine   app=nginx

最後に、KubeFedのカスタムリソースを確認する。

$ k api-resources | grep -e kubefed -e NAME
NAME                              SHORTNAMES   APIVERSION                            NAMESPACED   KIND
clusterpropagatedversions                      core.kubefed.io/v1alpha1              false        ClusterPropagatedVersion
federatedservicestatuses                       core.kubefed.io/v1alpha1              true         FederatedServiceStatus
federatedtypeconfigs              ftc          core.kubefed.io/v1beta1               true         FederatedTypeConfig
kubefedclusters                                core.kubefed.io/v1beta1               true         KubeFedCluster
kubefedconfigs                                 core.kubefed.io/v1beta1               true         KubeFedConfig
propagatedversions                             core.kubefed.io/v1alpha1              true         PropagatedVersion
dnsendpoints                                   multiclusterdns.kubefed.io/v1alpha1   true         DNSEndpoint
domains                                        multiclusterdns.kubefed.io/v1alpha1   true         Domain
ingressdnsrecords                              multiclusterdns.kubefed.io/v1alpha1   true         IngressDNSRecord
servicednsrecords                              multiclusterdns.kubefed.io/v1alpha1   true         ServiceDNSRecord
replicaschedulingpreferences      rsp          scheduling.kubefed.io/v1alpha1        true         ReplicaSchedulingPreference
federatedclusterroles                          types.kubefed.io/v1beta1              false        FederatedClusterRole
federatedconfigmaps               fcm          types.kubefed.io/v1beta1              true         FederatedConfigMap
federateddeployments              fdeploy      types.kubefed.io/v1beta1              true         FederatedDeployment
federatedingresses                fing         types.kubefed.io/v1beta1              true         FederatedIngress
federatedjobs                                  types.kubefed.io/v1beta1              true         FederatedJob
federatednamespaces               fns          types.kubefed.io/v1beta1              true         FederatedNamespace
federatedreplicasets              frs          types.kubefed.io/v1beta1              true         FederatedReplicaSet
federatedsecrets                               types.kubefed.io/v1beta1              true         FederatedSecret
federatedserviceaccounts          fsa          types.kubefed.io/v1beta1              true         FederatedServiceAccount
federatedservices                 fsvc         types.kubefed.io/v1beta1              true         FederatedService

KubeFedのクイックスタート

このAWSソリューション実装を理解するために、先ずそもそもKubeFedのクイックスタートを試してみたメモ。

クイックスタート

リポジトリをクローンする。

git clone https://github.com/kubernetes-sigs/kubefed.git
cd kubefed/

Kindでクラスターを起動する。

$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.20.2) 🖼 
 ✓ Preparing nodes 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂

ノードを確認する。

$ k get node
NAME                 STATUS   ROLES                  AGE     VERSION
kind-control-plane   Ready    control-plane,master   3m47s   v1.20.2

kubefedをデプロイする。

make deploy.kind

なかなかコマンドが通らない。

  • Goが必要
  • gsedが必要
  • 先に./scripts/download-binaries.shの実行が必要
  • 上記スクリプトでバイナリをダウンロードしたディレクトリにパスを通す
$ make deploy.kind

(省略)

Release "kubefed" does not exist. Installing it now.
NAME: kubefed
LAST DEPLOYED: Fri Mar 12 18:10:49 2021
NAMESPACE: kube-federation-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
I0312 18:11:13.086691   35295 join.go:148] Defaulting cluster context to joining cluster name kind-kind
I0312 18:11:13.086823   35295 join.go:160] Args and flags: name kind-kind, host: kind-kind, host-system-namespace: kube-federation-system, kubeconfig: , cluster-context: kind-kind, secret-name: , dry-run: false
I0312 18:11:13.177397   35295 join.go:241] Performing preflight checks.
I0312 18:11:13.182509   35295 join.go:247] Creating kube-federation-system namespace in joining cluster
I0312 18:11:13.188251   35295 join.go:390] Already existing kube-federation-system namespace
I0312 18:11:13.188296   35295 join.go:254] Created kube-federation-system namespace in joining cluster
I0312 18:11:13.188313   35295 join.go:412] Creating service account in joining cluster: kind-kind
I0312 18:11:13.200502   35295 join.go:422] Created service account: kind-kind-kind-kind in joining cluster: kind-kind
I0312 18:11:13.200522   35295 join.go:449] Creating cluster role and binding for service account: kind-kind-kind-kind in joining cluster: kind-kind
I0312 18:11:13.253592   35295 join.go:458] Created cluster role and binding for service account: kind-kind-kind-kind in joining cluster: kind-kind
I0312 18:11:13.253633   35295 join.go:818] Creating cluster credentials secret in host cluster
I0312 18:11:13.272069   35295 join.go:846] Using secret named: kind-kind-kind-kind-token-c6zft
I0312 18:11:13.293713   35295 join.go:891] Created secret in host cluster named: kind-kind-p9zzx
I0312 18:11:13.384075   35295 join.go:286] Created federated cluster resource

Helmチャートでkube-federation-systemに何かがインストールされている。

$ helm ls -A
NAME    NAMESPACE               REVISION        UPDATED                                 STATUS          CHART           APP VERSION
kubefed kube-federation-system  1               2021-03-12 18:10:49.627911 +0900 JST    deployed        kubefed-0.0.3            
$ k get pod -A
NAMESPACE                NAME                                          READY   STATUS    RESTARTS   AGE
kube-federation-system   kubefed-admission-webhook-b559b6d8-vjhgb      1/1     Running   0          4m45s
kube-federation-system   kubefed-controller-manager-79768548bf-9nnxl   1/1     Running   0          4m25s
kube-federation-system   kubefed-controller-manager-79768548bf-vbjgx   1/1     Running   0          4m22s
kube-system              coredns-74ff55c5b-5pzbn                       1/1     Running   2          63m
kube-system              coredns-74ff55c5b-6mc2g                       1/1     Running   2          63m
kube-system              etcd-kind-control-plane                       1/1     Running   2          63m
kube-system              kindnet-69p92                                 1/1     Running   2          63m
kube-system              kube-apiserver-kind-control-plane             1/1     Running   2          63m
kube-system              kube-controller-manager-kind-control-plane    1/1     Running   2          63m
kube-system              kube-proxy-5sss8                              1/1     Running   2          63m
kube-system              kube-scheduler-kind-control-plane             1/1     Running   2          63m
local-path-storage       local-path-provisioner-78776bfc44-h25s8       1/1     Running   4          63m

この状態で、クラスター自身がフェデレーションに登録されているがREADYになっていない。

$ kubectl -n kube-federation-system get kubefedcluster
NAME        AGE   READY
kind-kind   18m   

macOSで、APIエンドポイントの修正スクリプトが上手く機能しなかったので手動で修正する。IPを確認する。

$ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED       STATUS             PORTS                       NAMES
ba641073044b   kindest/node:v1.20.2   "/usr/local/bin/entr…"   2 hours ago   Up About an hour   127.0.0.1:61763->6443/tcp   kind-control-plane
$ docker inspect ba641073044b | jq -r '.[].NetworkSettings.Networks[].IPAddress'
172.18.0.2

Editする。

kubectl -n kube-federation-system edit kubefedcluster kind-kind

以下の部分を、

spec:
  apiEndpoint: https://127.0.0.1:61763

以下に直す。

spec:
  apiEndpoint: https://172.18.0.2:6443

これでREADYになった。

$ kubectl -n kube-federation-system get kubefedcluster
NAME        AGE   READY
kind-kind   36m   True

フェデレートされるネームスペースを作成する。

$ kubectl create ns federate-me
namespace/federate-me created

ネームスーペースとそのリソースをフェデレートするようにkubefedに伝える。

$ ./bin/kubefedctl federate ns federate-me
I0312 18:35:03.302374   38883 federate.go:472] Resource to federate is a namespace. Given namespace will itself be the container for the federated namespace
I0312 18:35:03.308846   38883 federate.go:501] Successfully created FederatedNamespace "federate-me/federate-me" from Namespace

フェデレートされるConfigMapを作成する。

$ kubectl -n federate-me create cm my-cm
configmap/my-cm created

ConfigMapをフェデレートするようにkubefedに伝える。

$ ./bin/kubefedctl -n federate-me federate configmap my-cm
I0312 18:37:13.120185   39381 federate.go:501] Successfully created FederatedConfigMap "federate-me/my-cm" from ConfigMap

リソースを確認する。

$ kubectl -n federate-me get federatedconfigmap
NAME    AGE
my-cm   12m
$ kubectl -n federate-me get federatednamespace
NAME          AGE
federate-me   15m

クイックスタートを通したものの、まだよく意味がわからない。

CalicoとCiliumでの細かい動作の違い

以下のセッションを見ていたら自分の記憶とちょっと違ったので確認したメモ。

具体的には以下の点。

  • ALBからのIngress接続を許可するため、VPCのIPブロックを許可すると、Podが全部接続可能になってしまう(PodはVPC CNIプラグインによってVPCのIPを持っているため)

自分も当初そう思っていたが、CiliumかCalicoかをいろいろ試していたとき、何かの条件ではそうならず、VPCのIPを許可していても、Podを許可していないと通信出来なかった記憶がある。

  • CiliumだったかCalicoだったか
  • 標準NetworkPolicyだったかカスタムリソースだったか
  • IngressだったかEgressだったか

この辺は覚えてない。

以下試した結論を書いておくと、CalicoとCiliumの場合で標準NetworkPolicyを使っていても動作が違った。Calicoの場合はVPCのIPブロックを許可すると全てのPodが許可されるが、Ciliumの場合は明示的をPodを許可しないと許可されなかった。

クラスターの作成

クラスターを作成する。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: netpol
  region: ap-northeast-1
vpc:
  cidr: "10.1.0.0/16"

availabilityZones:
  - ap-northeast-1a
  - ap-northeast-1c

managedNodeGroups:
  - name: managed-ng-1
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    ssh:
      allow: true
      publicKeyName: default
    privateNetworking: true

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]
eksctl create cluster -f cluster.yaml

Calico

Calicoをインストールする。

kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.7.5/config/v1.7/calico.yaml

確認する。

$ k get po -A
NAMESPACE     NAME                                                  READY   STATUS    RESTARTS   AGE
kube-system   aws-node-75xrn                                        1/1     Running   0          5m12s
kube-system   aws-node-s49js                                        1/1     Running   0          5m11s
kube-system   calico-node-k8wl5                                     1/1     Running   0          36s
kube-system   calico-node-lntxb                                     1/1     Running   0          36s
kube-system   calico-typha-5ff6788794-fz4vn                         1/1     Running   0          36s
kube-system   calico-typha-horizontal-autoscaler-7d57c996b4-hrv2v   1/1     Running   0          35s
kube-system   coredns-86f7d88d77-9t4ds                              1/1     Running   0          10m
kube-system   coredns-86f7d88d77-d85xq                              1/1     Running   0          10m
kube-system   kube-proxy-47sjz                                      1/1     Running   0          5m11s
kube-system   kube-proxy-l6psf                                      1/1     Running   0          5m12s

テスト用のNamespaceとPodを作る。

$ k create ns ns1
namespace/ns1 created
$ k create ns ns2
namespace/ns2 created
$ k -n ns1 run pod1 --image=nginx
pod/pod1 created
$ k -n ns1 run pod2 --image=nginx
pod/pod2 created
$ k -n ns2 run pod1 --image=nginx
pod/pod1 created

ns1内の通信のみ許可するポリシーを作成する。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: policy1
  namespace: ns1
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}
$ k apply -f policy1.yaml
networkpolicy.networking.k8s.io/policy1 created

テストしてみる。ns1/pod2からns1/pod1に接続できるが、ns2/pod1からns1/pod1には接続できない。

$ k -n ns1 get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP             NODE                                              NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          5m3s    10.1.103.145   ip-10-1-112-140.ap-northeast-1.compute.internal   <none>           <none>
pod2   1/1     Running   0          2m43s   10.1.76.11     ip-10-1-64-124.ap-northeast-1.compute.internal    <none>           <none>
$ k -n ns1 exec -it pod2 -- bash
root@pod2:/# curl 10.1.103.145
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@pod2:/# exit
exit
$ k -n ns2 exec -it pod1 -- bash
root@pod1:/# curl 10.1.103.145
^C
root@pod1:/# exit
exit
command terminated with exit code 130

ポリシーを変更し、VPCのIPレンジを全て許可する。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: policy1
  namespace: ns1
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}
    - ipBlock:
        cidr: 10.1.0.0/16
$ k apply -f policy1.yaml
networkpolicy.networking.k8s.io/policy1 configured

これで試す。確かに繋がってしまう。

$ k -n ns2 exec -it pod1 -- bash
root@pod1:/# curl 10.1.103.145
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@pod1:/# exit
exit

NetworkPolicyを削除する。

$ k -n ns1 delete netpol --all
networkpolicy.networking.k8s.io "policy1" deleted

Calicoを削除する。

k delete -fhttps://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/v1.7.5/config/v1.7/calico.yaml

CNIのゴミが残っているといやなので、念のためマネコンからEC2インスタンスを削除して新しいノードにする。

Cilium

Ciliumをインストールする。

helm repo update
helm install cilium cilium/cilium --version 1.9.5 \
  --namespace kube-system \
  --set cni.chainingMode=aws-cni \
  --set masquerade=false \
  --set tunnel=disabled \
  --set nodeinit.enabled=true

CoreDNSのPodが起動してこない。

$ k get pod -n kube-system
NAME                               READY   STATUS              RESTARTS   AGE
aws-node-7kzwg                     1/1     Running             0          6m26s
aws-node-w7mks                     1/1     Running             0          8m9s
cilium-9mz9h                       1/1     Running             0          5m53s
cilium-node-init-qbk66             1/1     Running             0          5m53s
cilium-node-init-rqd66             1/1     Running             0          5m53s
cilium-operator-7f555b8c74-gw6mn   1/1     Running             0          5m53s
cilium-operator-7f555b8c74-plqn6   1/1     Running             0          5m53s
cilium-xs9qc                       1/1     Running             0          5m53s
coredns-86f7d88d77-46shh           0/1     ContainerCreating   0          5m22s
coredns-86f7d88d77-gdgvj           0/1     ContainerCreating   0          5m7s
kube-proxy-jfwbf                   1/1     Running             0          6m26s
kube-proxy-snlwr                   1/1     Running             0          8m9s

これは以下のあたりの問題。

CNIを1.7.9にすると治るらしいのでアップデートする。

$ k apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/v1.7/aws-k8s-cni.yaml
clusterrolebinding.rbac.authorization.k8s.io/aws-node unchanged
clusterrole.rbac.authorization.k8s.io/aws-node unchanged
customresourcedefinition.apiextensions.k8s.io/eniconfigs.crd.k8s.amazonaws.com unchanged
daemonset.apps/aws-node configured
serviceaccount/aws-node unchanged

確認する。

$ k get pod -n kube-system
NAME                               READY   STATUS    RESTARTS   AGE
aws-node-lxw6g                     1/1     Running   0          102s
aws-node-n2pf9                     1/1     Running   0          2m29s
cilium-9mz9h                       1/1     Running   0          10m
cilium-node-init-qbk66             1/1     Running   0          10m
cilium-node-init-rqd66             1/1     Running   0          10m
cilium-operator-7f555b8c74-gw6mn   1/1     Running   0          10m
cilium-operator-7f555b8c74-plqn6   1/1     Running   0          10m
cilium-xs9qc                       1/1     Running   0          10m
coredns-86f7d88d77-46shh           1/1     Running   0          10m
coredns-86f7d88d77-gdgvj           1/1     Running   0          9m56s
kube-proxy-jfwbf                   1/1     Running   0          11m
kube-proxy-snlwr                   1/1     Running   0          12m

テスト用のPodを作る。

$ k -n ns1 run pod1 --image=nginx
pod/pod1 created
$ k -n ns1 run pod2 --image=nginx
pod/pod2 created
$ k -n ns2 run pod1 --image=nginx
pod/pod1 created

ns1内の通信のみ許可するポリシーを作成する。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: policy1
  namespace: ns1
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}
$ k apply -f policy1.yaml
networkpolicy.networking.k8s.io/policy1 created

テストしてみる。ns1/pod2からns1/pod1に接続できるが、ns2/pod1からns1/pod1には接続できない。

$ k -n ns1 get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP             NODE                                             NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          40s   10.1.84.166    ip-10-1-80-148.ap-northeast-1.compute.internal   <none>           <none>
pod2   1/1     Running   0          35s   10.1.109.192   ip-10-1-107-65.ap-northeast-1.compute.internal   <none>           <none>
$ k -n ns1 exec -it pod2 -- bash
root@pod2:/# curl 10.1.84.166
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@pod2:/# exit
exit
$ k -n ns2 exec -it pod1 -- bash
root@pod1:/# curl 10.1.84.166
^C
root@pod1:/# exit
exit
command terminated with exit code 130

ポリシーを変更し、VPCのIPレンジを全て許可する。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: policy1
  namespace: ns1
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}
    - ipBlock:
        cidr: 10.1.0.0/16
$ k apply -f policy1.yaml
networkpolicy.networking.k8s.io/policy1 configured

これで試す。Ciliumの場合は繋がらない!

$ k -n ns2 exec -it pod1 -- bash
root@pod1:/# curl 10.1.84.166
^C
root@pod1:/# exit
exit
command terminated with exit code 130

さらに、Namespaceを指定して許可してみる。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: policy1
  namespace: ns1
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}
    - ipBlock:
        cidr: 10.1.0.0/16
    - namespaceSelector:
        matchLabels:
          name: ns2
$ k label ns ns1 name=ns1
namespace/ns1 labeled
$ k label ns ns2 name=ns2
namespace/ns2 labeled
$ k apply -f policy1.yaml
networkpolicy.networking.k8s.io/policy1 configured

この場合は意図した通り繋がる。

$ k -n ns2 exec -it pod1 -- bash
root@pod1:/# curl 10.1.84.166
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@pod1:/# exit
exit

VSCodeやLensでEKSに接続する

VSCodeKubernetes拡張やLensでEKSに接続しようとしたとき、コンテキストを選択してもAWSプロファイルが適切でないと接続できないので、どうしたらいいのか調べたメモ。

.kube/configuserフィールドにあるトークンを取得するコマンドに環境変数としてプロファイルを書いてあげればよい。

users:
- name: sotosugi@falco.ap-northeast-1.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - token
      - -i
      - falco
      command: aws-iam-authenticator
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
      - name: AWS_DEFAULT_REGION
        value: ap-northeast-1
      - name: AWS_PROFILE
        value: sotosugi+hogehoge

VSCode等のとき以外でも、ターミナルでプロファイルを間違えていても正しいプロファイルで繋がるようになる。

参考リンク