Security: Network Policies, Access & Secrets

Default-deny pod traffic, manage cluster access with access entries, and keep real secrets out of etcd and Git.

A hardened EKS cluster locks down three planes: pod-to-pod traffic, who can reach the API, and how secrets are stored.

Network policies (default deny)

By default every pod can talk to every other pod. The VPC CNI now enforces Kubernetes NetworkPolicy natively (enable network policy on the add-on), so you can adopt a default-deny posture and then explicitly allow the flows you need — the same model you'd use with Calico or Cilium.

Cluster access — prefer access entries

  • The classic aws-auth ConfigMap is powerful and dangerous: one bad edit can lock everyone out. Prefer the newer access entries API (authenticationMode: API), which manages IAM-to-cluster mapping through AWS APIs with no in-cluster ConfigMap to corrupt.
  • Grant coarse access with AWS-managed access policies, and fine-grained access with normal Kubernetes RBAC bound to the mapped groups.

Secrets that are actually secret

  • Turn on envelope encryption of secrets with KMS so etcd never holds plaintext.
  • Better still, don't put secrets in etcd at all: mount them from AWS Secrets Manager / Parameter Store via the Secrets Store CSI driver, so rotation happens outside the cluster and nothing lands in Git.

Example

Example · yaml
# Default-deny all ingress in a namespace, then allow only what you need
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: prod
spec:
  podSelector: {}
  policyTypes: ["Ingress"]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-to-api
  namespace: prod
spec:
  podSelector:
    matchLabels: { app: api }
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels: { app: web }
      ports:
        - protocol: TCP
          port: 8080

When to use it

  • A security team installs a network policy CNI plugin and applies default-deny policies so no two namespaces can communicate unless explicitly allowed.
  • A platform team migrates from aws-auth ConfigMap to EKS Access Entries to manage cluster access via IAM without editing a shared ConfigMap.
  • A secrets management team uses AWS Secrets Manager with the External Secrets Operator to sync secrets to Kubernetes, eliminating plaintext Secret YAML in Git.

More examples

Default-deny with namespace allow

Combines a default-deny policy with an explicit allow rule so only the payment-api pod can reach port 5432 in the database namespace.

Example · yaml
# Default deny all in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: payments
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
# Allow payments to reach database namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-db
  namespace: payments
spec:
  podSelector:
    matchLabels:
      app: payment-api
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: database
    ports:
    - port: 5432

Create EKS Access Entry

Creates an access entry that grants the DeveloperRole read-only view access scoped to the team-a namespace, replacing the aws-auth ConfigMap approach.

Example · bash
aws eks create-access-entry \
  --cluster-name prod \
  --principal-arn arn:aws:iam::123456789012:role/DeveloperRole \
  --type STANDARD
aws eks associate-access-policy \
  --cluster-name prod \
  --principal-arn arn:aws:iam::123456789012:role/DeveloperRole \
  --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy \
  --access-scope type=namespace,namespaces=team-a

Sync secret from Secrets Manager

An ExternalSecret that pulls a value from AWS Secrets Manager every hour and creates a native Kubernetes Secret, keeping sensitive data out of Git.

Example · yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-credentials
  data:
  - secretKey: password
    remoteRef:
      key: prod/db/password

Discussion

  • Be the first to comment on this lesson.