TetrationによるKubernetes環境のポリシー制御を考える

#はじめに

この記事は Cisco Systems 合同会社 社員有志 による Advent Calendar 2019 の 12/25(水) 分になります。
2019年の他のエントリーについては以下を参照下さい。
https://qiita.com/advent-calendar/2019/cisco
同時に、記載の情報は2019/12時点の情報に基づきます。

#Tetrationってなんだ？？

知名度は低いですがCiscoはどんな場所（オンプレ/クラウド）、どんなOS（Windows/Linux/Unix）、どんなプラットフォーム（ベアメタル/仮想マシン/コンテナ環境）で動いていようともホワイトリストポリシーでアプリケーションを守る「ポリシー制御」の製品を持っています。それがCisco Tetrationです。

###**センサーエージェントでポリシーを実行**

Tetrationの仕組みそのものの説明は長くなるので割愛しますが、Tetrationにおけるポリシーの実行ポイントはセンサーエージェントをインストールしているホスト（ベアメタル/仮想マシン/コンテナホスト）内部です。センサーエージェントはTetration本体からホワイトリストポリシーを受け取り、そのポリシーをホストのファイアウォールソフトウェアのルールセットに翻訳して記述することでそのホストが本来通信すべき相手との通信のみを許可し、それ以外を全て拒否する通信ポリシー観点での『ゼロトラスト』を実現します。

#Kubernetes環境でのPod間通信の制御

この記事ではTetrationとKubernetesの連携機能をご紹介していくのですが、機能紹介の前に・・そもそもなぜそんな連携をする必要があるのか・・・みなさん疑問ではありませんか？

**「Network Policy使えばいいじゃん」**
>Network Policyについては[この辺りの記事](https://qiita.com/hirsim/items/972d12c2f7b0f5b6652d)とか参考になるかも・・


そう思った方・・私もそう思います！Kubernetesクラスタ内のアプリケーションをホワイトリストポリシーで守りたいならNetwork Policyという通信制御機能が（CNI依存ではありますが）Kubernetesにはありますのでそれを使えばいいわけです。ただここで皆さんに考えていただきたいのは、そもそもアプリケーションがコンテナだけで完結しているケースがどれほどあるのかという点です。

###**Kubernetesを使う事の意味**

そもそもKuberntesでアプリケーションを構築する理由は何でしょう？？
**『イミュータブルなアプリケーションインフラ環境を実現できる』**
私はこの一点に尽きると思います。（他にも特殊な事情はあるのかもしれませんがここでは一般論として）
これによりアプリケーションに再現性と可搬性が生まれdeploymentとscaleが容易になります。そして大事なポイントはこの利点を最大限享受できるのは**ステートレス**なアプリケーションであるという点です。KubernetesにはPVやPVC等、Podのデータ保持に必要なストレージリソースの定義が可能ですので**ステートフル**なアプリケーションにももちろん使えますが、向き不向きでいうと性質上明らかに**ステートレスアプリケーション**に向いていると言えます。
つまり、Kubernetesを使って構築しているアプリケーションの全体像を3tier appで例えると・・・
![スクリーンショット 2019-12-19 14.13.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/df933a60-b859-921c-ded8-6a1efe7ae667.png)
こうなっているケースは実際は少なく（全くないとは言っていない）・・・・・
![スクリーンショット 2019-12-19 14.37.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/ef915331-4915-f381-0295-2b7e4a230a96.png)
こんな感じになっているケースが多いのではないでしょうか。
例なので極端な書き方をしましたが、言いたい事としてはアプリケーションがKubernetesクラスタ内で完結することは少なく、DB等のステートフル要素のあるコンポーネントは外部のプラットフォーム上で動いていてそれと合わせて1つのアプリケーションとして成立していることが多いという点です。この環境を前提に**アプリケーションをホワイトリストポリシーで守る**ことを考えると、ポリシー制御のポイントとしてそれぞれのプラットフォーム環境のお作法でポリシーの定義をしなければならなくなります。つまりNetwork Policyだけで終わる話では無くなるのです。

#TetrationのKubernetes連携機能

Tetrationはアプリケーションセキュリティの製品です。アプリケーションがどこでどんなプラットフォーム上で動こうがポリシー制御できなければなりません。ポリシーそのものは前述の通りホストOSのファイアウォールルールセットをセンサーエージェントがコントロールすることで実行されますが、Kubernetes環境で動くアプリケーションが対象の場合はここでもう一工夫必要です。センサーエージェントはWorkerノードのホストOSにインストールされますがコンテナそのものにはインストールされていません。そもそもLinuxの場合はiptables(netfilter)のルールセットをコントロールすることでポリシーを実行しますがコンテナはカーネルシェアのテクノロジなのでコンテナローカルでiptables(netfilter)が動くわけではありません。つまり、WorkerノードのホストOSにインストールしたセンサーエージェントがホスト内で動作するPodをNamespace単位でそれぞれポリシー制御する必要があるわけです。

###**連携の仕組み**###

まずTetration本体にKubernetes-master apiserverにAPIアクセスする為の設定が必要です。同時に、Kubernetes-master側にはTetrationからのAPIアクセス用のUserの作成(証明書の作成)とRoleの設定(ClusterRole/ClusterRoleBindingの設定)が必要となります。

>UserとRoleの設定は[この辺りの記事](https://knowledge.sakura.ad.jp/21129/)とか参考になるかも

Kubernetes-master側、Tetration本体側で必要な設定が終わると以下のようにapi連携のコネクションが確立します。
![スクリーンショット 2019-12-20 11.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/fbf5f746-9f78-8989-df32-c522cf55ce5a.png)

これでTetrationはKubernetes-masterからNamespace,Pod,Serivce等の様々なコンテキストデータを得ることができ、Kubernetes上で公開しているServiceやPod間の通信に必要なポリシーをその"コンテキストデータ"を使って表現することができるようになります。そしてそこで定義したポリシーはWorkerノードにインストールされたセンサーエージェント経由で各Namespace毎のiptables(netfiler)のルールセットとして定義、実行されることになります。
![スクリーンショット 2019-12-24 9.40.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/4353b146-6ed1-2cbc-f078-fc24ba442917.png)


###**ポリシーの定義**

前述の通りTetrationではKubernetes-masterから取得したアプリケーションのコンテキストデータ(ServiceやPodの情報)を基にポリシーの定義が可能です。ここから先はLabの環境を使いながら具体的に説明していきます。Labでは以下のようなKubernetes-masterが1台、Workerが3台の環境にアプリケーション"wordpress"を展開しています。

```shell
[root@k8s-master ~]# kubectl get nodes 
NAME         STATUS   ROLES    AGE   VERSION
k8s-master   Ready    master   77d   v1.15.1
k8s-node1    Ready    <none>   77d   v1.15.1
k8s-node2    Ready    <none>   77d   v1.15.1
k8s-node3    Ready    <none>   77d   v1.15.1
```
```shell
[root@k8s-master ~]# kubectl get pods -o wide --namespace=wordpress
NAME                               READY   STATUS    RESTARTS   AGE   IP            NODE   
wordpress-6dfdd9f64f-d75j2         1/1     Running   4          18d   10.244.1.94   k8s-node1
wordpress-mysql-5b58bbd695-gxtc4   1/1     Running   1          18d   10.244.3.18   k8s-node3
```

そしてこの"wordpress"をKubernetesクラスタ外部に向けServiceとして公開しています。

```shell
[root@k8s-master ~]# kubectl get svc wordpress -o wide --namespace=wordpress
NAME        TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE   SELECTOR
wordpress   NodePort   172.18.202.253   <none>        80:30358/TCP   21d   app=wordpress,tier=frontend
```

ポリシーの定義にあたってはまずKubernetes-master経由で取得したコンテキストデータを使ってfilterを作成するところから始めます。wordpressのフロントエンドのwebとバックエンドのmysql間のポリシーを定義したいのでまずはこの2つのPodを表現するfilterを作成します。
![スクリーンショット 2019-12-20 17.15.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/7c129f15-1041-d5f4-8fff-018a18926e45.png)
"pod_name = wordpress-6dfdd9f64f-d75j2"という条件のfilter"Frontend"を作成し、"10.244.1.94"が該当していることが分かります。
![スクリーンショット 2019-12-20 18.31.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/7340c390-b4c7-849d-4a62-9c1c3ef17d1e.png)
"pod_name = wordpress-mysql-5b58bbd695-gxtc4"という条件のfilter"DB"を作成し、"10.244.3.18"が該当していることが分かります。これらのfilterを使い、Tetrationのポリシー定義用のワークスペースでFrontend -> mysqlの通信ポリシーを定義します。
![スクリーンショット 2019-12-20 18.53.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/9e67688f-8443-0b5f-e8a3-efe62639e4bc.png)
これを定義することでWorkerノード1とWorkerノード3のwordpressのnamespaceに
10.244.1.94 -> 10.244.3.18 port 3306 を許可するポリシーが書き込まれます。TetrationのUI上でもWorkerノードに書き込まれたポリシーのルールセットを確認可能です。Pod間の通信ポリシーは"Container Policies"に書き込まれます。
![スクリーンショット 2019-12-24 15.28.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/ddbac7d2-0a56-99ab-6256-2bdfeb3feaba.png)
ご存知の通りPodのIPアドレスは静的なものではなくup/downや起動する場所(Workerノード)により可変です。しかしTetrationではポリシーの定義にIPアドレスではなく"メタデータ"をベースにしたfilterを使います。Kubernetes-masterと常にapi経由でsyncしていますのでPodのIPが変わればfilterに該当するIPアドレスも変わることになりポリシーは常に最新の情報でアップデートされることになります。

#Tetrationの価値
ここまでならNetwork Policyを使っても同様のことが可能です。Tetrationの真の価値はアプリケーションが動く**「全て」**の環境を単一のユーザーインタフェースでポリシー制御できる点にあります。Labの環境ではwordpressのFrontend webの前にHAproxyがあり、構成的には以下の図のように
HAproxy -> wordpress-Frontend -> mysql
となっています。このHAproxyはKubernetesクラスタ外のLinuxの仮想マシンです。
![スクリーンショット 2019-12-23 18.20.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/b7bb843f-aafd-d8ac-cd06-586ab7d05d01.png)

このような構成のアプリケーションをホワイトリストポリシーで守ろうとする場合、Kubernetesクラスタ外のHAproxyも同様にポリシー制御の対象とする必要がありますが、Tetrationはポリシー制御の対象がKubernetesクラスタ内のPodでも外の仮想マシンでもベアメタルサーバでも、動作しているプラットフォームを意識することなくポリシーの定義とその実行が可能です。HAproxyとwordpress-Frontendの間のポリシーの定義にはwordpressの"Service"を表現するfilterを作成する必要があります。

![スクリーンショット 2019-12-23 18.54.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/ede34c44-d6cd-ea7f-e6cb-9df75bb85286.png)
serviceの表現にはfilterの条件として"service_name = wordpress"を使います。該当するinventoryがないのはServiceがPod等の実際のIPアドレスを持った実体ではなく論理的なオブジェクトだからです。ポリシーの定義には影響しませんのでここは気にしないでください。

![スクリーンショット 2019-12-23 19.01.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/24d8bffe-8e43-9aba-5e9d-36e6df1379cc.png)
HAproxyを表現するfilterは単純にHAproxyのIPアドレスを条件にすればいいので"Address = 172.18.221.1"となります。もしくはHAproxy固有のタグ情報などのメタデータがあればそれを利用してfilterを作成します。filterを作成したら先ほどと同様にTetrationのポリシー定義用のワークスペースでHAproxy -> wordpress-Frontend間の通信ポリシーを定義します。
![スクリーンショット 2019-12-24 10.15.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/dc313b67-5446-6672-0367-225799695358.png)
ここでのポイントは通信ポートの設定を"port 80"としている点です。wordpressはNodePort:30358としてServiceを公開していますのでこのケースでは本来port 30358を設定すべきですが、NodePortで使われるポート番号はダイナミックアサインでかつ規則性はありません。Tetrationは本来このアプリケーションが持つ**"port 80でサービスを公開"**という性質のままポリシー定義が可能なのです。port 80でポリシーを定義しても実際にHAproxyのiptablesルールセットにはport 30358でポリシーが定義されます。
![スクリーンショット 2019-12-24 12.32.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530018/bf688fe5-715b-c5f9-0bda-c2f8ee1530a9.png)
まさに**イミュータブルな性質**を持つKubernetesインフラ環境に合わせた実装と言えます。

(参考情報)
商用環境ではNodePortは使わずにtype:LoadBalancerでService作成することが多いと思いますが、TetrationはそのようなケースでもKubernetese-masterとAPI連携しつつF5のLoadBalancerにAPI経由で必要な設定を投入する連携機能も持ち合わせています。

#まとめ
アプリケーションが動作する場所やプラットフォームなど環境の違いによりポリシーの実装方式や設定方法がバラバラになり、それが余計な管理工数を生み、またそのことが環境毎のセキュリティレベルの差異やセキュリティホールに繋がったり、ということは本来避けねばなりません。今回はKubernetesとの連携機能のみにフォーカスしましたが、TetrationにとってKubernetesはアプリケーション環境の1つでしかありません。Tetrationはどんな場所・どんなプラットフォームで動くアプリケーションにも単一のユーザーインタフェースによるシンプルなポリシー定義を可能にします。また、今回はフォーカスしませんでしたがTetrationはプラットフォームに内在するソフトウェア脆弱性を把握しそれをポリシー定義に利用することもできます。アプリケーションセキュリティを検討している方の参考にしていただければ幸いです。


#免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。