Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Kubernetes Security: Pod Security and Network Policies

By Kokil Thapa | Last reviewed: September 2026

Kubernetes Security: Pod Security and Network Policies are the two controls most teams under-deploy until something breaks in production. Pod Security Standards stop workloads from running as root or mounting host paths. Network Policies segment traffic so a compromised pod cannot reach every service in the cluster. If you run Laravel or API workloads on Kubernetes, these layers sit below your application firewall and deserve the same attention as Linux hardening on the nodes themselves.

What is Kubernetes pod security and why does it matter?

Pod security controls what a container is allowed to do before it ever talks to the network. In 2026, that means Pod Security Standards (PSS) — three built-in profiles shipped with Kubernetes 1.25 and later. PodSecurityPolicy (PSP) was removed; PSS replaced it with simpler namespace-level enforcement.

Each profile defines allowed capabilities:

  • Privileged — unrestricted; use only for system components like CNI or storage drivers.
  • Baseline — blocks known privilege escalations but allows common legacy patterns.
  • Restricted — non-root users, dropped capabilities, no host namespaces; best for application workloads.

On real client projects, the gap is rarely malicious intent. A developer copies a Docker Compose file into a Deployment and sets privileged: true because a local volume mount failed. PSS catches that at admission time instead of during a penetration test.

Pod Security Standards ProfilesPrivilegedHost accessAny userBaselineNo hostPathSome caps OKRestrictedNon-root onlySeccomp runtimeAdmission Enforcement Modesenforce — block violating podsaudit — log only, allow creationwarn — allow plus API warning event
Pod Security Standards move workloads from privileged toward restricted with namespace label enforcement modes

Enabling Pod Security on a namespace

Apply labels to each namespace. Start with audit mode, read the logs, then switch to enforce:

kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

The built-in pod-security admission plugin reads these labels. No extra controller is required on a standard cluster. Pair PSS with seccomp profiles and read-only root filesystems for defense in depth.

How do Pod Security Standards compare to legacy PodSecurityPolicy?

PSP was powerful but painful. Cluster admins wrote complex RBAC so teams could bind policies. Upgrades broke silently. PSS inverts the model: Kubernetes ships three opinionated profiles, and you label namespaces.

CriteriaPodSecurityPolicy (removed)Pod Security Standards
ConfigurationCustom PSP objects + RBAC bindingsThree namespace labels
Enforcement pointAdmission controller + authzBuilt-in Pod Security admission
GranularityPer-policy, highly flexibleThree fixed profiles
Operational costHigh — drift across teamsLow — label-driven defaults
Custom exceptionsNative via policy objectsRequires exempt namespaces or tools like Kyverno or OPA Gatekeeper

For most application namespaces, restricted PSS plus a dedicated privileged namespace for operators is enough. Reserve custom policy engines for orgs that need PCI-style exceptions documented as code.

How do you write and apply Kubernetes Network Policies?

Network Policies are Kubernetes API objects. They only work if your CNI supports them — Calico, Cilium, and Weave do; basic Flannel without an overlay policy engine does not. A common production mistake is writing policies on a cluster where they are silently ignored.

Read the companion guide on Kubernetes Network Policies explained for CNI-specific notes. The pattern below works on any compliant CNI.

Step 1: Default deny all traffic in the namespace

Without a default deny, every pod can reach every pod. That is the Kubernetes default, and it is too open for production.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

This policy selects all pods and declares both ingress and egress types with no rules. Result: all traffic blocked except DNS if you add a separate egress rule (see step 3).

Step 2: Allow ingress from the ingress controller only

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-nginx
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: laravel-api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
          podSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

Label your ingress namespace consistently. The policy above permits only nginx pods to reach the Laravel API on port 8080.

Step 3: Allow egress to the database and DNS

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: laravel-api
  policyTypes:
    - Egress
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: mysql
      ports:
        - protocol: TCP
          port: 3306
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

Validate with kubectl exec and curl from a debug pod. If a connection hangs, the policy is working — or your CNI is not.

Network Policy Traffic FlowIngressControllerApp Podlaravel-apiNamespace: productionMySQLPort 3306kube-dnsUDP 53BlockedOther podsDefault deny — explicit allow rules only
Network Policies in Kubernetes Security enforce default deny with explicit ingress from the controller and egress to database and DNS

How do Pod Security and Network Policies work together?

Pod Security answers "what can this container do on the node?" Network Policies answer "who can this pod talk to?" They are complementary, not interchangeable. A restricted pod that cannot escalate privileges may still exfiltrate data if egress is open to the internet.

Layer them in this order:

  1. Harden nodes — patch Ubuntu, restrict SSH, enable auditd. See Ubuntu server security best practices.
  2. Apply restricted PSS to application namespaces; keep kube-system privileged.
  3. Deploy default-deny Network Policies per namespace.
  4. Add allow rules service by service as you deploy.
  5. Run runtime detection with Falco for Kubernetes runtime security.
  6. Scan images — use distroless base images where possible.

I've seen teams skip step 3 because staging "worked fine." Production microservices talk to dozens of internal endpoints. Without default deny, lateral movement after one compromised pod is trivial.

Defense-in-Depth StackNode Hardening — OS patches, SSH keys, audit logsPod Security Standards — admission controlNetwork Policies — east-west segmentationRuntime Security — Falco, Tetragon alertsApplication — auth, input validation
Kubernetes Security Pod Security and Network Policies sit in the middle of a layered defense model above the OS and below runtime tools

Mapping workloads to namespaces

A practical namespace layout for a multi-service enterprise application:

  • production — enforce restricted, default-deny network policies.
  • staging — enforce baseline, audit restricted, relaxed egress for debugging.
  • platform — privileged for monitoring agents and log collectors.
  • ingress-nginx — baseline; needs hostNetwork on some setups.

Document the label scheme in your runbook. Future you — or the next contractor — should not guess why staging accepts runAsUser: 0.

What are common mistakes when implementing Kubernetes security policies?

These failures show up repeatedly across clusters I help troubleshoot, including platforms similar to the booking systems on Adventure Third Pole Trek where uptime and data isolation both matter.

Mistake 1: Enforcing restricted PSS without fixing manifests

Restricted requires runAsNonRoot: true, dropped capabilities, and a seccomp profile. Old Deployments fail admission with opaque errors. Fix the pod spec first:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  seccompProfile:
    type: RuntimeDefault
containers:
  - name: app
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
          - ALL

Roll out in audit mode for one sprint. Collect violations from the API audit log before flipping enforce.

Mistake 2: Network Policies without DNS egress

Pods that cannot resolve names appear "broken." Every namespace with egress restrictions needs a kube-dns allow rule. Test with nslookup kubernetes.default from an app pod after applying policies.

Mistake 3: Forgetting control plane and webhook traffic

Admission webhooks, metrics scrapers, and service mesh sidecars inject pods that need their own policies. Istio and Linkerd add sidecar containers; your NetworkPolicy must allow the data plane ports or health checks fail.

Mistake 4: No visibility after lockdown

Policy enforcement without observability breeds shadow IT workarounds. Export denied connection metrics from Cilium or Calico. Correlate with Tetragon eBPF audit events when you need syscall-level detail.

Policy Rollout Decision TreeNew namespace?App workloadLabel: restrictedPlatform addonLabel: privilegedAudit mode 2 weeksFix failing DeploymentsEnforce + default denyAdd allow rules per serviceValidate checklistDNS egress worksMetrics scrape OKCI deploy succeedsRollback tested
Roll out Kubernetes Security Pod Security and Network Policies with audit-first namespace labels and a validation checklist before enforce mode

Testing policies before production

Use a throwaway namespace mirroring production labels. Deploy a debug pod and run connectivity tests. Store policy YAML in Git and apply through your pipeline — the same GitLab CI pattern I use on Kubespray-deployed clusters.

For API-heavy stacks, align network boundaries with your API security checklist. Internal service tokens mean nothing if any pod can reach the admin endpoint on port 8080.

How do you validate and monitor policy compliance?

Admission decisions generate audit events when audit mode is on. Query them with your logging stack or kubectl get events filtered by reason FailedCreate.

Useful checks after every deploy:

  • kubectl auth can-i create pods --namespace=production — confirm RBAC still works.
  • kubectl label namespace production --list — verify PSS labels survived a helm upgrade.
  • Network policy hit counters — Cilium cilium policy get or Calico flow logs.
  • Periodic namespace scans with kubectl get pods -A -o json piped through JSON formatter tools to find pods missing security contexts.

Policy-as-code tools extend PSS when three profiles are not enough. Compare options in the Kyverno vs OPA Gatekeeper guide. For teams without dedicated platform engineers, PSS labels plus hand-written NetworkPolicy YAML beats a complex policy engine you never maintain.

External references worth bookmarking: the official NetworkPolicy documentation and the CNCF project landscape for CNI and runtime security tooling choices.

Key Takeaways

  • Apply Pod Security Standards via namespace labels — audit first, then enforce restricted on app namespaces.
  • Start every production namespace with a default-deny NetworkPolicy before adding explicit allow rules.
  • Confirm your CNI actually enforces Network Policies; policies on unsupported CNIs provide false confidence.
  • Fix pod securityContext in manifests before switching PSS to enforce mode to avoid deployment outages.
  • Always allow DNS egress when restricting pod egress, or services fail with misleading timeout errors.
  • Combine PSS, Network Policies, distroless images, and runtime monitoring for workable defense in depth.

People Also Ask

Are Network Policies enabled by default in Kubernetes?

No. Kubernetes ships the NetworkPolicy API, but enforcement depends entirely on your CNI plugin. Clusters using plain Flannel or older configurations may accept NetworkPolicy objects without blocking any traffic. Verify with a test deny policy before relying on segmentation in production.

What happens when a pod violates Pod Security Standards?

With enforce mode active, the Pod Security admission plugin rejects the create or update request. The pod never schedules. In warn mode, the pod is created but the API server returns a warning. Audit mode logs the violation to the audit log without blocking or warning the caller.

Can I use Pod Security and Network Policies with managed Kubernetes?

Yes. EKS, GKE, and AKS all support PSS namespace labels on supported versions. Managed offerings typically ship with policy-capable CNIs — for example Calico on EKS or Azure CNI with network policy add-ons. Check your provider docs for the exact enablement flag.

Do Network Policies affect traffic leaving the cluster to the internet?

Yes, if you include egress rules. A default-deny egress policy blocks outbound internet access unless you add an allow rule to external CIDR blocks or a namespace running an egress gateway. Many teams allow egress to 0.0.0.0/0 on ports 443 and 80 initially, then tighten based on flow logs.

Build a cluster security baseline you can maintain

Kubernetes Security: Pod Security and Network Policies is not a one-time hardening sprint. It is a baseline you extend every time a new service ships. Label namespaces, deny by default, allow deliberately, and fix manifests before enforcement breaks your pipeline. If you want help designing that baseline for a production platform — or hardening the Linux layer underneath — contact us or explore testing and optimization services. Solid pod and network policy now saves a painful incident later.

Frequently Asked Questions

Pod security controls what a container is allowed to do before it ever talks to the network. In current Kubernetes clusters, that means Pod Security Standards — three built-in profiles shipped with Kubernetes 1.25 and later. They block privileged pods, root users, and host path mounts at admission time. On real client projects, the gap is rarely malicious intent; a developer copies a Docker Compose file and sets privileged true because a local volume mount failed. PSS catches that before production, not during a penetration test.

Pod Security Standards replaced PodSecurityPolicy starting in Kubernetes 1.25. PSP was removed entirely. PSS uses three namespace labels instead of custom policy objects and RBAC bindings, with enforcement handled by the built-in Pod Security admission plugin.

No. Kubernetes ships the NetworkPolicy API, but enforcement depends entirely on your CNI plugin. Clusters using plain Flannel or older configurations may accept NetworkPolicy objects without blocking any traffic. Verify with a test deny policy before relying on segmentation in production.

With enforce mode active, the Pod Security admission plugin rejects the create or update request and the pod never schedules. In warn mode, the pod is created but the API server returns a warning. Audit mode logs the violation to the audit log without blocking or warning the caller. I recommend running audit mode for one sprint, collecting violations from the API audit log, then flipping to enforce once manifests are fixed.

PSP was powerful but painful. Cluster admins wrote complex RBAC so teams could bind policies, and upgrades broke silently. PSS inverts the model: Kubernetes ships three opinionated profiles and you label namespaces. PSP offered per-policy flexibility with high operational cost and drift across teams. PSS offers three fixed profiles with low label-driven defaults. Custom exceptions in PSP were native via policy objects; with PSS they require exempt namespaces or tools like Kyverno or OPA Gatekeeper. For most application namespaces, restricted PSS plus a dedicated privileged namespace for operators is enough.

Apply labels to each namespace using kubectl. Start with audit mode, read the logs, then switch to enforce. Label production with pod-security.kubernetes.io/enforce=restricted, enforce-version=latest, audit=restricted, and warn=restricted. The built-in pod-security admission plugin reads these labels — no extra controller is required on a standard cluster. Pair PSS with seccomp profiles and read-only root filesystems for defense in depth. Document the label scheme in your runbook so future you or the next contractor does not guess why staging accepts runAsUser zero.

Privileged is unrestricted and should be used only for system components like CNI or storage drivers. Baseline blocks known privilege escalations but allows common legacy patterns. Restricted requires non-root users, dropped capabilities, and no host namespaces — best for application workloads like Laravel or API services. A practical layout keeps production on enforce restricted with default-deny network policies, staging on enforce baseline with audit restricted, and platform on privileged for monitoring agents and log collectors.

Network Policies are Kubernetes API objects that only work if your CNI supports them — Calico, Cilium, and Weave do; basic Flannel without an overlay policy engine does not. Start with a default-deny policy selecting all pods with both Ingress and Egress policyTypes and no rules. Then add explicit allow rules: ingress from your ingress-nginx namespace to app pods on the correct port, and egress to your database pods and kube-dns on UDP port 53. Validate with kubectl exec and curl from a debug pod. Store policy YAML in Git and apply through your pipeline.

Pod Security answers what can this container do on the node. Network Policies answer who can this pod talk to. They are complementary, not interchangeable. A restricted pod that cannot escalate privileges may still exfiltrate data if egress is open to the internet. Layer them after hardening nodes: apply restricted PSS to application namespaces, deploy default-deny Network Policies per namespace, then add allow rules service by service. Combine with distroless images, image scanning, and runtime detection with Falco. I have seen teams skip network policies because staging worked fine — production microservices talk to dozens of internal endpoints, and without default deny, lateral movement after one compromised pod is trivial.

Calico, Cilium, and Weave Net enforce NetworkPolicy resources. Basic Flannel without an overlay policy engine does not — a common production mistake is writing policies on a cluster where they are silently ignored, giving false confidence. Managed offerings typically ship with policy-capable CNIs, such as Calico on EKS or Azure CNI with network policy add-ons. After applying policies, export denied connection metrics from Cilium or Calico and correlate with flow logs when debugging blocked connections.

Yes. EKS, GKE, and AKS all support PSS namespace labels on supported versions. Managed offerings typically ship with policy-capable CNIs — for example Calico on EKS or Azure CNI with network policy add-ons. Check your provider documentation for the exact enablement flag. The same audit-first rollout applies: label namespaces, deploy default-deny policies, validate connectivity from a debug pod, then enforce restricted PSS once manifests include proper securityContext blocks with runAsNonRoot, dropped capabilities, and seccomp profiles.

Yes, if you include egress rules. A default-deny egress policy blocks outbound internet access unless you add an allow rule to external CIDR blocks or a namespace running an egress gateway. Many teams allow egress to 0.0.0.0/0 on ports 443 and 80 initially, then tighten based on flow logs from Cilium or Calico. Remember that every namespace with egress restrictions also needs a kube-dns allow rule on UDP port 53, or pods fail with misleading timeout errors when they cannot resolve names.

The most common cause is missing DNS egress. Pods that cannot resolve names appear broken even when application rules are correct. Every namespace with egress restrictions needs a kube-dns allow rule targeting kube-system with k8s-app kube-dns on UDP port 53. Test with nslookup kubernetes.default from an app pod after applying policies. Other frequent failures include forgetting admission webhooks, metrics scrapers, and service mesh sidecars — Istio and Linkerd inject containers that need their own policies for data plane ports and health checks.

Four failures show up repeatedly. First, enforcing restricted PSS without fixing manifests — old Deployments fail admission with opaque errors until you add runAsNonRoot, dropped capabilities, seccompProfile RuntimeDefault, and readOnlyRootFilesystem. Second, Network Policies without DNS egress. Third, forgetting control plane and webhook traffic when service mesh sidecars need allowed ports. Fourth, no visibility after lockdown — export denied connection metrics from your CNI and correlate with audit events. Roll out with audit-first namespace labels and a validation checklist before enforce mode.

Use a throwaway namespace mirroring production labels. Deploy a debug pod and run connectivity tests with kubectl exec, curl, and nslookup. Apply PSS in audit mode first and query FailedCreate events or audit logs for violations. For network policies, confirm your CNI actually enforces them — if a connection hangs after applying deny rules, the policy is working or your CNI is not. Store policy YAML in Git and apply through your pipeline, the same GitLab CI pattern used on Kubespray-deployed clusters. For API-heavy stacks, align network boundaries so internal service tokens are not useless because any pod can reach the admin endpoint.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: