Save 37% off PRO during our Black Friday Sale! »

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

B49933741d74e122bc1314b2975e9fc9?s=47 mrtc0
August 12, 2021

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

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

B49933741d74e122bc1314b2975e9fc9?s=128

mrtc0

August 12, 2021
Tweet

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. Linux コンテナの仕組み コンテナは Linux の仕組みを利用して隔離されたプロセス。様々な隔離技術を使っているが VM ほど分 離レベルは高くない。

  5. コンテナの主要技術 詳しくは https://container-security.dev/ を見てください

  6. コンテナセキュリティのポインタ • 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 をもとに紹介します。
  7. Docker 環境への攻撃ベクトルイメージ 💡 OWASP Docker TOP 10 の Threat Modeling

    も参考になります
  8. 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 バイナリを上書きし任意のコード実行が可能。 事例
  9. 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":[]}
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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)
  15. 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 で制限する。
  16. コンテナから読み書きできてはいけないファイル • /proc や /sys 配下などにはカーネルとやり取りするインターフェイスが存在するため、Read Only としてマウントしたり LSM でアクセスを制御している

    / # echo 1 > /proc/sysrq-trigger sh: can't create /proc/sysrq-trigger: Read-only file system / # cat /proc/kcore cat: can't open '/proc/kcore': Permission denied
  17. 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 等もチェックする。
  18. コンテナイメージへのクレデンシャルの混入 • イメージビルド時にプライベートリポジトリなど認証が必要な操作を行う場合、イメージレイヤに クレデンシャルが残ってしまうため 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 …
  19. コンテナイメージの改竄 • レジストリに不正アクセスされてイメージが改竄されるなど、コンテナイメージのエコシステムに はサプライチェーン攻撃のリスクがある • イメージの整合性を検証する 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
  20. Kubernetes の概要

  21. Kubernetes のセキュリティ • コンテナ(ランタイム)セキュリティ + Kubernetes のコンポーネントのセキュリティ

  22. 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
  23. Kubernetes API • コントロールプレーンにある Kubernetes API を外部に公開するフロントエンド。Kubernetes 利 用者はこの API

    を介してリソースを操作するため、認証が必須 • Kubernetes では様々な認証機能があるが OIDC / IAM Provider による認証がオススメ AuthN / AuthZ の流れ • AuthN … リクエストに含まれる資格情報が正しいか検証する • AuthZ … 認証されたユーザーが該当リソースへの権限を持っているか検証する • Admission Controller … リクエスト内容の検証や書き換えなどを行う
  24. 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 を拒否できる
  25. Kubernetes API https://hackerone.com/reports/455645

  26. 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"
  27. 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 は権限がほとんどないため、実質何もできな い
  28. 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
  29. 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..."
  30. Network デフォルトではすべての Pod が互いに通信することが可能であるため、コンテナに侵入された場合に横 展開される。また、マネージドサービスの場合は Metadata Server にアクセスされ権限昇格に繋がる。 EKS の場合

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

    … auditd ではコンテナのID/名前などは拾えない アンチウィルス … 既存の AV はコンテナに対応している? • 一つのクラスタに複数のロール/アプリケーションが動くようになり、Attack Surfaces が増え、 横展開、権限昇格の脅威が大きくなっている • コンテナ化によって依存パッケージの減少など、小さくてセキュアな環境が構築できるようにな り、アップデート戦略も比較的容易になった • Immutable な環境のため、「異常」を検知しやすくなった
  32. 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]
  33. OpenPolicyAgent • IaC と同様に「あるべき状態」を宣言し、ドリフトを検知するようなセキュリティテストや異常検 知がクラウドネイティブ環境でも大きなテーマとして扱われている • 宣言的なセキュリティポリシーフレームワークである Open Policy Agent

    は Istio / Envoy や Kubernetes Admission Controller として AuthN / AuthZ ロジックを定義できる
  34. CNCF Landscape (Security) https://landscape.cncf.io/

  35. これからのクラウドネイティブセキュリティ • クラウドネイティブなアーキテクチャでは、それぞれの開発工程でセキュリ ティを取り入れる必要があり、セキュリティ設計力が求められる • 組織の全員がセキュリティ, 信頼性に対して責任を持つ文化作り • 良いサービス(=安定性, 頻繁なデプロイなど)を提供するために、セキュリ

    ティに関しても復旧も視野にいれた自動化の仕組みを実現していく