Intro
Kubernetes Security Context commands are foundational for running workloads with least privilege. A security context defines privilege and access control settings for a Pod or container, including user and group IDs, Linux capabilities, seccomp profiles, and SELinux options. This guide provides practical commands and examples to help operators, developers, and DevOps engineers configure and verify security contexts safely and effectively.
The goal is operational safety: observe before changing, limit the blast radius, use placeholders instead of secrets, verify the result, and document how to recover if the expected state is not reached. By the end of this article, you will be able to inspect current security contexts, apply appropriate settings, and troubleshoot common issues with confidence.
Version and Environment Inventory
Before modifying any security context, you must understand your environment and current state. This section covers how to inventory your cluster, identify relevant components, and verify the Kubernetes version.
Step 1: Check Kubernetes Version and API Support
Security context fields have evolved across Kubernetes versions. Always confirm your cluster version and API availability before applying manifests.
kubectl version --short
Example output:
Client Version: v1.28.2
Server Version: v1.28.3
Key compatibility notes:
runAsUser,runAsGroup,fsGroup, andsupplementalGroupsare stable and available in all supported versions.seccompProfilebecame GA in v1.19; usesecurityContext.seccompProfile.typerather than annotations.allowPrivilegeEscalationis stable; set it tofalsewhenever possible.capabilitiesfield is stable; prefer thedroplist overadd.windowsOptionsare for Windows containers (e.g.,runAsUserName).
Step 2: Inventory Existing Security Contexts
Before changing anything, observe existing Pods and their security settings. This read-only step helps you understand the current risk posture.
List all Pods with wide output to see node placement and status:
kubectl get pods -A -o wide
To inspect a specific Pod's full security context, use kubectl get with YAML or JSON output. For example, to view the security context of a Pod named nginx-secure in namespace default:
kubectl get pod nginx-secure -n default -o yaml
Look for the securityContext section at the Pod and container levels. Here is a snippet from a Pod with a restrictive context:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: nginx
image: nginx:1.25
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 1000
You can also use kubectl describe to see events and quickly spot security-related issues, such as a Pod failing to start due to a non-root user or missing capabilities.
Step 3: Verify Prerequisites
Security contexts rely on the container runtime and OS features. Ensure:
- The container runtime (containerd, CRI-O) supports the fields you intend to use.
- If using seccomp profiles, the profile file is present on the node or loaded as a custom resource.
- SELinux or AppArmor policies align with your settings.
- The Pod's service account has permission for any additional resources, though security context changes do not require extra RBAC.
A quick check for seccomp support:
kubectl get nodes -o jsonpath='{.items[*].metadata.name}' | xargs -I {} kubectl get node {} -o jsonpath='{.status.nodeInfo.containerRuntimeVersion}' && echo
Example output: containerd://1.7.2
Safe Configuration Path
Now that you have observed the environment, you can make minimal, justified changes. This section provides concrete examples for common security context configurations, emphasizing a least-privilege approach.
General Principles
- Apply one change at a time.
- Always set
runAsNonRoot: trueunless the container genuinely needs root. - Use specific
runAsUserandrunAsGroupIDs to avoid relying on image defaults. - Drop all capabilities and add back only what is required.
- Set
allowPrivilegeEscalation: false. - Use a runtime default seccomp profile (
RuntimeDefault) as a baseline; consider a custom profile for stricter control. - Avoid privileged containers; if unavoidable, set
privileged: falseeverywhere else.
Example 1: Run as Non-Root User
A common hard requirement: the container must not run as root. Create a Pod manifest with a security context that sets a non-root user.
Save the following as nonroot-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nonroot-demo
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: app
image: alpine:3.19
command: ["sleep", "3600"]
securityContext:
allowPrivilegeEscalation: false
Apply it:
kubectl apply -f nonroot-pod.yaml
Expected output:
pod/nonroot-demo created
Verify the Pod is running and that the container processes are not root:
kubectl exec nonroot-demo -- id
Expected output (if user 1000 exists in the container):
uid=1000 gid=3000 groups=3000,2000
If the image does not have user 1000 defined, the container may fail with container has runAsNonRoot and image will run as root, indicating you need to choose a different base image or create the user in the image.
Example 2: Drop All Capabilities and Add Only What Is Needed
Linux capabilities grant fine-grained privileges. Dropping all and adding only necessary ones reduces risk.
Create capabilities-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: capabilities-demo
spec:
containers:
- name: net-admin
image: alpine:3.19
command: ["sleep", "3600"]
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
Apply and verify:
kubectl apply -f capabilities-pod.yaml
kubectl exec capabilities-demo -- capsh --print | grep Current
Expected output shows only the allowed capabilities, including net_bind_service.
Example 3: Apply a Seccomp Profile
Seccomp restricts syscalls. Start with the runtime default, then consider a custom profile.
Pod-level seccomp (applies to all containers):
apiVersion: v1
kind: Pod
metadata:
name: seccomp-demo
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: alpine:3.19
command: ["sleep", "3600"]
For a stricter custom profile, create a Localhost profile on the node. Example profile denying chmod:
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["chmod", "fchmod", "fchmodat"],
"action": "SCMP_ACT_ERRNO"
}
]
}
Save as custom-seccomp.json on the node, then reference it:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: custom-seccomp.json
Apply and test by attempting chmod inside the container; it should fail with Operation not permitted.
Step 4: Verify After Applying
After each change, verify the Pod starts and behaves as expected. Use kubectl get pods to check status, kubectl describe for events, and kubectl logs for application errors. For a quick functional test, use kubectl exec to run commands inside the container.
For Deployments, use kubectl rollout status to ensure the rollout completes:
kubectl rollout status deployment/nginx-secure -n default
Expected output: deployment "nginx-secure" successfully rolled out
Verification and Diagnostics
This section covers how to verify that security contexts are working as intended and how to diagnose issues when they are not.
Verify Actual Runtime Security Settings
You can inspect the effective security context of a running container by looking at its process attributes or by using kubectl exec to query the environment.
For example, to check the user and groups:
kubectl exec -it nonroot-demo -- id
Expected output: uid=1000 gid=3000 groups=2000 (or similar, depending on image).
To verify capabilities inside the container, use capsh (may need to install):
kubectl exec capabilities-demo -- capsh --print
Look for Current: capabilities line.
To check the seccomp mode, use kubectl get pod with JSONPath or inspect the container runtime. For example:
kubectl get pod seccomp-demo -o jsonpath='{.spec.securityContext.seccompProfile.type}'
Expected output: RuntimeDefault
Diagnose Common Failures
1. Container fails with CreateContainerConfigError
Often caused by invalid security context fields. Use kubectl describe pod <name> to see the event. Common error: invalid value: 0: must be greater than or equal to 1 for runAsUser. Fix by setting a valid UID.
2. Pod stuck in ContainerCreating or CrashLoopBackOff
Could be due to seccomp profile not found. Check events:
kubectl describe pod seccomp-demo
Look for: cannot load seccomp profile. Fix by ensuring the profile file exists on the node and has correct permissions.
3. Permission denied inside container despite non-root
If the container cannot write to a volume, ensure fsGroup is set to the group that owns the volume, or use a supplemental group. For example:
securityContext:
fsGroup: 2000
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [2000]
4. Network binding fails
If the application needs to bind to a port below 1024, add NET_BIND_SERVICE capability as shown earlier. Alternatively, configure the app to use a higher port.
5. Container cannot setuid or perform privileged operations
This is expected when allowPrivilegeEscalation: false and capabilities are dropped. If truly needed, add the specific capability, but prefer changing the application to avoid it.
Logging and Monitoring
Security context failures often surface in container logs or events. Use kubectl logs --previous to see the last logs of a crashed container:
kubectl logs nonroot-demo --previous
For ongoing monitoring, consider setting up audit logging or a policy engine like OPA Gatekeeper or Kyverno to enforce security contexts.
Failure Modes and Recovery
Even with careful planning, things can go wrong. This section outlines common failure scenarios, their symptoms, and recovery steps.
Scenario 1: Pod Refuses to Start Due to Security Context
Symptom: Pod status is CreateContainerConfigError or Error.
Diagnosis: Run kubectl describe pod <name> and look for events indicating invalid field values, missing seccomp profile, or unsupported options.
Recovery: Edit the Pod or Deployment to correct the security context. For example, if runAsUser: 0 with runAsNonRoot: true, change runAsUser to a non-zero UID or remove runAsNonRoot. Then delete and recreate the Pod (or rollout the Deployment).
Scenario 2: Application Fails at Runtime Due to Missing Permissions
Symptom: Container starts but application exits with permission errors or crashes.
Diagnosis: Check container logs with kubectl logs <pod>. Look for messages like "permission denied" or "operation not permitted".
Recovery: Determine which capability or user change is needed. Grant the minimal additional privilege. For example, if the app needs to change system time, add SYS_TIME capability. Update the manifest and apply.
Scenario 3: Rollout of a Security Context Change Causes Downtime
Symptom: After updating a Deployment with a new security context, new Pods fail and old Pods are terminated, leaving no available replicas.
Diagnosis: Check kubectl rollout status deployment/<name> for failure message. Inspect new Pods with kubectl describe and kubectl logs.
Recovery: Immediately rollback to the previous revision:
kubectl rollout undo deployment/nginx-secure
Then debug the issue in a separate namespace or with a single Pod before reapplying.
Scenario 4: Seccomp Profile Blocks Required Syscalls
Symptom: Container fails with an errno (often EPERM or EACCES) on a specific operation.
Diagnosis: Check application logs or use strace if available. Also, verify the applied seccomp profile: kubectl get pod <name> -o jsonpath='{.spec.securityContext.seccompProfile}'.
Recovery: Modify the custom seccomp profile to allow the needed syscall, or temporarily switch to RuntimeDefault for testing. Reload the profile and restart the Pod.
General Recovery Best Practices
- Always have a rollback plan: use versioned manifests, GitOps, or at least
kubectl rollout undo. - Test changes in a staging environment first.
- Keep a backup of the original pod spec:
kubectl get pod <name> -o yaml > pod-backup.yamlbefore editing. - Document the failure and recovery in your runbook.
Operations Checklist
Use the following checklist before and after modifying security contexts in production.
Before Applying Changes
- [ ] Confirm Kubernetes version supports the security context fields you plan to use.
- [ ] Check current security context:
kubectl get pod <name> -o yaml. - [ ] Identify the container's runtime user and group:
kubectl exec <pod> -- id(if running). - [ ] List current capabilities:
kubectl exec <pod> -- capsh --print(if available). - [ ] Verify seccomp profile status:
kubectl get pod <name> -o jsonpath='{.spec.securityContext.seccompProfile}'. - [ ] Back up the Pod/Deployment YAML:
kubectl get <resource> <name> -o yaml > backup.yaml. - [ ] Determine the minimum required privileges (user, capabilities, etc.) by consulting application documentation or testing locally.
- [ ] Prepare a rollback command:
kubectl rollout undo deployment/<name>or keep original YAML ready. - [ ] Notify relevant team members about the change window.
After Applying Changes
- [ ] Check Pod status:
kubectl get pods -n <namespace> -o wide. - [ ] Verify the security context is set correctly:
kubectl get pod <name> -o yaml | grep -A10 securityContext. - [ ] Confirm the container runs with the expected user:
kubectl exec <pod> -- id. - [ ] Validate capabilities:
kubectl exec <pod> -- capsh --print(if available). - [ ] Check application logs for errors:
kubectl logs <pod>. - [ ] Test critical functionality (e.g., an HTTP health check).
- [ ] Monitor for a few minutes:
kubectl get pods -w. - [ ] Update documentation and runbooks with the new configuration.
- [ ] Remove any temporary diagnostic tools or permissions.
Example Checklist Filled for a Real Workload
Assume you are securing an Nginx deployment in namespace web.
- Current state: Pod
nginx-6d4b7c9f8-abcderunning as root, no seccomp, all capabilities. - Desired state: Run as UID 1000, drop all capabilities, seccomp RuntimeDefault.
- Backup:
kubectl get deployment nginx -n web -o yaml > nginx-deployment-backup.yaml. - Apply change: Edit deployment to add security context.
- Rollout:
kubectl rollout status deployment/nginx -n web. - Verify:
kubectl exec -n web <new-pod> -- idreturnsuid=1000. - Test:
curlthe service; expect HTTP 200. - Rollback if needed:
kubectl rollout undo deployment/nginx -n web.
Keep this checklist as a template and adapt it to your workflow.
Conclusion
Kubernetes Security Context commands are essential for hardening your workloads. By following a structured approach—inventorying the environment, making minimal changes, verifying outcomes, and planning for recovery—you can reduce the attack surface without sacrificing functionality.
Start with the basics: run containers as non-root, drop unnecessary capabilities, and enforce a seccomp profile. Use the commands and examples in this guide to inspect and adjust your security contexts safely. Remember that security is an ongoing process; regularly review your configurations and stay updated with Kubernetes releases.
For further learning, explore Kubernetes documentation on Pod Security Standards, Pod Security Admission, and tools like kube-bench for auditing your cluster's security posture.