Clusters Are Created With Private Endpoint Enabled And Public Access Disabled
More Info:
Disable access to the Kubernetes API from outside the node network if it is not required.
Risk Level
Low
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AKS
- CIS Critical Security Controls v8
- 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)
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Gather current API server access configuration
- On any machine with
azaccess:az aks show \--resource-group MY_RESOURCE_GROUP \--name MY_AKS_CLUSTER \--query "apiServerAccessProfile" \--output jsonc - Review:
enablePrivateClusterenablePrivateClusterPublicFQDNauthorizedIpRangesenablePublicFqdn(if present)
- On any machine with
-
Decide if public API access is required
- Identify all users/automation that access the API:
- From on-prem networks
- From developer laptops
- From other Azure services or VNets
- Determine if these can instead:
- Access from within the AKS VNet or peered VNets
- Use a VPN/ExpressRoute into the VNet
- If any use case truly requires access from the public internet, document the minimum set of source IP ranges required.
- Identify all users/automation that access the API:
-
If keeping public endpoint, restrict it to specific CIDR ranges
- On any machine with
azaccess, if you must retain public access:az aks update \--resource-group MY_RESOURCE_GROUP \--name MY_AKS_CLUSTER \--api-server-authorized-ip-ranges 203.0.113.0/24 198.51.100.10/32 - Replace the CIDRs with the minimal, documented ranges needed.
- On any machine with
-
If feasible, disable the public endpoint and use private access
- Confirm private connectivity is or will be in place:
- AKS cluster deployed as a private cluster (
enablePrivateCluster: true), or plan to recreate it as such. - VNets/peering/VPN/ExpressRoute are configured so administrators and CI/CD can reach the AKS VNet.
- AKS cluster deployed as a private cluster (
- When ready to disable the public endpoint:
az aks update \--resource-group MY_RESOURCE_GROUP \--name MY_AKS_CLUSTER \--api-server-access-profile enablePublicFqdn=false
- Be aware this can break all existing accesses relying on the public FQDN; ensure alternative access paths first.
- Confirm private connectivity is or will be in place:
-
Configure or validate private DNS for the API server
- On any machine with
azaccess, list private DNS zone links for the AKS VNet:az network private-dns link vnet list \--resource-group MY_DNS_RESOURCE_GROUP \--zone-name "privatelink.<region>.azmk8s.io" \--output table - If no appropriate link exists, create one between the AKS VNet and the AKS private DNS zone according to your network design and Azure documentation.
- On any machine with
-
Verify final state against the intent and document
- Re-run:
az aks show \--resource-group MY_RESOURCE_GROUP \--name MY_AKS_CLUSTER \--query "apiServerAccessProfile" \--output jsonc
- Confirm:
- If the goal is full compliance:
enablePrivateClusteristrueandenablePublicFqdn(or equivalent) isfalse. - If public access is retained:
authorizedIpRangescontains only the minimal, documented CIDR ranges.
- If the goal is full compliance:
- Record your decision (private only vs restricted public) and the evidence output for future reviews.
- Re-run:
Using kubectl
kubectl cannot modify AKS control-plane networking (private endpoint or public API access); these settings are managed at the cloud provider/cluster configuration layer (Azure portal/CLI/IaC), not via Kubernetes API objects. Use kubectl only to verify cluster reachability; follow the guidance in the Manual Steps section to actually remediate this finding.
Automation
#!/usr/bin/env bash
#
# Check AKS clusters for:
# - Private endpoint enabled
# - Public API disabled
#
# Requirements:
# - Azure CLI logged in and with subscription access
# - jq installed
set -euo pipefail
# If you want to scope to a single subscription, uncomment and set this:
# az account set --subscription "SUBSCRIPTION_ID"
echo "subscription_id,resource_group,cluster_name,private_cluster_enabled,public_fqdn_enabled,problem"
# List all AKS clusters in all accessible subscriptions
az aks list --query '[].{id:id, name:name, rg:resourceGroup, sub:split(id, "/")[2]}' -o tsv | while IFS=$'\t' read -r id name rg sub; do
# Get full cluster properties in JSON
json="$(az aks show --ids "$id" -o json)"
# Extract fields
private_cluster_enabled="$(printf '%s' "$json" | jq -r '.apiServerAccessProfile.enablePrivateCluster // false')"
public_fqdn_enabled="$(printf '%s' "$json" | jq -r '.apiServerAccessProfile.enablePublicFqdn // true')"
# Determine if this violates the intent:
# - We prefer: private_cluster_enabled == true AND public_fqdn_enabled == false
problem="false"
reason=""
if [ "$private_cluster_enabled" != "true" ]; then
problem="true"
reason="no_private_endpoint"
fi
if [ "$public_fqdn_enabled" != "false" ]; then
if [ "$problem" = "true" ]; then
reason="${reason}+public_endpoint_enabled"
else
problem="true"
reason="public_endpoint_enabled"
fi
fi
echo "${sub},${rg},${name},${private_cluster_enabled},${public_fqdn_enabled},${problem}${reason:+($reason)}"
done
Run location:
- Any machine with Azure CLI access and appropriate RBAC rights.
How to interpret the output:
private_cluster_enabled=trueANDpublic_fqdn_enabled=falseANDproblem=false→ aligned with the benchmark intent.- Any row with
problem=true(...)indicates something to review:problem=true(no_private_endpoint)→ cluster not using a private endpoint.problem=true(public_endpoint_enabled)→ public API endpoint still enabled.problem=true(no_private_endpoint+public_endpoint_enabled)→ both issues present (most concerning case).