> ## 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.

# Ensure Clusters Are Created With Private Endpoint Enabled And Public Access Disabled

### More Info:

Create clusters with the private API server endpoint enabled and public endpoint access disabled so that all communication between nodes and the API server stays within the VPC.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify clusters and current endpoint exposure**
           * On any machine with AWS CLI access:
             ```bash theme={null}
             aws eks list-clusters --region us-east-1
             aws eks list-clusters --region us-west-2
             ```
           * For each cluster:
             ```bash theme={null}
             aws eks describe-cluster \
               --region us-east-1 \
               --name <cluster-name> \
               --query "cluster.resourcesVpcConfig.{private:endpointPrivateAccess,public:endpointPublicAccess,publicCidrs:publicAccessCidrs}" \
               --output table
             ```
           * Record whether `private` is `true`, `public` is `false`, and whether any CIDRs are allowed.

        2. **Review access requirements and break-glass needs**
           * With your platform/network team, decide whether:
             * All administrative/API access can occur from within the VPC via peering/VPN/Direct Connect.
             * Any users or automation require public API access (for break-glass or existing workflows).
           * If public access is truly unnecessary, plan to set `endpointPublicAccess=false`.
           * If some public access is required, document the minimal set of IP CIDRs that must reach the API and prepare to restrict via `publicAccessCidrs` instead of fully disabling public access.

        3. **Confirm network path for private-only access**
           * Verify that all nodes and admin entry points have a private path to the cluster’s VPC subnets:
             * Check VPC peering / Transit Gateway / VPN / Direct Connect configuration.
             * Confirm that security groups, route tables, and NACLs permit HTTPS (443) to the EKS control plane private endpoint from admin networks and node subnets.
           * If this is not currently in place, implement and validate connectivity before disabling public access.

        4. **Update cluster endpoint configuration (if approved)**
           * On any machine with AWS CLI access, for a cluster where private-only is acceptable:
             ```bash theme={null}
             aws eks update-cluster-config \
               --region us-east-1 \
               --name <cluster-name> \
               --resources-vpc-config endpointPrivateAccess=true,endpointPublicAccess=false
             ```
           * If you must temporarily retain restricted public access instead of disabling it:
             ```bash theme={null}
             aws eks update-cluster-config \
               --region us-east-1 \
               --name <cluster-name> \
               --resources-vpc-config endpointPrivateAccess=true,endpointPublicAccess=true,publicAccessCidrs=10.0.0.0/16,203.0.113.10/32
             ```
           * Schedule and communicate this change; expect an impact on any clients currently reaching the public endpoint.

        5. **Verify the configuration and connectivity**
           * Confirm endpoint flags:
             ```bash theme={null}
             aws eks describe-cluster \
               --region us-east-1 \
               --name <cluster-name> \
               --query "cluster.resourcesVpcConfig"
             ```
             Ensure `"endpointPrivateAccess": true` and `"endpointPublicAccess": false` (or, if intentionally retained, `true` with minimal `publicAccessCidrs`).
           * From a bastion or admin host inside the VPC, verify `kubectl` still works:
             ```bash theme={null}
             kubectl --context <cluster-context> get nodes
             ```

        6. **Document the decision and residual risk**
           * Record for each cluster:
             * Final values of `endpointPrivateAccess`, `endpointPublicAccess`, and `publicAccessCidrs`.
             * The rationale if public access is not fully disabled.
             * Any compensating controls (IP restrictions, strong auth, logging).
           * Revisit this decision periodically and after major network/organizational changes.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot be used to enable a private EKS API endpoint or disable public access, because this setting is part of the managed control plane configuration. Make these changes via the AWS console, AWS CLI, or your IaC definitions as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Report EKS cluster endpoint exposure for multiple clusters (MANUAL review).
        #
        # Requirements:
        #   - aws CLI v2 configured with appropriate credentials
        #   - jq installed
        #
        # Usage examples:
        #   ./eks-endpoint-audit.sh                  # all regions in account
        #   AWS_REGION=us-east-1 ./eks-endpoint-audit.sh
        #   AWS_REGIONS="us-east-1 eu-west-1" ./eks-endpoint-audit.sh
        #
        # Interpretation (problem indicators):
        #   - endpointPublicAccess == true          => RISK: public API endpoint is enabled
        #   - endpointPrivateAccess == false        => RISK: no private access from VPC
        #   - Both conditions together              => HIGHEST RISK
        #
        # This script ONLY reports state; changing endpoint settings must be done
        # deliberately per cluster via AWS CLI/console/IaC after review.

        set -euo pipefail

        # Discover regions
        if [[ -n "${AWS_REGIONS:-}" ]]; then
          REGIONS="${AWS_REGIONS}"
        elif [[ -n "${AWS_REGION:-}" ]]; then
          REGIONS="${AWS_REGION}"
        else
          REGIONS="$(aws ec2 describe-regions --all-regions --query 'Regions[].RegionName' --output text)"
        fi

        echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
        echo "Account ID: $(aws sts get-caller-identity --query 'Account' --output text)"
        echo "Regions: ${REGIONS}"
        echo

        # Header
        printf "%-15s %-35s %-8s %-8s %-60s\n" \
          "REGION" "CLUSTER" "PUB" "PRIV" "PUBLIC_ACCESS_CIDRS"
        printf "%0.s-" {1..140}; echo

        for region in ${REGIONS}; do
          clusters=$(aws eks list-clusters --region "${region}" --query 'clusters[]' --output text 2>/dev/null || true)
          if [[ -z "${clusters}" ]]; then
            continue
          fi

          for cluster in ${clusters}; do
            desc_json=$(aws eks describe-cluster --region "${region}" --name "${cluster}" --output json)

            pub=$(echo "${desc_json}"  | jq -r '.cluster.resourcesVpcConfig.endpointPublicAccess')
            priv=$(echo "${desc_json}" | jq -r '.cluster.resourcesVpcConfig.endpointPrivateAccess')
            cidrs=$(echo "${desc_json}" | jq -r '.cluster.resourcesVpcConfig.publicAccessCidrs | join(",")')

            printf "%-15s %-35s %-8s %-8s %-60s\n" \
              "${region}" "${cluster}" "${pub}" "${priv}" "${cidrs}"
          done
        done

        cat <<'EOF'

        Interpretation guidance (MANUAL review required):

        - Desired (per CIS EKS 5.4.2):
            PUB=false  and  PRIV=true

        - Problematic states:
            1) PUB=true and PRIV=false
               - API server only reachable via public endpoint from the internet CIDRs.
               - ACTION: Strongly consider switching to private-only, with controlled jump/bastion or VPN.

            2) PUB=true and PRIV=true
               - Private access exists, but public endpoint is still exposed.
               - Review 'PUBLIC_ACCESS_CIDRS':
                   * 0.0.0.0/0 or very broad CIDRs => high risk; restrict or disable.
                   * Narrow CIDRs may be acceptable based on your risk appetite and access model.

            3) PUB=false and PRIV=false
               - Misconfigured / unusable state for normal operation.
               - Investigate immediately; cluster access may be broken.

        Decisions to make per cluster:
          - Is any public endpoint exposure (PUB=true) acceptable in this environment?
          - If yes, are PUBLIC_ACCESS_CIDRS tightly restricted to necessary corporate IP ranges?
          - Can you operate with PRIV-only access (recommended) using VPN/Direct Connect/VPC peering/bastion?

        To change settings after review (example, NOT executed by this script):

          aws eks update-cluster-config \
            --region <region> \
            --name <cluster-name> \
            --resources-vpc-config endpointPrivateAccess=true,endpointPublicAccess=false

        Apply changes via your standard change-management / IaC process.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
