Skip to main content
Pulumi logo Pulumi logo
  1. Docs
  2. Reference
  3. Pre-built Policy Packs
  4. CIS Kubernetes
  5. Google Cloud (GKE)

CIS Kubernetes - Google Cloud (GKE)

    This page lists all 50 policies in the CIS Kubernetes pack for Google Cloud (GKE), as published in cis-kubernetes-gcp version 1.0.1.

    Policies by control

    4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.

    4.2 Pod Security Standards — Enforce Pod Security Standard Baseline profile to prevent privileged containers and host namespace access.

    4.3 Network Security — Use network policies to isolate traffic and restrict network access between pods.

    4.5 Binary Authorization — Ensure only trusted container images can be deployed.

    4.6 Pod Security — Apply RuntimeDefault seccomp profile to all workloads and ensure default namespace is not used.

    5.1 Container Images — Ensure IAM controls and trusted image sources.

    5.2 Node Service Accounts — Use dedicated service accounts with Workload Identity for GKE nodes.

    5.3 Secrets Encryption — Encrypt Kubernetes secrets using Cloud KMS customer-managed keys.

    5.4 Workload Identity — Use GKE Metadata Server and Workload Identity for workload authentication.

    5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.

    5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.

    5.7 Logging — Enable Cloud Logging, Cloud Monitoring, and auditd logging.

    5.8 Authentication and Authorization — Disable client certificate authentication, enable Google Groups for RBAC, and disable legacy ABAC.

    5.9 Encryption — Use customer-managed encryption keys (CMEK) for persistent and boot disks.

    5.10 Additional Security Controls — Disable Kubernetes Dashboard, avoid alpha clusters, and enable security posture.

    Policy details

    gke-alpha-clusters-not-production

    Severity: medium · Enforcement: advisory

    Ensure GKE alpha clusters are not used, as they contain unstable features not suitable for production.

    • 5.10 Additional Security Controls — Disable Kubernetes Dashboard, avoid alpha clusters, and enable security posture.
    Remediation
    Fix: Avoid Alpha Clusters for Production

    Do not enable alpha features in production clusters:

    import * as gcp from "@pulumi/gcp";
    
    // Good: Standard cluster without alpha features
    const cluster = new gcp.container.Cluster("cluster", {
        name: "production-cluster",
        location: "us-central1",
        // Do NOT set enableKubernetesAlpha: true
        // ... other configuration
    });
    
    // Bad: Alpha cluster (for testing only)
    const alphaCluster = new gcp.container.Cluster("alpha-cluster", {
        name: "testing-cluster",
        location: "us-central1",
        enableKubernetesAlpha: true,  // DON'T DO THIS in production
    });
    

    Alpha cluster limitations:

    • Cannot be upgraded (must recreate)
    • No SLA or support
    • Alpha features may be removed or change without notice
    • Not recommended for any production workloads
    • Automatically deleted after 30 days

    Use alpha clusters only for testing Kubernetes alpha features in non-production environments.

    gke-binary-authorization-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have Binary Authorization enabled to verify image signatures and attestations.

    • 4.5 Binary Authorization — Ensure only trusted container images can be deployed.
    Remediation
    Fix: Enable Binary Authorization

    Configure Binary Authorization on the GKE cluster:

    import * as gcp from "@pulumi/gcp";
    
    // Enable Binary Authorization on cluster
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Binary Authorization
        binaryAuthorization: {
            evaluationMode: "PROJECT_SINGLETON_POLICY_ENFORCE",
        },
    
        // ... other configuration
    });
    
    // Create Binary Authorization policy
    const policy = new gcp.binaryauthorization.Policy("policy", {
        defaultAdmissionRule: {
            evaluationMode: "REQUIRE_ATTESTATION",
            enforcementMode: "ENFORCED_BLOCK_AND_AUDIT_LOG",
            requireAttestationsBy: [attestor.name],
        },
        // Allow images from specific registries
        clusterAdmissionRules: [{
            cluster: pulumi.interpolate`${cluster.location}.${cluster.name}`,
            evaluationMode: "REQUIRE_ATTESTATION",
            enforcementMode: "ENFORCED_BLOCK_AND_AUDIT_LOG",
            requireAttestationsBy: [attestor.name],
        }],
    });
    
    // Create attestor for image signing
    const attestor = new gcp.binaryauthorization.Attestor("attestor", {
        name: "prod-attestor",
        attestationAuthorityNote: {
            noteReference: note.name,
        },
    });
    

    Binary Authorization modes:

    • PROJECT_SINGLETON_POLICY_ENFORCE: Enforce project-wide policy (recommended)
    • DISABLED: No enforcement (not recommended)

    Benefits:

    • Ensures only signed/verified images run
    • Prevents deployment of untrusted images
    • Integrates with CI/CD for image attestation
    • Compliance with supply chain security requirements

    gke-client-certificate-auth-disabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have client certificate authentication disabled in favor of more secure methods.

    • 5.8 Authentication and Authorization — Disable client certificate authentication, enable Google Groups for RBAC, and disable legacy ABAC.
    Remediation
    Fix: Disable Client Certificate Authentication

    Disable client certificate issuance for the cluster:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Disable client certificate authentication
        masterAuth: {
            clientCertificateConfig: {
                issueClientCertificate: false,
            },
        },
    
        // ... other configuration
    });
    

    Recommended authentication methods instead:

    • Google Cloud IAM with gcloud/kubectl
    • Workload Identity for pod-to-GCP authentication
    • OIDC providers for user authentication
    • Google Groups for RBAC

    Client certificates are difficult to rotate and manage securely.

    gke-cmek-boot-disks

    Severity: medium · Enforcement: advisory

    Ensure GKE node pools use customer-managed encryption keys (CMEK) for boot disk encryption.

    • 5.9 Encryption — Use customer-managed encryption keys (CMEK) for persistent and boot disks.
    Remediation
    Fix: Enable CMEK for Boot Disks

    Configure node pools to use CMEK for boot disk encryption:

    import * as gcp from "@pulumi/gcp";
    
    // Create KMS key
    const keyRing = new gcp.kms.KeyRing("keyring", {
        name: "gke-keyring",
        location: "us-central1",
    });
    
    const cryptoKey = new gcp.kms.CryptoKey("boot-disk-key", {
        name: "boot-disk-key",
        keyRing: keyRing.id,
        purpose: "ENCRYPT_DECRYPT",
    });
    
    // Grant GCE service account access to use the key
    const cryptoKeyBinding = new gcp.kms.CryptoKeyIAMBinding("boot-disk-key-binding", {
        cryptoKeyId: cryptoKey.id,
        role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
        members: [
            "serviceAccount:service-PROJECT_NUMBER@compute-system.iam.gserviceaccount.com",
        ],
    });
    
    // Configure node pool with CMEK
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            bootDiskKmsKey: cryptoKey.id,
        },
    });
    

    Benefits:

    • Control over encryption keys
    • Key rotation capabilities
    • Audit trail for key usage
    • Compliance with data residency requirements

    Note: By default, GKE uses Google-managed encryption. CMEK provides additional control.

    gke-cmek-persistent-disks

    Severity: medium · Enforcement: advisory

    Ensure Compute Engine persistent disks use customer-managed encryption keys (CMEK).

    • 5.9 Encryption — Use customer-managed encryption keys (CMEK) for persistent and boot disks.
    Remediation
    Fix: Enable CMEK for Persistent Disks

    Configure persistent disks to use CMEK:

    import * as gcp from "@pulumi/gcp";
    
    // Create KMS key
    const keyRing = new gcp.kms.KeyRing("keyring", {
        name: "disk-keyring",
        location: "us-central1",
    });
    
    const cryptoKey = new gcp.kms.CryptoKey("disk-key", {
        name: "disk-key",
        keyRing: keyRing.id,
        purpose: "ENCRYPT_DECRYPT",
    });
    
    // Grant GCE service account access to use the key
    const cryptoKeyBinding = new gcp.kms.CryptoKeyIAMBinding("disk-key-binding", {
        cryptoKeyId: cryptoKey.id,
        role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
        members: [
            "serviceAccount:service-PROJECT_NUMBER@compute-system.iam.gserviceaccount.com",
        ],
    });
    
    // Create disk with CMEK
    const disk = new gcp.compute.Disk("disk", {
        name: "encrypted-disk",
        zone: "us-central1-a",
        type: "pd-standard",
        size: 100,
        diskEncryptionKey: {
            kmsKeySelfLink: cryptoKey.id,
        },
    });
    
    // Or use in Kubernetes StorageClass
    const storageClass = new k8s.storage.v1.StorageClass("encrypted-sc", {
        metadata: { name: "encrypted-storage" },
        provisioner: "kubernetes.io/gce-pd",
        parameters: {
            type: "pd-standard",
            "disk-encryption-kms-key": cryptoKey.id,
        },
    });
    

    Benefits:

    • Control over encryption keys
    • Key rotation capabilities
    • Audit trail for key usage
    • Compliance with data residency requirements

    Note:

    • By default, GKE uses Google-managed encryption
    • CMEK provides additional control
    • Applies to dynamically provisioned PersistentVolumes

    gke-container-registry-iam-minimized

    Severity: high · Enforcement: advisory

    Ensure container registry IAM permissions used by GKE are restricted to specific users/service accounts with appropriate roles.

    • 5.1 Container Images — Ensure IAM controls and trusted image sources.
    Remediation
    Fix: Minimize Container Registry IAM Permissions

    Grant minimal required permissions for Artifact Registry:

    import * as gcp from "@pulumi/gcp";
    
    const repository = new gcp.artifactregistry.Repository("repo", {
        repositoryId: "my-repo",
        format: "DOCKER",
        location: "us-central1",
    });
    
    // GKE nodes: Read-only access
    const gkeReaderBinding = new gcp.artifactregistry.RepositoryIamMember("gke-reader", {
        repository: repository.name,
        location: repository.location,
        role: "roles/artifactregistry.reader",
        member: pulumi.interpolate`serviceAccount:${gkeNodeSa.email}`,
    });
    
    // CI/CD: Writer access (limited to CI/CD service account)
    const cicdWriterBinding = new gcp.artifactregistry.RepositoryIamMember("cicd-writer", {
        repository: repository.name,
        location: repository.location,
        role: "roles/artifactregistry.writer",
        member: pulumi.interpolate`serviceAccount:${cicdSa.email}`,
    });
    
    // Developers: Reader access only (use CI/CD to push)
    const devReaderBinding = new gcp.artifactregistry.RepositoryIamMember("dev-reader", {
        repository: repository.name,
        location: repository.location,
        role: "roles/artifactregistry.reader",
        member: "group:developers@example.com",
    });
    

    IAM roles for Artifact Registry:

    • roles/artifactregistry.reader: Pull images (GKE nodes, developers)
    • roles/artifactregistry.writer: Push images (CI/CD only)
    • roles/artifactregistry.repoAdmin: Manage repository (admins)

    Best practices:

    • Use service accounts for programmatic access
    • Grant write access only to CI/CD pipelines
    • Use groups for user management
    • Avoid allUsers and allAuthenticatedUsers

    gke-container-registry-read-only-cluster-access

    Severity: medium · Enforcement: advisory

    Ensure GKE node service accounts only have reader access to Artifact Registry/Container Registry.

    • 5.1 Container Images — Ensure IAM controls and trusted image sources.
    Remediation
    Fix: Grant Read-Only Registry Access to GKE Nodes

    Configure node service account with read-only access:

    import * as gcp from "@pulumi/gcp";
    
    // Create dedicated service account for GKE nodes
    const gkeNodeSa = new gcp.serviceaccount.Account("gke-nodes", {
        accountId: "gke-nodes",
        displayName: "GKE Node Service Account",
    });
    
    // Grant read-only access to Artifact Registry
    const artifactRegistryReader = new gcp.projects.IAMMember("ar-reader", {
        role: "roles/artifactregistry.reader",
        member: pulumi.interpolate`serviceAccount:${gkeNodeSa.email}`,
    });
    
    // For Container Registry (legacy), grant storage.objectViewer
    const gcsReader = new gcp.projects.IAMMember("gcr-reader", {
        role: "roles/storage.objectViewer",
        member: pulumi.interpolate`serviceAccount:${gkeNodeSa.email}`,
        // Optionally restrict to specific GCS buckets
    });
    
    // Use in node pool
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            serviceAccount: gkeNodeSa.email,
            oauthScopes: [
                "https://www.googleapis.com/auth/cloud-platform",
            ],
        },
    });
    

    Why read-only:

    • Nodes should pull images, not push
    • Image pushes should go through CI/CD pipelines
    • Prevents compromised nodes from pushing malicious images
    • Follows principle of least privilege

    Required roles:

    • Artifact Registry: roles/artifactregistry.reader
    • Container Registry: roles/storage.objectViewer (for GCS buckets)

    gke-control-plane-authorized-networks-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have authorized networks configured to restrict control plane access to specific IP ranges.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Enable Authorized Networks for GKE Control Plane

    Configure authorized networks to restrict control plane access:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Configure authorized networks
        masterAuthorizedNetworksConfig: {
            cidrBlocks: [
                {
                    cidrBlock: "203.0.113.0/24",  // Office network
                    displayName: "office",
                },
                {
                    cidrBlock: "198.51.100.0/24",  // CI/CD network
                    displayName: "cicd",
                },
            ],
        },
    
        // ... other configuration
    });
    

    Note:

    • Include all networks that need access (kubectl, CI/CD, monitoring)
    • Use narrow CIDR ranges for better security
    • Avoid using 0.0.0.0/0 which allows all IPs

    gke-cos-containerd-node-image

    Severity: medium · Enforcement: advisory

    Ensure GKE node pools use Container-Optimized OS (COS) with containerd runtime.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Use Container-Optimized OS with containerd

    Configure node pools to use COS with containerd:

    import * as gcp from "@pulumi/gcp";
    
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            imageType: "COS_CONTAINERD",  // Recommended
            // or "UBUNTU_CONTAINERD" for Ubuntu with containerd
        },
    });
    

    Recommended image types:

    • COS_CONTAINERD: Container-Optimized OS with containerd (recommended)
    • UBUNTU_CONTAINERD: Ubuntu with containerd (acceptable alternative)

    Avoid:

    • COS: COS with Docker (deprecated, Docker shim removed in Kubernetes 1.24+)
    • UBUNTU: Ubuntu with Docker (deprecated)
    • WINDOWS_LTSC_CONTAINERD / WINDOWS_SAC_CONTAINERD: Windows nodes (use if required)

    Benefits of COS with containerd:

    • Optimized for running containers
    • Automatic security updates
    • Smaller attack surface
    • containerd is the standard Kubernetes runtime

    gke-google-groups-rbac-enabled

    Severity: medium · Enforcement: advisory

    Ensure GKE clusters use Google Groups for RBAC to simplify permission management.

    • 5.8 Authentication and Authorization — Disable client certificate authentication, enable Google Groups for RBAC, and disable legacy ABAC.
    Remediation
    Fix: Enable Google Groups for RBAC

    Configure Google Groups integration for RBAC management:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Google Groups for RBAC
        authenticatorGroupsConfig: {
            securityGroup: "gke-security-groups@yourdomain.com",
        },
    
        // ... other configuration
    });
    
    // Example RoleBinding using Google Group
    const roleBinding = new k8s.rbac.v1.ClusterRoleBinding("developers", {
        subjects: [{
            kind: "Group",
            name: "developers@yourdomain.com",
            apiGroup: "rbac.authorization.k8s.io",
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "edit",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    

    Benefits:

    • Centralized user management through Google Workspace/Cloud Identity
    • Users added/removed from groups automatically gain/lose cluster access
    • Easier to audit and manage permissions
    • Supports nested groups

    gke-google-managed-ssl-certificates

    Severity: low · Enforcement: advisory

    Ensure Google-managed SSL certificates are used for GKE ingress when applicable.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Use Google-Managed SSL Certificates

    Option 1: ManagedCertificate resource (GKE Ingress):

    import * as gcp from "@pulumi/gcp";
    import * as k8s from "@pulumi/kubernetes";
    
    // Create Google-managed SSL certificate
    const cert = new gcp.compute.ManagedSslCertificate("cert", {
        managed: {
            domains: ["example.com", "www.example.com"],
        },
    });
    
    // Use in Ingress annotation
    const ingress = new k8s.networking.v1.Ingress("ingress", {
        metadata: {
            annotations: {
                "networking.gke.io/managed-certificates": "cert-name",
                "kubernetes.io/ingress.class": "gce",
            },
        },
        spec: {
            rules: [{
                host: "example.com",
                http: {
                    paths: [{
                        path: "/*",
                        pathType: "ImplementationSpecific",
                        backend: {
                            service: {
                                name: "service",
                                port: { number: 80 },
                            },
                        },
                    }],
                },
            }],
        },
    });
    

    Option 2: Kubernetes ManagedCertificate CRD:

    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: cert-name
    spec:
      domains:
        - example.com
        - www.example.com
    

    Benefits:

    • Automatic certificate provisioning
    • Automatic renewal (no expiration)
    • Free (no certificate costs)
    • Managed by Google Cloud

    gke-legacy-abac-disabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have legacy Attribute-Based Access Control (ABAC) disabled in favor of RBAC.

    • 5.8 Authentication and Authorization — Disable client certificate authentication, enable Google Groups for RBAC, and disable legacy ABAC.
    Remediation
    Fix: Disable Legacy ABAC

    Ensure ABAC is disabled (this is the default for new clusters):

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Explicitly disable legacy ABAC (default is false)
        enableLegacyAbac: false,
    
        // ... other configuration
    });
    

    Why disable ABAC:

    • ABAC is deprecated in Kubernetes
    • ABAC is less flexible and harder to manage than RBAC
    • ABAC permissions are defined in a static file that’s difficult to audit
    • RBAC provides fine-grained, dynamic access control
    • All GKE clusters should use RBAC (enabled by default)

    gke-linux-auditd-logging-enabled

    Severity: medium · Enforcement: advisory

    Ensure GKE node pools have Linux auditd logging enabled for OS-level security auditing.

    • 5.7 Logging — Enable Cloud Logging, Cloud Monitoring, and auditd logging.
    Remediation
    Fix: Enable Linux auditd Logging

    Enable Linux auditd logging on node pools:

    import * as gcp from "@pulumi/gcp";
    
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            linuxNodeConfig: {
                sysctls: {
                    // Configure sysctl parameters if needed
                },
            },
            // Enable Cloud Logging for system logs
            loggingVariant: "DEFAULT",
        },
    });
    
    // Ensure cluster has logging enabled
    const cluster = new gcp.container.Cluster("cluster", {
        loggingConfig: {
            enableComponents: [
                "SYSTEM_COMPONENTS",
                "WORKLOADS",
            ],
        },
    });
    

    Linux auditd logging:

    • Captures OS-level audit events
    • Logs file access, system calls, authentication
    • Integrated with Cloud Logging
    • Available on Container-Optimized OS

    Logging variants:

    • DEFAULT: Standard Cloud Logging (recommended)
    • MAX_THROUGHPUT: Higher throughput, may impact performance

    What gets logged:

    • File system access
    • System calls
    • Process execution
    • Authentication events
    • Network connections

    Note:

    • COS (Container-Optimized OS) has auditd pre-configured
    • Logs are automatically sent to Cloud Logging when enabled
    • Review audit rules based on security requirements

    gke-logging-monitoring-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have Cloud Logging and Cloud Monitoring enabled for system and workload observability.

    • 5.7 Logging — Enable Cloud Logging, Cloud Monitoring, and auditd logging.
    Remediation
    Fix: Enable Logging and Monitoring for GKE Cluster

    Configure logging and monitoring services:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Cloud Logging (recommended components)
        loggingConfig: {
            enableComponents: [
                "SYSTEM_COMPONENTS",  // System logs (kubelet, container runtime, etc.)
                "WORKLOADS",          // Application container logs
            ],
        },
    
        // Enable Cloud Monitoring (recommended components)
        monitoringConfig: {
            enableComponents: [
                "SYSTEM_COMPONENTS",  // System metrics
                "WORKLOADS",          // Workload metrics (requires GKE 1.24+)
            ],
            managedPrometheus: {
                enabled: true,  // Enable managed Prometheus collection
            },
        },
    
        // ... other configuration
    });
    

    Components:

    • SYSTEM_COMPONENTS: Logs/metrics from control plane and system pods
    • WORKLOADS: Logs/metrics from user workload pods
    • Managed Prometheus: Prometheus-compatible metric collection

    gke-metadata-server-enabled

    Severity: medium · Enforcement: advisory

    Ensure GKE clusters have Workload Identity enabled via GKE Metadata Server.

    • 5.4 Workload Identity — Use GKE Metadata Server and Workload Identity for workload authentication.
    Remediation
    Fix: Enable GKE Metadata Server for Workload Identity

    Enable Workload Identity on the cluster:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Workload Identity
        workloadIdentityConfig: {
            workloadPool: "my-project.svc.id.goog",
        },
    
        // ... other configuration
    });
    
    // Node pools must also enable GKE Metadata Server
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            workloadMetadataConfig: {
                mode: "GKE_METADATA",
            },
        },
    });
    

    Benefits:

    • Allows pods to authenticate to GCP APIs using Kubernetes Service Accounts
    • Eliminates need for service account keys in pods
    • Provides fine-grained IAM permissions per workload

    gke-network-policy-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have network policy support enabled (via GKE Dataplane V2 or Calico).

    • 4.3 Network Security — Use network policies to isolate traffic and restrict network access between pods.
    Remediation
    Fix: Enable Network Policy Support

    Option 1: GKE Dataplane V2 (Recommended):

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Dataplane V2 (includes network policy support)
        datapathProvider: "ADVANCED_DATAPATH",
    
        // Requires VPC-native cluster
        ipAllocationPolicy: {
            clusterSecondaryRangeName: "pods",
            servicesSecondaryRangeName: "services",
        },
    
        // ... other configuration
    });
    

    Option 2: Calico Network Policy:

    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Calico network policy
        networkPolicy: {
            enabled: true,
            provider: "CALICO",
        },
    
        // Enable network policy addon
        addonsConfig: {
            networkPolicyConfig: {
                disabled: false,
            },
        },
    
        // ... other configuration
    });
    

    GKE Dataplane V2 benefits:

    • Built on eBPF for better performance
    • Native network policy support
    • Better observability and security features
    • Recommended for new clusters

    gke-node-auto-repair-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE node pools have auto-repair enabled to automatically fix unhealthy nodes.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Enable Node Auto-Repair

    Configure auto-repair in node pool management settings:

    import * as gcp from "@pulumi/gcp";
    
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        management: {
            autoRepair: true,  // Enable auto-repair
            autoUpgrade: true, // Also recommended
        },
    });
    

    How auto-repair works:

    • GKE periodically checks node health
    • If a node fails health checks, it’s automatically recreated
    • Workloads are gracefully drained before node recreation
    • Helps maintain cluster health and availability

    Health checks include:

    • Kubelet status
    • Container runtime status
    • Node responsiveness

    gke-node-auto-upgrade-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE node pools have auto-upgrade enabled to automatically update nodes with security patches.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Enable Node Auto-Upgrade

    Configure auto-upgrade in node pool management settings:

    import * as gcp from "@pulumi/gcp";
    
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        management: {
            autoUpgrade: true,  // Enable auto-upgrade
            autoRepair: true,   // Also recommended
        },
    });
    

    How auto-upgrade works:

    • Nodes automatically upgrade to match control plane version
    • Upgrades happen during maintenance windows
    • Workloads are gracefully drained before upgrade
    • Keeps nodes secure with latest patches

    Best practice:

    • Use Release Channels for predictable upgrade schedules
    • Configure maintenance windows for controlled upgrade timing
    • Enable both auto-upgrade and auto-repair

    gke-not-using-default-service-account

    Severity: high · Enforcement: advisory

    Ensure GKE node pools do not use the Compute Engine default service account.

    • 5.2 Node Service Accounts — Use dedicated service accounts with Workload Identity for GKE nodes.
    Remediation
    Fix: Use Dedicated Service Account for GKE Nodes

    Create a dedicated service account with minimal permissions:

    import * as gcp from "@pulumi/gcp";
    
    // Create dedicated service account for GKE nodes
    const gkeNodeSa = new gcp.serviceaccount.Account("gke-nodes", {
        accountId: "gke-nodes",
        displayName: "GKE Node Service Account",
    });
    
    // Grant minimal required permissions
    const logWriterBinding = new gcp.projects.IAMMember("gke-log-writer", {
        role: "roles/logging.logWriter",
        member: pulumi.interpolate`serviceAccount:${gkeNodeSa.email}`,
    });
    
    const metricWriterBinding = new gcp.projects.IAMMember("gke-metric-writer", {
        role: "roles/monitoring.metricWriter",
        member: pulumi.interpolate`serviceAccount:${gkeNodeSa.email}`,
    });
    
    const monitoringViewerBinding = new gcp.projects.IAMMember("gke-monitoring-viewer", {
        role: "roles/monitoring.viewer",
        member: pulumi.interpolate`serviceAccount:${gkeNodeSa.email}`,
    });
    
    // Use dedicated service account in node pool
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            serviceAccount: gkeNodeSa.email,
            oauthScopes: [
                "https://www.googleapis.com/auth/cloud-platform",
            ],
        },
    });
    

    The Compute Engine default service account:

    • Has Editor role by default (overly permissive)
    • Format: PROJECT_NUMBER-compute@developer.gserviceaccount.com
    • Should not be used for GKE nodes

    gke-private-endpoint-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have private endpoint enabled and public access disabled to restrict control plane access.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Enable Private Endpoint for GKE Cluster

    Configure private cluster settings to enable private endpoint:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("private-cluster", {
        name: "private-gke-cluster",
        location: "us-central1",
    
        // Enable private cluster configuration
        privateClusterConfig: {
            enablePrivateEndpoint: true,  // Control plane only accessible via private IP
            enablePrivateNodes: true,     // Nodes only have private IPs
            masterIpv4CidrBlock: "172.16.0.0/28",  // CIDR for control plane
        },
    
        // Optional: Configure authorized networks for limited public access
        masterAuthorizedNetworksConfig: {
            cidrBlocks: [
                {
                    cidrBlock: "10.0.0.0/8",  // Your corporate network
                    displayName: "corporate-network",
                },
            ],
        },
    
        // ... other configuration
    });
    

    Note:

    • enablePrivateEndpoint: true ensures the control plane is only accessible via private IP
    • enablePrivateNodes: true ensures worker nodes only have private IPs
    • Use authorized networks only if you need limited public access for CI/CD or management

    gke-private-nodes-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE clusters have private nodes enabled so worker nodes only have internal IPs.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Enable Private Nodes

    Configure private nodes for the cluster:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable private cluster with private nodes
        privateClusterConfig: {
            enablePrivateNodes: true,           // Nodes only have private IPs
            enablePrivateEndpoint: true,        // Also recommended
            masterIpv4CidrBlock: "172.16.0.0/28",
        },
    
        // Requires VPC-native cluster
        ipAllocationPolicy: {
            clusterSecondaryRangeName: "pods",
            servicesSecondaryRangeName: "services",
        },
    
        // ... other configuration
    });
    

    Private nodes characteristics:

    • Worker nodes have only internal IP addresses
    • No direct internet connectivity
    • Internet access via Cloud NAT or proxy
    • Improved security posture

    Requirements:

    • VPC-native cluster (IP aliasing)
    • Cloud NAT for outbound internet access
    • Private Google Access for GCP API access

    gke-release-channel-enabled

    Severity: medium · Enforcement: advisory

    Ensure GKE clusters use Release Channels for automated version management.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Enable Release Channel

    Configure a release channel for the cluster:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable release channel
        releaseChannel: {
            channel: "REGULAR",  // or "RAPID" or "STABLE"
        },
    
        // ... other configuration
    });
    

    Release channel options:

    • RAPID: Early access to new features (for testing)
    • REGULAR: Balanced updates (recommended for most workloads)
    • STABLE: Conservative updates (for stability-critical workloads)

    Benefits:

    • Automatic control plane and node upgrades
    • Predictable upgrade schedule
    • Coordinated rollout of new features
    • Reduces manual version management overhead
    • Ensures timely security updates

    gke-secrets-encryption-kms-enabled

    Severity: critical · Enforcement: advisory

    Ensure GKE clusters encrypt Kubernetes secrets using Cloud KMS Customer-Managed Encryption Keys.

    • 5.3 Secrets Encryption — Encrypt Kubernetes secrets using Cloud KMS customer-managed keys.
    Remediation
    Fix: Enable Cloud KMS Encryption for GKE Secrets

    Configure database encryption with Cloud KMS for GKE cluster:

    import * as gcp from "@pulumi/gcp";
    
    // Create a Cloud KMS key ring and key
    const keyRing = new gcp.kms.KeyRing("gke-keyring", {
        name: "gke-keyring",
        location: "us-central1",
    });
    
    const cryptoKey = new gcp.kms.CryptoKey("gke-secrets-key", {
        name: "gke-secrets-key",
        keyRing: keyRing.id,
        purpose: "ENCRYPT_DECRYPT",
    });
    
    // Create GKE cluster with database encryption
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
        databaseEncryption: {
            state: "ENCRYPTED",
            keyName: cryptoKey.id,
        },
        // ... other configuration
    });
    

    Important: Application-layer secrets encryption using Cloud KMS must be enabled to protect Kubernetes Secret resources.

    gke-security-posture-enabled

    Severity: medium · Enforcement: advisory

    Ensure GKE clusters have Security Posture enabled for continuous security monitoring and recommendations.

    • 5.10 Additional Security Controls — Disable Kubernetes Dashboard, avoid alpha clusters, and enable security posture.
    Remediation
    Fix: Enable GKE Security Posture

    Configure Security Posture and Workload Vulnerability Scanning:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Security Posture
        securityPostureConfig: {
            mode: "BASIC",  // or "ENTERPRISE" for more features
            vulnerabilityMode: "VULNERABILITY_BASIC",  // or "VULNERABILITY_ENTERPRISE"
        },
    
        // ... other configuration
    });
    

    Security Posture modes:

    • BASIC: Free tier with essential security insights
    • ENTERPRISE: Advanced features (requires Security Command Center Premium)
    • DISABLED: No security posture monitoring

    Vulnerability scanning modes:

    • VULNERABILITY_DISABLED: No vulnerability scanning
    • VULNERABILITY_BASIC: Basic workload vulnerability scanning
    • VULNERABILITY_ENTERPRISE: Advanced scanning with more features

    Features:

    • Continuous security posture assessment
    • Workload vulnerability detection
    • Configuration best practice recommendations
    • Integration with Security Command Center
    • Compliance reporting (CIS Kubernetes Benchmark)

    Benefits:

    • Proactive security monitoring
    • Automated vulnerability detection
    • Actionable security recommendations
    • Compliance insights

    gke-shielded-nodes-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE node pools have Shielded Nodes enabled for enhanced boot-level security.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Enable Shielded Nodes

    Configure Shielded GKE Nodes:

    import * as gcp from "@pulumi/gcp";
    
    // Enable at cluster level
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable Shielded Nodes feature
        enableShieldedNodes: true,
    
        // ... other configuration
    });
    
    // Configure at node pool level
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            shieldedInstanceConfig: {
                enableSecureBoot: true,          // Recommended
                enableIntegrityMonitoring: true, // Recommended
            },
        },
    });
    

    Shielded Nodes features:

    • Secure Boot: Verifies boot components are signed
    • Integrity Monitoring: Detects boot-level modifications
    • vTPM: Virtual Trusted Platform Module for key storage

    Benefits:

    • Protects against rootkits and bootkits
    • Ensures nodes boot with verified software
    • Detects unauthorized boot-level changes

    gke-shielded-nodes-integrity-monitoring

    Severity: high · Enforcement: advisory

    Ensure GKE node pools have integrity monitoring enabled for Shielded Nodes.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Enable Integrity Monitoring

    Configure integrity monitoring for Shielded Nodes:

    import * as gcp from "@pulumi/gcp";
    
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            shieldedInstanceConfig: {
                enableIntegrityMonitoring: true,  // Enable integrity monitoring
                enableSecureBoot: true,           // Also recommended
            },
        },
    });
    

    How integrity monitoring works:

    • Measures boot components and stores in vTPM
    • Compares measurements on each boot
    • Reports anomalies to Cloud Monitoring
    • Detects unauthorized boot-level changes

    Benefits:

    • Early detection of compromised nodes
    • Continuous verification of node integrity
    • Integration with Cloud Monitoring for alerts

    gke-shielded-nodes-secure-boot

    Severity: high · Enforcement: advisory

    Ensure GKE node pools have Secure Boot enabled for Shielded Nodes.

    • 5.5 Node Configuration — Ensure nodes use COS with containerd, auto-repair, auto-upgrade, release channels, and Shielded Nodes.
    Remediation
    Fix: Enable Secure Boot

    Configure Secure Boot for Shielded Nodes:

    import * as gcp from "@pulumi/gcp";
    
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            shieldedInstanceConfig: {
                enableSecureBoot: true,           // Enable Secure Boot
                enableIntegrityMonitoring: true,  // Also recommended
            },
        },
    });
    

    How Secure Boot works:

    • Verifies digital signatures of boot components
    • Only allows signed and trusted software to boot
    • Prevents execution of malicious bootloaders
    • Uses UEFI firmware for verification

    Benefits:

    • Prevents rootkits and bootkits from loading
    • Ensures only trusted software runs at boot
    • Provides strongest boot-time security

    Note: Secure Boot may be incompatible with some kernel modules or custom configurations.

    gke-vpc-flow-logs-intranode-visibility

    Severity: medium · Enforcement: advisory

    Ensure GKE clusters have intranode visibility enabled for pod-to-pod network observability.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Enable Intranode Visibility

    Enable intranode visibility for pod-to-pod traffic monitoring:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Enable intranode visibility
        enableIntranodeVisibility: true,
    
        // ... other configuration
    });
    
    // Also enable VPC Flow Logs on the subnet
    const subnet = new gcp.compute.Subnetwork("subnet", {
        name: "gke-subnet",
        ipCidrRange: "10.0.0.0/20",
        network: network.id,
        region: "us-central1",
    
        // Enable VPC Flow Logs
        logConfig: {
            aggregationInterval: "INTERVAL_5_SEC",
            flowSampling: 1.0,  // 100% sampling
            metadata: "INCLUDE_ALL_METADATA",
        },
    });
    

    Intranode visibility:

    • Exposes pod-to-pod traffic on same node
    • Required for VPC Flow Logs to see all traffic
    • Enables comprehensive network monitoring

    VPC Flow Logs:

    • Log network flows for analysis
    • Security monitoring and forensics
    • Troubleshooting connectivity issues

    gke-vpc-native-cluster-required

    Severity: medium · Enforcement: advisory

    Ensure GKE clusters use VPC-native networking (IP aliasing) instead of routes-based networking.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Enable VPC-Native Networking for GKE Cluster

    Configure IP aliasing to create a VPC-native cluster:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
        network: "my-vpc",
        subnetwork: "my-subnet",
    
        // Enable VPC-native networking
        ipAllocationPolicy: {
            clusterSecondaryRangeName: "pods",     // Secondary range for pods
            servicesSecondaryRangeName: "services", // Secondary range for services
        },
    
        // ... other configuration
    });
    

    Benefits of VPC-native clusters:

    • Pods get IP addresses directly from VPC subnet ranges
    • Better integration with VPC features (firewall rules, VPC peering, Shared VPC)
    • Required for Private GKE clusters
    • Better scalability and performance
    • Required for GKE Dataplane V2 and network policies

    gke-web-ui-disabled

    Severity: low · Enforcement: advisory

    Ensure GKE clusters have the Kubernetes Dashboard (Web UI) disabled to reduce attack surface.

    • 5.10 Additional Security Controls — Disable Kubernetes Dashboard, avoid alpha clusters, and enable security posture.
    Remediation
    Fix: Disable Kubernetes Web UI

    Disable the Kubernetes Dashboard addon:

    import * as gcp from "@pulumi/gcp";
    
    const cluster = new gcp.container.Cluster("cluster", {
        name: "my-gke-cluster",
        location: "us-central1",
    
        // Disable Kubernetes Dashboard
        addonsConfig: {
            kubernetesDashboard: {
                disabled: true,
            },
        },
    
        // ... other configuration
    });
    

    Alternatives to Kubernetes Dashboard:

    • Google Cloud Console (GKE Workloads UI)
    • kubectl command-line tool
    • Kubernetes IDE extensions (Lens, VS Code Kubernetes)
    • Cloud-native dashboards (Grafana, etc.)

    The Kubernetes Dashboard has had security vulnerabilities and is not recommended for production use.

    gke-worker-node-firewall-configured

    Severity: high · Enforcement: advisory

    Ensure VPC firewall rules are configured to restrict access to GKE worker nodes.

    • 5.6 Network Configuration — Configure VPC-native clusters, private endpoints/nodes, authorized networks, and intranode visibility.
    Remediation
    Fix: Configure Firewall Rules for GKE Worker Nodes

    Create restrictive firewall rules for node network tags:

    import * as gcp from "@pulumi/gcp";
    
    // Allow only necessary traffic to worker nodes
    const allowSshFromBastion = new gcp.compute.Firewall("allow-ssh-from-bastion", {
        network: network.id,
        direction: "INGRESS",
        targetTags: ["gke-node"],  // GKE nodes typically have this tag
        sourceTags: ["bastion"],
        allows: [{
            protocol: "tcp",
            ports: ["22"],
        }],
    });
    
    // Allow health checks from GCP load balancers
    const allowHealthChecks = new gcp.compute.Firewall("allow-health-checks", {
        network: network.id,
        direction: "INGRESS",
        targetTags: ["gke-node"],
        sourceRanges: [
            "35.191.0.0/16",  // GCP health check ranges
            "130.211.0.0/22",
        ],
        allows: [{
            protocol: "tcp",
            ports: ["10256"],  // kube-proxy health check
        }],
    });
    
    // Deny all other inbound traffic (implicit, but can be explicit)
    const denyAll = new gcp.compute.Firewall("deny-all-to-nodes", {
        network: network.id,
        direction: "INGRESS",
        priority: 1000,
        targetTags: ["gke-node"],
        sourceRanges: ["0.0.0.0/0"],
        denies: [{
            protocol: "all",
        }],
    });
    

    Best practices:

    • Use private nodes to eliminate public IP exposure
    • Restrict SSH access to bastion hosts
    • Allow only necessary health check traffic
    • Use network tags to target GKE nodes
    • Review and minimize NodePort services

    gke-workload-identity-enabled

    Severity: high · Enforcement: advisory

    Ensure GKE node pools have Workload Identity enabled (GKE_METADATA mode) for secure pod-to-GCP authentication.

    • 5.2 Node Service Accounts — Use dedicated service accounts with Workload Identity for GKE nodes.
    Remediation
    Fix: Enable Workload Identity on Node Pools

    Configure node pools to use GKE Metadata Server:

    import * as gcp from "@pulumi/gcp";
    
    // Cluster must have Workload Identity enabled first
    const cluster = new gcp.container.Cluster("cluster", {
        workloadIdentityConfig: {
            workloadPool: "my-project.svc.id.goog",
        },
    });
    
    // Enable Workload Identity on node pool
    const nodePool = new gcp.container.NodePool("pool", {
        cluster: cluster.name,
        nodeConfig: {
            workloadMetadataConfig: {
                mode: "GKE_METADATA",  // Required for Workload Identity
            },
        },
    });
    
    // Bind Kubernetes SA to GCP SA
    const k8sSa = new k8s.core.v1.ServiceAccount("app-sa", {
        metadata: {
            name: "app-sa",
            namespace: "default",
            annotations: {
                "iam.gke.io/gcp-service-account": gcpSa.email,
            },
        },
    });
    
    const binding = new gcp.serviceaccount.IAMBinding("workload-identity-binding", {
        serviceAccountId: gcpSa.name,
        role: "roles/iam.workloadIdentityUser",
        members: [
            "serviceAccount:my-project.svc.id.goog[default/app-sa]",
        ],
    });
    

    Benefits:

    • Pods authenticate as GCP service accounts without keys
    • Fine-grained IAM permissions per workload
    • Automatic credential rotation

    k8s-cluster-admin-role-binding-minimized

    Severity: high · Enforcement: advisory

    Ensure cluster-admin ClusterRole is bound to a minimal number of users and service accounts.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Minimize cluster-admin Role Bindings

    Use more specific roles instead of cluster-admin:

    // Instead of binding cluster-admin, create specific roles
    const role = new k8s.rbac.v1.Role("specificRole", {
        metadata: { namespace: "default" },
        rules: [{
            apiGroups: [""],
            resources: ["pods"],
            verbs: ["get", "list", "watch"],
        }],
    });
    
    const roleBinding = new k8s.rbac.v1.RoleBinding("specificBinding", {
        metadata: { namespace: "default" },
        roleRef: {
            apiGroup: "rbac.authorization.k8s.io",
            kind: "Role",
            name: role.metadata.name,
        },
        subjects: [{
            kind: "User",
            name: "specific-user",
        }],
    });
    

    k8s-default-namespace-not-used

    Severity: medium · Enforcement: advisory

    Ensure workloads are not deployed to the default namespace.

    • 4.6 Pod Security — Apply RuntimeDefault seccomp profile to all workloads and ensure default namespace is not used.
    Remediation
    Fix: Use Dedicated Namespaces

    Create and use dedicated namespaces:

    const namespace = new k8s.core.v1.Namespace("app-namespace", {
        metadata: {
            name: "my-app",
        },
    });
    
    const deployment = new k8s.apps.v1.Deployment("app", {
        metadata: {
            namespace: namespace.metadata.name,
        },
        // ... rest of deployment spec
    });
    

    k8s-default-service-accounts-not-used

    Severity: medium · Enforcement: advisory

    Ensure workloads do not use the default service account.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Use Dedicated Service Accounts

    Create and use dedicated service accounts for workloads:

    const serviceAccount = new k8s.core.v1.ServiceAccount("appServiceAccount", {
        metadata: {
            namespace: "default",
            name: "my-app-sa",
        },
    });
    
    const deployment = new k8s.apps.v1.Deployment("app", {
        spec: {
            template: {
                spec: {
                    serviceAccountName: serviceAccount.metadata.name,
                    // ... rest of pod spec
                },
            },
        },
    });
    

    k8s-pod-security-allow-privilege-escalation-minimized

    Severity: high · Enforcement: advisory

    Ensure containers do not allow privilege escalation.

    • 4.2 Pod Security Standards — Enforce Pod Security Standard Baseline profile to prevent privileged containers and host namespace access.
    Remediation
    Fix: Disable Privilege Escalation

    Set allowPrivilegeEscalation to false in container security context:

    const pod = new k8s.core.v1.Pod("pod", {
        spec: {
            containers: [{
                name: "app",
                image: "nginx",
                securityContext: {
                    allowPrivilegeEscalation: false,
                    runAsNonRoot: true,
                    capabilities: {
                        drop: ["ALL"],
                    },
                },
            }],
        },
    });
    

    k8s-pod-security-host-ipc-minimized

    Severity: high · Enforcement: advisory

    Ensure containers do not share the host IPC namespace.

    • 4.2 Pod Security Standards — Enforce Pod Security Standard Baseline profile to prevent privileged containers and host namespace access.
    Remediation
    Fix: Disable Host IPC Sharing

    Remove hostIPC from pod spec:

    const pod = new k8s.core.v1.Pod("pod", {
        spec: {
            hostIPC: false,  // Explicitly set to false or remove
            containers: [{
                name: "app",
                image: "nginx",
            }],
        },
    });
    

    k8s-pod-security-host-network-minimized

    Severity: high · Enforcement: advisory

    Ensure containers do not share the host network namespace.

    • 4.2 Pod Security Standards — Enforce Pod Security Standard Baseline profile to prevent privileged containers and host namespace access.
    Remediation
    Fix: Disable Host Network Sharing

    Remove hostNetwork from pod spec:

    const pod = new k8s.core.v1.Pod("pod", {
        spec: {
            hostNetwork: false,  // Explicitly set to false or remove
            containers: [{
                name: "app",
                image: "nginx",
            }],
        },
    });
    

    k8s-pod-security-host-pid-minimized

    Severity: high · Enforcement: advisory

    Ensure containers do not share the host process ID namespace.

    • 4.2 Pod Security Standards — Enforce Pod Security Standard Baseline profile to prevent privileged containers and host namespace access.
    Remediation
    Fix: Disable Host PID Sharing

    Remove hostPID from pod spec:

    const pod = new k8s.core.v1.Pod("pod", {
        spec: {
            hostPID: false,  // Explicitly set to false or remove
            containers: [{
                name: "app",
                image: "nginx",
            }],
        },
    });
    

    k8s-pod-security-privileged-containers-minimized

    Severity: critical · Enforcement: advisory

    Ensure containers do not run in privileged mode.

    • 4.2 Pod Security Standards — Enforce Pod Security Standard Baseline profile to prevent privileged containers and host namespace access.
    Remediation
    Fix: Disable Privileged Mode

    Remove privileged flag from container security context:

    const pod = new k8s.core.v1.Pod("pod", {
        spec: {
            containers: [{
                name: "app",
                image: "nginx",
                securityContext: {
                    privileged: false,  // Explicitly set to false or remove
                    runAsNonRoot: true,
                    capabilities: {
                        drop: ["ALL"],
                    },
                },
            }],
        },
    });
    

    k8s-rbac-bind-impersonate-escalate-minimized

    Severity: critical · Enforcement: advisory

    Ensure Roles and ClusterRoles do not grant dangerous permissions: bind, impersonate, and escalate, which can lead to privilege escalation.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Remove Dangerous RBAC Permissions

    Avoid granting bind, impersonate, and escalate permissions:

    // Bad: DON'T grant these dangerous permissions
    const dangerousRole = new k8s.rbac.v1.ClusterRole("dangerous", {
        rules: [{
            apiGroups: ["rbac.authorization.k8s.io"],
            resources: ["clusterroles", "roles"],
            verbs: ["bind", "escalate"],  // DON'T DO THIS
        }, {
            apiGroups: [""],
            resources: ["users", "groups", "serviceaccounts"],
            verbs: ["impersonate"],  // DON'T DO THIS
        }],
    });
    
    // Good: Grant only necessary read permissions
    const safeRole = new k8s.rbac.v1.ClusterRole("safe", {
        rules: [{
            apiGroups: ["rbac.authorization.k8s.io"],
            resources: ["clusterroles", "roles"],
            verbs: ["get", "list", "watch"],  // Read-only
        }],
    });
    

    Why these are dangerous:

    • bind: Allows binding roles with more permissions than the user has
    • impersonate: Allows acting as another user/service account
    • escalate: Allows creating roles with more permissions than the user has

    k8s-rbac-secret-access-minimized

    Severity: critical · Enforcement: advisory

    Ensure Roles and ClusterRoles do not grant excessive permissions to secrets (create, update, patch, delete, or wildcard verbs).

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Minimize Secret Access Permissions

    Limit secret access to read-only (get, list, watch) unless write access is explicitly required:

    // Good: Read-only secret access
    const readOnlyRole = new k8s.rbac.v1.Role("secretReader", {
        metadata: { namespace: "default" },
        rules: [{
            apiGroups: [""],
            resources: ["secrets"],
            verbs: ["get", "list", "watch"],  // Read-only access
        }],
    });
    
    // Bad: Avoid granting write access to secrets
    const writeRole = new k8s.rbac.v1.Role("secretWriter", {
        rules: [{
            apiGroups: [""],
            resources: ["secrets"],
            verbs: ["*"],  // DON'T DO THIS
        }],
    });
    

    Only grant create/update/delete/patch permissions when absolutely necessary and document the justification.

    k8s-rbac-system-anonymous-bindings-minimized

    Severity: high · Enforcement: advisory

    Ensure that RoleBindings and ClusterRoleBindings do not grant permissions to system:anonymous unless absolutely necessary.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Minimize system:anonymous Bindings

    Remove bindings to system:anonymous unless required for specific health check endpoints:

    // Bad: Granting permissions to anonymous users
    const badBinding = new k8s.rbac.v1.ClusterRoleBinding("anonymous-access", {
        subjects: [{
            kind: "User",
            name: "system:anonymous",  // DON'T DO THIS
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "view",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    
    // Good: Require authentication
    const goodBinding = new k8s.rbac.v1.ClusterRoleBinding("authenticated-access", {
        subjects: [{
            kind: "Group",
            name: "system:authenticated",  // Only authenticated users
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "view",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    
    // Acceptable: Very limited anonymous access for health checks only
    const healthCheckRole = new k8s.rbac.v1.ClusterRole("healthcheck", {
        rules: [{
            nonResourceURLs: ["/healthz", "/readyz"],
            verbs: ["get"],
        }],
    });
    

    Anonymous access bypasses authentication and should be avoided in production clusters.

    k8s-rbac-system-authenticated-bindings-minimized

    Severity: medium · Enforcement: advisory

    Ensure that RoleBindings and ClusterRoleBindings do not grant excessive permissions to system:authenticated group beyond default bindings.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Minimize system:authenticated Bindings

    Use specific groups or service accounts instead of granting permissions to all authenticated users:

    // Bad: Granting broad permissions to all authenticated users
    const badBinding = new k8s.rbac.v1.ClusterRoleBinding("all-users-admin", {
        subjects: [{
            kind: "Group",
            name: "system:authenticated",  // DON'T DO THIS for broad roles
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "admin",  // Too broad
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    
    // Good: Use specific groups
    const goodBinding = new k8s.rbac.v1.ClusterRoleBinding("dev-team-access", {
        subjects: [{
            kind: "Group",
            name: "developers@example.com",  // Specific group
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "view",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    
    // Good: Use service accounts for workload access
    const saBinding = new k8s.rbac.v1.RoleBinding("app-access", {
        metadata: { namespace: "production" },
        subjects: [{
            kind: "ServiceAccount",
            name: "app-service-account",
            namespace: "production",
        }],
        roleRef: {
            kind: "Role",
            name: "app-role",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    

    Default allowed bindings:

    • system:basic-user - Allows basic self-discovery
    • system:discovery - Allows API discovery

    Binding to system:authenticated grants access to ALL users who can authenticate, including service accounts.

    k8s-rbac-system-masters-group-avoided

    Severity: critical · Enforcement: advisory

    Ensure that RoleBindings and ClusterRoleBindings do not bind to the system:masters group.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Avoid system:masters Group

    Remove bindings to the system:masters group and use more granular RBAC permissions:

    // Bad: Binding to system:masters
    const badBinding = new k8s.rbac.v1.ClusterRoleBinding("admin-binding", {
        subjects: [{
            kind: "Group",
            name: "system:masters",  // DON'T DO THIS
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "cluster-admin",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    
    // Good: Create specific roles with limited permissions
    const limitedRole = new k8s.rbac.v1.ClusterRole("limited-admin", {
        rules: [{
            apiGroups: ["apps"],
            resources: ["deployments"],
            verbs: ["get", "list", "watch"],
        }],
    });
    
    const goodBinding = new k8s.rbac.v1.ClusterRoleBinding("limited-binding", {
        subjects: [{
            kind: "User",
            name: "specific-user@example.com",  // Bind to specific users
        }],
        roleRef: {
            kind: "ClusterRole",
            name: limitedRole.metadata.name,
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    

    The system:masters group bypasses all authorization checks and should only be used for break-glass scenarios.

    k8s-rbac-system-unauthenticated-bindings-minimized

    Severity: high · Enforcement: advisory

    Ensure that RoleBindings and ClusterRoleBindings do not grant permissions to system:unauthenticated beyond default discovery bindings.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Minimize system:unauthenticated Bindings

    Remove non-default bindings to system:unauthenticated group:

    // Bad: Granting permissions to unauthenticated users
    const badBinding = new k8s.rbac.v1.ClusterRoleBinding("unauthenticated-access", {
        subjects: [{
            kind: "Group",
            name: "system:unauthenticated",  // DON'T DO THIS (unless for discovery)
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "view",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    
    // Good: Require authentication
    const goodBinding = new k8s.rbac.v1.ClusterRoleBinding("authenticated-access", {
        subjects: [{
            kind: "Group",
            name: "system:authenticated",  // Only authenticated users
        }],
        roleRef: {
            kind: "ClusterRole",
            name: "view",
            apiGroup: "rbac.authorization.k8s.io",
        },
    });
    

    Default allowed bindings:

    • system:public-info-viewer - Allows read-only access to API version info
    • system:discovery - Allows read-only access to API discovery endpoints

    Any other bindings to system:unauthenticated should be carefully reviewed and justified.

    k8s-rbac-wildcard-use-minimized

    Severity: high · Enforcement: advisory

    Ensure Roles and ClusterRoles do not use wildcards for resources, verbs, or apiGroups.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Remove Wildcards from RBAC Rules

    Be specific about resources, verbs, and API groups:

    const role = new k8s.rbac.v1.Role("specificRole", {
        metadata: { namespace: "default" },
        rules: [{
            apiGroups: [""],  // Specific API group, not "*"
            resources: ["pods", "services"],  // Specific resources, not "*"
            verbs: ["get", "list", "watch"],  // Specific verbs, not "*"
        }],
    });
    

    k8s-seccomp-runtime-default-required

    Severity: medium · Enforcement: advisory

    Ensure that all pods have seccomp profile set to RuntimeDefault.

    • 4.6 Pod Security — Apply RuntimeDefault seccomp profile to all workloads and ensure default namespace is not used.
    Remediation
    Fix: Apply RuntimeDefault Seccomp Profile

    Set the seccomp profile to RuntimeDefault at the pod or container level:

    // Good: Pod-level seccomp (applies to all containers)
    const pod = new k8s.core.v1.Pod("secure-pod", {
        spec: {
            securityContext: {
                seccompProfile: {
                    type: "RuntimeDefault",
                },
            },
            containers: [{
                name: "app",
                image: "nginx",
            }],
        },
    });
    
    // Good: Container-level seccomp
    const deployment = new k8s.apps.v1.Deployment("secure-deployment", {
        spec: {
            template: {
                spec: {
                    containers: [{
                        name: "app",
                        image: "nginx",
                        securityContext: {
                            seccompProfile: {
                                type: "RuntimeDefault",
                            },
                        },
                    }],
                },
            },
        },
    });
    
    // Bad: No seccomp profile or Unconfined
    const insecurePod = new k8s.core.v1.Pod("insecure", {
        spec: {
            securityContext: {
                seccompProfile: {
                    type: "Unconfined",  // DON'T DO THIS
                },
            },
            containers: [{ name: "app", image: "nginx" }],
        },
    });
    

    Seccomp profile types:

    • RuntimeDefault: Uses container runtime’s default profile (required by CIS)
    • Localhost: Uses custom profile from node filesystem (not allowed by this policy)
    • Unconfined: Disables seccomp (not allowed)

    k8s-service-account-token-mounted-minimized

    Severity: medium · Enforcement: advisory

    Ensure service account tokens are not automatically mounted in pods unless explicitly required.

    • 4.1 RBAC and Authentication — Implement proper RBAC controls to restrict system group bindings and minimize permissions.
    Remediation
    Fix: Disable Service Account Token Auto-Mounting

    Set automountServiceAccountToken: false unless the pod needs Kubernetes API access:

    // Good: Disable auto-mounting when not needed
    const pod = new k8s.core.v1.Pod("myPod", {
        metadata: { name: "my-pod" },
        spec: {
            automountServiceAccountToken: false,  // Explicitly disable
            containers: [{
                name: "app",
                image: "nginx:latest",
            }],
        },
    });
    
    // Also disable at ServiceAccount level
    const sa = new k8s.core.v1.ServiceAccount("myServiceAccount", {
        metadata: { name: "my-sa" },
        automountServiceAccountToken: false,  // Disable by default
    });
    

    Only enable when the pod explicitly requires Kubernetes API access.

    k8s-trusted-images-only

    Severity: high · Enforcement: advisory

    Ensure that only container images from trusted registries are used, and that specific image tags (not :latest) are specified.

    • 5.1 Container Images — Ensure IAM controls and trusted image sources.
    Remediation
    Fix: Use Trusted Container Images

    Use images from trusted registries with specific tags or digests:

    // Good: Trusted registry with specific tag
    const deployment = new k8s.apps.v1.Deployment("app", {
        spec: {
            template: {
                spec: {
                    containers: [{
                        name: "app",
                        image: "gcr.io/my-project/app:v1.2.3",  // Specific version
                    }],
                },
            },
        },
    });
    
    // Best: Use image digest for immutability
    const immutableDeployment = new k8s.apps.v1.Deployment("app", {
        spec: {
            template: {
                spec: {
                    containers: [{
                        name: "app",
                        image: "gcr.io/my-project/app@sha256:abc123...",  // Image digest
                    }],
                },
            },
        },
    });
    
    // Bad: Untrusted registry or :latest tag
    const badDeployment = new k8s.apps.v1.Deployment("app", {
        spec: {
            template: {
                spec: {
                    containers: [{
                        name: "app",
                        image: "random-registry.com/app:latest",  // DON'T DO THIS
                    }],
                },
            },
        },
    });
    

    Configure trusted registries in your policy pack:

    new PolicyPack("my-pack", {
        policies: [
            {
                ...k8sTrustedImagesOnlyPolicy,
                configSchema: {
                    trustedRegistries: [
                        "123456789012.dkr.ecr.us-east-1.amazonaws.com",  // Your ECR
                        "gcr.io/my-project",  // Your GCR
                        "mycompany.azurecr.io",  // Your ACR
                    ],
                },
            },
        ],
    });
    

    Default trusted registries include:

    • Google Container Registry (gcr.io, pkg.dev)
    • AWS ECR (.dkr.ecr..amazonaws.com, public.ecr.aws)
    • Azure Container Registry (*.azurecr.io)
    • Official Kubernetes registries (registry.k8s.io, k8s.gcr.io)
    • Docker Hub official images (docker.io/library)
    • GitHub Container Registry (ghcr.io)
    • Quay.io (quay.io)
    • Microsoft Container Registry (mcr.microsoft.com)

      The infrastructure as code platform for any cloud.