Container Security: Best Practices for Docker and Kubernetes Environments
Containers security involves a set of practices, tools, and configurations used to protect containerized applications throughout their lifecycle from image creation to runtime operation. It guarantees that containers are built from trusted sources, run with minimal privileges, do not store sensitive data inside images, and operate within a secure and monitored environment.
While containers provide consistency, portability, and lightweight packaging, they also present unique security risks. A single vulnerable base image, a misconfigured Kubernetes workload, or a leaked secret can compromise an entire system. In containerized environments, security should be integrated from the outset, rather than being added later. This includes securing images, managing secrets safely, enforcing runtime protection policies, and continuously monitoring workloads from development through production.
Components of container security
Container security is a combination of several domains that work together to protect applications end-to-end. The most important components include:
Image security
We must ensure that every image we build, or pull is free from known vulnerabilities, follows best practices, and comes from a trusted source.
Secrets management
Passwords, API keys, and tokens should never be stored inside the image, inside the environment variables exposed in logs or in the Git repositories.
Instead, secure them as Docker secrets, Kubernetes secrets, or external vaults (AWS Secrets Manager, HashiCorp Vault) must be used.
Runtime security
Even if images are secure, containers can still be attacked at runtime. Runtime security involves:
- Limiting container privileges
- Enforcing read-only file systems
- Monitoring
syscallsand container behavior using tools likeFalco - Applying Kubernetes
NetworkPoliciesfor traffic control
These container security pillars work together to reduce attack surfaces and protect workloads at every stage.
How to secure container images effectively
Container images form the foundation of every containerized application. If an image contains vulnerabilities, outdated libraries, or unnecessary packages, the entire system inherits those risks. Our goal is to create clean, minimal, and trusted images.
Use trusted and minimal base images
Smaller base images reduce the attack surface. For example:
Here’s an example of how a really risky base image looks like:
FROM ubuntu:latest
Here’s how more secure base image should look like:
FROM alpine:3.20
Alpine contains fewer packages, which reduces CVEs and improves scanning results.
Scanning images regularly
Before pushing images, you should always scan them for vulnerabilities. Tools like Trivy make this simple.
If you want to try it yourself then run:
trivy image nginx:latest
Trivy reports vulnerabilities, their severity, and recommended fixes.
Avoid “latest” Tags
Using latest makes builds unpredictable. It may pull an updated version that introduces breaking changes or vulnerabilities without warning.
Always pin versions:
FROM python:3.10.6
This ensures deterministic, safe builds.
Avoid installing unnecessary packages
Every additional utility like curl, vim, wget adds more potential vulnerabilities. Only install what the application truly needs.
Pin versions of dependencies
Always pin versions to avoid unintended updates:
RUN pip install flask==2.2.5
This ensures reproducibility and prevents unexpected security regressions.
With image security handled, the next major concern is managing sensitive secrets.
How to manage secrets securely in docker and kubernetes
Hard-coding secrets in images or environment variables is one of the most common mistakes developers make. We must store and inject secrets safely.
Docker secrets (for Swarm or local development)
Docker provides a built-in secrets feature for encrypted storage. After creating a secret:
echo "myPassword123" | docker secret create db_password -
The secret becomes available only at runtime and is never baked into the image.
Kubernetes secrets
Kubernetes provides a native Secret object, which is the recommended method for storing sensitive data within clusters.
Here is a simple Secret definition:
apiVersion: v1kind: Secretmetadata:name: db-secrettype: Opaquedata:username: YWRtaW4= # base64 encodedpassword: c2VjdXJlMTIz # base64 encoded
We use kubectl apply -f secret.yaml to create this resource.
In Pods, we can mount the secret as environment variables:
env:- name: DB_USERNAMEvalueFrom:secretKeyRef:name: db-secretkey: username
Avoid storing secrets in Git
Even encoded data (like Base64) is not encrypted. We should use tools like:
- Google Secret Manager
- AWS Secrets Manager
- HashiCorp Vault
These systems provide encryption, versioning, auditing, and automatic rotation.
Now that secrets are handled securely, we can focus on securing containers while they run.
How to implement runtime protection for containers?
Once containers are running, we need to enforce strict rules to prevent vulnerabilities from being exploited.
Run containers as non-root users
By default, many images run as root, which introduces major security risks. We can fix this in a Dockerfile by following a simple line:
RUN addgroup -S appgroup && adduser -S appuser -G appgroupUSER appuser
Use read-only file systems
Using read-only file systems prevents attackers from modifying the container’s internal state, like:
securityContext:readOnlyRootFilesystem: true
Apply kubernetes network policies
Network policies limit which Pods can talk to which services. This helps prevent lateral movement inside a cluster. Here’s a simple allow-list example:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: allow-webspec:podSelector:matchLabels:app: webingress:- from:- podSelector:matchLabels:role: frontend
Use runtime protection tools
Tools like Falco, Aqua Enforcer, Sysdig Secure monitor container behavior and alert us if a container executes suspicious commands like writing to system directories or starting unexpected processes.
Now that runtime protection is covered, let’s explore the tools that help automate all these tasks.
Types of tools for container security
A secure container workflow uses multiple complementary tools. Here are the most widely used options:
Trivy
A lightweight vulnerability scanner for images, file systems, configurations, and Git repositories.
Aqua security
A commercial solution offering scanning, runtime defense, and compliance enforcement.
Clair
An open-source vulnerability scanner optimized for registries.
Anchore engine
Provides image scanning, compliance rules, and automated CI/CD pipeline checks.
Each tool fits differently in a DevOps pipeline, depending on the team’s requirements and infrastructure.
How container security patterns work in Docker and Kubernetes
We have covered individual concepts, such as non-root users, secrets, and read-only file systems. Now, let’s see how they look combined in a real-world scenario.
1. The secure docker file
The following Dockerfile uses a minimal base, creates a specific user, and ensures no root processes are used.
# 1. Use a specific versionFROM python:3.11# 2. Create a non-root user and group immediatelyRUN addgroup -S appgroup && adduser -S appuser -G appgroupWORKDIR /app# 3. Copy only the necessary filesCOPY requirements.txt .# 4. Pin dependencies to specific versionsRUN pip install --no-cache-dir -r requirements.txtCOPY . .# 5. Switch to the non-root userUSER appuser# 6. Run the applicationCMD ["python", "app.py"]
2. The secure kubernetes deployment
This manifest enforces the read-only filesystem rule. Remember when you make a container read-only, the app can no longer write to disk. If your app needs to write temporary files (like logs or cache), you must mount a temporary volume, as shown below.
apiVersion: apps/v1kind: Deploymentmetadata:name: secure-appspec:template:spec:securityContext:# Ensure the Pod cannot run as root user at the cluster levelrunAsNonRoot: truerunAsUser: 1000fsGroup: 2000containers:- name: my-secure-appimage: my-app:latestports:- containerPort: 8080# Inject secrets securely (never plain text)env:- name: DB_PASSWORDvalueFrom:secretKeyRef:name: db-secretkey: passwordsecurityContext:# Prevent writing to the container's file systemreadOnlyRootFilesystem: true# Prevent the container from gaining more privileges (Escalation)allowPrivilegeEscalation: falsecapabilities:drop: ["ALL"] # Drop all Linux capabilities, add back only if needed# Fix for Read-Only Filesystem:# Since the root is read-only, we mount a volume for /tmp# so the app can still write temporary files if needed.volumeMounts:- mountPath: /tmpname: tmp-volumevolumes:- name: tmp-volumeemptyDir: {}
By combining these files, you ensure that:
- The image is small and scanned.
- The container runs as a restricted user.
- Secrets are injected dynamically.
- Even if hacked, the attacker cannot write files to the system (Read-Only) or install system packages (Dropped Capabilities).
Best practices for securing containers
Here are the essential practices every team should adopt:
- Use minimal base images to reduce vulnerabilities
- Scan images on every PR or pipeline run
- Keep Docker, Kubernetes, and base images up to date
- Avoid running containers as root
- Enforce network policies for Pod communication
Following these practices ensures that security is integrated into every stage of the container lifecycle.
Conclusion
Container security is a continuous process that covers several aspects, including image creation, secret handling, runtime behavior, and ongoing monitoring. By ensuring proper image hygiene, securely storing secrets, implementing runtime controls, and performing constant scanning, we can establish a robust and resilient security foundation for both Docker and Kubernetes environments.
By applying these techniques consistently, teams improve reliability, reduce operational risk, and ensure production workloads remain safe and predictable. To deepen your understanding and strengthen your container skills further, explore our related learning paths:
- Working With Containers: Introduction to Kubernetes
- Working With Containers: Introduction to Docker
- Introduction to DevOps
Frequently asked questions
1. What is container security?
Container security ensures that applications running inside containers remain protected from vulnerabilities, misconfigurations, and runtime threats across their entire lifecycle.
2. How do you secure containers?
We secure containers by scanning images, using minimal and trusted base images, managing secrets correctly, enforcing runtime restrictions, and monitoring activity with security tools.
3. Which tool is used for container security?
Popular tools include Trivy, Aqua, Anchore, Falco, and Clair. Each tool focuses on different stages such as scanning, runtime defense, or compliance.
4. How can runtime security tools detect threats in real time?
Runtime security tools observe system calls, file access patterns, and unexpected processes to identify malicious behavior instantly.
5. How to implement container security?
Start by securing the image, managing secrets correctly, enforcing least privilege at runtime, using network policies, scanning regularly, and monitoring container actions.
6. What are the goals of container security?
The goals include preventing vulnerabilities, protecting sensitive data, avoiding unauthorized access, reducing attack surface, and maintaining compliance.
'The Codecademy Team, composed of experienced educators and tech experts, is dedicated to making tech skills accessible to all. We empower learners worldwide with expert-reviewed content that develops and enhances the technical skills needed to advance and succeed in their careers.'
Meet the full teamRelated articles
- Article
What is Kubernetes
Learn Kubernetes, its key features, architecture, and why it's essential for scalability and automation. - Article
Docker VS Kubernetes
Explore the essential roles Docker and Kubernetes play in modern application deployment. - Article
What is a Docker Container - A Complete Guide
Learn what Docker files, images, and containers are and how to create them.
Learn more on Codecademy
- Explore DevSecOps for containers: Learn virtualization, containerization, Kubernetes, Docker, DevSecOps and containers, Containers security challenges, API microgateways, and how to build modular container images.
- Intermediate.1 hour
- Components of container security
- How to secure container images effectively
- How to manage secrets securely in docker and kubernetes
- How to implement runtime protection for containers?
- Types of tools for container security
- How container security patterns work in Docker and Kubernetes
- Best practices for securing containers
- Conclusion
- Frequently asked questions