GKE Pod Security Standardsの設定について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、gcloud CLI、Terraformなど)まで、分かりやすく解説します。

この記事では、GKEクラスタでPod Security Standardsが未設定の場合のリスクと対策を解説します。

ポリシーの説明

Pod Security Standards(PSS)は、Kubernetesの標準的なセキュリティ制御機能で、Pod Security Policy(PSP)の後継として設計されました。Kubernetes v1.23以降で正式にGAとなり、GKEではv1.25以降で完全サポートされています。

PSSは、Podの実行時に以下の3つのレベルでセキュリティポリシーを適用します:

  • Privileged: 制限なし(システムレベルのワークロード用)
  • Baseline: 既知の特権昇格を防ぐ最小限の制限
  • Restricted: 現在のPodセキュリティのベストプラクティスを強制

GKEでは、これらの標準を以下の3つのモードで適用できます:

  • enforce: ポリシーに違反するPodの作成を拒否
  • audit: 違反を監査ログに記録(既存Podには影響なし)
  • warn: 違反時に警告メッセージを表示

Pod Security Standardsのレベル比較

レベル説明主な制限事項推奨環境
privileged制限なしなし(非推奨)テスト環境のみ
baseline最小限のセキュリティ制限特権コンテナ禁止、ホストネットワーク制限など開発環境
restricted最も厳格なセキュリティ制限非rootユーザー強制、読み取り専用ルートファイルシステムなど本番環境

修復方法

Google Cloud コンソールを使用して、GKEクラスタにPod Security Standardsを適用します。

  1. Google Cloud コンソールにアクセス
    • GKEクラスタ一覧にアクセスします
    • 対象のクラスタ名をクリックして詳細画面を開きます
  2. Cloud Shellを起動
    • コンソール右上の「Cloud Shellをアクティブにする」アイコンをクリックします
    • kubectlコマンドでクラスタに接続します:
    gcloud container clusters get-credentials [CLUSTER_NAME] --zone [ZONE] --project [PROJECT_ID]
    

     

  3. 現在のPod Security設定を確認
    kubectl get namespaces -o json | jq '.items[] | {name: .metadata.name, labels: .metadata.labels}'
    

     

  4. ネームスペースにPod Security Standardsラベルを適用

    既存のネームスペースに対して適切なセキュリティレベルを設定します:

    # defaultネームスペースにbaselineレベルを適用
    kubectl label namespace default \
      pod-security.kubernetes.io/enforce=baseline \
      pod-security.kubernetes.io/audit=restricted \
      pod-security.kubernetes.io/warn=restricted
    
    # 本番環境のネームスペースにはrestrictedレベルを推奨
    kubectl label namespace production \
      pod-security.kubernetes.io/enforce=restricted \
      pod-security.kubernetes.io/audit=restricted \
      pod-security.kubernetes.io/warn=restricted \
      --overwrite
    

     

  5. クラスタ全体のデフォルト設定を構成

    GKEクラスタ全体でPod Security Standardsのデフォルトを設定(GKE 1.25以降):

    # クラスタレベルでのデフォルト設定
    gcloud container clusters update [CLUSTER_NAME] \
      --zone [ZONE] \
      --project [PROJECT_ID] \
      --pod-security-policy-config='{"policyEnforcementLevel":"restricted","exemptNamespaces":["kube-system","kube-public","kube-node-lease","gke-system"]}'
    

     

    新規ネームスペース作成時に自動適用されるテンプレート:

    # namespace-template.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: new-secure-namespace
      labels:
        pod-security.kubernetes.io/enforce: baseline
        pod-security.kubernetes.io/audit: restricted
        pod-security.kubernetes.io/warn: restricted
    

     

  6. 設定の検証

    制限されたPodの作成を試みて、ポリシーが機能していることを確認:

    # 特権Podの作成を試行(失敗するはず)
    kubectl run test-privileged --image=nginx --restart=Never \
      --overrides='{"spec":{"containers":[{"name":"test","image":"nginx","securityContext":{"privileged":true}}]}}' \
      -n production
    

     

gcloud CLIでの修復手順

完全な修復をgcloud CLIで実施する手順です。

  1. クラスタの認証情報を取得
    gcloud container clusters get-credentials [CLUSTER_NAME] \
      --zone [ZONE] \
      --project [PROJECT_ID]
    

     

  2. 現在のPod Security設定を確認
    # 全ネームスペースのPSS設定を確認
    kubectl get namespaces -L pod-security.kubernetes.io/enforce \
      -L pod-security.kubernetes.io/audit \
      -L pod-security.kubernetes.io/warn
    

     

  3. 既存ネームスペースにPSSを適用
    # スクリプトで一括適用
    for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
      case $ns in
        kube-*|gke-*|istio-*|cert-manager)
          # システムネームスペースはprivilegedまたはbaseline
          kubectl label ns $ns \
            pod-security.kubernetes.io/enforce=privileged \
            pod-security.kubernetes.io/audit=baseline \
            pod-security.kubernetes.io/warn=baseline \
            --overwrite
          ;;
        *prod*|*production*)
          # 本番環境はrestricted
          kubectl label ns $ns \
            pod-security.kubernetes.io/enforce=restricted \
            pod-security.kubernetes.io/audit=restricted \
            pod-security.kubernetes.io/warn=restricted \
            --overwrite
          ;;
        *)
          # その他はbaseline
          kubectl label ns $ns \
            pod-security.kubernetes.io/enforce=baseline \
            pod-security.kubernetes.io/audit=restricted \
            pod-security.kubernetes.io/warn=restricted \
            --overwrite
          ;;
      esac
    done
    

     

  4. 違反Podの検出と修正
    # 違反する可能性のあるPodを検出
    kubectl get pods --all-namespaces -o json | jq -r '
      .items[] |
      select(.spec.securityContext.privileged == true or
             .spec.hostNetwork == true or
             .spec.containers[].securityContext.privileged == true) |
      "\(.metadata.namespace)/\(.metadata.name)"'
    

     

  5. 監査ログの確認
    # Cloud Loggingで違反を確認
    gcloud logging read '
      resource.type="k8s_cluster"
      protoPayload.authenticationInfo.principalEmail=~"system:serviceaccount:kube-system:pod-security-webhook"
      severity>=WARNING' \
      --limit=50 \
      --format="table(timestamp, protoPayload.resourceName, protoPayload.response.reason)"
    

     

Terraformでの修復手順

Pod Security Standardsを適用したGKEクラスタとネームスペースのTerraformコードと、主要な修正ポイントを説明します。

# GKEクラスタの定義(Pod Security Standards対応)
resource "google_container_cluster" "primary" {
  name     = "secure-gke-cluster"
  location = var.region

  # 最小バージョンを1.25以上に設定(Pod Security Standards完全サポート)
  # 注意: 1.25未満ではPod Security Policyを使用する必要があります
  min_master_version = "1.27"

  # Pod Security Standardsのデフォルト設定
  pod_security_policy_config {
    enabled = true  # PSPは非推奨だが、PSSへの移行期間中は有効化
  }

  # クラスタのセキュリティ設定
  master_auth {
    client_certificate_config {
      issue_client_certificate = false
    }
  }

  # ワークロードアイデンティティの有効化
  workload_identity_config {
    workload_pool = "${var.project_id}.svc.id.goog"
  }

  # Binary Authorizationの有効化(追加のセキュリティ層)
  binary_authorization {
    evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE"
  }

  # ネットワークポリシーの有効化
  network_policy {
    enabled = true
    provider = "CALICO"
  }

  # セキュリティポスチャーダッシュボードの有効化
  security_posture_config {
    mode               = "BASIC"
    vulnerability_mode = "VULNERABILITY_BASIC"
  }

  # ノードプールの設定でもセキュリティを強化
  node_config {
    shielded_instance_config {
      enable_secure_boot          = true
      enable_integrity_monitoring = true
    }

    # ワークロードメタデータの保護
    workload_metadata_config {
      mode = "GKE_METADATA"  # より安全なメタデータサービス
    }

    # サービスアカウントは最小権限の原則で設定
    service_account = google_service_account.gke_node_sa.email
    oauth_scopes = [
      "<https://www.googleapis.com/auth/cloud-platform>"
    ]
  }
}

# Pod Security Standardsを適用したネームスペース
resource "kubernetes_namespace" "secure_namespaces" {
  for_each = var.namespaces

  metadata {
    name = each.key

    labels = {
      # Pod Security Standardsの適用
      "pod-security.kubernetes.io/enforce" = each.value.enforce_level
      "pod-security.kubernetes.io/audit"   = each.value.audit_level
      "pod-security.kubernetes.io/warn"    = each.value.warn_level

      # 追加のメタデータ
      "environment" = each.value.environment
      "managed-by"  = "terraform"
    }

    annotations = {
      "security-policy" = "pod-security-standards"
      "description"     = each.value.description
    }
  }
}

# NetworkPolicyでさらにセキュリティを強化
resource "kubernetes_network_policy" "default_deny" {
  for_each = var.namespaces

  metadata {
    name      = "default-deny-all"
    namespace = kubernetes_namespace.secure_namespaces[each.key].metadata[0].name
  }

  spec {
    pod_selector {}

    policy_types = ["Ingress", "Egress"]

    # デフォルトで全てのトラフィックを拒否
    # 個別のNetworkPolicyで必要な通信のみ許可する
  }
}

# OPA Gatekeeperとの統合(Pod Security Standardsを補完)
resource "helm_release" "gatekeeper" {
  name       = "gatekeeper"
  repository = "<https://open-policy-agent.github.io/gatekeeper/charts>"
  chart      = "gatekeeper"
  namespace  = "gatekeeper-system"
  version    = "3.14.0"

  create_namespace = true

  set {
    name  = "replicas"
    value = "3"
  }

  set {
    name  = "auditInterval"
    value = "60"
  }
}

# Pod Security Standardsのテスト用リソース
resource "kubernetes_manifest" "pss_test_pod" {
  manifest = {
    apiVersion = "v1"
    kind       = "Pod"
    metadata = {
      name      = "security-context-demo"
      namespace = "production"
    }
    spec = {
      # restrictedレベルに準拠した設定
      securityContext = {
        runAsNonRoot = true
        runAsUser    = 1000
        fsGroup      = 2000
        seccompProfile = {
          type = "RuntimeDefault"
        }
      }
      containers = [{
        name  = "sec-ctx-demo"
        image = "gcr.io/google-samples/hello-app:1.0"

        securityContext = {
          allowPrivilegeEscalation = false
          readOnlyRootFilesystem   = true
          runAsNonRoot             = true
          runAsUser                = 1000
          capabilities = {
            drop = ["ALL"]
          }
        }

        resources = {
          requests = {
            memory = "64Mi"
            cpu    = "250m"
          }
          limits = {
            memory = "128Mi"
            cpu    = "500m"
          }
        }

        volumeMounts = [{
          name      = "tmp"
          mountPath = "/tmp"
        }]
      }]

      volumes = [{
        name = "tmp"
        emptyDir = {}
      }]
    }
  }

  depends_on = [kubernetes_namespace.secure_namespaces]
}

# 変数定義
variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "region" {
  description = "GCP region"
  type        = string
  default     = "asia-northeast1"
}

variable "namespaces" {
  description = "Namespaces with Pod Security Standards configuration"
  type = map(object({
    enforce_level = string
    audit_level   = string
    warn_level    = string
    environment   = string
    description   = string
  }))
  default = {
    "development" = {
      enforce_level = "baseline"
      audit_level   = "restricted"
      warn_level    = "restricted"
      environment   = "dev"
      description   = "Development environment with baseline security"
    }
    "staging" = {
      enforce_level = "restricted"
      audit_level   = "restricted"
      warn_level    = "restricted"
      environment   = "staging"
      description   = "Staging environment with restricted security"
    }
    "production" = {
      enforce_level = "restricted"
      audit_level   = "restricted"
      warn_level    = "restricted"
      environment   = "prod"
      description   = "Production environment with maximum security"
    }
  }
}

# Pod Security Standardsのレベル説明
# - privileged: 制限なし(非推奨)
# - baseline: 最小限のセキュリティ制限
# - restricted: 最も厳格なセキュリティ制限(推奨)

output "namespace_security_levels" {
  description = "Applied Pod Security Standards for each namespace"
  value = {
    for ns, config in var.namespaces : ns => {
      enforce = config.enforce_level
      audit   = config.audit_level
      warn    = config.warn_level
    }
  }
}

 

まとめ

この記事では、GKEクラスタでPod Security Standardsを適用したセキュリティ強化について、リスクと対策を解説しました。

Pod Security Standardsを適用することで、特権昇格、コンテナエスケープ、機密情報漏洩などのリスクを大幅に軽減できます。特に、restrictedレベルを適用することで、最も厳格なセキュリティ制御を実現できます。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

 

参考情報

関連ドキュメント

この記事をシェアする

クラウドセキュリティ対策実践集一覧へ戻る

貴社の利用状況に合わせた見積もりを作成します。

料金プランを詳しく見る