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を適用します。
- Google Cloud コンソールにアクセス
- GKEクラスタ一覧にアクセスします
- 対象のクラスタ名をクリックして詳細画面を開きます
- Cloud Shellを起動
- コンソール右上の「Cloud Shellをアクティブにする」アイコンをクリックします
- kubectlコマンドでクラスタに接続します:
gcloud container clusters get-credentials [CLUSTER_NAME] --zone [ZONE] --project [PROJECT_ID]
- 現在のPod Security設定を確認
kubectl get namespaces -o json | jq '.items[] | {name: .metadata.name, labels: .metadata.labels}'
- ネームスペースに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
- クラスタ全体のデフォルト設定を構成
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
- 設定の検証
制限された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で実施する手順です。
- クラスタの認証情報を取得
gcloud container clusters get-credentials [CLUSTER_NAME] \ --zone [ZONE] \ --project [PROJECT_ID]
- 現在のPod Security設定を確認
# 全ネームスペースのPSS設定を確認 kubectl get namespaces -L pod-security.kubernetes.io/enforce \ -L pod-security.kubernetes.io/audit \ -L pod-security.kubernetes.io/warn
- 既存ネームスペースに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
- 違反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)"'
- 監査ログの確認
# 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機能で簡単に検出及び管理する事が可能です。
運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。
最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。