<

一足遅れて Kubernetes を学び始める - 15. セキュリティ -

ストーリー

  1. 一足遅れて Kubernetes を学び始める - 01. 環境選択編 -
  2. 一足遅れて Kubernetes を学び始める - 02. Docker For Mac -
  3. 一足遅れて Kubernetes を学び始める - 03. Raspberry Pi -
  4. 一足遅れて Kubernetes を学び始める - 04. kubectl -
  5. 一足遅れて Kubernetes を学び始める - 05. workloads その 1 -
  6. 一足遅れて Kubernetes を学び始める - 06. workloads その 2 -
  7. 一足遅れて Kubernetes を学び始める - 07. workloads その 3 -
  8. 一足遅れて Kubernetes を学び始める - 08. discovery&LB その 1 -
  9. 一足遅れて Kubernetes を学び始める - 09. discovery&LB その 2 -
  10. 一足遅れて Kubernetes を学び始める - 10. config&storage その 1 -
  11. 一足遅れて Kubernetes を学び始める - 11. config&storage その 2 -
  12. 一足遅れて Kubernetes を学び始める - 12. リソース制限 -
  13. 一足遅れて Kubernetes を学び始める - 13. ヘルスチェックとコンテナライフサイクル -
  14. 一足遅れて Kubernetes を学び始める - 14. スケジューリング -
  15. 一足遅れて Kubernetes を学び始める - 15. セキュリティ -
  16. 一足遅れて Kubernetes を学び始める - 16. コンポーネント -

前回

一足遅れて Kubernetes を学び始める - 14. スケジューリング -では、Affinity などで Pod のスケジューリングについて学習しました。今回は、セキュリティについて学習します。

サービスアカウント

Pod で実行するためのプロセスを制御するために割り振られるアカウントのことをサービスアカウントというそうです。

# sample-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sample-serviceaccount
  namespace: default
imagePullSecrets:
  - name: hogehoge

これを apply してみます。

pi@raspi001:~/tmp $ k apply -f sample-serviceaccount.yaml
pi@raspi001:~/tmp $ k get serviceaccounts sample-serviceaccount -o yaml
...
secrets:
- name: sample-serviceaccount-token-4xhgm

サービスアカウントが作成されました。また、imagePullSecrets の内容が secrets に登録されました。(sample-serviceaccount-token-4xhgm) imagePullSecrets は private な docker レジストリに使います。

pi@raspi001:~/tmp $ k get secrets sample-serviceaccount-token-4xhgm -o yaml
apiVersion: v1
data:
  ca.crt: ...
  namespace: ZGVmYXVsdA==
  token: ...
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: sample-serviceaccount
    kubernetes.io/service-account.uid: 4bd076da-8854-11e9-af26-b827eb8ccd80
  creationTimestamp: "2019-06-06T12:12:04Z"
  name: sample-serviceaccount-token-4xhgm
  namespace: default
  resourceVersion: "584634"
  selfLink: /api/v1/namespaces/default/secrets/sample-serviceaccount-token-4xhgm
  uid: 4bfbe8bb-8854-11e9-af26-b827eb8ccd80
type: kubernetes.io/service-account-token

認証に必要な token が登録されていますね。

RBAC (Role Based Access Control)

RBAC は、さきほど作成したサービスアカウントと、どういった操作を許可するのかを定めた Role を紐付け(RoleBinding)して、権限管理をします。1 つの Role に対して複数のサービスアカウントを RoleBinding できます。

RBAC は、2つのレベルがあり、1つは Namespace レベルで、もう一つはクラスタレベルがあります。 設定範囲がクラスタの方が大きい感じです。(namespace 横断して設定する場合はクラスタレベルにする)

  • Role と ClusterRole
  • RoleBinding と ClusterRoleBinding

操作の種類ですが、どの Deployment や DaemonSet のようなリソースに対して下記のものがあります。

*全ての処理
create作成
delete削除
get取得
list一覧取得
update更新
patch一部変更
watch変更の追従

Kubernetes の RBAC について

今回はKubernetes 道場 20 日目 - Role / RoleBinding / ClusterRole / ClusterRoleBinding についてを参考に進めます。

新しく作ったサービスアカウントでコンテキストを作成し、そのアカウントから Pod 情報を取得できるか試してみます。 そのためには、サービスアカウントの認証情報を通しておく必要があります。

※ Role と ClusterRole に大きな違いはないため、Role を試します。

pi@raspi001:~/tmp $ TOKEN=$(k get secret/sample-serviceaccount-token-jd279 -o json | jq -r .data.token)
pi@raspi001:~/tmp $ DECODE_TOKEN=$(echo -n $TOKEN | base64 -d)
pi@raspi001:~/tmp $ k config set-credentials sample-serviceaccount --token $DECODE_TOKEN

では、コンテキスト(sample-sa-context)を作成して、それを使用します。

pi@raspi001:~/tmp $ k config set-context sample-sa-context --user sample-serviceaccount --cluster kubernetes
pi@raspi001:~/tmp $ k config use-context sample-sa-context
pi@raspi001:~/tmp $ k config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO                NAMESPACE
          kubernetes-admin@kubernetes   kubernetes   kubernetes-admin
*         sample-sa-context             kubernetes   sample-serviceaccount

新たに作成したサービスアカウントで Pod の情報が取得できるか試してみます。

pi@raspi001:~/tmp $ k get po
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:sample-serviceaccount" cannot list resource "pods" in API group "" in the namespace "default"

Error になりました。sample-serviceaccount は何も Role をバインドしていないからですね。 では、RoleBinding していきます。

元に戻ります。

pi@raspi001:~/tmp $ k config use-context kubernetes-admin@kubernetes
# sample-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: sample-role
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
# sample-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: sample-rolebinding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: sample-role
subjects:
  - kind: ServiceAccount
    name: sample-serviceaccount
    namespace: default
pi@raspi001:~/tmp $ k apply -f sample-role.yaml
pi@raspi001:~/tmp $ k apply -f sample-rolebinding.yaml

では、もう一度試してみます。

pi@raspi001:~/tmp $ k config use-context sample-sa-context
pi@raspi001:~/tmp $ k get po
NAME                                      READY   STATUS    RESTARTS   AGE
...

おお、取得できました! もとに戻しておきます。

pi@raspi001:~/tmp $ k config use-context kubernetes-admin@kubernetes

SecurityContext

コンテナに対してセキュリティ設定をすることができます。 例えば、Capabilities の追加・削除、実行するユーザ、グループの変更、ファイルの ReadOnly 化などができるそうです。

# sample-capabilities.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-capabilities
spec:
  containers:
    - name: nginx-container
      image: nginx:1.12
      securityContext:
        capabilities:
          add: ["SYS_ADMIN"]
          drop: ["AUDIT_WRITE"]

apply し、中身を確認してみます。

pi@raspi001:~/tmp $ k apply -f sample-capabilities.yaml
pi@raspi001:~/tmp $ k exec -it sample-capabilities /bin/bash
root@sample-capabilities:/# apt update && apt install libcap2-bin
root@sample-capabilities:/# capsh --print | grep Current
Current: = 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_sys_admin,cap_mknod,cap_setfcap+eip
root@sample-capabilities:/# exit

cap_sys_admin が増えてますね。audit_write は見つかりません。 そもそも、どんな種類があるのか分からなかったので、こちらを参考にしました。

PodSecurityContext

Pod(全てのコンテナ)に対してセキュリティ設定をすることができます。 例えば、実行するユーザやグループの制御、root 実行を拒否したり、カーネルパラメータを上書きすることもできます。

# sample-runuser.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sample-runuser
spec:
  securityContext:
    runAsUser: 99
    # runAsGroup: 99
    supplementalGroups:
      - 1001
      - 1002
  containers:
    - name: centos-container
      image: centos:7
      command: ["/bin/sleep", "3600"]

では、apply しています。

pi@raspi001:~/tmp $ k apply -f sample-runuser.yaml
pi@raspi001:~/tmp $ k exec -it sample-runuser -- id
uid=99(nobody) gid=99(nobody) groups=99(nobody),1001,1002
pi@raspi001:~/tmp $ k exec -it sample-runuser -- ps aux | grep sleep
nobody       1  0.0  0.0   2032   372 ?        Ss   14:02   0:00 /bin/sleep 3600

実行したユーザが nobody(99)に変更されていますね。また、supplementalGroups で、プライマリ GID に指定の GID を追加することができます。

そのほか

PodSecurityPolicy や、NetworkPolicy、そして認証、認可の AdmissionControl というものもあるそうです。

お片付け

pi@raspi001:~/tmp $ k delete -f sample-serviceaccount.yaml -f sample-role.yaml -f sample-rolebinding.yaml -f sample-capabilities.yaml -f sample-runuser.yaml
pi@raspi001:~/tmp $ k config delete-context sample-sa-context

最後に

主に RBAC について学習しました。 複数人で開発する際は、コンテキストを分けて開発を進めるのが良いみたいですね。 今回で取り組んだように、誰がどの権限を持っているかを RBAC で管理できるので、 必要以上の権限を与えられて事故るようなことは少なくなりますね。 (といっても、まだ個人でしか使ってないので分かりませんが...) 次回は、最後でこちらです。

役立ったら、☕でサポートしてね!

シェアしよう

関連するタグ