> ## 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 Control Plane Endpoint

### More Info:

Enable Endpoint Private Access to restrict access to the clusters control plane to only an allowlist of authorized IPs.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS EKS
* 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. **Gather current cluster endpoint configuration**\
           Run on any machine with AWS CLI access and IAM permissions:
           ```bash theme={null}
           aws eks describe-cluster \
             --region us-east-1 \
             --name my-eks-cluster \
             --query 'cluster.resourcesVpcConfig.{endpointPrivateAccess:endpointPrivateAccess,endpointPublicAccess:endpointPublicAccess,publicAccessCidrs:publicAccessCidrs}' \
             --output table
           ```
           Replace `us-east-1` and `my-eks-cluster` with your actual region and cluster name.

        2. **Decide desired access model with security/network teams**
           * Preferred: **private-only** API (no public access) for production clusters.
           * If public access is required (e.g., for admins from office/VPN): define a **minimal set of trusted IPv4 CIDR blocks**, ideally `/32` or small ranges, and ensure they do not overlap with reserved ranges.
           * Confirm your nodes and any automation can reach the private endpoint via VPC/VPN/Direct Connect/Transit Gateway.

        3. **Configure private endpoint access (if not already enabled)**\
           If `endpointPrivateAccess` is `false`, enable it:
           ```bash theme={null}
           aws eks update-cluster-config \
             --region us-east-1 \
             --name my-eks-cluster \
             --resources-vpc-config endpointPrivateAccess=true
           ```
           This keeps node↔API communication inside the VPC. No pod restart is required, but control‑plane connectivity paths change; ensure routing and security groups allow this.

        4. **Restrict or disable public endpoint access**
           * To **disable** public access entirely:
             ```bash theme={null}
             aws eks update-cluster-config \
               --region us-east-1 \
               --name my-eks-cluster \
               --resources-vpc-config endpointPublicAccess=false
             ```
           * If public access is needed, **tighten CIDRs** to your allowlist (example uses single admin IP):
             ```bash theme={null}
             aws eks update-cluster-config \
               --region us-east-1 \
               --name my-eks-cluster \
               --resources-vpc-config \
               "endpointPublicAccess=true,publicAccessCidrs=203.0.113.5/32,198.51.100.10/32"
             ```
           Replace the example CIDRs with your approved ranges.

        5. **Verify the updated configuration**\
           After the update completes (may take a few minutes), re-run on any machine with AWS CLI access:
           ```bash theme={null}
           aws eks describe-cluster \
             --region us-east-1 \
             --name my-eks-cluster \
             --query 'cluster.resourcesVpcConfig.{endpointPrivateAccess:endpointPrivateAccess,endpointPublicAccess:endpointPublicAccess,publicAccessCidrs:publicAccessCidrs}' \
             --output table
           ```
           Confirm `endpointPrivateAccess` is `true`, and that `endpointPublicAccess` and `publicAccessCidrs` match your chosen policy.

        6. **Functionally test access paths**
           * From a **node inside the VPC**, confirm API access still works:
             ```bash theme={null}
             kubectl get nodes
             ```
           * From a **client IP not in any allowed CIDR**, confirm the public endpoint is no longer reachable (connection timeout or TLS failure).
           * From an **allowed client IP** (if public access is enabled), confirm API access succeeds with valid credentials.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot change control plane endpoint access, because this setting is managed at the cloud provider / EKS control plane level, not via Kubernetes API objects. Use the cloud provider console/CLI/IaC to update the cluster’s endpoint access as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Report EKS control plane endpoint exposure for all clusters in an account/region.
        # Requires: aws CLI, jq
        #
        # Run on: any machine with AWS credentials and aws/jq installed.

        set -euo pipefail

        AWS_REGION="${1:-us-east-1}"

        echo "Inspecting EKS clusters in region: ${AWS_REGION}" >&2
        echo

        # Header
        printf "%-40s %-8s %-7s %-18s %-30s\n" \
          "CLUSTER_NAME" "PRIVATE" "PUBLIC" "PUBLIC_ACCESS_MODE" "PUBLIC_ACCESS_CIDRS"
        printf -- "%.0s-" {1..120}; echo

        clusters_json="$(aws eks list-clusters --region "${AWS_REGION}")"
        cluster_names=($(echo "${clusters_json}" | jq -r '.clusters[]'))

        if [ "${#cluster_names[@]}" -eq 0 ]; then
          echo "No EKS clusters found in region ${AWS_REGION}" >&2
          exit 0
        fi

        for cluster in "${cluster_names[@]}"; do
          desc="$(aws eks describe-cluster --region "${AWS_REGION}" --name "${cluster}")"

          private_access="$(echo "${desc}" \
            | jq -r '.cluster.resourcesVpcConfig.endpointPrivateAccess')"
          public_access="$(echo "${desc}" \
            | jq -r '.cluster.resourcesVpcConfig.endpointPublicAccess')"
          public_cidrs="$(echo "${desc}" \
            | jq -r '.cluster.resourcesVpcConfig.publicAccessCidrs | join(",")')"

          # Derived "mode" for easier review:
          # - FULLY_PRIVATE:     private=true,  public=false
          # - RESTRICTED_PUBLIC: private=true,  public=true,  CIDRs not 0.0.0.0/0
          # - OPEN_PUBLIC:       public=true and includes 0.0.0.0/0
          # - PUBLIC_NO_PRIVATE: private=false, public=true (with any CIDRs)
          mode="UNKNOWN"
          if [ "${public_access}" = "false" ] && [ "${private_access}" = "true" ]; then
            mode="FULLY_PRIVATE"
          elif [ "${public_access}" = "true" ] && [[ "${public_cidrs}" == *"0.0.0.0/0"* ]]; then
            mode="OPEN_PUBLIC"
          elif [ "${public_access}" = "true" ] && [ "${private_access}" = "false" ]; then
            mode="PUBLIC_NO_PRIVATE"
          elif [ "${public_access}" = "true" ] && [ "${private_access}" = "true" ]; then
            mode="RESTRICTED_PUBLIC"
          fi

          printf "%-40s %-8s %-7s %-18s %-30s\n" \
            "${cluster}" \
            "${private_access}" \
            "${public_access}" \
            "${mode}" \
            "${public_cidrs}"
        done

        cat <<'EOF'

        How to interpret results (potential problems):

        1) endpointPrivateAccess = false
           - Modes: PUBLIC_NO_PRIVATE or OPEN_PUBLIC
           - Issue: Nodes and workloads must reach the API over the public internet; control-plane
             traffic is not restricted to the VPC as recommended.

        2) endpointPublicAccess = true AND publicAccessCidrs includes 0.0.0.0/0
           - Mode: OPEN_PUBLIC
           - Issue: The API server is reachable from any IP on the internet.

        3) endpointPublicAccess = true AND publicAccessCidrs contains broad CIDRs
           (e.g. 0.0.0.0/0, 0.0.0.0/1, 10.0.0.0/8, etc.)
           - Mode: RESTRICTED_PUBLIC (but possibly overly permissive)
           - Issue: Review whether each CIDR is truly required and minimize where possible.

        4) Preferred states with respect to this control:
           - FULLY_PRIVATE:
               endpointPrivateAccess = true
               endpointPublicAccess  = false
           - RESTRICTED_PUBLIC (if public access is required):
               endpointPrivateAccess = true
               endpointPublicAccess  = true
               publicAccessCidrs     = tightly scoped, specific /32s or small ranges

        Note: This script only reports configuration. Changes must be made via aws eks update-cluster-config
        or your IaC/console workflow after a risk/operations review.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
