The move to containerized workloads has proven to be a revolutionary step in the evolution of software engineering and distributed systems. One of the most prominent container software providers, Docker, is a common fixture in most modern engineering organizations. However, with new, disruptive technology comes new security risks and considerations.
Is your engineering organization taking the necessary steps to secure your Docker environments? This article will lay out a checklist of Docker security best practices, starting with the development phase, continuing on to deployment, and finally the runtime environment.
Make It Painless for Developers to Engage
It might be strange to start a list of technical guidelines with a non-technical piece of advice, but making it as painless as possible for development teams to engage security should be a paramount priority. Early security involvement on projects can save time and pain spent on refactoring and hasty patching. Developers are more likely to engage security if it’s an easy, intuitive process.
Only Use Trusted Image Sources
Ideally, InfoSec and DevOps teams should be partnering to offer an internal, persistently audited and monitored internal image repository. That may not always be possible, so the next best option is to utilize “Official Images” provided by Docker Hub. These images come from verified sources, exemplify best practices for Dockerfiles, and offer publicly available security scans. Unknown or unverified image sources should almost always be avoided.
Ensure Base Images Utilize Minimal Configuration
The more packages, modules, libraries, services, and daemons a host runs, the more vulnerable it is to compromise. “Minimizing attack surface” is one of the guiding principles of information security, and Docker containers are no different. Docker configuration best practice is to choose base images with the bare-minimum collection of packages and features needed to successfully support your application.
Static Analysis Tools Exist—Use Them!
Even though your image sources might be trusted, that doesn’t mean they aren’t susceptible to newer vulnerabilities that might escape first-pass detection. OWASP provides a handy cheat sheet for Docker security, including a list of free and commercial static analysis tools.
Avoid Depending on Security Anti-Patterns
Docker-based applications should not depend on security anti-patterns to function correctly. Docker containers should not require things like host root access, elevating privilege, or disabling protections like SELinux. If planned software features require any of these, it might be good to talk through the design with your development teams to see if there are alternatives.
The code has been written, and an MVP is ready to deploy. The deployment phase offers a great opportunity to utilize automation and testing to augment your Docker security posture with another layer of protection. Engage DevOps teams to help configure automatic CI/CD testing and hooks to enable detection of potential security problems before they are deployed.
Utilize a Policy Engine
Open Policy Agent provides a powerful and flexible “policy engine,” essentially acting as an automated, declaratively defined arbiter of security and configuration policy. Combined with their conftest module, you can automatically enforce policy against static configuration files like Dockerfiles. Configure a pre-commit hook with OPA and conftest enforce policy on Docker configuration before it’s committed.
No Hard-Coded Secrets
Sensitive values like AWS credentials and SSH keys should never be hard-coded into configuration or code. These files are usually plaintext, and often committed to version control. Committed secrets often require time-consuming, difficult secret rotation. A tool like gitleaks or trufflehog can help detect secrets that have been committed or might potentially be.
The application is live, serving customer traffic. Your Docker runtimes are likely exposed to the internet, and with this comes a whole new source of potential security compromises. Static analysis and configuration scanning can capture some of the low-hanging fruit in terms of vulnerabilities, but most attacks happen in runtime. It is critical to ensure your application is protected from these attacks.
Enforce POLP Access
Principle of least privilege (POLP) is a common information security methodology, essentially stating that only a minimal number of users or services should be granted the minimum level of access needed to successfully carry out their intended function. You can apply POLP in multiple contexts when it comes to Docker runtimes in production:
- Limit the number of users who can access or make changes to a live environment.
- Restrict Docker containers to the bare minimum of host privileges and capabilities needed to operate correctly.
- Limit access to the Docker daemon to only a minimum set of trusted users.
- If you expose the Docker daemon REST API via TCP, enforce HTTPS and limit access to only trusted networks.
Alert on Configuration Changes
The configuration of any production system should be monitored for even slight deltas. Any change should generate an obvious alert that attributes directly back to the originating host. Modern, container-based architecture utilizes Docker containers as an immutable build artifact. Configuration changes should be populated via deployments, originating from your CI/CD system, not ad-hoc changes to individual systems.
Protect the Host
With the emphasis on container security, sometimes the security of the underlying host itself falls by the wayside. The standard playbook for securing critical hosts, particularly web-facing infrastructure, still applies. Some high-level must-haves:
- Limit network access to the hosts. Firewalls should separate a private network for host-to-host communication from any WAN.
- Disable interactive users. With auto-scaling, configuration management, and centralized logging, there should be limited need for any user access.
- If user access is required, implement security bastion hosts.
- Utilize immutable infrastructure to ensure new, up-to-date OS images are consistently deployed or patch the OS regularly.
Active Runtime Protection at All Times
Modern runtime environments are complex. They present multiple attack vectors, and often mixed workloads. The goal of any pragmatic security approach is to minimize attack surface. Ultimately, even the best security is not a guarantee against an attack, making comprehensive, active runtime protection all the more essential.
In a modern, cloud-focused engineering organization, security can provide a robust ecosystem of tools and documentation to DevOps and development teams, enabling them to own the pre-runtime security objectives. To secure the runtime itself and detect actual breaches when they occur, security teams should implement a Cloud Workload Protection Platform (CWPP) like Intezer Protect, which is specifically engineered for end-to-end cloud workload runtime protection.
Logs provide a record of everything going on in an application, host, container, or daemon. Production Docker environments should be logging—at a minimum—the security and application events from the Docker containers themselves, the Docker daemon, and the host nodes as well. These logs should be aggregated and stored in a central location, where they can be parameterized and analyzed. While security logs can be monitored for real-time anomaly detection, their primary value is in post-incident investigation.
It would be easy—and unfortunately totally unrealistic—to think that implementing the guidelines discussed in this article would be the end of your worries about securing your Docker application runtime. Effective security requires a pragmatic, vigilant, persistent approach. Armed with the information in this article, engineering teams can apply effective, holistic security methods and measures to their Docker runtime environment.