> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Restrict Access To The Control Plane Endpoint

### More Info:

Enable Master Authorized Networks to restrict access to the clusters control plane (master endpoint) to an allowlist of authorized IP addresses.

### Risk Level

High

### Address

Security

### Compliance Standards

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS OKE
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List current control plane access configuration**
           * On any machine with `gcloud` and the correct project/permissions:
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME \
               --region=CLUSTER_REGION \
               --project=PROJECT_ID \
               --format="yaml(name,endpoint,masterAuthorizedNetworksConfig,privateClusterConfig)"
             ```
           * Review `masterAuthorizedNetworksConfig`:
             * If `enabled: true` and `cidrBlocks` is populated with specific IP ranges, MAN is enabled.
             * If it is absent, `enabled: false`, or `0.0.0.0/0` is present, the control plane is overly exposed.

        2. **Identify legitimate admin and automation source IPs**
           * Collect the public IPs (or ranges) used by:
             * Platform/cluster administrators.
             * CI/CD systems, bastion hosts, VPNs, and on‑prem connectivity endpoints that need `kubectl` access.
           * Prefer stable ranges: VPN egress IPs, corporate NAT ranges, or bastion hosts over individual, dynamic user IPs.

        3. **Decide the target allowed IP ranges**
           * Normalize and consolidate IPs into the smallest sensible set of CIDR blocks (e.g. `203.0.113.10/32`, `198.51.100.0/24`).
           * Explicitly decide whether any broad ranges (e.g. `0.0.0.0/0`, `/16`) are truly required; in most cases they should be removed.
           * Confirm with stakeholders that all operationally required access is covered by the finalized allowlist.

        4. **Configure / tighten Master Authorized Networks**
           * Using the Google Cloud Console:
             * Go to: Kubernetes Engine → Clusters → select the cluster.
             * Edit the cluster → Networking / Security section.
             * Enable “Master Authorized Networks” (if disabled).
             * Add each approved CIDR block; remove any unapproved or overly broad ranges.
             * Save and apply changes (this may trigger a control plane update operation).
           * Or using `gcloud` on any machine with access:
             ```bash theme={null}
             gcloud container clusters update CLUSTER_NAME \
               --region=CLUSTER_REGION \
               --project=PROJECT_ID \
               --enable-master-authorized-networks \
               --master-authorized-networks=203.0.113.10/32,198.51.100.0/24
             ```
           * Be careful not to exclude your own current IP; otherwise, further `kubectl` and `gcloud` access to the API endpoint may be blocked.

        5. **(Optional) Combine with private control plane if feasible**
           * If your environment supports it and it fits your network design, review whether the cluster is (or should be) a private cluster, limiting the control plane to internal addresses:
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME \
               --region=CLUSTER_REGION \
               --project=PROJECT_ID \
               --format="yaml(privateClusterConfig)"
             ```
           * Decide, with your network/security teams, whether converting to or using a private cluster plus MAN further improves your exposure posture.

        6. **Verify remediation and document rationale**
           * On any machine with `gcloud`:
             ```bash theme={null}
             gcloud container clusters describe CLUSTER_NAME \
               --region=CLUSTER_REGION \
               --project=PROJECT_ID \
               --format="yaml(masterAuthorizedNetworksConfig)"
             ```
           * Confirm:
             * `enabled: true` is present.
             * `cidrBlocks` only contains your approved ranges; no `0.0.0.0/0` or unnecessary broad CIDRs.
           * Capture the output and the business justification for each allowed CIDR in your change records or security documentation for future audits.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot configure the control plane endpoint or Master Authorized Networks; this setting is managed at the cloud provider / managed control plane level (console, provider CLI, or IaC). Refer to the Manual Steps section for how to review and change this configuration in your provider.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # audit-gke-master-authorized-networks.sh
        #
        # Purpose:
        #   Report whether Master Authorized Networks are enabled for a set of GKE clusters
        #   and list the allowed CIDR ranges where enabled.
        #
        # Requirements:
        #   - gcloud CLI installed and authenticated
        #   - jq installed
        #
        # Scope:
        #   - This runs from any machine with gcloud access to the relevant project(s).
        #
        # Usage:
        #   # Single project, all regions/zones:
        #   ./audit-gke-master-authorized-networks.sh PROJECT_ID
        #
        #   # Multiple projects:
        #   ./audit-gke-master-authorized-networks.sh PROJECT_ID_1 PROJECT_ID_2 ...
        #

        set -euo pipefail

        if ! command -v gcloud >/dev/null 2>&1; then
          echo "ERROR: gcloud CLI not found in PATH" >&2
          exit 1
        fi

        if ! command -v jq >/dev/null 2>&1; then
          echo "ERROR: jq not found in PATH" >&2
          exit 1
        fi

        if [ "$#" -lt 1 ]; then
          echo "Usage: $0 PROJECT_ID [PROJECT_ID...]" >&2
          exit 1
        fi

        echo "timestamp,project,location,cluster_name,endpoint_private,master_authorized_networks_enabled,allowed_cidrs"

        for PROJECT in "$@"; do
          # List all clusters (regional and zonal) in the project
          # Output in JSON to be parsed reliably
          CLUSTERS_JSON=$(gcloud container clusters list \
            --project="${PROJECT}" \
            --format=json)

          # If no clusters, continue
          if [ "$(echo "${CLUSTERS_JSON}" | jq 'length')" -eq 0 ]; then
            continue
          fi

          echo "${CLUSTERS_JSON}" | jq -c '.[]' | while read -r cluster; do
            NAME=$(echo "${cluster}" | jq -r '.name')
            LOCATION=$(echo "${cluster}" | jq -r '.location')

            # Get full description including masterAuthorizedNetworksConfig
            DESC_JSON=$(gcloud container clusters describe "${NAME}" \
              --project="${PROJECT}" \
              --region="${LOCATION}" \
              --format=json 2>/dev/null || \
              gcloud container clusters describe "${NAME}" \
                --project="${PROJECT}" \
                --zone="${LOCATION}" \
                --format=json 2>/dev/null || echo "{}")

            # Detect whether private endpoint is enabled (private cluster)
            ENDPOINT_PRIVATE=$(echo "${DESC_JSON}" | jq -r '.privateClusterConfig.enablePrivateEndpoint // false')

            # Detect whether Master Authorized Networks is enabled
            MAN_ENABLED=$(echo "${DESC_JSON}" | jq -r '.masterAuthorizedNetworksConfig.enabled // false')

            # Collect all CIDR blocks (if enabled)
            CIDRS=$(echo "${DESC_JSON}" \
              | jq -r '[.masterAuthorizedNetworksConfig.cidrBlocks[]?.cidrBlock] | join(";")')

            # If MAN is disabled, set CIDRS to empty string for clarity
            if [ "${MAN_ENABLED}" != "true" ]; then
              CIDRS=""
            fi

            printf "%s,%s,%s,%s,%s,%s,%s\n" \
              "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
              "${PROJECT}" \
              "${LOCATION}" \
              "${NAME}" \
              "${ENDPOINT_PRIVATE}" \
              "${MAN_ENABLED}" \
              "${CIDRS}"
          done
        done
        ```

        Explanation of problematic output:

        * Focus on the `master_authorized_networks_enabled` column:
          * `false` indicates the control plane endpoint is not restricted by Master Authorized Networks and should be reviewed.
        * Even when `master_authorized_networks_enabled` is `true`, review the `allowed_cidrs`:
          * Very broad ranges like `0.0.0.0/0`, `::/0`, or organizationally-uncontrolled CIDRs are problematic and should be tightened.
        * Consider `endpoint_private`:
          * If `endpoint_private` is `false` (public endpoint) and `master_authorized_networks_enabled` is `false` or has overly broad CIDRs, this is especially high risk.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
