Chuyển đến nội dung chính

レッスン7: SecurityContext, Capabilities & ServiceAccounts

SecurityContextのPodレベルとContainerレベル設定: runAsUser、runAsNonRoot、readOnlyRootFilesystem。 Linux capabilities。ServiceAccountの作成とバインド、automountServiceAccountToken。

SecurityContext — Podレベル vs Containerレベル、Linux capabilities

1. SecurityContext

SecurityContextはPodまたはContainerの権限とアクセス制御を定義します。

apiVersion: v1
kind: Pod
spec:
  securityContext:            # Podレベル: 全コンテナに適用
    runAsUser: 1000           # コンテナ実行UID
    runAsGroup: 3000          # プライマリGID
    fsGroup: 2000             # マウントボリュームのGID
    runAsNonRoot: true        # root実行を拒否

  containers:
  - name: app
    image: myapp
    securityContext:          # Containerレベル: Podレベルをオーバーライド
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true   # ルートFSを読み取り専用にマウント
      capabilities:
        add: ["NET_BIND_SERVICE"]    # capabilityを追加
        drop: ["ALL"]               # すべてdropし、必要なもののみ追加
設定項目レベル効果
runAsUserPod/Container特定のUIDでプロセスを実行
runAsNonRootPod/ContainerUID = 0(root)の場合は実行を拒否
readOnlyRootFilesystemContainerルートファイルシステムを読み取り専用でマウント
allowPrivilegeEscalationContainer権限昇格(sudoなど)をブロック
privilegedContainer特権モードで実行(ホスト上のrootと同等)
fsGroupPodボリュームファイルのGID(共有ボリュームアクセス用)

試験のポイント: ContainerレベルのsecurityContextはPodレベルの設定をオーバーライドします。PodにrunAsUser: 1000、コンテナにrunAsUser: 2000が設定されている場合、そのコンテナはUID 2000で実行されます。よく出題されるパターン: kubectl exec pod -- idまたはwhoamiでユーザーを確認。

2. Linux Capabilities

Capabilitiesにより、完全なroot権限なしで特定の権限を付与できます。

# よく使われる例:
NET_BIND_SERVICE  — 1024未満のポートにバインド(例: ポート80)
NET_ADMIN         — ネットワーク管理(ifconfigなど)
SYS_TIME          — システムクロックの変更
CHOWN             — ファイル所有者の変更
SETUID/SETGID     — ユーザー/グループIDの変更

securityContext:
  capabilities:
    drop: ["ALL"]             # ベストプラクティス: まずすべてdrop
    add: ["NET_BIND_SERVICE"] # 必要なもののみ再追加

3. ServiceAccounts

PodはKubernetes APIへの認証にServiceAccountを使用します。

# ServiceAccountの作成
kubectl create serviceaccount my-sa

# Roleにバインド
kubectl create rolebinding my-binding \
  --role=pod-reader \
  --serviceaccount=default:my-sa

# PodにSAを割り当て
spec:
  serviceAccountName: my-sa     # 特定のSAを使用
  automountServiceAccountToken: false  # SAトークンの自動マウントを無効化

# デフォルトでは: default SAが /var/run/secrets/kubernetes.io/serviceaccount/ にマウントされる
# トークンファイルを使ってコンテナ内からK8s APIを呼び出せる
概念説明
デフォルトSA各Namespaceに組み込みのdefault SAがある(最小権限)
トークンマウント無効化しない限り、トークンはPodに自動マウントされる
automountServiceAccountToken: falseトークンマウントを無効化(セキュリティのベストプラクティス)

試験のポイント: PodがKubernetes APIを呼び出す必要がある場合(Operatorパターンなど)、適切な権限を持つServiceAccountが必要です。APIアクセスが不要な場合は、automountServiceAccountToken: falseを設定するのがベストプラクティスです。CKADでよく出題されるパターン: SAの作成、Roleのバインド、Pod specへのSA設定。

4. readOnlyRootFilesystem + emptyDir

# readOnlyRootFilesystem: true の場合、アプリはルートFSに書き込めない。
# しかし一時ファイルの書き込みが必要な場合がある → emptyDirボリュームを使用:

spec:
  containers:
  - name: app
    image: myapp
    securityContext:
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: tmp
      mountPath: /tmp        # 一時ファイルをここに書き込み
    - name: cache
      mountPath: /app/cache
  volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

5. チートシート

タスクYAML / コマンド
非rootでコンテナを実行securityContext: runAsNonRoot: true
特定のUIDで実行securityContext: runAsUser: 1000
読み取り専用ファイルシステムsecurityContext: readOnlyRootFilesystem: true
全capabilitiesをdropcapabilities: drop: ["ALL"]
ServiceAccountを割り当てspec: serviceAccountName: my-sa
コンテナ内のユーザーを確認kubectl exec pod -- whoami

6. 練習問題

Q1: Pod specのsecurityContext.runAsUser: 1000がPodレベルに設定されています。Pod内の1つのコンテナにsecurityContext.runAsUser: 2000が設定されています。そのコンテナはどのUIDで実行されますか?

  • A) 0(root、Podレベルがオーバーライドするため)
  • B) 1000(Podレベルが優先)
  • C) 2000(ContainerレベルがPodレベルをオーバーライド) ✓
  • D) 両方のUIDで同時に実行

解説: ContainerレベルのsecurityContext設定はPodレベルをオーバーライドします。このコンテナはUID 2000で実行されます。同じPod内でContainer固有のsecurityContextが設定されていない他のコンテナは、PodレベルのUID 1000を継承します。

Q2: アプリケーションコンテナがポート80(1024未満の特権ポート)にバインドする必要がありますが、rootで実行すべきではありません。どう設定しますか?

  • A) securityContext.privileged: trueを設定
  • B) securityContext.runAsUser: 0を設定
  • C) 他のすべてをdropしてNET_BIND_SERVICE capabilityを追加 ✓
  • D) ポート80の代わりにNodePort Serviceを使用

解説: Linux capabilitiesにより細かな権限付与が可能です。NET_BIND_SERVICEは完全なroot権限なしで1024未満のポートへのバインドを許可します。ベストプラクティスはまずすべてのcapabilitiesをdropし、必要なもののみ追加: capabilities: { drop: ["ALL"], add: ["NET_BIND_SERVICE"] }。

Q3: readOnlyRootFilesystem: trueで実行中のPodがあります。アプリケーションが/tmpに書き込もうとして失敗します。最適な解決策はどれですか?

  • A) readOnlyRootFilesystem: trueを削除
  • B) securityContext.privileged: trueを設定
  • C) /tmpにemptyDirボリュームをマウント ✓
  • D) /tmpにConfigMapをマウント

解説: readOnlyRootFilesystemはコンテナのファイルシステムへの書き込みを防止しますが、emptyDirボリュームは別の書き込み可能なマウントです。/tmpにemptyDirをマウントすることで、ルートファイルシステムは読み取り専用のまま、アプリケーションは一時ファイルを書き込めます。