Container Security Best Practices
Containerization continues to transform how modern organizations build, deploy, and manage applications. But rushing to implement it—without understanding the foundational principles or container security best practices—can expose critical vulnerabilities. Whether you’re wondering what it means to dockerize something or assessing how container isolation is achieved, these five security anti-patterns serve as cautionary lessons from the field.
1. Misunderstanding Container Isolation and Trust Boundaries
Many teams mistakenly believe that containerization provides full system isolation by default. In reality, container isolation relies on namespace separation, cgroups, and kernel-level security features—not absolute sandboxing. All containers on a host share the same kernel, which can expose the system to container escape attacks if misconfigured.
For those exploring what it means to dockerize something, it’s crucial to understand that dockerizing an app doesn’t automatically secure it. The isolation model requires tuning, policy enforcement, and regular auditing.
Best Practices:
- Run Docker containers as non-root wherever possible to improve isolation.
- Use user namespaces and mandatory access controls like AppArmor or SELinux.
- Implement tainted nodes and strict pod security policies.
2. Security Tools Sprawl
The abundance of container security tools is a double-edged sword. While tools for image scanning, runtime detection, and policy enforcement are valuable, indiscriminately stacking them can introduce more vulnerabilities and complexity.
Some tools even require privileged access, undermining your container isolation setup. Instead of relying on a sprawling mix, invest in lean, effective tooling that integrates with your existing CI/CD workflows.
Best Practices:
- Use automated policy enforcement rather than manual checks.
- Limit to essential, well-supported container security platforms.
- Monitor how each tool impacts isolation and runtime behavior.
3. Service Mesh Without Observability = Blind Spots
Mutual TLS and service meshes are effective at securing in-cluster communications—a “must-have” for any production-grade Docker container strategy. However, they can introduce observability blind spots, especially when encryption hides malicious lateral movement.
For teams building out their service mesh stack, it’s vital to implement decryption-aware observability solutions that respect security and maintain visibility.
Best Practices:
- Ensure that must-have Docker containers used in observability pipelines don’t introduce additional risk.
- Deploy traffic analysis tools compatible with service mesh architecture.
- Use root CA certificates in observability containers with scoped access.
4. Relying on Minimal Base Images Without Supply Chain Assurance
Small, purpose-built base images like Alpine or Distroless are often marketed as must-have Docker containers for their lightweight design and minimal attack surface. However, if their provenance is unclear or they lack active maintenance, these images may introduce outdated libraries, vulnerabilities—or worse, embedded malware.
Containerization isn’t just about making things small. It’s about ensuring that what you deploy is trustworthy.
Best Practices:
- Validate SBOMs (Software Bills of Materials) and monitor upstream changes.
- Always verify and scan your base images.
- Maintain a curated internal registry of vetted base containers.
5. Baking Secrets Into Containers
Hardcoding secrets into containers—or even into environment variables—is a critical anti-pattern. It defeats the purpose of container isolation by making sensitive information trivially accessible to anyone with image access or basic tooling.
If you’re trying to understand what dockerizing something entails, know this: dockerizing is not just about packaging your app—it’s about preparing it for secure, repeatable, and ephemeral use. Embedding secrets violates that principle entirely.
Best Practices:
- Implement automated scanning to detect embedded credentials before deployment.
- Use Kubernetes secrets or integrate with external secrets managers.
- Prevent access to secrets at build time using
.dockerignore.
So—What Does It Mean to Dockerize Something?
To dockerize an application means packaging the app, its runtime, libraries, and environment settings into a Docker container so it can run consistently across environments. But dockerizing doesn’t stop at “it works on my machine.” True dockerization includes:
- Setting secure defaults
- Minimizing dependencies
- Respecting container isolation boundaries
- Following best practices for image layering, secrets management, and network controls
Containerization done well increases agility and resilience. Done poorly, it becomes a liability.
Baking Secrets Into Containers
Obviously, we all want a site to be ‘https’ (secured with TLS) instead of ‘http’ (unencrypted) and have authentication for the APIs a containerized piece of software is exchanging data with. However, baking these API keys, certificates and other secrets directly into the software container is a really bad idea! It is pretty easy to inspect containers and also copy files into and out of them when they are running (or as a disk image using certain docker or podman commands).
Secrets should remain that – secret. When uploading to a registry, all of the files in that container can be accessed or inspected by downloading the container. What that means is the secrets that are hosted in the container can simply be taken out. Secrets should be stored in specific tools that are made for this purpose, and storing these secrets as “secrets objects” in Kubernetes is not secure by default either. Storing secrets in etcd without encryption is even worse. Researchers in Germany recently discovered that tens of thousands of publicly available containers are leaking authentication credentials, API Keys, certificates, and other types of secrets. According to these German researchers that’s almost 10% of all containers hosted in public registries! Think about all of the SaaS providers your organization may use. Do you know if they use containers that are leaking secrets that could lead to your data being stolen or compromised? How about your internal environment? Do you provide such services? If client data is stolen, there can be massive liability.
I hope this gave you a good overview of some of the practices we have seen that can actually hamper the security of a containerized environment, while internal teams might think they are “doing all the right things”. I can’t provide a prescriptive solution for all of these anti-patterns. The goal of this article is to help you understand the consequences, both positive and negative when managing a containerized workload or workloads. You need to perform a risk and benefit analysis of all of your practices and which tools (and how many) are appropriate for your situation. Oteemo’s general guidance is:
- Run containers as non-root users inside the container.
- Run Docker (or any container runtime) as a non-root user on the host.
- Run Docker (or any other container runtime) without SYSCAP privileges if possible. Add specific privileges only when absolutely necessary.
- Use a service mesh and node taints to isolate containers requiring root access and/or SYSCAP privileges to specific, specialized “privileged” nodes where possible. This does not imply trust, just limiting attack surfaces and isolating damage.
- Patch the hosts kernel frequently (Control plane and worker nodes).
- Separate data by tainting nodes and enforcing data boundaries.
- Use a service mesh to enforce mTLS but make sure to enable observability and monitoring so YOU can decrypt and inspect the traffic.
- Balance using “small” images with good supply chain management. Amazon Linux 2 containers have become my personal favorite. Reasonably sized, updated, and very clean vulnerability scans. It maintains binary compatibility with RHEL and CentOS. For Debian based specific purpose containers consider Google Distroless.
- Choose your security tools carefully. Unless you need a specific function from a new tool that covers a compliance or serious capability gap, try to limit runtime security tools to one or at most two.
- Scan containers for vulnerabilities and malware prior to uploading to an internal registry or deploying. Re-scan containers while they are running in the cluster regularly. Amazon Inspector, if in AWS, is a really useful cloud based service to scan containers in ECR.
- Run containers, and all systems and services, internally except with specific exceptions for content you are intentionally trying to serve publicly. A new campaign has been launched which brings this to a head. A threat actor, TeamTNT, is attacking publicly exposed services to steal credentials, deploy malware, install cryptominers, etc. https://www.darkreading.com/cloud/aws-cloud-credential-stealing-campaign-spreads-azure-google
- Enable observability and logging for all workloads in the cluster including system logs.
- Use containers that have updated applications and libraries. Rebase if necessary to upgrade or remove things like root or use a trusted partner, like Oteemo! We can rebase and host upstream or internally developed containers.
- Use a CNI that enforces network policies AND configure them appropriately for your environment.
Final Thoughts: How Is Container Isolation Achieved?
Container isolation is achieved through a combination of kernel features and runtime configurations—namespaces (for process, user, network), cgroups (for resource limits), seccomp profiles, and container runtime enforcement (e.g., containerd, CRI-O). But isolation is only effective when it’s intentionally configured.
If your teams are dockerizing apps without tuning these features, you’re not truly achieving isolation—you’re just creating illusionary boundaries.











