Skip to content

EKS Networking Quiz - Part 1 ​

Last Updated: September 11, 2026

This quiz reviews EKS networking, address planning, policies and controller ownership. Examples use conventional Linux EC2 networking unless stated otherwise. APIs/configuration were checked against official sources and local schemas; no cloud networking changes or live packet tests were performed.

Multiple Choice Questions ​

  1. What is the default CNI for conventional EKS EC2 nodes?
    • A) Calico
    • B) Flannel
    • C) Amazon VPC CNI
    • D) Weave Net
Show Answer

Answer: C) Amazon VPC CNI

Conventional EKS EC2 nodes use Amazon VPC CNI. Auto Mode provides managed networking capabilities and Hybrid Nodes use a supported alternative CNI, so “every EKS cluster runs this DaemonSet” is too broad.

The CNI configures ordinary Pod networking using VPC addresses, with different secondary-IP, prefix and security-group-for-Pod paths. A routable address does not bypass routes, security groups, NACLs or policies, and avoiding an overlay is not a measured performance guarantee.

For Linux, the old amazon-vpc-cni ConfigMap with lower-case warm-ip-target/enable-pod-eni keys is not the configuration mechanism shown here. Use the actual add-on schema/Helm values or supported aws-node environment variables through their owner. Inspect the installed build first:

bash
set -euo pipefail
CNI_ADDON_VERSION=$(aws eks describe-addon --cluster-name "${EXAMPLE_CLUSTER:?}" \
  --region "${EXAMPLE_REGION:?}" --addon-name vpc-cni --query addon.addonVersion --output text)
aws eks describe-addon-configuration --region "$EXAMPLE_REGION" --addon-name vpc-cni \
  --addon-version "$CNI_ADDON_VERSION" --query configurationSchema --output text
kubectl --kubeconfig "${EXAMPLE_KUBECONFIG:?}" -n kube-system get daemonset aws-node \
  -o jsonpath='{range .spec.template.spec.containers[*]}{.name}{": "}{.image}{"\n"}{end}'

For example, the following is an add-on configuration fragment, not a Kubernetes ConfigMap. The values are illustrative warm-pool targets; merge them with reviewed existing settings and check the selected version’s schema. Windows IPAM ConfigMap settings are a different interface.

json
{"env":{"WARM_IP_TARGET":"5","MINIMUM_IP_TARGET":"10"}}

Pod security groups and native NetworkPolicy each have additional prerequisites. Do not enable them as unrelated side effects of an IP-pool example or apply an unconfigured second CNI over a working cluster.

  1. How are ordinary Pods addressed in IPv4 secondary-IP mode?
    • A) One dedicated VPC per Pod
    • B) An address from the node ENI/IP pool
    • C) An overlay address only
    • D) A separate subnet for every Pod
Show Answer

Answer: B) An address from the node ENI/IP pool

In ordinary IPv4 secondary-IP mode, IPAMD manages ENI/IP pools on the node and CNI setup assigns a pool address to the Pod network namespace. After CNI cleanup and any applicable reuse delay, addresses can return to the warm pool; they are not necessarily immediately unassigned from EC2.

The conventional max-Pods calculation below is for that mode. Each ENI's primary address is reserved; the historical extra two account for host-network system Pods:

text
ENIs × (IPv4 addresses per ENI − 1) + 2
m5.large: 3 × (10 − 1) + 2 = 29

This is not a universal workload limit. Subnet space, kubelet maxPods, compute resources, custom networking and branch-ENI limits also matter. Prefix mode allocates a /28 to an ENI address slot, not exactly one prefix per ENI; Pod security groups use a separate branch-ENI path. Host-network Pods share node networking and are another exception to a simple one-secondary-IP-per-Pod description.

  1. What enables the ordinary VPC CNI intra-VPC routing model?
    • A) All Pods must use one subnet
    • B) All Pods share host networking
    • C) VPC-routable Pod addresses with the required routes and controls
    • D) A mandatory service mesh
Show Answer

Answer: C) VPC-routable Pod addresses with the required routes and controls

For the ordinary VPC CNI path, Pods have VPC-routable addresses. Cross-node traffic can use node/ENI and VPC routing; same-node traffic can remain in the host networking stack. SGs, NACLs, policy rules and custom inspection routes still determine reachability.

The example 10.0.1.23 → 10.0.2.45 describes an ordinary intra-VPC path, not proof that every packet always traverses a VPC route table or never follows a configured appliance route. Same-node Pod traffic is not fully visible in VPC Flow Logs. Most Pods have their own network namespace; hostNetwork Pods are an exception.

Do not infer guaranteed latency/throughput improvements from the absence of an overlay. Measure the actual path and account for cross-AZ transfer, target type, SNAT and workload behavior. A service mesh is an optional additional layer, not a prerequisite for ordinary Pod routing.

  1. Which Kubernetes resource expresses Pod ingress/egress policy?
    • A) Service
    • B) Ingress
    • C) NetworkPolicy
    • D) SecurityContext
Show Answer

Answer: C) NetworkPolicy

NetworkPolicy selects Pods and isolates only the specified traffic directions. Without a policy selecting a Pod/direction, it is non-isolated. Policies are additive: an extra restrictive-looking policy cannot remove traffic already allowed by another policy.

Use a compatible enforcement implementation. Current Amazon VPC CNI supports native network policies when enabled; the old statement that it cannot enforce them is incorrect. The managed add-on uses an enableNetworkPolicy configuration field, not the assumed ENABLE_NETWORK_POLICY environment variable:

json
{"enableNetworkPolicy":"true"}

This is a fragment to merge through the selected add-on version/schema. Verify the policy agent and AWS compute/kernel/Pod-owner/interface limitations before testing. Standard startup mode can briefly allow traffic before policy attachment; strict startup mode needs all required system/DNS allowances. Do not install floating Calico manifests and native policy enforcement together without a supported migration design.

The following is for reviewed lab namespaces and controller-managed workloads. Namespace and Pod selectors in the same peer item are ANDed; separate peer items would be ORed. The DNS exception is explicit:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow
  namespace: policy-lab
spec:
  podSelector:
    matchLabels: {app: api}
  policyTypes: [Ingress, Egress]
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: frontend-lab
      podSelector:
        matchLabels: {role: frontend}
    ports:
    - {protocol: TCP, port: 8080}
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: database-lab
      podSelector:
        matchLabels: {app: database}
    ports:
    - {protocol: TCP, port: 5432}
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels: {k8s-app: kube-dns}
    ports:
    - {protocol: UDP, port: 53}
    - {protocol: TCP, port: 53}

Use actual namespace/Pod labels and listener ports. NodeLocal DNSCache or other DNS paths need different allowances. A Service/Ingress routes traffic; it does not replace these L3/L4 access rules. SecurityContext controls workload privileges, not a declarative network allow list.

  1. Which DNS component is normally configured for conventional EKS cluster service discovery?
    • A) Route 53 private hosted zones alone
    • B) CoreDNS
    • C) A mandatory legacy kube-dns deployment
    • D) Cloud Map alone
Show Answer

Answer: B) CoreDNS

Conventional EKS uses CoreDNS for cluster DNS. Do not assume every EKS mode automatically creates a visible CoreDNS Deployment: Auto Mode supplies managed DNS, and tools that disable default bootstrap add-ons must configure their selected add-ons explicitly.

For an EKS-managed CoreDNS add-on, preserve custom configuration through its supported corefile configuration value and exact-version schema. Direct ConfigMap edits can be overwritten by the add-on. For self-managed CoreDNS, change configuration through its manifest/GitOps owner. Review required ready, forwarding, Kubernetes zones and reload behavior rather than replacing the whole ConfigMap with a generic sample.

DNS answers depend on resource type:

ResourceTypical DNS behavior
Ordinary Service<service>.<namespace>.svc.<cluster-domain> resolves to the Service IP family
Headless ServiceEndpoint addresses, subject to readiness/publication settings
ExternalName ServiceCNAME to the configured external name
Legacy IPv4 Pod recordA dashed address such as 10-0-1-23.<namespace>.pod.<cluster-domain>, depending on the CoreDNS pods mode

cluster.local is a common default, not a universal domain. pods insecure provides legacy IP-based answers without verifying Pod existence; it is not a security guarantee. Test DNS from an approved in-cluster diagnostic workload, not an arbitrary laptop resolver.

EKS managed CoreDNS supports configured autoscaling for compatible add-on versions. Keep one owner for replica count; a manual kubectl scale is not the right control loop when managed autoscaling/HPA is active.

The following Corefile fragment replaces an existing cache stanza after review; it is not YAML. CoreDNS 1.14.7 accepts denial 1000 but normalizes it to a minimum effective capacity of 1024. The example makes that capacity explicit; success 10000 is rounded down to 9984:

text
cache {
    success 10000
    denial 1024
    prefetch 10 10m 20%
}

Cache capacities/TTL/prefetch settings require workload measurements; this is not a performance benchmark. Observe DNS errors, cache behavior and CPU/memory after a controlled change.

Short Answer Questions ​

  1. What limits Pod density, and how does prefix delegation change it?
Show Answer

Separate three limits: EC2 interface/address capacity, available subnet addresses and Kubernetes/compute capacity. In ordinary IPv4 secondary-IP mode the historical formula is ENIs × (IPs per ENI − 1) + 2: t3.small gives 11, m5.large 29 and c5.4xlarge 234. These are formula results, not the effective limit of every managed group.

In IPv4 prefix mode, one /28 contributes 16 addresses and occupies one secondary-address slot. Multiple prefixes can occupy an ENI. The old “one prefix per ENI minus one address” calculation yielding 47 for m5.large was incorrect. Compatible managed groups cap maxPods at 110 for fewer than 30 vCPUs and 250 otherwise; CPU/memory and the actual CNI configuration may limit usable workload capacity further.

An example managed add-on configuration fragment is:

json
{"env":{"ENABLE_PREFIX_DELEGATION":"true","WARM_PREFIX_TARGET":"1"}}

Review the exact-version schema and existing configuration before merging it. WARM_PREFIX_TARGET is spare prefix capacity, not a maximum of one prefix per ENI. WARM_IP_TARGET/MINIMUM_IP_TARGET override its behavior when configured. Prefix mode needs contiguous /28 space and a supported instance/CNI; it does not expand the subnet.

Prefix delegation and security groups for Pods can coexist. Branch-ENI Pods still use their own per-instance branch capacity and do not gain prefix density. Plan new/recycled nodes and PDB-aware migration rather than toggling variables and assuming all running Pods/maxPods changed. Custom AL2023 AMIs may need reviewed NodeConfig maxPods; raising kubelet limits alone creates no IPs or CPU.

bash
kubectl --kubeconfig "${EXAMPLE_KUBECONFIG:?}" get nodes \
  -o custom-columns=NAME:.metadata.name,PODS:.status.allocatable.pods,POD_ENI:.status.allocatable.vpc\\.amazonaws\\.com/pod-eni

Inspect actual allocatable capacity and CNI/EC2 allocation. Do not assume the aws-node container includes curl; use the documented introspection/debug path for the installed build and selected node.

  1. How are security groups assigned to selected Pods on conventional EKS EC2 nodes?
Show Answer

Security Groups for Pods uses a trunk ENI on the node and branch ENIs for selected Pods. The EKS VPC resource controller creates/manages that path using permissions on the cluster IAM role, including AmazonEKSVPCResourceController; these are not simply per-Pod ServiceAccount permissions.

For the conventional Linux EC2 example, verify a trunking-compatible instance type (not every Nitro type qualifies), a compatible VPC CNI and ENABLE_POD_ENI=true through its configuration owner. Review POD_SECURITY_GROUP_ENFORCING_MODE, DNS/probes, routes and SG rules. Strict and standard modes differ in SNAT and which SGs apply, especially outside the VPC and on node-local paths.

Create a dedicated sgp-lab namespace and replace the SG placeholder with an approved group in the correct VPC. This controller-managed sleeping client demonstrates selection, not successful database access:

yaml
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
  name: db-client-policy
  namespace: sgp-lab
spec:
  podSelector:
    matchLabels: {role: db-client}
  securityGroups:
    groupIds: [sg-REPLACE_WITH_APPROVED_GROUP]
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-client
  namespace: sgp-lab
spec:
  replicas: 1
  selector:
    matchLabels: {role: db-client}
  template:
    metadata:
      labels: {role: db-client}
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        seccompProfile: {type: RuntimeDefault}
      containers:
      - name: client
        image: public.ecr.aws/docker/library/busybox:1.37.0
        command: [sleep, '3600']
        resources:
          requests: {cpu: 10m, memory: 16Mi}
          limits: {cpu: 100m, memory: 32Mi}
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities: {drop: [ALL]}

Use either a podSelector or serviceAccountSelector as appropriate. Verify the newly created Pod, CNINode/branch capacity and allowed/denied application connections. Changing SecurityGroupPolicy selection does not retrofit running Pods; separate SG rule changes have their own connection-tracking behavior. Host-network Pods use node networking.

Prefix delegation is compatible but does not enlarge branch-ENI Pod capacity. The traditional SecurityGroupPolicy feature is not the Auto Mode NodeClass Pod-subnet/SG selection feature; follow the applicable compute-specific API instead of treating them as identical.

  1. Which load balancer does AWS Load Balancer Controller create for a LoadBalancer Service, and how is ownership configured?
Show Answer

AWS Load Balancer Controller reconciles a LoadBalancer Service to an NLB, not a CLB. The old quiz mixed it with the legacy in-tree service controller. Current LBC uses service.k8s.aws/nlb for explicit ownership and has defaulted new NLBs to internal since v2.2. Configure the intended scheme explicitly.

This is a new Service for an existing reviewed app=echo workload in lb-lab, after installing/authorizing the controller and validating eligible subnets/SG rules. It provisions a billable internal NLB; do not apply it casually to a production namespace:

yaml
apiVersion: v1
kind: Service
metadata:
  name: echo-nlb
  namespace: lb-lab
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-scheme: internal
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
spec:
  type: LoadBalancer
  loadBalancerClass: service.k8s.aws/nlb
  allocateLoadBalancerNodePorts: false
  selector: {app: echo}
  ports:
  - name: http
    port: 8080
    targetPort: 8080
    protocol: TCP

IP targets send traffic to eligible Pod IPs; instance targets use node/NodePort paths. The example disables unused NodePort allocation for IP mode. Auto Mode uses its own ownership class (eks.amazonaws.com/nlb) and supported configuration set. Do not mutate controller-selection annotations/classes on an existing legacy Service to attempt an unreviewed migration; this can leak or expose resources.

Configuration choices must match the selected controller version and listener design: Annotation names in the table omit the common service.beta.kubernetes.io/ prefix.

RequirementCurrent configuration / consideration
Internal or public schemeaws-load-balancer-scheme: internal or internet-facing; routes/subnets must match
IP targetsaws-load-balancer-nlb-target-type: ip
Custom frontend SGsaws-load-balancer-security-groups; review backend rule management and health-check paths
Explicit subnetsaws-load-balancer-subnets; still subject to eligibility/AZ/IP constraints
Cross-zone behavioraws-load-balancer-attributes with load_balancing.cross_zone.enabled; evaluate availability, topology and cost
Legacy S3 access logsaws-load-balancer-attributes with access_logs.s3.*; NLB access logs cover TLS requests only and need the reviewed bucket/delivery permissions
TLS terminationaws-load-balancer-ssl-cert and matching Service listener ports via aws-load-balancer-ssl-ports; this is NLB TLS termination, not ALB HTTP routing

The old aws-load-balancer-internal, cross-zone and access-log annotations are deprecated in favor of scheme/attribute settings. Current NLB also offers enhanced CloudWatch log delivery; select its documented integration rather than assuming S3 annotations configure it. Access logs are best effort, not a complete request ledger. ALB alternative: use an Ingress with a configured alb IngressClass and IP targets to a ClusterIP backend. This avoids accidentally creating both an NLB and ALB for the same example backend:

yaml
apiVersion: v1
kind: Service
metadata:
  name: echo-backend
  namespace: lb-lab
spec:
  type: ClusterIP
  selector: {app: echo}
  ports:
  - {port: 8080, targetPort: 8080, protocol: TCP}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: echo-alb
  namespace: lb-lab
  annotations:
    alb.ingress.kubernetes.io/scheme: internal
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: echo-backend
            port: {number: 8080}

Before installation, prepare the controller ServiceAccount and scoped IAM permissions. The reviewed chart 3.5.0 contains controller v3.5.0; region/VPC are explicit for environments where IMDS discovery is unavailable. Render and inspect before deployment:

bash
helm repo add eks https://aws.github.io/eks-charts
helm repo update eks
helm template aws-load-balancer-controller eks/aws-load-balancer-controller \
  --version 3.5.0 --kube-version 1.36.0 --namespace kube-system \
  --set-string clusterName="${EXAMPLE_CLUSTER:?}" \
  --set-string region="${EXAMPLE_REGION:?}" --set-string vpcId="${EXAMPLE_VPC_ID:?}" \
  --set serviceAccount.create=false --set-string serviceAccount.name=aws-load-balancer-controller \
  > lbc-reviewed.yaml
CapabilityCLB (legacy)NLBALB
Main routing layerL4/L7 legacy listenersL4HTTP/HTTPS L7
Direct IP targetsNoYesYes
Per-AZ static address optionNoYesNo native static frontend IP
HTTP path routingNoNoYes

NLB currently supports TCP, TLS, UDP, TCP_UDP, QUIC and TCP_QUIC listeners. Controller support/configuration must be checked separately (LBC 3.5 documents QUIC port annotations). The old qualitative “good/very good” performance table was not a benchmark. Choose and measure against the application; neither universal cross-zone enablement nor a blanket latency ranking is a production rule.

Hands-on Questions ​

  1. Implement and validate same-namespace traffic with a DNS exception and blocked cross-namespace TCP paths.
Show Answer

Use a policy selecting all Pods in the intended namespace, allowing same-namespace peers plus an explicit DNS exception. This is L3/L4 policy, not proof of complete tenant or node isolation.

Prerequisites: an approved conventional IPv4 Linux test cluster with native VPC CNI NetworkPolicy already enabled through its supported owner/configuration, controller-managed test Pods, working CoreDNS and no conflicting organization-wide policy. Do not install Calico or toggle an invented ENABLE_NETWORK_POLICY variable as part of this lab.

Create two new namespaces and record their UIDs. Use one Bash session for the following snippets:

bash
set -euo pipefail
umask 077
: "${EXAMPLE_KUBECONFIG:?Use the reviewed IPv4 Linux lab cluster kubeconfig}"
NP_LAB_DIR=$(mktemp -d /tmp/eks-network-policy.XXXXXX)
NP_LAB_ID="$(date +%s)-$$"
NP_NAMESPACE_A="np-a-$NP_LAB_ID"
NP_NAMESPACE_B="np-b-$NP_LAB_ID"
for ns in "$NP_NAMESPACE_A" "$NP_NAMESPACE_B"; do
  kubectl --kubeconfig "$EXAMPLE_KUBECONFIG" create namespace "$ns" -o json \
    > "$NP_LAB_DIR/$ns-created.json"
  jq -e '.metadata.uid | type == "string" and length > 0' \
    "$NP_LAB_DIR/$ns-created.json" >/dev/null
done

The HTTP servers also provide a known Python TCP diagnostic. Each Service and container use port 8080. These are test workloads, not production sizing; record image digests for repeatability.

bash
for ns in "$NP_NAMESPACE_A" "$NP_NAMESPACE_B"; do
  kubectl --kubeconfig "$EXAMPLE_KUBECONFIG" -n "$ns" create -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: network-probe
spec:
  replicas: 1
  selector:
    matchLabels: {app: network-probe}
  template:
    metadata:
      labels: {app: network-probe}
    spec:
      automountServiceAccountToken: false
      nodeSelector: {kubernetes.io/os: linux}
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        seccompProfile: {type: RuntimeDefault}
      containers:
      - name: probe
        image: python:3.13-alpine
        command: [python, -m, http.server, "8080", --directory, /tmp]
        ports:
        - containerPort: 8080
        readinessProbe:
          tcpSocket: {port: 8080}
        resources:
          requests: {cpu: 50m, memory: 64Mi}
          limits: {cpu: 200m, memory: 128Mi}
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities: {drop: [ALL]}
---
apiVersion: v1
kind: Service
metadata:
  name: network-probe
spec:
  type: ClusterIP
  selector: {app: network-probe}
  ports:
  - {port: 8080, targetPort: 8080, protocol: TCP}
EOF
  kubectl --kubeconfig "$EXAMPLE_KUBECONFIG" -n "$ns" \
    rollout status deployment/network-probe --timeout=180s
done

Baseline: require same-namespace and cross-namespace TCP connections to succeed before applying a policy. DNS/exec failures are different from denied TCP connections. ICMP ping is not a portable NetworkPolicy enforcement test.

bash
check_tcp() {
  kubectl --kubeconfig "$EXAMPLE_KUBECONFIG" -n "$1" exec deployment/network-probe \
    -c probe -- python -c '
import socket, sys
try:
    address = socket.gethostbyname(sys.argv[1])
except OSError as error:
    print("DNS failed:", error, file=sys.stderr)
    sys.exit(43)
try:
    connection = socket.create_connection((address, 8080), timeout=3)
    connection.close()
except OSError as error:
    print("TCP failed:", error, file=sys.stderr)
    sys.exit(42)
print("TCP succeeded")
' "network-probe.$2"
}

# All four paths must work before applying the policy.
check_tcp "$NP_NAMESPACE_A" "$NP_NAMESPACE_A"
check_tcp "$NP_NAMESPACE_B" "$NP_NAMESPACE_B"
check_tcp "$NP_NAMESPACE_A" "$NP_NAMESPACE_B"
check_tcp "$NP_NAMESPACE_B" "$NP_NAMESPACE_A"

Apply to namespace A only: an empty peer podSelector selects Pods in that policy namespace. The DNS peer combines the kube-system namespace with the CoreDNS Pod label. Adapt it for NodeLocal DNSCache or other DNS paths. Standard policy attachment is asynchronous, so test propagation with positive controls and both blocked directions:

bash
kubectl --kubeconfig "$EXAMPLE_KUBECONFIG" -n "$NP_NAMESPACE_A" create -f - <<'EOF'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: namespace-boundary
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
  ingress:
  - from:
    - podSelector: {}
  egress:
  - to:
    - podSelector: {}
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - {protocol: UDP, port: 53}
    - {protocol: TCP, port: 53}
EOF

expect_tcp_block() {
  if check_tcp "$1" "$2"; then
    return 1
  else
    result=$?
    [ "$result" -eq 42 ] || {
      printf '%s\n' 'DNS or exec failure is not proof of policy denial.' >&2
      exit 1
    }
    return 0
  fi
}
NP_VERIFIED=false
for attempt in $(seq 1 30); do
  check_tcp "$NP_NAMESPACE_A" "$NP_NAMESPACE_A"
  check_tcp "$NP_NAMESPACE_B" "$NP_NAMESPACE_B"
  if expect_tcp_block "$NP_NAMESPACE_A" "$NP_NAMESPACE_B" &&
     expect_tcp_block "$NP_NAMESPACE_B" "$NP_NAMESPACE_A"; then
    # Repeat positive controls after observing both blocked cross-namespace paths.
    check_tcp "$NP_NAMESPACE_A" "$NP_NAMESPACE_A"
    check_tcp "$NP_NAMESPACE_B" "$NP_NAMESPACE_B"
    NP_VERIFIED=true
    break
  fi
  sleep 2
done
[ "$NP_VERIFIED" = true ] || {
  printf '%s\n' 'Expected policy behavior was not observed; inspect the enforcement path.' >&2
  exit 1
}

Success means the tested TCP paths behaved as expected while DNS and server availability checks passed. It does not prove every protocol/interface is filtered. Preserve the platform’s node, metadata-service and security-group controls separately.

Extensions: to allow only particular same-namespace Pods or ports, replace/review the broad same-namespace allowances. Adding a narrower policy cannot remove an existing broad allow. For a reviewed external API, an additional egress policy can select the required CIDR/port; this documentation prefix is not a live destination:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-reviewed-external-api
  namespace: app-namespace
spec:
  podSelector:
    matchLabels: {app: web}
  policyTypes: [Egress]
  egress:
  - to:
    - ipBlock:
        cidr: 203.0.113.0/24
    ports:
    - {protocol: TCP, port: 443}

Standard NetworkPolicy does not provide an FQDN allow list. NAT/endpoint selection can affect which IP is evaluated. A blanket 0.0.0.0/0 excluding only RFC1918 ranges is neither a specific external-service rule nor complete protection for link-local metadata endpoints.

Clean up only the recorded namespaces after testing:

bash
for ns in "${NP_NAMESPACE_A:?}" "${NP_NAMESPACE_B:?}"; do
  expected_uid=$(jq -er '.metadata.uid' "${NP_LAB_DIR:?}/$ns-created.json") || exit 1
  current_uid=$(kubectl --kubeconfig "${EXAMPLE_KUBECONFIG:?}" get namespace "$ns" \
    --ignore-not-found -o jsonpath='{.metadata.uid}') || exit 1
  if [ -z "$current_uid" ]; then
    continue
  elif [ "$current_uid" = "$expected_uid" ]; then
    kubectl --kubeconfig "$EXAMPLE_KUBECONFIG" delete namespace "$ns" --wait=true || exit 1
  else
    printf '%s\n' 'Namespace UID changed; no deletion attempted for this namespace.' >&2
    exit 1
  fi
done

Advanced Questions ​

  1. Compare remedies for VPC CNI address exhaustion and distinguish node density from total address space.
Show Answer

First identify the exhausted resource: subnet addresses, contiguous prefix blocks, per-node ENI slots, branch ENIs, kubelet maxPods or compute capacity. They need different remedies. The old “prefix delegation is always the simplest solution” conclusion was too broad.

ApproachHelps withImportant limitation
Prefix delegationMore Pod addresses per ordinary ENI slot; allocation efficiencyNeeds contiguous /28s; does not enlarge IPv4 space or branch-ENI capacity
Warm/minimum pool tuningUnused preallocated addressesTrades allocation readiness/API calls for address use
Custom networkingSeparates node and Pod subnet demandSame VPC/AZ requirements, routes/SGs and planned node migration
Additional VPC CIDRs/subnetsMore allocatable address spaceOverlap/quotas/routing/control-plane reconciliation must be reviewed
Larger new subnet rangesPlanned address growthExisting subnets cannot simply be resized; ranges must fit associated VPC CIDRs
IPv6 cluster designRemoves most shared IPv4 Pod-address pressureNew-cluster/IP-family planning, supported compute/CNI and egress requirements
Alternative CNIDifferent IPAM/routing modelRequires a supported, tested migration; not an in-place manifest toggle
FargateDelegates node/IP allocation operationsEach Pod still consumes subnet/VPC addresses; does not fix an exhausted subnet

Prefix mode: ordinary IPv4 prefixes are /28 blocks, each consuming one address slot. The original “up to 5x” value is an unverified generic claim, not a benchmark; use actual instance/CNI/kubelet limits. Security groups for Pods can coexist, but branch Pods retain their own limits. Inspect fragmentation and reserve prefix space or use new subnets if needed; do not assume free individual IP count proves a contiguous block exists.

Warm pools: WARM_IP_TARGET is free-address headroom and MINIMUM_IP_TARGET is minimum total allocation. They can override prefix/ENI warm-target behavior. The example values 5/10 must be tuned to the workload and API-call budget:

json
{"env":{"WARM_IP_TARGET":"5","MINIMUM_IP_TARGET":"10"}}

MAX_ENI limits the node allocation up to the EC2 instance-type ceiling; setting it to 5 does not create support for five ENIs on a type that supports fewer. Review actual allocation metrics before changing limits.

Custom networking: merge this configuration through the existing CNI owner after preparing same-VPC, same-AZ Pod subnets and SGs. The stable zone label is topology.kubernetes.io/zone, not the deprecated beta label:

json
{
  "env": {
    "AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG": "true",
    "ENI_CONFIG_LABEL_DEF": "topology.kubernetes.io/zone"
  }
}
yaml
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
  name: us-west-2a
spec:
  subnet: subnet-REPLACE_WITH_POD_SUBNET_IN_SAME_VPC_AND_AZ
  securityGroups:
  - sg-REPLACE_WITH_APPROVED_POD_GROUP

Create a matching ENIConfig for every used AZ. Node annotation overrides must be reviewed. Replacement nodes with the correct zone label can reuse the existing ENIConfig; they do not require recreating it every time. Existing Pods do not all change networking immediately. Validate replacement nodes and migrate with capacity, PDB and data checks.

CIDR/subnet changes: add eligible non-overlapping CIDRs and associated subnets through their IaC owner, then review routes, security, endpoints and discovery tags. EKS can take up to an hour to recognize a newly associated VPC CIDR for control-plane operations. Creating a /16 subnet also requires an available associated /16 range; “larger” does not bypass VPC limits.

Alternative CNI/IPv6: plan the complete control-plane, DNS, service/load-balancer, policy, bootstrap and rollback path. Do not apply a floating Calico overlay manifest and disable aws-node on a running cluster as a generic cutover. An existing EKS cluster’s IP family cannot simply be toggled to IPv6. Support and AWS integration depend on the specific compute/CNI mode.

Fargate: a namespace label does not create a profile, and eks.amazonaws.com/v1alpha1 kind: FargateProfile is not a built-in Kubernetes API. Use the EKS API or eksctl (or an explicitly installed supported controller). This API example requires an unused profile name, reviewed private subnets and execution role:

bash
# New profile example; this does not create or enlarge subnet address space.
aws eks create-fargate-profile --cluster-name "${EXAMPLE_CLUSTER:?}" \
  --region "${EXAMPLE_REGION:?}" --fargate-profile-name "${NEW_FARGATE_PROFILE:?}" \
  --pod-execution-role-arn "${FARGATE_EXECUTION_ROLE_ARN:?}" \
  --subnets "${PRIVATE_SUBNET_A:?}" "${PRIVATE_SUBNET_B:?}" \
  --selectors '[{"namespace":"ipam-fargate"}]'

Create the matching namespace/workloads separately and verify profile activation. Fargate changes operational responsibility, not the finite address capacity of the chosen subnets. Compare the remedies against measured demand instead of applying every strategy together. No network migration or performance benchmark was executed in this audit.

VPC Foundation Checks ​

  1. Which private subnet pair is aligned and avoids public 10.0.0.0/24 and 10.0.1.0/24?
  • A) 10.0.2.0/22 and 10.0.6.0/22
  • B) 10.0.4.0/22 and 10.0.8.0/22
  • C) 10.0.0.0/22 and 10.0.1.0/22
  • D) Any two different strings
Show Answer

Answer: B) 10.0.4.0/22 and 10.0.8.0/22

A /22 starts on a four-value boundary in the third octet. Canonicalization of 10.0.2.0/22 produces 10.0.0.0/22, which overlaps the public ranges.

  1. How many addresses can be assigned in an ordinary AWS IPv4 /24 subnet before resource use?
  • A) 256
  • B) 254
  • C) 251
  • D) Always 240
Show Answer

Answer: C) 251

AWS reserves the first four and last address per ordinary subnet. The total is 256 and assignable count 251; BYOIP has documented exceptions.

  1. Does an elb subnet role tag create an Internet Gateway route?
  • A) Yes
  • B) No; route configuration and controller discovery are separate
  • C) Only in a private subnet
  • D) It also opens all security groups
Show Answer

Answer: B) No; route configuration and controller discovery are separate

Tags can influence discovery, subject to controller/version/feature gates. They do not create routes or constitute a security boundary.

  1. Is a public internet path mandatory for every EKS node?
  • A) Yes, always through a NAT gateway
  • B) Yes, always through an IGW
  • C) No; required service access can use appropriate private endpoints/mirrors
  • D) No network access is needed
Show Answer

Answer: C) No; required service access can use appropriate private endpoints/mirrors

Plan actual API, registry, DNS and workload dependencies. The AWS EKS service endpoint is different from the Kubernetes cluster API endpoint.

  1. Which is the normal kubelet destination port for control-plane traffic?
  • A) Every TCP port 1025–65535
  • B) TCP 10250
  • C) Every NodePort by default
  • D) UDP 53 only
Show Answer

Answer: B) TCP 10250

Review private API TCP443, DNS TCP/UDP53, actual webhook/workload ports and real SG associations separately. Stateful SG return traffic differs from stateless NACL rules.

References ​