Securing Docker Containers: A Practical Primer for DevOps Engineers

Docker

YOUR COSMETIC CARE STARTS HERE

Find the Best Cosmetic Hospitals

Trusted • Curated • Easy

Looking for the right place for a cosmetic procedure? Explore top cosmetic hospitals in one place and choose with confidence.

“Small steps lead to big changes — today is a perfect day to begin.”

Explore Cosmetic Hospitals Compare hospitals, services & options quickly.

✓ Shortlist providers • ✓ Review options • ✓ Take the next step with confidence

Containerization has made it faster and easier to ship software, but speed and security are not automatic companions. Whether you are running a handful of microservices or a large Kubernetes fleet, Docker containers introduce their own attack surface that must be managed deliberately. The good news is that most of the foundational controls are well-understood and straightforward to implement.

This article summarizes the core security practices every DevOps engineer should apply when working with Docker containers, regardless of the orchestration layer on top.

1. Treat the Container Like a Real Machine

A common misconception is that process isolation inside a container implies security. Isolation reduces the blast radius of a compromise, but it is not a security boundary on its own. Apply the same hardening principles you would to any server:

  • Run as a non-root user. Add a USER instruction in your Dockerfile to drop privileges before the application starts. Running as root inside a container can translate to root on the host if container breakout occurs.
  • Apply the principle of least privilege. Use Linux namespaces and cgroups to restrict what processes can see and consume. Docker exposes these through flags such as --cap-drop and --cap-add.
  • Avoid world-writable directories and files. Audit filesystem permissions inside your images just as you would on a production server.
  • Use read-only filesystems where possible. The --read-only flag prevents processes inside the container from writing to the container filesystem, limiting persistence opportunities for attackers.
# Example: non-root user in a Dockerfile
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
COPY --chown=appuser:appgroup . /app
WORKDIR /app
CMD ["node", "server.js"]Code language: PHP (php)

2. Only Use Images from Trusted Sources

Pulling a public image is convenient, but you are trusting everything the image author chose to include. Malicious or misconfigured layers can introduce backdoors, outdated vulnerable packages, or unexpected binaries.

Practical guidelines:

  • Prefer official or verified images. Docker Hub marks images as “Docker Official Images” or “Verified Publisher.” These go through additional review and automated scanning.
  • Enable Docker Content Trust (DCT). Setting the environment variable DOCKER_CONTENT_TRUST=1 instructs the Docker client to only pull images that carry a valid cryptographic signature from the image publisher. This protects against tampered images in transit.
  • Host a private registry. For production workloads, mirror approved base images in a private registry (such as AWS ECR, Google Artifact Registry, or a self-hosted Harbor instance) and restrict developers to pulling from there.
  • Scan images for vulnerabilities. Integrate a scanner such as Trivy, Grype, or Snyk into your CI pipeline to catch known CVEs before images reach production.
# Enable Docker Content Trust for the current shell session
export DOCKER_CONTENT_TRUST=1
docker pull myrepo/myimage:latest  # will fail if image is unsignedCode language: PHP (php)

Note on Docker Hub: A security incident disclosed at DockerCon 2019 affected approximately 190,000 Docker Hub accounts, serving as a reminder that no hosted registry should be trusted without additional controls. Content trust and private mirrors add meaningful defence-in-depth.

3. Use Docker Bench for Security

Docker Bench for Security is an open-source shell script maintained by the Docker team. It audits your Docker host and running containers against the CIS Docker Benchmark—a community standard covering daemon configuration, image hygiene, container runtime settings, and more.

Running it is straightforward:

# Run Docker Bench for Security using Docker itself
docker run --rm --net host --pid host --userns host --cap-add audit_control \
  -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
  -v /etc:/etc:ro \
  -v /usr/bin/containerd:/usr/bin/containerd:ro \
  -v /usr/bin/runc:/usr/bin/runc:ro \
  -v /usr/lib/systemd:/usr/lib/systemd:ro \
  -v /var/lib:/var/lib:ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  --label docker_bench_security \
  docker/docker-bench-securityCode language: PHP (php)

Each check is rated as PASS, WARN, or INFO. You can pipe the output into your CI system to fail a build when critical warnings appear, making security checks a first-class part of your delivery pipeline. The repository is available at github.com/docker/docker-bench-security.

4. Limit Direct Access to Kubernetes Nodes

When Docker containers are orchestrated by Kubernetes, the security perimeter extends to the nodes themselves. Unrestricted SSH access to nodes is one of the most common and dangerous misconfigurations in Kubernetes clusters.

  • Restrict SSH access. Limit node SSH access to a very small group of platform administrators. Where cloud-provider tooling allows, remove direct SSH access entirely and use systems like AWS Systems Manager Session Manager or GCP OS Login.
  • Use kubectl exec for debugging. Developers who need to inspect or debug a running container should use kubectl exec rather than accessing the underlying node. This gives them a shell inside the container namespace without host-level access.
  • Enforce IAM and RBAC policies. Define Kubernetes RBAC roles that grant only the permissions required for each team or service account. Avoid binding the cluster-admin role to user-facing accounts.
# Open a shell in a running pod without touching the node
kubectl exec -it <pod-name> -n <namespace> -- /bin/shCode language: PHP (php)

5. Isolate Workloads Using Kubernetes Namespaces and Policies

A compromised workload in a flat Kubernetes cluster can potentially reach every other workload. Namespaces and policy controls reduce this lateral movement risk.

  • Use namespaces to segment workloads. Group related services into dedicated namespaces (e.g., payments, auth, logging) rather than leaving everything in default.
  • Apply ResourceQuotas and LimitRanges. Namespaced resource quotas prevent a compromised or runaway container from consuming all cluster resources and affecting other tenants.
  • Use Kubernetes RBAC authorization. Kubernetes’ built-in authorization plugin allows you to create fine-grained policies defining which users or service accounts can perform which actions on which resources, scoped to specific namespaces.
  • Consider Pod Security Admission or OPA/Gatekeeper. Policy admission controllers let you enforce security standards (e.g., no privileged containers, no host network access) at the cluster level, before workloads are scheduled.

6. Protect the Network

Network controls are the last line of defence if a container is compromised. Even well-hardened containers should not be able to freely communicate with every other service in the cluster.

  • Apply Kubernetes NetworkPolicies. NetworkPolicy resources define ingress and egress rules at the pod level. By default, Kubernetes allows all pod-to-pod communication; adding a default-deny NetworkPolicy and then allowlisting only the required connections significantly limits lateral movement.
  • Use Ingress controllers to control external access. Define Ingress resources to explicitly declare which services are reachable via HTTP/HTTPS from outside the cluster, rather than exposing services directly with NodePort or LoadBalancer types.
  • Consider a service mesh for mTLS. Tools like Istio or Linkerd can enforce mutual TLS between services automatically, ensuring that service-to-service traffic is encrypted and authenticated even within the cluster.
  • Audit exposed ports. Review every container’s EXPOSE instruction and every Kubernetes Service definition. Eliminate any port that is not required for the service to function.
# Example: default-deny NetworkPolicy for a namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: payments
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - EgressCode language: PHP (php)

7. Keep Images and Dependencies Up to Date

Container images are point-in-time snapshots. An image built six months ago almost certainly contains packages with known CVEs by the time it reaches production, or shortly after. Treat image freshness as an ongoing operational concern:

  • Rebuild base images on a regular schedule, not just when application code changes.
  • Use minimal base images (e.g., alpine or distroless) to reduce the number of packages that need patching.
  • Integrate vulnerability scanning (Trivy, Grype, Snyk) into both CI and as a recurring registry scan so you are notified when new CVEs affect images already in production.

Summary: Docker Security Checklist

AreaKey Action
Runtime privilegesRun as non-root; drop unnecessary Linux capabilities
Image provenanceEnable Docker Content Trust; use verified or private registries
Benchmark complianceRun Docker Bench for Security in CI
Kubernetes accessRemove direct node SSH; use kubectl exec and RBAC
Workload isolationUse namespaces, ResourceQuotas, and admission policies
Network segmentationApply NetworkPolicies; restrict Ingress; consider mTLS
Image currencyRebuild images regularly; scan for CVEs continuously

Containers are powerful tools, but isolation is not invincibility. Each layer of your stack—image build, registry, runtime, orchestrator, and network—introduces its own risks and its own mitigations. Applying the controls above will meaningfully reduce your attack surface and make incidents easier to contain when they do occur.

Original article concept sourced from containerjournal.com. Expanded and updated for accuracy by the BestDevOps editorial team.

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x