4 Kubernetes Annotations That Instantly Improve Your Security Posture

Discover four Kubernetes annotations that instantly harden your cluster's security: seccomp syscall filtering, AppArmor profiles, Pod Security Admission enforcement, and ingress TLS-only access. Practical YAML examples included.

Most Kubernetes teams focus on RBAC, network policies, and pod security contexts — and they should. But there is a set of battle-tested Kubernetes annotations that can instantly harden your cluster's security posture with minimal effort. These annotations control everything from syscall filtering to ingress encryption, and most clusters run without them.

Kubernetes annotations are key-value metadata attached to pods, services, ingresses, and other resources. Unlike labels, annotations are not used for selection — they carry operational or security directives that the control plane and node-level components (like container runtimes and admission controllers) read and enforce at runtime. In this guide, we cover four annotations that deliver immediate, measurable security improvements with zero code changes.

Why Security Annotations Matter

According to theKubernetes Pod Security Standards, most real-world clusters run workloads in "Privileged" mode by default — not because the workloads need it, but because no policy explicitly restricts them. A 2025 cloud-native survey found that 68% of container security incidents involved excessive Linux capabilities or unrestricted syscalls — both of which can be blocked with a single annotation.

Annotations give you a declarative way to enforce security constraints at the resource level without modifying container images or rebuilding deployments. They complement RBAC (which controls who can do what) and network policies (which control traffic flow) by adding a third layer:runtime behavior restriction.

The Three Security Layers Every Cluster Needs

1 · RBAC + IAM
Who has access to the API server. Roles, bindings, service accounts.
2 · Network Policies
What traffic flows between pods. Default-deny, egress/ingress rules.
3 · Annotations + Security Context
How pods behave at runtime. Syscalls, profiles, admission policies.

Annotation 1: Restrict Syscalls With Seccomp

Seccomp (secure computing mode) limits the system calls a container can make. By default, containers inherit the Docker/Kubernetes default seccomp profile, which allows 300+ syscalls — far more than most applications need. A compromised container with unrestricted syscalls can escalate privileges, load kernel modules, or exploit kernel vulnerabilities.

The annotationseccomp.security.alpha.kubernetes.io/pod (or the newer seccomp-profile field in the security context) lets you pin a specific seccomp profile to a pod:

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: "runtime/default"
spec:
  containers:
  - name: app
    image: nginx:alpine

The fix:Set the annotation to"runtime/default" for most workloads. For high-security pods, create a custom seccomp profile that whitelists only the syscalls your application actually needs (trace with strace -c -p or audit2allow). The Kubernetes documentation recommends seccomp for all production workloads as a baseline hardening step.

To verify seccomp is active on a running pod:

kubectl exec  -- cat /proc/1/status | grep Seccomp
# Output: Seccomp:	2  (2 = filtered, 0 = disabled, 1 = strict)

Annotation 2: Enforce AppArmor Profiles

AppArmor is a Mandatory Access Control (MAC) system that confines programs to a limited set of resources. Kubernetes supports AppArmor through the annotationcontainer.apparmor.security.beta.kubernetes.io/. Without it, most containers run without any AppArmor profile, leaving the host kernel exposed to container breakout attempts.

apiVersion: v1
kind: Pod
metadata:
  name: apparmor-protected
  annotations:
    container.apparmor.security.beta.kubernetes.io/app: "localhost/k8s-apparmor-profile"
spec:
  containers:
  - name: app
    image: python:3.11-slim

The fix:Use"runtime/default" to apply the node's default AppArmor profile, or create a custom profile with aa-genprof and load it on each node. The AppArmor profile path must exist at /etc/apparmor.d/ on every node where the pod runs. For teams adopting Kubernetes AppArmor best practices, start with theruntime/default profile and iterate toward custom profiles for critical workloads.

To check whether AppArmor is enforcing:

kubectl get pod  -o jsonpath='{.metadata.annotations}' | grep apparmor
# Verify the container runtime log for "apparmor=" messages

⚠️ Key Difference: Seccomp vs AppArmor

Seccomp filters syscalls at the kernel interface level — it controls what system calls a process can make. AppArmor controls file access, network access, and capability use at the application level.They are complementary, not redundant.Use both for defense-in-depth.

Seccomp
Syscall allow/deny list
Works on any Linux
AppArmor
File + network + capability rules
Ubuntu/Debian hosts only

Annotation 3: Enforce Pod Security Standards With PSA

Pod Security Admission (PSA) replaced the deprecated PodSecurityPolicy in Kubernetes v1.25+. PSA uses annotations to define the security standard for a namespace or pod. The three levels —Privileged,Baseline, andRestricted— map to increasingly strict sets of security controls.

Enforce PSA with this namespace-level annotation:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  annotations:
    pod-security.kubernetes.io/enforce: "restricted"
    pod-security.kubernetes.io/enforce-version: "latest"
    pod-security.kubernetes.io/audit: "baseline"
    pod-security.kubernetes.io/warn: "baseline"

The fix:Start withaudit: baseline and warn: baseline to detect violations without blocking. After fixing violations, switch to enforce: baseline for most namespaces and enforce: restricted for security-critical ones. Only use enforce: privileged for system infrastructure pods that genuinely need host access.

PSA annotations give you granular control per namespace. Combined withShieldOps security analysis, you can identify exactly which pods violate the Restricted standard and fix them one by one.

To see which PSA level applies to a running pod:

kubectl get pod  -n  -o yaml | grep -A5 "pod-security"

Annotation 4: Disable HTTP on Ingress Resources

A surprisingly common security gap: ingresses that accept both HTTP and HTTPS traffic, with HTTP requests either serving insecure content or redirecting. An attacker intercepting unencrypted traffic to your ingress can steal session tokens, inject malicious payloads, or perform man-in-the-middle attacks.

Thekubernetes.io/ingress.allow-http annotation on your Ingress resources forces TLS-only access:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-api
  annotations:
    kubernetes.io/ingress.allow-http: "false"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.shieldops-ai.dev
    secretName: api-tls
  rules:
  - host: api.shieldops-ai.dev
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 443

The fix:Addkubernetes.io/ingress.allow-http: "false" to every ingress that serves production traffic. Pair it with nginx.ingress.kubernetes.io/ssl-redirect: "true" for the NGINX ingress controller. Always terminate TLS at the ingress level using cert-manager for automatic certificate renewal.

For a complete security posture check of your ingress resources, useShieldOps compliance scanningwhich validates TLS configuration against PCI DSS and SOC 2 requirements.

Quick Implementation Checklist

  • ⬜ Addseccomp.security.alpha.kubernetes.io/pod: runtime/default to all deployments
  • ⬜ Enable AppArmor viacontainer.apparmor.security.beta.kubernetes.io/*: runtime/default
  • ⬜ Apply PSA annotations at namespace level (enforce: baseline minimum)
  • ⬜ Addkubernetes.io/ingress.allow-http: "false" to all production ingresses
  • ⬜ Verify annotations are active withkubectl describe and runtime logs
  • ⬜ Scan existing workloads withShieldOpsfor missing annotations

Related ShieldOps Reads

Frequently Asked Questions

Can I use these annotations on existing pods without restarting?

No — pod-level annotations in Kubernetes are immutable once the pod is created. You must update the deployment, statefulset, or daemonset template, then roll out new pods. The new pods will pick up the annotations.

Will seccomp or AppArmor break my application?

If you useruntime/default, most applications work without changes. Custom profiles can break applications that depend on unusual syscalls (e.g., ptrace-based debuggers, FUSE filesystems). Always test in a staging environment with audit mode before enforcing.

What's the difference between `pod-security.kubernetes.io/enforce` and the old PodSecurityPolicy?

PodSecurityPolicy was a single cluster-scoped resource that applied the same policy to all pods. PSA is namespace-scoped and uses three well-defined standards (Privileged, Baseline, Restricted). It is simpler, more predictable, and is the only supported path as PSP was removed in Kubernetes 1.25.

Do these annotations work with managed Kubernetes services (EKS, AKS, GKE)?

Yes — all four annotations work on EKS, AKS, and GKE. AppArmor requires a node OS that supports it (Ubuntu, COS, Bottlerocket). Seccomp works on all Linux nodes. Managed Kubernetes services fully support PSA annotations via their integrated admission controllers.

How do I enforce annotations across all namespaces?

Use a mutating admission webhook (like Kyverno or OPA Gatekeeper) to inject these annotations automatically. For example, a Kyverno ClusterPolicy can add the seccomp annotation to every pod in every namespace. Combined withShieldOps policy engine, you can audit and enforce annotation compliance across your fleet.

What happens when I set both seccomp annotation and securityContext.seccompProfile?

ThesecurityContext.seccompProfile field (GA since Kubernetes 1.27) takes precedence over the annotation. If both are set, the securityContext value wins. Migration path: move from annotations to the native seccompProfile field when you upgrade to Kubernetes 1.27+.

Does disabling HTTP on ingress affect Let's Encrypt certificate renewal?

Yes — cert-manager's HTTP-01 challenge requires port 80 to be reachable. If you disable HTTP entirely, switch to DNS-01 challenges (cert-manager.io/challenge-type: dns-01) or use a separate ingress for ACME challenges with HTTP enabled.

Conclusion

These four annotations — seccomp, AppArmor, PSA, and ingress TLS enforcement — form a powerful zero-effort security layer that integrates directly into your existing Kubernetes manifests. No sidecars, no agents, no image rebuilds. Deploy them today, and your cluster's security posture improves the moment new pods roll out.

Ready to audit your cluster for missing security annotations?Start a free ShieldOps analysisand discover which of your workloads are running without these critical protections.

Ready to apply these concepts?

Try ShieldOps AI and start scanning your infrastructure right away.

Start Free Scan

Your take

Rate this article or leave a comment

Have more questions? Check our

FAQ
🤖