2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kubernetesを学ぶ9日間 - Day 8: セキュリティベスト・プラクティス

2
Last updated at Posted at 2025-12-17

はじめに

「ジャンルなしオンラインもくもく会 Advent Calendar 2025」の17日目の記事です。

Week 3の始まりとして、Kubernetesクラスタのセキュリティを強化します。これまでHelm/Kustomizeでマニフェスト管理し、ArgoCDでGitOpsを実現しましたが、セキュリティが不十分では本番運用できません。

今日は本番運用を想定してセキュリティ設定を実装します。

本シリーズの全体構成

前回までのおさらい

Kubernetesセキュリティの4C

Kubernetesセキュリティは**4つの層(4C)**で考えます

今回は Cluster層のセキュリティ を実装します。


1. Pod Security Standards(PSS)

Pod Security Standardsとは?

Podが実行できる機能を制限する仕組みです。以前のPod Security Policy(PSP)に代わる標準です。

3つのポリシーレベル

レベル 説明 用途
Privileged 制限なし 信頼できるシステムコンポーネント
Baseline 基本的な制限 ほとんどのアプリケーション
Restricted 厳格な制限 セキュリティクリティカルなアプリ

Namespace レベルで適用

# production namespace に Restricted ポリシーを適用
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    # enforce: ポリシー違反のPodは起動を拒否
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest

    # audit: 違反をログに記録(起動は許可)
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest

    # warn: 違反を警告表示(起動は許可)
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest

Restricted ポリシーに準拠したDeployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      # 1. 非rootユーザーで実行
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        fsGroup: 10001
        seccompProfile:
          type: RuntimeDefault

      containers:
      - name: app
        image: myapp:v1.0.0
        ports:
        - containerPort: 8080

        # 2. コンテナレベルのセキュリティ設定
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
              - ALL  # すべてのLinux capabilitiesを削除

        # 3. リソース制限
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"

        # 4. 書き込み可能な一時ボリューム
        volumeMounts:
        - name: tmp
          mountPath: /tmp

      volumes:
      - name: tmp
        emptyDir: {}

ポリシー違反の検証

# ポリシー違反のPodをデプロイしてみる
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: insecure-pod
  namespace: production
spec:
  containers:
  - name: nginx
    image: nginx
EOF

# エラー出力例
Error from server (Forbidden): error when creating "STDIN": pods "insecure-pod" is forbidden:
violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false),
unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]),
runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true),
seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

2. RBAC(Role-Based Access Control)

RBACとは?

誰が(User/ServiceAccount)、何を(リソース)、どうできるか(操作)を制御する仕組み

Role と ClusterRole の違い

種類 スコープ 用途
Role Namespace内 特定namespaceのリソース
ClusterRole クラスタ全体 Nodeなどクラスタリソース

実装例: 開発チーム用のRole

# Role: production namespace内での読み取り専用権限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer-read-only
  namespace: production
rules:
- apiGroups: ["", "apps", "batch"]
  resources:
    - pods
    - pods/log
    - deployments
    - services
    - configmaps
    - jobs
  verbs:
    - get
    - list
    - watch

---
# RoleBinding: UserをRoleにバインド
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-read-only-binding
  namespace: production
subjects:
- kind: User
  name: john@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer-read-only
  apiGroup: rbac.authorization.k8s.io

ServiceAccount用のRBAC

# ServiceAccount作成
apiVersion: v1
kind: ServiceAccount
metadata:
  name: backend-sa
  namespace: production

---
# Role: ConfigMapとSecretの読み取り専用
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: config-reader
  namespace: production
rules:
- apiGroups: [""]
  resources:
    - configmaps
    - secrets
  verbs:
    - get
    - list

---
# RoleBinding: ServiceAccountをRoleにバインド
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: backend-config-reader-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: backend-sa
  namespace: production
roleRef:
  kind: Role
  name: config-reader
  apiGroup: rbac.authorization.k8s.io

---
# DeploymentでServiceAccountを使用
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  namespace: production
spec:
  template:
    spec:
      serviceAccountName: backend-sa  # ServiceAccountを指定
      containers:
      - name: app
        image: backend:v1.0.0

RBAC検証

# john@example.com としてログイン
kubectl config use-context john-context

# 読み取りは成功
kubectl get pods -n production

# 作成は失敗
kubectl run test -n production --image=nginx
# Error from server (Forbidden): pods is forbidden: User "john@example.com" cannot create resource "pods" in API group "" in the namespace "production"

ServiceAccountの権限検証

kubectl auth can-i コマンドでServiceAccountの権限を確認できます

# ServiceAccountとしてconfigmapsの取得が可能か確認
$ kubectl auth can-i get configmaps \
    --as=system:serviceaccount:production:backend-sa \
    -n production
yes

# ServiceAccountとしてdeploymentsの作成が可能か確認
$ kubectl auth can-i create deployments \
    --as=system:serviceaccount:production:backend-sa \
    -n production
no

# ServiceAccountとしてsecretsの取得が可能か確認
$ kubectl auth can-i get secrets \
    --as=system:serviceaccount:production:backend-sa \
    -n production
yes

3. Secrets管理

Secretsの課題

  • ❌ デフォルトではbase64エンコードのみ(暗号化なし)
  • ❌ Gitに直接コミットすると漏洩リスク
  • ❌ 複数環境で異なるSecretを管理するのが大変

解決策1: Sealed Secrets(GitOpsフレンドリー)

# Sealed Secrets Controllerインストール
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system

# kubeseal CLIインストール
brew install kubeseal

# 通常のSecretを作成
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=supersecret \
  --dry-run=client -o yaml > secret.yaml

# SealedSecretに変換(暗号化)
kubeseal -f secret.yaml -w sealed-secret.yaml

# SealedSecretをGitに安全にコミット可能
cat sealed-secret.yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  encryptedData:
    username: AgBY7Z... # 暗号化されたデータ
    password: AgCx9K...
# SealedSecretをクラスタに適用
kubectl apply -f sealed-secret.yaml

# Controllerが自動的にSecretに復号化
kubectl get secret db-credentials -n production -o yaml

解決策2: External Secrets Operator(クラウド統合)

AWS Secrets Manager、Azure Key Vault、GCP Secret Managerと統合

# ExternalSecret: AWS Secrets Managerから取得
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secret-store
    kind: SecretStore

  target:
    name: db-credentials
    creationPolicy: Owner

  data:
  - secretKey: username
    remoteRef:
      key: production/database
      property: username

  - secretKey: password
    remoteRef:
      key: production/database
      property: password

4. Network Policy(ネットワーク分離)

Network Policyとは?

Pod間の通信を制御するファイアウォールです。デフォルトでは全Podが相互通信可能なので、Network Policyで制限することで「最小権限の原則」をネットワークレベルで実現します。

CNI依存の注意

NetworkPolicyはKubernetesの標準リソースですが、実際の施行にはCNIのサポートが必要です。

CNI NetworkPolicy対応 備考
Flannel ❌ 非対応 ネットワーキングのみ
Calico ✅ 対応 BGPルーティング対応
Cilium ✅ 対応 eBPF、L7ポリシー、gRPC対応

📋 本記事の環境について

本記事のクラスタはFlannelを使用しているため、NetworkPolicyの動作確認はできていません。
将来的にCiliumなどgRPC対応のCNIへの移行を予定しています。
NetworkPolicyの詳細実装は別記事で解説予定です。


5. イメージセキュリティ

コンテナイメージのセキュリティは重要ですが、本記事では概要のみ紹介します。

主要ツール

ツール 用途 参考リンク
Trivy イメージ脆弱性スキャン aquasecurity/trivy
Cosign イメージ署名・検証 sigstore/cosign
Kyverno ポリシーエンジン(署名検証等) kyverno.io

6. 認証基盤(OIDC/LDAP連携)

Kubernetesの認証をより安全にするため、外部認証プロバイダとの連携が推奨されます。

選択肢

方式 特徴 推奨
Google OIDC 手軽、無料 個人・小規模
Okta 開発者無料枠あり バランス良い
Dex + LDAP 自己完結、柔軟 企業・ホームラボ

メリット

  • SSO: 一度のログインで複数クラスタにアクセス
  • MFA: 多要素認証でセキュリティ強化
  • 監査: 認証イベントの一元管理
  • 自動失効: 退職者のアクセス自動無効化

📝 詳細記事

OIDC/LDAP連携の詳細実装は別記事で解説予定です。


7. 監査ログ(Audit Logging)

Audit Policy設定

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Secret/ConfigMap/Tokenへのアクセスをログ
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets", "configmaps", "serviceaccounts/token"]

# 重要なリソースの変更をログ
- level: RequestResponse
  verbs: ["create", "update", "patch", "delete"]
  resources:
  - group: "apps"
    resources: ["deployments", "statefulsets", "daemonsets"]

# 認証・認可の失敗をログ
- level: Metadata
  omitStages:
  - RequestReceived

API Server設定(Talos Linux)

# talos-config.yaml
machine:
  apiServer:
    auditPolicy:
      apiVersion: audit.k8s.io/v1
      kind: Policy
      rules:
      - level: RequestResponse
        resources:
        - group: ""
          resources: ["secrets"]

まとめ

所感

今回は「セキュリティベストプラクティス」と題しつつも、Cluster層に焦点を絞って実装しました。4Cの全てを網羅しようとすると範囲が広過ぎで後日調べてまとめていきたいと思います

実際に検証してみてそれぞれの目的もはっきりしているが、どのように組み合わせて運用していくのかがまたセキュリティのキモなのかなと想像していますが、昨今のトレンド(?)を追いかけつつ、知識を深めていきたいです

そして蛇足ですが...「Tailscale Extensionを追加しよう」という軽い気持ちが、まさかのクラスタ再構築に発展し、アドベントカレンダー締め切りギリギリになるとは思いませんでした...

次回予告

明日(12/18)は、Chaos Meshでカオスエンジニアリング入門です。本番環境で意図的に障害を起こし、システムの耐障害性を検証します!


参考リンク

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?