Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践コンテナ & Kubernetes セキュリティ

mrtc0
August 12, 2021

実践コンテナ & Kubernetes セキュリティ

/dev/hardening - Hardening Drivers Conferences 2021
OWASP Evening 2021.08 - Container Security / Privacy by Design

mrtc0

August 12, 2021
Tweet

More Decks by mrtc0

Other Decks in Technology

Transcript

  1. 実践コンテナ & Kubernetes セキュリティ /dev/hardening - Hardening Drivers Conferences 2021

    OWASP Evening 2021.08 - Container Security / Privacy by Design Kohei Morita / @mrtc0 GMO Pepabo, Inc. / OWASP Fukuoka https://flic.kr/p/a3NYdi #devhardening
  2. Kohei Morita / @mrtc0 GMO ペパボ セキュリティ対策室 シニアエンジニア OWASP Fukuoka

    Chapter Leader セキュリティ・キャンプ 講師 / ステアリングコミッティ https://blog.ssrf.in
  3. 今日話すこと • OWASP Docker Security Cheat Sheet を題材にコンテナ、Dokcer への攻撃例と対策について •

    コンテナを運用するツールとして注目を集めている Kubernetes への攻撃例と対策について • CloudNative セキュリティについて
  4. コンテナセキュリティのポインタ • OWASP Docker Security Cheat Sheet https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html • OWASP

    Docker TOP 10 https://github.com/OWASP/Docker-Security • NIST SP 800-190 Application Container Security Guide https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf • CIS Docker Benchmarks https://www.cisecurity.org/benchmark/docker/ OWASP Evening ということで OWASP Docker Security Cheat Sheet をもとに紹介します。
  5. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #0 - Keep

    Host and Docker up to date ホストと Docker を最新版にアップデートすること。 コンテナはホストとカーネルを共有しているため、カーネルの脆弱性によってはホスト側にエスケープ(BreakOut)でき る。 Dirty Cow … カーネルの脆弱性。Docker コンテナからホストに Breakout が可能。 Shocker … CAP_DAC_READ_SEARCH が許可されていたため、コンテナからホストのファイルシステムにアクセスできた。 CVE-2019-5736 … 細工されたコンテナを実行することで runc バイナリを上書きし任意のコード実行が可能。 事例
  6. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #1 - Do

    not expose the Docker daemon socket (event to the containers) Docker の API を叩くソケット /var/run/docker.sock を誰でも叩ける状態にしないこと。この API を利用してホスト側に Breakout することが可能。rootful Docker の場合は root 権限を取得される。 外部に公開する場合は TLS の設定が必要になるが、CA の管理などが煩雑。そのため、 DOCKER_HOST=ssh://user@host などで SSH での利用がオススメ。また、authz Plugin を使う手もある。 # host の / をマウントしたコンテナを作成 root@3ba2c2752b26:/# curl -L \ --unix-socket /var/run/docker.sock \ -X POST \ -H 'Content-Type: application/json' \ --data-binary '{..., "Image": "ubuntu","Volumes": {"/hostfs/": {}},"HostConfig": {"Binds": ["/:/hostfs"]}}' \ http://v1.24/containers/create ... {"Id":"8e15f2d344fa7bf9588f82a097e7c506429b936e85bc2a60350a018a7277403f","Warnings":[]}
  7. non-root ユーザーによる Docker 操作 • Docker をインストールしたあとに一般ユーザーでも Docker を操作できるように sudo

    usermod -aG docker $USER するケース • Docker Daemon が root で動いている場合、コンテナの作成を通じて root を取得できる $ id uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),4(adm), ... 998(docker) # host の / をコンテナの /hostfs にマウント $ docker run --rm -it -v /:/hostfs alpine:latest head /hostfs/etc/shadow root:!$6$zk2YoWYaQiea6.jg...:18564:0:99999:7::: … # host の /root/.ssh/authorized_keys に書き込み $ docker run --rm -it -v /:/hostfs alpine:latest sh # echo ‘ssh-rsa AAAAB…’ >> /hostfs/.ssh/authorized_keys
  8. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #2 - Set

    a user Breakout された場合の影響を小さくするためにコンテナ内のユーザーを非特権にする。 • docker run 時に -u オプションで指定する • Dockerfile で USER 命令で指定する • userns-remap を使う ◦ User Namespace を使って UID を re-map するのでコンテナ内では root として動かすことができる ~$ docker run --rm -it alpine:latest sleep 10 ~$ ps aux | grep sleep root 3225 0.6 0.0 1568 4 pts/0 Ss+ 06:39 0:00 sleep 10 ~$ docker run --rm -it -u 000 alpine:latest sleep 10 ~$ ps aux | grep sleep vagrant 3372 1.0 0.0 1568 4 pts/0 Ss+ 06:40 0:00 sleep 10
  9. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #3 - Limit

    capabilities (Grant only specific capabilities, needed by a container) --privileged を使うとすべての Capability が追加されるため、必要に応じて --cap-drop で落とすか、--cap-add で追加 するのが望ましい。 また、特定の Capability の追加は Breakout の原因となるため注意。 ubuntu@docker:~$ docker run --cap-add syslog --rm -it ubuntu:20.04 root@1577bebb133d:/# dmesg | head [ 0.000000] Linux version 5.4.0-47-generic (buildd@lcy01-amd64-014) (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)) #51-Ubuntu SMP Fri Sep 4 19:50:52 UTC 2020 (Ubuntu 5.4.0-47.51-generic 5.4.55) [ 0.000000] Command line: earlyprintk=serial console=ttyS0 root=/dev/vda1 rw panic=1 no_timer_check [ 0.000000] KERNEL supported cpus: [ 0.000000] Intel GenuineIntel [ 0.000000] AMD AuthenticAMD ... root@1577bebb133d:/# dmesg -C root@1577bebb133d:/# dmesg
  10. Privileged Container • 特権コンテナは強力な権限を持っているほか、Seccomp なども適用されないため、ホストとの分離 が弱い • 攻撃例 ◦ keyctl(2)

    で鍵を取得 ◦ カーネルモジュールのロード ◦ その他 cgroup release_agent や uevent_helper, core_pattern, binfmt_misc などの call_usermodehelper_exec を呼び出す機能で Breakout https://asciinema.org/a/361484 https://asciinema.org/a/361483
  11. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #4 - Add

    –no-new-privileges flag setuid / setgid バイナリによる権限昇格を防ぐために no-new-privileges オプションを使う。 No New Privileges は子プロセスが新しい特権を取得できないようにする Linux の機能。 # Dockerfile FROM ubuntu:18.04 RUN cp /bin/bash /bin/bash2 && chmod 4755 /bin/bash2 RUN useradd -ms /bin/bash newuser USER newuser CMD ["/bin/bash"] $ docker run -it --rm test:latest newuser@985fc45b58c1:/$ id uid=1000(newuser) gid=1000(newuser) groups=1000(newuser) newuser@985fc45b58c1:/$ /bin/bash2 -p bash2-4.4# id uid=1000(newuser) gid=1000(newuser) euid=0(root) groups=1000(newuser) $ docker run -it --security-opt=no-new-privileges:true --rm test:latest newuser@d96857132041:/$ id uid=1000(newuser) gid=1000(newuser) groups=1000(newuser) newuser@d96857132041:/$ /bin/bash2 -p newuser@d96857132041:/$ id uid=1000(newuser) gid=1000(newuser) groups=1000(newuser)
  12. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #5 - Disable

    inter-container communication (--icc=false) デフォルトで Docker コンテナはすべてのコンテナと通信ができる。コンテナ間の通信を制限するには Docker Daemon のオプションに icc=false を設定する。コンテナ間の通信を許可する場合は --link オプションで指定する。 RULE #6 - Use Linux Security Module (seccomp, AppArmor, or SELinux) LSM を使って保護する。Debian / Ubuntu などでは AppArmor, CentOS / RHEL などでは SELinux が使われる。 どれもデフォルトのプロファイルが適用されており、カーネルの脆弱性や Breakout を防ぐ / 緩和するために機能してい るため、無効にするべきではない。 RULE #7 - Limit resources (memory, CPU, file descriptors, processes, restarts) DoS 対策のためにメモリや CPU の使用量などを cgroup や ulimit で制限する。
  13. OWASP Docker Security Cheat Sheet で見るコンテナセキュリティ RULE #8 - Set

    filesystem and volumes to read-only コンテナのファイルシステムを read-only にすることで、そもそも改ざんされないようにする。 一時ファイルなどについては tmpfs をマウントする。 RULE #9 - Use static analysis tools コンテナイメージに含まれるパッケージの脆弱性スキャンを行う。Docker などのコンテナランタイム自体の設定ファイル も inspec などを利用して設定ミスを検出する。 RULE #11 - Lint the Dockerfile at build time にあるように、ベースイメージの pinning 等もチェックする。
  14. コンテナイメージへのクレデンシャルの混入 • イメージビルド時にプライベートリポジトリなど認証が必要な操作を行う場合、イメージレイヤに クレデンシャルが残ってしまうため docker history やイメージのエクスポートで漏洩する可能性 がある • Docker

    では buildkit を使うことで安全にクレデンシャルを扱うことができる FROM ubuntu:20.04 … RUN --mount=type=secret,id=aws,target=/home/user/.aws/credentials,uid=1000 \ aws s3 cp … docker build --secret id=aws,src=$HOME/.aws/credentials …
  15. コンテナイメージの改竄 • レジストリに不正アクセスされてイメージが改竄されるなど、コンテナイメージのエコシステムに はサプライチェーン攻撃のリスクがある • イメージの整合性を検証する Docker Content Trust を利用する

    ◦ Publisher は秘密鍵でイメージに署名 ◦ User が Pull する際は Publisher の公開鍵などを利用し整合性と作成者を検証 • タグではなく digest を指定することで不正なイメージの意図しないデプロイを防ぐことができる docker run alpine:be9bdc0ef8e96dbc428dc189b31e2e3b05523d96d12ed627c37aa2936653258c ~ $ docker trust inspect --pretty ubuntu:latest Signatures for ubuntu:latest SIGNED TAG DIGEST SIGNERS latest c95a8e48bf88e9849f3e0f723d9f49fa12c5a00cfc6e60d2bc99d87555295e4c (Repo Admin) Administrative keys for ubuntu:latest Repository Key: 8273733f491f362bb36710fd8a99f78c3fbaecd8d09333985c76f1064b80760f Root Key: 1f9bc7ae6335ae41ee03e983c0e31303901be567b4cdb3fc7c7363f0591128ff
  16. Kubernetes セキュリティのポインタ • OWASP Kubernetes Security Cheat Sheet https://cheatsheetseries.owasp.org/cheatsheets/Kubernetes_Security_Cheat_Sheet.html •

    CIS Kubernetes Benchmark https://www.cisecurity.org/benchmark/kubernetes/ • Kubernetes Hardening Guidance - CISA / NSA https://media.defense.gov/2021/Aug/03/2002820425/-1/-1/1/CTR_KUBERNETES%20HAR DENING%20GUIDANCE.PDF
  17. Kubernetes API • コントロールプレーンにある Kubernetes API を外部に公開するフロントエンド。Kubernetes 利 用者はこの API

    を介してリソースを操作するため、認証が必須 • Kubernetes では様々な認証機能があるが OIDC / IAM Provider による認証がオススメ AuthN / AuthZ の流れ • AuthN … リクエストに含まれる資格情報が正しいか検証する • AuthZ … 認証されたユーザーが該当リソースへの権限を持っているか検証する • Admission Controller … リクエスト内容の検証や書き換えなどを行う
  18. Kubernetes API Anonymous Request • 認証情報を含まないリクエストを送信すると Anonymous Request として処理される •

    このとき RBAC としては system:anonymous User と system:unauthenticated Group になる • もしこのロールに権限を付与した場合、外部からクラスタを操作できてしまうことに繋がる ❯ curl -k https://192.168.99.110:8443/api/v1/namespaces/ { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "namespaces is forbidden: User \"system:anonymous\" cannot list resource …”, "reason": "Forbidden", "details": { "kind": "namespaces" }, "code": 403 } ❯ curl -k https://192.168.99.110:8443/api/v1/namespaces/ { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "Unauthorized", "reason": "Unauthorized", "code": 401 } kube-apiserver に anonymous-auth=false を設定することで Anonymous Request を拒否できる
  19. kubelet • Node で実行される Pod の管理を行うエージェント。API を通して Pod の一覧やコンテナでコマン ドの実行が可能。

    • kube-apiserver 同様に Anonymous Request の拒否と Authorization Mode を適切に設定するこ とを推奨 $ curl -s -k https://localhost:10250/pods | jq .items[].metadata.name "coredns-558bd4d5db-wn86h" "test" "etcd-minikube" "kube-apiserver-minikube" "kube-controller-manager-minikube" "kube-scheduler-minikube" "storage-provisioner" "kube-proxy-6hkc6"
  20. ServiceAccount • ServiceAccount Token は Pod の /var/run/secrets/kubernetes.io/serviceaccounts/ 配下にマウ ントされる

    • Pod が侵害された場合は、その ServiceAccount の権限に応じてリソースの操作が可能になる root@test:/# ls /var/run/secrets/kubernetes.io/serviceaccount/ ca.crt namespace token root@test:/# KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) root@test:/# curl -sSk \ -H "Authorization: Bearer $KUBE_TOKEN" \ https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/default/pods/$HOSTNAME ... "status": "Failure", "message": "pods \"test\" is forbidden: User \"system:serviceaccount:default:default\" …”, "reason": "Forbidden", ... • 例えば Job を生成するような権限を持った SA Token がマウントされている場合は Privileged コンテナや hostPath マウントするようなコンテナを作り、権限昇格が可能になる • default SA に権限を付与しない、automountServiceAccountToken を設定して自動でマウントしないなど ✍ デフォルトでマウントされる default SA は権限がほとんどないため、実質何もできな い
  21. Secrets • Secret の manifest は Base64 でエンコードされているだけなので GitOps と相性が悪いため、暗

    号化等が必要 既存のツールがたくさんある。それぞれ Pros / Cons あるので、クラスタに合わせて利用するツー ルを選定すると良い。 • vault-k8s • external-secrets • sealed-secrets • SOPS • bank-vaults • kubesec apiVersion: v1 data: password: cEBzc3cwcmQ= kind: Secret metadata: creationTimestamp: null name: password
  22. etcd • Kubernetes クラスタのデータを保管する KV Store として利用されている。Secret も含まれているのでアクセス 制御と暗号化を行う必要がある •

    多くの場合は TLS クライアント認証が用いられるようになっているが、暗号化はデフォルトで行われない ❯ kubectl create secret generic password --from-literal=flag='p@ssw0rd' secret/password created $ ETCDCTL_API=3 etcdctl \ --endpoints https://127.0.0.1:2379 \ --cacert /var/lib/minikube/certs/etcd/ca.crt \ --key /var/lib/minikube/certs/etcd/healthcheck-client.key \ --cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \ get -w fields /registry/secrets/default/password ... "Value" : "k8s\x00\n\f\n\x02v1\x12\x06Secret\x12\xcc\x01\n\xaf\x01\n\bpassword\x12\x00\x1a\adefault\"\x00*$12610d47-8a48-4b6f-bbe7-2f0f73150f282\x008\x 00B\b\b͈ͥ\x06\x10\x00z\x00\x8a\x01_\n\x0ekubectl-create\x12\x06Update\x1a\x02v1\"\b\b͈ͥ\x06\x10\x002\bFieldsV1:-\n+{\"f:data\":{\".\":{},\"f:flag\":{}},\" f:type\":{}}\x12\x10\n\x04flag\x12\bp@ssw0rd\x1a\x06Opaque\x1a\x00\"\x00" # 平文で保存されている ... # 暗号化するとこうなる "Value" : "k8s:enc:aesgcm:v1:key1:ZZS(՝Uu\x1e\x81\xc0owc\x83j\x8e\x05\x8b\a(\x85\xb2\x0e\x8dd%\xc9!\xeey7\x..."
  23. Network デフォルトではすべての Pod が互いに通信することが可能であるため、コンテナに侵入された場合に横 展開される。また、マネージドサービスの場合は Metadata Server にアクセスされ権限昇格に繋がる。 EKS の場合

    インスタンス情報の取得 VPC, SecurityGroup 情報の取得 ECR リポジトリからイメージの取得 GKE の場合 Metadata に含まれるクレデンシャルを使って kubelet に なりすまし、Secret などの取得が可能 Network Policy を使い、特定の Pod 同士のみが疎通できるようにする。 Istio などを用いてアプリケーション(Sidecar)同士が認証するなど、サービスメッシュによる通信制御を行う。 対策
  24. クラウドネイティブ化によるセキュリティの変化 • 一方で、従来の守り方では通用しない点も出てきている FIM … コンテナのファイルシステムを Read Only にできない場合、どう検知する? コマンド実行監視

    … auditd ではコンテナのID/名前などは拾えない アンチウィルス … 既存の AV はコンテナに対応している? • 一つのクラスタに複数のロール/アプリケーションが動くようになり、Attack Surfaces が増え、 横展開、権限昇格の脅威が大きくなっている • コンテナ化によって依存パッケージの減少など、小さくてセキュアな環境が構築できるようにな り、アップデート戦略も比較的容易になった • Immutable な環境のため、「異常」を検知しやすくなった
  25. Falco • カーネルモジュール / eBPF などを利用してシステムコールや Kubernetes の audit ログを監査するツール

    例えば... • Pod 内で execve が発行されプロセスが Spawn された • /etc や /usr/bin などの特定のディレクトリやファイルに変更があった • Pod から不審なサーバーに接続した • Secret にアクセスがあった などなどを YAML ベースのルールをもとに検知&アラート発砲できる - rule: Launch Privileged Container desc: Detect the initial process started in a privileged container. condition: > container_started and container and container.privileged=true and not falco_privileged_containers and not user_privileged_containers output: Privileged container started ... priority: INFO tags: [container, cis, mitre_privilege_escalation, mitre_lateral_movement]