Kubernetes勉強会第2回 〜RBAC、セキュリティを高める方法、PodSecurityPolicy、NetworkPolicy〜

Kubernetes in Action

Kubernetes in Action

「Kubernetes in Action」を読んで学んだ結果を社内で共有しました。 その第2回の内容です。

RBAC

KubernetesのRBACについて

13. Securing cluster nodes and the network

nodeのネットワークを使用する方法

  • podが自身のvirtualネットワークではなく、nodeのネットワークを使いたい場合、 hostNetworkプロパティを設定すればOK。
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-host-network
spec:
  hostNetwork: true #これ
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
  • hostNetworkプロパティをtrueにすれば、nodeあてのネットワークアクセスはそのpodに届くことになる

  • Kubernetes Control Plane components がpodとしてdeployされるとき、hostNetworkがONでデプロイされる。

    • なのでまるでpodの中で動いていないように振る舞う
  • 同じようにnodeのportを使いたい場合は、hostPortを設定すればOK。
    • しかしその場合、そのpodはnodeに1つしか配置できない。なぜなら同じportを複数のpodで使えないから。
  • 同じように hostPID: true、 hostIPC: true もできる
  • もしGCP上でこれらを試したい場合は、 gcloud compute firewall-rulesコマンドを使って設定する必要がある。参考

コンテナのプロセス実行ユーザを制限する

  • podのコンテナのプロセスの実行ユーザを限定する方法として、以下のようにユーザidを指定できる
apiVersion: v1
kind: Pod
metadata:
  name: pod-as-user-guest
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      runAsUser: 405 # これ

またrootユーザとしてコンテナのプロセスを実行することを防ぐことができる 例えばhostディレクトリをマウントするコンテナが会った場合、rootユーザであればそのマウントしたディレクトリにフルアクセスできてしまう。しかしrootユーザ以外で動かせばそうではない。

apiVersion: v1
kind: Pod
metadata:
  name: pod-run-as-non-root
spec:
  containers:
  - name: main
    image: alpine
    command: ["/bin/sleep", "999999"]
    securityContext:
      runAsNonRoot: true #これ

セキュリティをあげるための方法

  • podのコンテナのプロセスの実行ユーザを限定する(user idを指定)
  • コンテナのプロセスをrootで動かさない
  • コンテナをprivilegedで動かすと、nodeのカーネルにフルアクセスできてしまうので避ける
  • SELinuxを設定する
  • コンテナがfileシステムに書き込めないようにする(=read only)に設定する。
    • コンテナのreadOnlyRootFilesystemをtrueに
  • readonlyにしつつ、特定のvolumeは書き込めるようにもできる

またlinuxcapabilitiesをコンテナに指定することができる

SecurityContextをもっと詳しく知るためには以下を参照

13.3 Restricting the use of security-related features in pods

PodSecurityPolicyリソース

PodSecurityPolicyリソースとは

参考: Pod Security Policies

PodSecurityPolicy とはクラスタ全体のセキュリティ上のポリシーを定義する機能です。ホストに影響を与える可能性がある 特権 (privileged) や HostIPC などの機能を制限し Pod に脆弱性があった場合にクラスタを守ることができます。

引用元: Kubernetes: Pod Security Policy によるセキュリティの設定 PodSecurityPolicyに関しては上記の記事を読めば十分。(Z Labのエンジニアは本当に強い…)

PodSecurityPolicyはクラスタレベルのリソースです。 pod内でどんな機能が使えるのかもしくは使えないのかを定義することができます。 PodSecurityPolicyは働くためにはPodSecurityPolicy admission control pluginが API serverで動いている必要があります。

もし誰かがPodリソースを作成(API Serverへpost)しようとした場合、PodSecurityPolicy admission control pluginはPodの定義を定義されたPodSecurityPolicyに反していないかバリデートします。 もしクラスタのPolicyに従っていれば受け入れられetcdに保存されます。従っていなければ即時に却下されます。 PodSecurityPolicy admission control pluginはPodリソースをpolicyの設定に沿って変更するかもしれません(例えばコンテナ実行ユーザをPodSecurityPolicyで指定したユーザにoverrideすることができる)。 ちなみにpolicyを新しく作成しても既存のpodには影響を与えません。なぜならPodSecurityPoliciesはpodが作成/更新されるとき適用されるため。

PodSecurityPolicyで制限できること

  • どのpodがホストのIPC, PID or Network namespaceを使用できるか
  • どのホストポートをpodが使えるか
  • どのユーザでコンテナのプロセスを動かすか
  • privileged containeを持ったpodを作れるかどうか
  • どの kernel capabilitieを許可するか、またデフォルトでどのkernel capabilitieを追加or削除するか
  • どんな SELinuxLabelをコンテナが使うか
  • コンテナがrootファイルシステムを書き込み許可するかどうか
  • コンテナがどのfile system groupを実行できるか
  • podがどのvolumeタイプを使用できるか

apiVersion: extensions/v1beta1
  kind: PodSecurityPolicy
  metadata:
    name: restricted-psp
  spec:
    hostIPC: false   
    hostPID: false
    hostNetwork: false
    hostPorts:    # 使用できるport rangeを指定
    - min: 10000
      max: 11000
    - min: 13000
      max: 14000
    privileged: false
    readOnlyRootFilesystem: true
    runAsUser:
      rule: RunAsAny
    fsGroup:
      rule: RunAsAny
    supplementalGroups:
      rule: RunAsAny
    seLinux:
      rule: RunAsAny # コンテナが必要とするどんなSELinux groupも使用することができる
    volumes: 
    - '*'            # 全てのvolume typeを使用することができる

PodSecurityPolicyをRoleとして定義でき、RBACによって、ServiceAccountに紐付ける(bindingする)ことができる。

# 先のPodSecurityPolicyリソースを作成
& kubectl create -f restricted-psp.yaml

# PodSecurityPolicyをClusterRoleとして定義
$ kubectl create clusterrole psp-cluster-role --verb=use --resource=podsecuritypolicies --resource-name=restricted-psp

# ServiceAccountを作成
$ kubectl create serviceaccount psp-service-account

# ClusterRoleをServiceAccountに紐付ける(binding)
$ kubectl create clusterrolebinding psp-restricted --clusterrole=psp-cluster-role \
    --serviceaccount=default:psp-service-account

# あとはpodにServiceAccount:psp-service-accountを指定して、例えばprivileged: trueにするとpodは作成できなくなる。

13.4 Isolating the pod network

Network Policies

もしnetworking pluginがpod間のネットワーク通信制限機能をサポートしていれば、NetworkPolicyリソースを作成することによって、 ネットワークの隔離をすることができる。 NetworkPolicyリソースはlabel selectorにマッチしたpodに対して適用される。そしてpodへの外への通信とpodの中への通信を制限することができる。 ingress rule, egress ruleと呼ばれる。Ingressリソースとは関係がない。 ingressはネットワークの流入、egressはネットワークの流出のルールを定義できる。

このpodはこのpodへしかリクエストを送れないor受け取れないとかこのportを使ってしかあのpodへリクエストを送れないor受け取れないとかが設定できる。 また特定のlabelがついたnamespace内のpodからリクエストを受け取らないということができる。 もしくはcidrを使ってリクエストを制限することもできる。

例:

以下のingress/egressルールにマッチするものだけ通信が許可される。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
spec:
  podSelector:
    matchLabels:
      role: db # このlabelを持ったpodがこのNetworkPolicyルールの対象になる
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

13.5 Summary

  • podは自分のではなくnodeの Linux namespacesを使うことができる
  • コンテナはコンテナイメージで指定されたユーザ/グループとは別のユーザ/グループで実行するように設定することができる
  • コンテナはprivileged modeで動かすことができ、privileged modeだとpodに公開されていないnodeのdeviceにアクセスすることができる。
  • コンテナはプロセスがファイル書き込みをしないようにread onlyで動くように設定することができる(また特定のvolumeのみ書き込みが可能に設定できる)
  • Cluster-levelリソースであるPodSecurityPolicyは、nodeの安全を脅かすpodの生成を防ぐことができる。
  • PodSecurityPolicyはRBACのClusterRoleとClusterRoleBindingを使って特定のuserに紐付けることができる。
  • NetworkPolicyリソースはpodのinbound/outbound trafficを制限することができる。

Podのセキュリティを高めるためには以下を参照

Kubernetesのセキュリティを高めるためには以下を参照