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 Pulumi Cloud feature is available in the Business Critical edition.

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

    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.