Skip to content
Back to skills

K8s Security Policies

ASecurity

Pod Security Standards and Pod Security Admission, NetworkPolicy fundamentals with default-deny and service-to-service patterns, restricted-profile pod security contexts, and Kyverno examples. Use when hardening workloads or writing NetworkPolicy and admission rules.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
securityrustgoreactnodekubernetesgitapidatabasefrontendsecurity

Works with

  • api

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add HermeticOrmus/LibreSecOps-Claude-Code --skill k8s-security-policies --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of K8s Security Policies?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for K8s Security Policies
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hermeticormus-k8s-security-policies-libresecops-claude-code/badge)](https://www.skillsdirectory.com/skills/hermeticormus-k8s-security-policies-libresecops-claude-code)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: "k8s-security-policies"
description: "Pod Security Standards and Pod Security Admission, NetworkPolicy fundamentals with default-deny and service-to-service patterns, restricted-profile pod security contexts, and Kyverno examples. Use when hardening workloads or writing NetworkPolicy and admission rules."
---

# K8s Security Policies

> Pod Security Standards, NetworkPolicy patterns, admission control strategies, and workload security enforcement.

## Knowledge Base

### Pod Security Standards (PSS) -- The Three Profiles

Pod Security Standards define three progressively restrictive security profiles. These are not policies themselves -- they are standards that admission controllers enforce.

| Profile | Purpose | Restrictions |
|---------|---------|------------|
| **Privileged** | Unrestricted. For system-level workloads. | None. Everything allowed. |
| **Baseline** | Prevents known privilege escalations. Minimally restrictive. | No privileged containers, no hostPath, no hostNetwork/PID/IPC, restricted capabilities, restricted volume types, no host ports |
| **Restricted** | Heavily restricted. Best practice for untrusted workloads. | Baseline + must run as non-root, must drop ALL capabilities (may add NET_BIND_SERVICE), seccomp profile required, restricted seccomp/AppArmor profiles |

### Pod Security Admission (PSA) Controller

PSA is the built-in admission controller that enforces PSS. Three modes per namespace:

| Mode | Behavior |
|------|----------|
| `enforce` | Violations are rejected. Pod will not be created. |
| `audit` | Violations are recorded in audit log but pod is created. |
| `warn` | Violations generate a warning to the user but pod is created. |

**Best practice**: Start with `audit` + `warn`, fix violations, then switch to `enforce`.

```yaml
# Namespace labels for PSA
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest
```

### NetworkPolicy Fundamentals

NetworkPolicy is Kubernetes' built-in network segmentation. Key behaviors:

- **Without any NetworkPolicy**, all pods can communicate with all other pods (cluster-wide flat network).
- **Once any NetworkPolicy selects a pod** (via `podSelector`), that pod's traffic is restricted to what the policies explicitly allow.
- NetworkPolicies are **additive** -- multiple policies selecting the same pod combine their allowed traffic.
- NetworkPolicies are **namespace-scoped** but can reference other namespaces via `namespaceSelector`.
- **Egress policies are often forgotten** -- even with ingress restrictions, a compromised pod can phone home without egress controls.
- **DNS egress must be explicitly allowed** when using egress policies (UDP port 53 to kube-dns).

## Patterns

### Pattern 1: Default Deny All Traffic

```yaml
# Apply to every namespace that should have network restrictions
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}  # Selects ALL pods in namespace
  policyTypes:
    - Ingress
    - Egress
  # No ingress or egress rules = deny all
---
# Allow DNS egress (required for service discovery)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
```

**Why this works**: Starting with default-deny forces explicit allow rules for every communication path. This is the network equivalent of dropping all capabilities and adding back only what is needed. The DNS allow is necessary because Kubernetes service discovery requires DNS resolution.

### Pattern 2: Microservice Communication Policy

```yaml
# Frontend can talk to API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-ingress-from-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080
---
# API can talk to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-ingress-from-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 5432
---
# API egress to database and external APIs
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Egress
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: database
      ports:
        - protocol: TCP
          port: 5432
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16
      ports:
        - protocol: TCP
          port: 443
```

**Why this works**: Each policy explicitly defines which pods can communicate, on which ports, in which direction. The API egress policy allows database access and external HTTPS, but excludes private IP ranges (preventing lateral movement to internal services not explicitly allowed).

### Pattern 3: Pod Security Context (Restricted Profile Compliant)

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 1001
        runAsGroup: 1001
        fsGroup: 1001
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: app
          image: myapp:v1.2.3@sha256:abc123...
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "500m"
          ports:
            - containerPort: 8080
              protocol: TCP
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: cache
              mountPath: /app/cache
      volumes:
        - name: tmp
          emptyDir:
            sizeLimit: 64Mi
        - name: cache
          emptyDir:
            sizeLimit: 128Mi
```

**Why this works**: This manifest complies with the PSS Restricted profile. Non-root user, all capabilities dropped, privilege escalation blocked, read-only root filesystem (with emptyDir for writable paths), seccomp enabled, resource limits set, service account token not mounted, and image pinned by digest.

### Pattern 4: Kyverno Policy -- Require Labels

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
  annotations:
    policies.kyverno.io/title: Require Labels
    policies.kyverno.io/severity: medium
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: require-team-label
      match:
        any:
          - resources:
              kinds:
                - Deployment
                - StatefulSet
                - DaemonSet
      validate:
        message: "The label 'team' is required."
        pattern:
          metadata:
            labels:
              team: "?*"
    - name: require-app-label
      match:
        any:
          - resources:
              kinds:
                - Deployment
                - StatefulSet
                - DaemonSet
      validate:
        message: "The label 'app' is required for NetworkPolicy targeting."
        pattern:
          spec:
            template:
              metadata:
                labels:
                  app: "?*"
```

**Why this works**: Labels are the foundation of NetworkPolicy targeting and RBAC scoping in Kubernetes. Requiring `team` and `app` labels ensures every workload can be targeted by network policies and attributed to an owner.

## Anti-Patterns

### Anti-Pattern 1: No NetworkPolicy

Without any NetworkPolicy, every pod can communicate with every other pod on every port. A compromised frontend can directly access the database, exfiltrate data to external servers, and scan internal services.

### Anti-Pattern 2: Privileged Containers Without Justification

`privileged: true` disables all container isolation. Only a few workloads legitimately need this (CNI plugins, CSI drivers, node monitoring agents). Application containers should never be privileged.

### Anti-Pattern 3: PSA Set to "Privileged"

Setting `pod-security.kubernetes.io/enforce: privileged` on application namespaces effectively disables Pod Security Standards. It should only be used for `kube-system` and infrastructure namespaces.

### Anti-Pattern 4: Ingress-Only NetworkPolicy

Protecting ingress without controlling egress leaves data exfiltration wide open. Always implement both ingress and egress policies.

### Anti-Pattern 5: Using hostPath Volumes

`hostPath` volumes mount host directories into containers, bypassing namespace isolation. A pod with `hostPath: {path: "/"}` has access to the entire host filesystem. Use PersistentVolumeClaims instead.

## References

- [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
- [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
- [NetworkPolicy Documentation](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
- [Kyverno Documentation](https://kyverno.io/docs/)
- [OPA Gatekeeper](https://open-policy-agent.github.io/gatekeeper/)
- [NSA/CISA Kubernetes Hardening Guide](https://media.defense.gov/2022/Aug/29/2003066362/-1/-1/0/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF)
- [NetworkPolicy Editor (Cilium)](https://editor.networkpolicy.io/)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…