Back to Checks
stackit

SKE clusters do not expose their Kubernetes API endpoint to the internet

ske_cluster_no_public_endpoint
Service: skeSeverity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:NotDefined

The Kubernetes API server of an SKE cluster should not be reachable from the entire internet. Enable the ACL extension to restrict access to a known set of source CIDRs, or run the control plane inside a STACKIT Network Area (SNA) so that it is not published on the internet at all.

Risk

A publicly reachable Kubernetes API server lets anyone on the internet attempt authentication, exploit unpatched control plane vulnerabilities, or brute-force credentials. Combined with leaked or weak credentials, this can lead to full cluster takeover, workload tampering, and data exfiltration.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler stackit --checks ske_cluster_no_public_endpoint

Recommendation

Restrict access to the Kubernetes API. Enable the SKE ACL extension and allowlist only the source CIDRs that legitimately need to reach the API server, never 0.0.0.0/0 or ::/0. Where available, place the control plane in a STACKIT Network Area so the endpoint is not exposed to the internet.

Remediation

Other

1In the STACKIT Portal open Kubernetes Engine (SKE) and select the affected cluster. 2. Open the cluster configuration and enable the ACL extension. 3. Add only the source CIDRs that must reach the Kubernetes API (for example your office or VPN egress ranges) and make sure 0.0.0.0/0 and ::/0 are not present. 4. Save the cluster configuration and re-run Prowler to confirm the finding is resolved.

Check Code

from prowler.lib.check.models import Check, CheckReportStackIT
from prowler.providers.stackit.services.ske.ske_client import ske_client


class ske_cluster_no_public_endpoint(Check):
    """
    Check if SKE clusters expose their Kubernetes API endpoint to the internet.

    A cluster passes when its control plane is confined to a STACKIT Network
    Area, or when the ACL extension restricts the Kubernetes API to a set of
    source CIDRs that does not include an unrestricted range.
    """

    def execute(self) -> list[CheckReportStackIT]:
        """
        Execute the check for all SKE clusters in the StackIT project.

        Returns:
            list: A list of CheckReportStackIT findings
        """
        findings = []

        for cluster in ske_client.clusters:
            report = CheckReportStackIT(
                metadata=self.metadata(),
                resource=cluster,
            )

            if cluster.has_public_endpoint():
                report.status = "FAIL"
                unrestricted_cidrs = cluster.unrestricted_cidrs()
                if unrestricted_cidrs:
                    report.status_extended = (
                        f"SKE cluster {cluster.name} exposes its Kubernetes API "
                        f"endpoint to the internet because its ACL allows "
                        f"unrestricted access from {', '.join(unrestricted_cidrs)}."
                    )
                else:
                    report.status_extended = (
                        f"SKE cluster {cluster.name} exposes its Kubernetes API "
                        f"endpoint to the internet because the ACL extension is "
                        f"not enabled."
                    )
            else:
                report.status = "PASS"
                if cluster.has_private_control_plane():
                    report.status_extended = (
                        f"SKE cluster {cluster.name} has a private control plane "
                        f"and its Kubernetes API endpoint is not reachable from "
                        f"the internet."
                    )
                else:
                    report.status_extended = (
                        f"SKE cluster {cluster.name} restricts access to its "
                        f"Kubernetes API endpoint to "
                        f"{len(cluster.allowed_cidrs)} allowed CIDR(s)."
                    )

            findings.append(report)

        return findings