Docker Container Image Security: 13 Best Practices

 

Transcript:

In this video, we will discuss the best practices for securing Docker container images. How can we reduce the risk of attacks on our Docker container images? The short answer is by reducing the attack surface and time spent on detecting the malicious activity. Yeah, but how to do that? Watch and find out.

Keep your container images lean and boring. The smaller the attack surface in your production image, the better. Therefore, try to minimize the number of components that represent a potentially exploitable path. Depending on your application, consider using a minimalistic Linux distro, a distloress image, or even a scratch. Use multi-stage to transfer the app into a final base image. The final image should contain the immutable set of components required for your application to run. No package manager if possible. A package manager in production kills immutability and widens the attack surface. Attackers can use the package manager to install malicious packages with the vulnerabilities. Therefore, if your use case allows to do so, try to use slimbased images without a package manager. Non route and minimum privileges. Running the container as root or giving it a full set of privileges will give the intruders a host level access to container resources and the ability to exercise kernel attacks. So set the unprivileged user and group in the docker file to run the container. Also, if possible, try to avoid using the privileged flag in production because it gives all Linux kernel capabilities to the container. Instead, limit the granted privileges only to those needed by the container. You can first run cap drop all just to be sure and then add the required privileges with the cap at.

Strive towards immutability when possible. Immutability means that the container must correspond to the container image. It means no config tweaks, uh no changes in the privileges, no patches or fixes in the production. If something changes, you rebuild and redeploy the artifact. The key approach to more secure containers in this regard is to use base images with only the essential set of components required by your application and it should be immutable. Also, there shouldn't be any package manager and uh no privilege escalation. Also, you can use the runtime settings like uh tmpfs or mount to store the data outside the container. You can prevent the privilege escalation at runtime by using the security opt no new privileges option. You can also use the readonly flag to run the container with the readonly file system if it fits your use case. Aim for deterministic container images. Deterministic means that given the same input, the build produces the exact same bites. This way you can detect tempering or dependency change between the build runs. Pin everything to achieve determinism tool chain build system OS version. Also pin the base image by digest not by tag because tags can drift. But the digest always points to the image that you used in the first place.

Use SBOMs. A software bill of materials or an SBOM gives you a list of what's inside your image. Direct and indirect dependencies, their versions, licenses, and so on. SBOMS accelerate CV remediation because you can match a new CVE to the affected image. Generate an SBOMB with every image and store it alongside the image digest. There are several open-source tools for generating sbombs. For instance, sift or cyclonx generator. You can generate an SBOM at the pre-built stage to check the dependency state. But generating an sbomb at the build stage is a must because this way you get the list of exactly what you ship and run.

Integrate provenence. Provenence proves where this image came from by providing the metadata about where, when, and how this image was built. It is metadata that software consumers can verify independently of uh software producers. The important part of provenence is software attestation. You can use cosign for that. So you sign the artifact and the software consumer then verifies the signature and the required station in their CI/CD. Other provenence processes and tools are described in the supply chain levels for software artifacts framework or salsa for short. Drop me a comment if you want a separate video on that. Kow do-it-yourself base images. Quite a few teams build their images on some random base which can be poorly maintained, infected with CVS, lacking SBOMs, and just inviting malicious actors. So opt for a well-maintained regularly updated base image from a trusted vendor. The images should come with an SBOMB and should be easily verified by the check samp for instance instead of uh Alpine Linux with only the community support. You can use alpakita Linux with LTS releases and SLA for patches from bellsoft. Use LTS versions if possible. Consider using base images with LTS software versions. LTS releases are supported for several years. Plus, they have clearly defined security updates policies. For instance, NOJS LTS versions are released every year and receive security patches and critical fixes for 2 and 1/2 years. Java LTS versions are released every 2 years. And the support period depends on the JDK vendor. It varies from 3 years to more than seven years. As for the operating systems, Ubuntu LTS versions are released every two years and receive security patches for 5 years. Alpaquita LTS versions come out every 2 years and receive security patches for 4 years. Update base image regularly. If you don't update the base image, you accumulate nonvulnerabilities and extend the attack surface. Reliable vendors update their images constantly. But when a vendor releases an updated version of their image, your builds won't be updated automatically. So set up automatic uh updates monitoring using tools like dependabot and renovate. This way you can promptly rebuild, rescan and resign the container image.

No secrets in containers. Secrets baked into the image are a serious security risk. Use a dedicated secrets management tools like hash corp worlds, Google secrets manager or kubernetes secrets. You can store your secrets there and then patch them at runtime. Use security scanners. Security scanners are tools that analyze the software environments for security flaws. Scanners vary in purpose. They can scan dependencies, configs, sbombs, container images. They can search for CVS, secrecy, and configs. They can scan the source code for security weaknesses or even monitor the malicious activity. So you can use them at different stages of software development life cycle. You should also define policies for acting upon the scanning results. For instance, you can block or allow the build or deploy, create an additional artifact, perform a manual review and so on. Implement host hardening. Containers share the host kernel. So if the host is vulnerable, everything on it is vulnerable. You can use a dedicated OS for Kubernetes nodes such as Bottle Rock or a minimalistic OS such as Alpakita LTS. The key is that the system must be immutable and without any unnecessary components. Update the kernel on a regular basis plus enable Linux security modules to set the required security policies. Okay, I know this whole info may seem overwhelming. So, if you want to learn more about these approaches, I have written a dedicated article with a more detailed description of each approach and code samples. The link is in the description.

 

Summary

This video shows how to build a complete UI for a Spring Boot application using Vaadin, a Java web framework that provides rich, customizable UI components entirely in Java. The guide walks through creating a login page, a main layout with navigation, and a data grid that supports filtering, lazy loading, and detailed dialogs. It also demonstrates how to build a multi-tab dialog with read-only details and an admin-only edit form using Vaadin Binder for validation and data binding. The video explains how to integrate Spring Security, handle database data from MongoDB, and build responsive layouts. Finally, it shows how to apply a custom cyberpunk theme and encourages exploring Vaadin’s broader capabilities.

About Catherine

Java developer passionate about Spring Boot. Writer. Developer Advocate at BellSoft

Social Media

Videos
card image
Jan 20, 2026
JDBC vs ORM vs jOOQ: Choose the Right Java Database Tool

Still unsure what is the difference between JPA, Hibernate, JDBC, or jOOQ and when to use which? This video clarifies the entire Java database access stack with real, production-oriented examples. We start at the foundation, which is JDBC, a low-level API every other tool eventually relies on for database communication. Then, we go through the ORM concept, JPA as a specification of ORM, Hibernate as the implementation and extension of JPA, and Blaze Persistence as a powerful upgrade to JPA Criteria API. From there, we take a different path with jOOQ: a database-first, SQL-centric approach that provides type-safe queries and catches many SQL errors at compile time instead of runtime. You’ll see when raw JDBC makes sense for small, focused services, when Hibernate fits CRUD-heavy domains, and when jOOQ excels at complex reporting and analytics. We discuss real performance pitfalls such as N+1 queries and lazy loading, and show practical combination strategies like “JPA for CRUD, jOOQ for reports.” The goal is to equip you with clarity so that you can make informed architectural decisions based on domain complexity, query patterns, and long-term maintainability.

Videos
card image
Jan 13, 2026
Hibernate: Ditch or Double Down? When ORM Isn't Enough

Every Java team debates Hibernate at some point: productivity champion or performance liability? Both are right. This video shows you when to rely on Hibernate's ORM magic and when to drop down to SQL. We walk through production scenarios: domain models with many-to-many relations where Hibernate excels, analytical reports with window functions where JDBC dominates, and hybrid architectures that use both in the same Spring Boot codebase. You'll see real code examples: the N+1 query trap that kills performance, complex window functions and anti-joins that Hibernate can't handle, equals/hashCode pitfalls with lazy loading, and practical two-level caching strategies. We also explore how Hibernate works under the hood—translating HQL to database-specific SQL dialects, managing sessions and transactions through JDBC, implementing JPA specifications. The strategic insight: modern applications need both ORM convenience for transactional business logic and SQL precision for data-intensive analytics. Use Hibernate for CRUD and relationship management. Use SQL where ORM abstractions leak or performance demands direct control.

Further watching

Videos
card image
Feb 6, 2026
Backend Developer Roadmap 2026: What You Need to Know

Backend complexity keeps growing, and frameworks can't keep up. In 2026, knowing React or Django isn't enough. You need fundamentals that hold up when systems break, traffic spikes, or your architecture gets rewritten for the third time.I've been building production systems for 15 years. This roadmap covers three areas that separate people who know frameworks from people who can actually architect backend systems: data, architecture, and infrastructure. This is about how to think, not what tools to install.

Videos
card image
Jan 29, 2026
JDBC Connection Pools in Microservices. Why They Break Down (and What to Do Instead)

In this livestream, Catherine is joined by Rogerio Robetti, the founder of Open J Proxy, to discuss why traditional JDBC connection pools break down when teams migrate to microservices, and what is a more efficient and reliable approach to organizing database access with microservice architecture.

Videos
card image
Jan 27, 2026
Sizing JDBC Connection Pools for Real Production Load

Many production outages start with connection pool exhaustion. Your app waits seconds for connections while queries take milliseconds; yet, most teams run default settings that collapse under load. This video shows how to configure connection pools that survive real production traffic: sizing based on database limits and thread counts, setting timeouts that prevent cascading failures, and implementing an open source database proxy Open J Proxy for centralized connection management with virtual connection handles, client-side load balancing, and slow query segregation. For senior Java developers, DevOps engineers, and architects who need database performance that holds under pressure.