Antrea Nepheによるセキュリティグループの管理

この記事は[TUNA-JP Advent Calendar 2022](https://qiita.com/advent-calendar/2022/tuna-jp) 12月16日分の投稿です。

# はじめに

[Antrea CNI](https://antrea.io)はパブリッククラウド上のインスタンスに対するセキュリティポリシーをAntrea Native Policyによる管理をサポートしています。この機能は[Nephe](https://github.com/antrea-io/nephe)として開発されています。今回は[Getting Started](https://github.com/antrea-io/nephe/blob/main/docs/getting-started.md)に従ってNepheを利用して、AWS上のEC2インスタンスのセキュリティグループを管理してみます。

Getting StartedではKind、EKS，AKSが対象となっていますが、vSphere環境にkubeadm 1.25.4で作成したVanilla Kubernetesで動作を確認しました。

```bash
$ kubectl get node -o wide
NAME         STATUS   ROLES           AGE   VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
cl1-master   Ready    control-plane   25m   v1.25.4   192.168.150.101   <none>        Ubuntu 20.04.5 LTS   5.4.0-135-generic   containerd://1.5.9
cl1-node1    Ready    <none>          23m   v1.25.4   192.168.150.102   <none>        Ubuntu 20.04.5 LTS   5.4.0-135-generic   containerd://1.5.9
cl1-node2    Ready    <none>          23m   v1.25.4   192.168.150.103   <none>        Ubuntu 20.04.5 LTS   5.4.0-135-generic   containerd://1.5.9
```

# 準備

Kubernetesクラスターに以下のコンポーネントをインストールする必要があります。

- [Antrea v1.9.0](https://github.com/antrea-io/antrea/releases/tag/v1.9.0)

```bash
$ kubectl apply -f https://github.com/antrea-io/antrea/releases/download/v1.9.0/antrea.yml
```

- [Cert Manager](https://github.com/cert-manager/cert-manager/releases/tag/v1.10.1) (ドキュメントではv1.8推奨となっていますが、最新のv1.10.1で試しました)

```bash
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml
```

antreaとcert-managerが実行されていることが確認できます。

```bash
$ kubectl get pod -A
NAMESPACE      NAME                                      READY   STATUS    RESTARTS   AGE
cert-manager   cert-manager-74d949c895-xqgkl             1/1     Running   0          17s
cert-manager   cert-manager-cainjector-d9bc5979d-8hhhx   1/1     Running   0          17s
cert-manager   cert-manager-webhook-84b7ddd796-p9ks8     1/1     Running   0          17s
kube-system    antrea-agent-6q9fv                        2/2     Running   0          25s
kube-system    antrea-agent-ghcgn                        2/2     Running   0          25s
kube-system    antrea-agent-zhs55                        2/2     Running   0          25s
kube-system    antrea-controller-6b76f4549-q9xt9         1/1     Running   0          25s
kube-system    coredns-565d847f94-4w7v7                  1/1     Running   0          118s
kube-system    coredns-565d847f94-zmhvb                  1/1     Running   0          118s
kube-system    etcd-cl1-master                           1/1     Running   1          2m11s
kube-system    kube-apiserver-cl1-master                 1/1     Running   1          2m12s
kube-system    kube-controller-manager-cl1-master        1/1     Running   1          2m11s
kube-system    kube-proxy-8ms4s                          1/1     Running   0          80s
kube-system    kube-proxy-8pmjj                          1/1     Running   0          100s
kube-system    kube-proxy-l95rs                          1/1     Running   0          118s
kube-system    kube-scheduler-cl1-master                 1/1     Running   1          2m11s
```

# Nepheの利用

## Nepheのインストール

[GitHub](https://github.com/antrea-io/nephe)のReleaseにある[nephe.yaml](https://github.com/antrea-io/nephe/releases/download/v0.2.0/nephe.yml)を利用してNepheをインストールします。

```bash
$ kubectl apply -f https://github.com/antrea-io/nephe/releases/download/v0.2.0/nephe.yml
namespace/nephe-system created
customresourcedefinition.apiextensions.k8s.io/cloudentityselectors.crd.cloud.antrea.io created
customresourcedefinition.apiextensions.k8s.io/cloudprovideraccounts.crd.cloud.antrea.io created
customresourcedefinition.apiextensions.k8s.io/virtualmachines.crd.cloud.antrea.io created
role.rbac.authorization.k8s.io/leader-election-role created
role.rbac.authorization.k8s.io/secret-viewer-role created
clusterrole.rbac.authorization.k8s.io/manager-role created
clusterrole.rbac.authorization.k8s.io/resource-viewer-role created
rolebinding.rbac.authorization.k8s.io/leader-election-rolebinding created
rolebinding.rbac.authorization.k8s.io/secret-viewer-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/resource-viewer-rolebinding created
service/nephe-controller-service created
service/nephe-controller-webhook-service created
deployment.apps/nephe-controller created
apiservice.apiregistration.k8s.io/v1alpha1.runtime.cloud.antrea.io created
certificate.cert-manager.io/serving-cert created
issuer.cert-manager.io/selfsigned-issuer created
mutatingwebhookconfiguration.admissionregistration.k8s.io/nephe-controller-mutating-webhook-configuration created
validatingwebhookconfiguration.admissionregistration.k8s.io/nephe-controller-validating-webhook-configuration created
```

`nephe-system`ネームスペースに`nephe-controller`が作成されます。

```bash
$ kubectl get pod -A
NAMESPACE      NAME                                      READY   STATUS    RESTARTS   AGE
cert-manager   cert-manager-74d949c895-xqgkl             1/1     Running   0          10m
cert-manager   cert-manager-cainjector-d9bc5979d-8hhhx   1/1     Running   0          10m
cert-manager   cert-manager-webhook-84b7ddd796-p9ks8     1/1     Running   0          10m
kube-system    antrea-agent-6q9fv                        2/2     Running   0          10m
kube-system    antrea-agent-ghcgn                        2/2     Running   0          10m
kube-system    antrea-agent-zhs55                        2/2     Running   0          10m
kube-system    antrea-controller-6b76f4549-q9xt9         1/1     Running   0          10m
kube-system    coredns-565d847f94-4w7v7                  1/1     Running   0          11m
kube-system    coredns-565d847f94-zmhvb                  1/1     Running   0          11m
kube-system    etcd-cl1-master                           1/1     Running   1          11m
kube-system    kube-apiserver-cl1-master                 1/1     Running   1          11m
kube-system    kube-controller-manager-cl1-master        1/1     Running   1          11m
kube-system    kube-proxy-8ms4s                          1/1     Running   0          11m
kube-system    kube-proxy-8pmjj                          1/1     Running   0          11m
kube-system    kube-proxy-l95rs                          1/1     Running   0          11m
kube-system    kube-scheduler-cl1-master                 1/1     Running   1          11m
nephe-system   nephe-controller-5f97c454dc-hcwpt         1/1     Running   0          9m4s
```

## CloudProviderAccountの登録

NepheがクラウドのAPIにアクセスするための`CloudProviderAccount` CRを作成します。クラウドAPIにアクセスするための認証情報が必要となります。AWSの場合、Accesss KeyとSecret Access Keyが必要になるため、認証情報をJSON形式でSecretに登録します。

```bash
CRED=$(echo '{"accessKeyId": "XXXXXXXXXX0123456789", "accessKeySecret": "xxxxxxxxxxxYYYYYYYYYYzzzzzzzz01234567890"}' | openssl base64 | tr -d '\n')

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: aws-account-creds
  namespace: nephe-system
type: Opaque
data:
  credentials: $(echo $CRED)
EOF
```

Secretが作成されます。

```bash
$ kubectl get secrets -n nephe-system
NAME                TYPE                DATA   AGE
aws-account-creds   Opaque              1      21s
serving-cert        kubernetes.io/tls   3      157m
```

以下のマニフェストで`CloudProviderAccount`を作成します。`CloudProviderAccount`はAWSにアクセスするためのSecretと、制御対象とするリージョンを指定します。

```yaml
apiVersion: crd.cloud.antrea.io/v1alpha1
kind: CloudProviderAccount
metadata:
  name: cloudprovideraccount-aws-sample
  namespace: sample-ns
spec:
  awsConfig:
    region: 'ap-northeast-1'
    secretRef:
      name: aws-account-creds
      namespace: nephe-system
      key: credentials
```

Nepheで利用するネームスペースを作成して、`CloudProviderAccount`を作成します。

```bash
$ kubectl create ns sample-ns
$ kubectl apply -f cloudprovideraccount.yaml
```

`CloudProviderAccount`が作成されたことを確認します。

```bash
$ kubectl get cloudprovideraccounts.crd.cloud.antrea.io -n sample-ns
NAME                              AGE
cloudprovideraccount-aws-sample   108s
```

## クラウドVMのインポート

Nepheで制御する仮想マシンをネームスペースにインポートするために、`CloudEntitySelector`を作成します。`CloudEntitySelector`は`CloudProviderAccount`で参照可能なVMの内管理対象とするものを特定することが可能です。AWSの場合は`.spec.vmSelector`として以下を指定可能です。

- vpcMatch: matchID, matchName
- vmMatch: matchID, matchName

以下のような`CloudEntitySelector`を作成し`vpcMatch`を利用して既存のVPCにあるEC2インスタンスを制御してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/511998de-bf84-d148-8f8c-85329f12a6bf.png)

```yaml
apiVersion: crd.cloud.antrea.io/v1alpha1
kind: CloudEntitySelector
metadata:
  name: cloudentityselector-aws-sample
  namespace: sample-ns
spec:
  accountName: cloudprovideraccount-aws-sample
  vmSelector:
    - vpcMatch:
        matchID: vpc-0c63c6f1b66431fe8
```

`CloudEntitySelector`を作成します。

```bash
$ kubectl apply -f cloudentityselector.yaml
$ kubectl get cloudentityselectors.crd.cloud.antrea.io -n sample-ns
NAME                             AGE
cloudentityselector-aws-sample   65s
```

`CloudEntitySelector`で指定したVPCにはEC2インスタンスが存在するため、`VirtualMachine`としてインポートされます。今回の環境では各インスタンスはdefaultのセキュリティグループを割り当てているため、パブリックIPに対してSSHすることはできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/e584bfea-fa4c-5373-e54c-f9065b7e78a3.png)

`virtualmachines.crd.cloud.antrea.io`リソースを確認すると、EC2インスタンスが認識されています。

```
$ kubectl get virtualmachines.crd.cloud.antrea.io 
NAME                  CLOUD-PROVIDER   VIRTUAL-PRIVATE-CLOUD   STATE     AGENTED
i-012f32960b16d05c5   AWS              vpc-0c63c6f1b66431fe8   running   false
i-092d3505ee68b7c1c   AWS              vpc-0c63c6f1b66431fe8   running   false
```

各VirtualMachineリソースに対して、ExternalEntity(`externalentities.crd.antrea.io`)が作成され、Antrea `NetworkPolicy`で制御対象とするExternalEntityとして利用可能になります。

```bash
$ kubectl describe externalentities.crd.antrea.io virtualmachine-i-012f32960b16d05c5
Name:         virtualmachine-i-012f32960b16d05c5
Namespace:    sample-ns
Labels:       kind.nephe=virtualmachine
              name.nephe=i-012f32960b16d05c5
              name.tag.nephe=ubuntu1
              namespace.nephe=sample-ns
              vpc.nephe=vpc-0c63c6f1b66431fe8
Annotations:  <none>
API Version:  crd.antrea.io/v1alpha2
Kind:         ExternalEntity
Metadata:
  Creation Timestamp:  2022-12-11T12:22:31Z
  Generation:          1
  Managed Fields:
    API Version:  crd.antrea.io/v1alpha2
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          .:
          f:kind.nephe:
          f:name.nephe:
          f:name.tag.nephe:
          f:namespace.nephe:
          f:vpc.nephe:
        f:ownerReferences:
          .:
          k:{"uid":"d98b022e-8c28-4239-90c0-c72094a0d94c"}:
      f:spec:
        .:
        f:endpoints:
        f:externalNode:
    Manager:    nephe-controller
    Operation:  Update
    Time:       2022-12-11T12:22:31Z
  Owner References:
    API Version:           crd.cloud.antrea.io/v1alpha1
    Block Owner Deletion:  true
    Controller:            true
    Kind:                  VirtualMachine
    Name:                  i-012f32960b16d05c5
    UID:                   d98b022e-8c28-4239-90c0-c72094a0d94c
  Resource Version:        553096
  UID:                     ec67aa0c-f084-4f43-8b6a-cc5f5d95c97a
Spec:
  Endpoints:
    Ip:           10.0.26.34
    Ip:           13.231.219.60
  External Node:  nephe-controller
Events:           <none>
```

## Antrea Network Policyの適用

以下のAntrea Network PolicyによりVirtualMachineを対象ととするポリシーを定義します。`externalEntitySelector`で`kind.nephe: virtualmachine`を指定しているため、上記でインポートされたEC2インタスンスがExternalEntityとしてポリシーの制御対象になります。

```yaml
apiVersion: crd.antrea.io/v1alpha1
kind: NetworkPolicy
metadata:
  name: vm-anp
  namespace: sample-ns
spec:
  priority: 100
  appliedTo:
  - externalEntitySelector:
      matchLabels:
         kind.nephe: virtualmachine
  ingress:
  - action: Allow
    from:
      - ipBlock:
          cidr: 0.0.0.0/0
    ports:
      - protocol: TCP
        port: 22
```

上記ポリシーを作成すると、Nepheによってセキュリティグループが新たに作成され、指定したルールが設定されます。

```bash
$ kubectl get networkpolicies.crd.antrea.io  -A
NAMESPACE   NAME     TIER          PRIORITY   DESIRED NODES   CURRENT NODES   AGE
sample-ns   vm-anp   application   100        1               1               8s
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/5d7feb1c-017f-dc67-9d9d-a4d81ca13491.png)

インスタンスを確認すると、セキュリティグループがdefaultからNepheが作成した`nephe-at-7b58a7b...`に変更され、実際にEC2インスタンスにsshすることが可能になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/fd2624a4-175a-8b12-26b6-5a09eb635a8f.png)

## Antrea Network Policyの修正

適用済みのAntrea Network Policyを以下のように修正すると、Security Groupのインバウンドルールが修正されました。

```bash
apiVersion: crd.antrea.io/v1alpha1
kind: NetworkPolicy
metadata:
  name: vm-anp
  namespace: sample-ns
spec:
  priority: 100
  appliedTo:
  - externalEntitySelector:
      matchLabels:
         kind.nephe: virtualmachine
  ingress:
  - action: Allow
    from:
      - ipBlock:
          cidr: 0.0.0.0/0
    ports:
      - protocol: TCP
        port: 22
      - protocol: TCP
        port: 80
```

HTTPプロトコルも新たに通信可能になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/711cbe3f-34b5-ab5c-7fd6-8cf4a13d11c2.png)

## ExternalEntityの自動追加

管理対象のVPCにEC2インスタンスが追加されると、NepheがVPCのEC2インスタンスの追加を検出して、ExternalEntityとして自動的に登録され、Security Groupが適用されます。

```json
{"level":"info","ts":"2022-12-13T01:10:25.265Z","logger":"controllers.NetworkPolicy.CloudSync","msg":"Unable to find resource in tracker","CloudResource":{"Type":"NetworkInterface","Name":"eni-018cc17f075069f9e","Vpc":"vpc-0c63c6f1b66431fe8","AccountID":"sample-ns/cloudprovideraccount-aws-sample","CloudProvider":"AWS"}}
{"level":"info","ts":"2022-12-13T01:10:25.835Z","logger":"controllers.CloudEntitySelector","msg":"discovered compute resources statistics","account":"sample-ns/cloudprovideraccount-aws-sample","virtual-machines":2}
{"level":"info","ts":"2022-12-13T01:10:25.841Z","logger":"setup.virtualmachine-resource","msg":"default","name":"i-0b17b1a575547bd38"}
{"level":"info","ts":"2022-12-13T01:10:25.845Z","logger":"setup.virtualmachine-resource","msg":"validate create","name":"i-0b17b1a575547bd38"}
{"level":"info","ts":"2022-12-13T01:10:25.850Z","logger":"converter.VMConverter.processEvent","msg":"Received event","Key":{"namespace":"sample-ns","name":"virtualmachine-i-0b17b1a575547bd38"},"Agented":false}
{"level":"info","ts":"2022-12-13T01:10:25.854Z","logger":"controllers.CloudEntitySelector","msg":"created","vm-name":"i-0b17b1a575547bd38"}
{"level":"info","ts":"2022-12-13T01:10:25.855Z","logger":"controllers.CloudEntitySelector","msg":"virtual-machine crd statistics","account":"sample-ns/cloudprovideraccount-aws-sample","created":1,"deleted":0,"updated":0}
{"level":"info","ts":"2022-12-13T01:10:25.855Z","logger":"converter.VMConverter.processEvent","msg":"Received event","Key":{"namespace":"sample-ns","name":"virtualmachine-i-0b17b1a575547bd38"},"Agented":false}
```

# まとめ

Antrea Nepheを利用するとKubernetes上のAntrea Network Policyを利用してパブリッククラウド上の仮想マシンの通信の制御が可能になります。AntreaはInterworkingを利用することによりNSX Managerから管理可能になりますが、NepheのAntrea Network PolicyはNSX上で確認することができませんでした。今後NSXからも管理可能になったりするのかもしれません。