{"id":3301,"date":"2026-01-25T18:00:20","date_gmt":"2026-01-25T18:00:20","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/01\/25\/making-the-most-of-your-docker-hardened-images-enterprise-trial-part-3\/"},"modified":"2026-01-25T18:00:20","modified_gmt":"2026-01-25T18:00:20","slug":"making-the-most-of-your-docker-hardened-images-enterprise-trial-part-3","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/01\/25\/making-the-most-of-your-docker-hardened-images-enterprise-trial-part-3\/","title":{"rendered":"Making the Most of Your Docker Hardened Images Enterprise Trial \u2013 Part 3"},"content":{"rendered":"<h2 class=\"wp-block-heading\">Customizing Docker Hardened Images<\/h2>\n<p>In <a href=\"https:\/\/www.docker.com\/blog\/making-the-most-of-your-docker-hardened-images-trial-part-1\/\">Part 1<\/a> and <a href=\"https:\/\/www.docker.com\/blog\/making-the-most-of-your-docker-hardened-images-enterprise-trial-part-2\/\">Part 2<\/a>, we established the baseline. You migrated a service to a <a href=\"https:\/\/docs.docker.com\/dhi\/\" rel=\"nofollow noopener\" target=\"_blank\">Docker Hardened Image (DHI)<\/a>, witnessed the vulnerability count drop to zero, and verified the cryptographic signatures and <a href=\"https:\/\/docs.docker.com\/dhi\/core-concepts\/slsa\/\" rel=\"nofollow noopener\" target=\"_blank\">SLSA provenance<\/a> that make DHI a compliant foundation.<\/p>\n<p>But no matter how secure a base image is, it is useless if you can\u2019t run your application on it. This brings us to the most common question engineers ask during a DHI trial: <em>what if I need a custom image?<\/em><\/p>\n<p>Hardened images are minimal by design. They lack package managers (apt, apk, yum), utilities (wget, curl), and even shells like bash or sh. This is a security feature: if a bad actor breaks into your container, they find an empty toolbox.<\/p>\n<p>However, developers often need these tools during setup. You might need to install a monitoring agent, a custom CA certificate, or a specific library.<\/p>\n<p>In this final part of our series, we will cover the two strategies for customizing DHI: the Docker Hub UI (for platform teams creating \u201cGolden Images\u201d) and the multi-stage build pattern (for developers building applications).<\/p>\n<h3 class=\"wp-block-heading\">Option 1: The Golden Image (Docker Hub UI)<\/h3>\n<p>If you are a Platform or DevOps Engineer, your goal is likely to provide a \u201cblessed\u201d base image for your internal teams. For example, you might want a standard Node.js image that <em>always<\/em> includes your corporate root CA certificate and your security logging agent.The <a href=\"https:\/\/docs.docker.com\/dhi\/how-to\/customize\/\" rel=\"nofollow noopener\" target=\"_blank\">Docker Hub UI<\/a> is the preferred path for this. The strongest argument for using the Hub UI is maintenance automation.<\/p>\n<h3 class=\"wp-block-heading\">The Killer Feature: Automatic Rebuilds<\/h3>\n<p>When you customize an image via the UI, Docker understands the relationship between your custom layers and the hardened base. If Docker releases a patch for the underlying DHI base image (e.g., a fix in glibc or openssl), Docker Hub automatically rebuilds your custom image.<\/p>\n<p>You don\u2019t need to trigger a CI pipeline. You don\u2019t need to monitor CVE feeds. The platform handles the patching and rebuilding, ensuring your \u201cGolden Image\u201d is always compliant with the latest security standards.<\/p>\n<h3 class=\"wp-block-heading\">How It Works<\/h3>\n<p>Since you have an Organization setup for this trial, you can explore this directly in Docker Hub.First, navigate to <strong>Repositories<\/strong> in your organization dashboard. Locate the image you want to customize (e.g., dhi-node), then the Customizations tab and click the \u201cCreate customization\u201d action. This initiates a customization workflow as follows:<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=1873999967  fetchpriority=\"high\" decoding=\"async\" width=\"1594\" height=\"1106\" src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/01\/Screenshot-2026-01-23-at-23.09.16.png\" class=\"fade-in attachment-full size-full\" alt=\"Screenshot 2026 01 23 at 23.09.16\" title=\"- Screenshot 2026 01 23 at 23.09.16\" \/>\n        <\/div>\n<p>In the \u201cAdd packages\u201d section, you can search for and select OS packages directly from the distribution\u2019s repository. For example, here we are adding bash to the image for debugging purposes. You can also add \u201cOCI Artifacts\u201d to inject custom files like certificates or agents.<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=134368480  fetchpriority=\"high\" decoding=\"async\" width=\"1596\" height=\"1096\" src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/01\/Screenshot-2026-01-23-at-23.09.48.png\" class=\"fade-in attachment-full size-full\" alt=\"Screenshot 2026 01 23 at 23.09.48\" title=\"- Screenshot 2026 01 23 at 23.09.48\" \/>\n        <\/div>\n<p>Finally, configure the runtime settings (User, Environment Variables) and review your build. Docker Hub will verify the configuration and queue the build. Once complete, this image will be available in your organization\u2019s private registry and will automatically rebuild whenever the base DHI image is updated.<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=1398169113  data-opt-src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/01\/Screenshot-2026-01-23-at-23.09.30.png\"  decoding=\"async\" width=\"1596\" height=\"1080\" src=\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20100%%20100%%22%20width%3D%22100%%22%20height%3D%22100%%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22100%%22%20height%3D%22100%%22%20fill%3D%22transparent%22%2F%3E%3C%2Fsvg%3E\" class=\"fade-in attachment-full size-full\" alt=\"Screenshot 2026 01 23 at 23.09.30\" title=\"- Screenshot 2026 01 23 at 23.09.30\" \/>\n        <\/div>\n<p>This option is best suited for creating standardized \u201cgolden\u201d base images that are used across the entire organization. The primary advantage is <strong>zero-maintenance security patching<\/strong> due to automatic rebuilds by Docker Hub. However, it is less flexible for rapid, application-specific iteration by individual development teams.<\/p>\n<h2 class=\"wp-block-heading\">Option 2: Multi-Stage Build<\/h2>\n<p>If you are an developper, you likely define your environment in a Dockerfile that lives alongside your code. You need flexibility, and you need it to work locally on your machine.<\/p>\n<p>Since DHI images don\u2019t have apt-get or curl, you cannot simply RUN apt-get install my-lib in your Dockerfile. It will fail.<\/p>\n<p>Instead, we use the multi-stage build pattern. The concept is simple:<\/p>\n<ol class=\"wp-block-list\">\n<li>Stage 1 (Builder): Use a standard \u201cfat\u201d image (like debian:bookworm-slim) to download, compile, and prepare your dependencies.<\/li>\n<li>Stage 2 (Runtime): Copy <em>only<\/em> the resulting artifacts into the pristine DHI base.<\/li>\n<\/ol>\n<p>This keeps your final image minimal, non-root, and secure, while still allowing you to install whatever you need.<\/p>\n<h3 class=\"wp-block-heading\">Hands-on Tutorial: Adding a Monitoring Agent<\/h3>\n<p>Let\u2019s try this locally. We will simulate a common real-world scenario: adding the Datadog APM library (dd-trace) globally to a Node.js DHI image.<\/p>\n<h4 class=\"wp-block-heading\">1. Setup<\/h4>\n<p>Create a new directory for this test and add a simple server.js file. This script attempts to load the dd-trace library to verify our installation.<\/p>\n<p>app\/server.js<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\n\/\/ Simple Express server to demonstrate DHI customization\nconsole.log('Node.js version:', process.version);\ntry {\n  require('dd-trace');\n  console.log('dd-trace module loaded successfully!');\n} catch (e) {\n  console.error('Failed to load dd-trace:', e.message);\n  process.exit(1);\n}\nconsole.log('Running as UID:', process.getuid(), 'GID:', process.getgid());\nconsole.log('DHI customization test successful!');\n\n<\/pre>\n<\/div>\n<h4 class=\"wp-block-heading\">2. Hardened Dockerfile<\/h4>\n<p>Now, create the Dockerfile. We will use a standard Debian image to install the library, and then copy it to our DHI Node.js image. Create a new directory for this test and add a simple server.js file. This script attempts to load the dd-trace library to verify our installation.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\n# Stage 1: Builder - a standard Debian Slim image that has apt, curl, and full shell access.\nFROM debian:bookworm-slim AS builder\n\n\n# Install Node.js (matching our target version) and tools\nRUN apt-get update &amp;amp;&amp;amp; \n    apt-get install -y curl &amp;amp;&amp;amp; \n    curl -fsSL https:\/\/deb.nodesource.com\/setup_24.x | bash - &amp;amp;&amp;amp; \n    apt-get install -y nodejs\n\n\n# Install Datadog APM agent globally (we force the install prefix to \/usr\/local so we know exactly where files go)\nRUN npm config set prefix \/usr\/local &amp;amp;&amp;amp; \n    npm install -g dd-trace@5.0.0\n\n\n# Stage 2: Runtime - we switch to the Docker Hardened Image.\nFROM &amp;lt;your-org-namespace&amp;gt;\/dhi-node:24.11-debian13-fips\n\n\n# Copy only the required library from the builder stage\nCOPY --from=builder \/usr\/local\/lib\/node_modules\/dd-trace \/usr\/local\/lib\/node_modules\/dd-trace\n\n\n# Environment Configuration\n# DHI images are strict. We must explicitly tell Node where to find global modules.\nENV NODE_PATH=\/usr\/local\/lib\/node_modules\n\n\n# Copy application code\nCOPY app\/ \/app\/\n\n\nWORKDIR \/app\n\n\n# DHI Best Practice: Use the exec form ([\"node\", ...]) \n# because there is no shell to process strings.\nCMD [\"node\", \"server.js\"]\n\n<\/pre>\n<\/div>\n<h4 class=\"wp-block-heading\">3. Build and Run<\/h4>\n<p>Build the custom image:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\ndocker build -t dhi-monitoring-test .\n<\/pre>\n<\/div>\n<p>Now run it. If successful, the container should start, find the library, and exit cleanly.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\ndocker run --rm dhi-monitoring-test\n<\/pre>\n<\/div>\n<p>Output:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\nNode.js version: v24.11.0\ndd-trace module loaded successfully!\nRunning as UID: 1000 GID: 1000\nDHI customization test successful!\n\n<\/pre>\n<\/div>\n<p>Success! We have a working application with a custom global library, running on a hardened, non-root base.<\/p>\n<h2 class=\"wp-block-heading\">Security Check<\/h2>\n<p>We successfully customized the image. But did we compromise its security?<\/p>\n<p>This is the most critical lesson of operationalizing DHI: hardened base images protect the OS, but they do not protect you from the code you add.Let\u2019s verify our new image with <a href=\"https:\/\/docs.docker.com\/scout\/\" rel=\"nofollow noopener\" target=\"_blank\">Docker Scout<\/a>.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\ndocker scout cves dhi-monitoring-test --only-severity critical,high\n<\/pre>\n<\/div>\n<p>Sample Output:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\n    \u2717 Detected 1 vulnerable package with 1 vulnerability\n...\n   0C     1H     0M     0L  lodash.pick 4.4.0           \npkg:npm\/lodash.pick@4.4.0                               \n                                                        \n    \u2717 HIGH CVE-2020-8203 [Improperly Controlled Modification of Object Prototype Attributes]\n\n<\/pre>\n<\/div>\n<p>This result is accurate and important. The base image (OS, OpenSSL, Node.js runtime) is still secure. However, the dd-trace library we just installed pulled in a dependency (lodash.pick) that contains a High severity vulnerability.<\/p>\n<p>This proves that your verification pipeline works.<\/p>\n<p>If we hadn\u2019t scanned the <em>custom<\/em> image, we might have assumed we were safe because we used a \u201cHardened Image.\u201d By using Docker Scout on the final artifact, we caught a supply chain vulnerability introduced by <em>our<\/em> customization.<\/p>\n<p>Let\u2019s check how much \u201cbloat\u201d we added compared to the clean base.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\">\ndocker scout compare --to &amp;lt;your-org-namespace&amp;gt;\/dhi-node:24.11-debian13-fips dhi-monitoring-test\n\n<\/pre>\n<\/div>\n<p>You will see that the only added size corresponds to the dd-trace library (~5MB) and our application code. We didn\u2019t accidentally inherit apt, curl, or the build caches from the builder stage. The attack surface remains minimized.<\/p>\n<h2 class=\"wp-block-heading\">A Note on Provenance: Who Signs What?<\/h2>\n<p>In Part 2, we verified the SLSA Provenance and cryptographic signatures of Docker Hardened Images. This is crucial for establishing a trusted supply chain. When you customize an image, the question of who \u201cowns\u201d the signature becomes important.<\/p>\n<ol class=\"wp-block-list\">\n<li><strong>Docker Hub UI Customization<\/strong>: When you customize an image through the Docker Hub UI, Docker itself acts as the builder for your custom image. This means the resulting customized image inherits signed provenance and attestations directly from Docker\u2019s build infrastructure. If the base DHI receives a security patch, Docker automatically rebuilds and re-signs your custom image, ensuring continuous trust. This is a significant advantage for platform teams creating \u201cgolden images.\u201d<\/li>\n<\/ol>\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Local Dockerfile<\/strong>: When you build a custom image using a multi-stage Dockerfile locally (as we did in our tutorial), <em>you<\/em> are the builder. Your docker build command produces a <em>new<\/em> image with a <em>new<\/em> digest. Consequently, the original DHI signature from Docker does not apply to your final custom image (because the bits have changed and you are the new builder).<br \/>However, the chain of trust is not entirely broken:<\/li>\n<\/ol>\n<ul class=\"wp-block-list\">\n<li>Base Layers: The underlying DHI layers within your custom image still retain their original Docker attestations.<\/li>\n<li>Custom Layer: Your organization is now the \u201cbuilder\u201d of the new layers.<\/li>\n<\/ul>\n<p>For production deployments using the multi-stage build, you should integrate <a href=\"https:\/\/docs.docker.com\/dhi\/how-to\/verify\/#verify-signatures-with-cosign\" rel=\"nofollow noopener\" target=\"_blank\">Cosign<\/a> or <a href=\"https:\/\/docs.docker.com\/engine\/security\/trust\/\" rel=\"nofollow noopener\" target=\"_blank\">Docker Content Trust<\/a> into your CI\/CD pipeline to sign your custom images. This closes the loop, allowing you to enforce policies like: <em>\u201cOnly run images built by MyOrg, which are based on verified DHI images and have our internal signature.\u201d<\/em><\/p>\n<h2 class=\"wp-block-heading\">Measuring Your ROI: Questions for Your Team<\/h2>\n<p>As you conclude your Docker Hardened Images trial, it\u2019s critical to quantify the value for your organization. Reflect on the concrete results from your migration and customization efforts using these questions:<\/p>\n<ul class=\"wp-block-list\">\n<li><strong>Vulnerability Reduction<\/strong>: How significantly did DHI impact your CVE counts? Compare the \u201cbefore and after\u201d vulnerability reports for your migrated services. What is the estimated security risk reduction?<\/li>\n<li><strong>Engineering Effort:<\/strong> What was the actual engineering effort required to migrate an image to DHI? Consider the time saved on patching, vulnerability triage, and security reviews compared to managing traditional base images.<\/li>\n<li><strong>Workflow<\/strong>: How well does DHI integrate into your team\u2019s existing development and CI\/CD workflows? Do developers find the customization patterns (Golden Image \/ Builder Pattern) practical and efficient? Is your team likely to adopt this long-term?<\/li>\n<\/ul>\n<p><strong>Compliance &amp; Audit<\/strong>: Has DHI simplified your compliance reporting or audit processes due to its SLSA provenance and FIPS compliance? What is the impact on your regulatory burden?<\/p>\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n<p>Thanks for following through to the end! Over this 3-part blog series, you have moved from a simple trial to a fully operational workflow:<\/p>\n<ol class=\"wp-block-list\">\n<li><strong>Migration<\/strong>: You replaced a standard base image with DHI and saw immediate vulnerability reduction.<\/li>\n<li><strong>Verification<\/strong>: You independently validated signatures, FIPS compliance, and SBOMs.<\/li>\n<li><strong>Customization<\/strong>: You learned to extend DHI using the Hub UI (for auto-patching) or multi-stage builds, while checking for new vulnerabilities introduced by your own dependencies.<\/li>\n<\/ol>\n<p>The lesson here is that the \u201cHardened\u201d in Docker Hardened Images isn\u2019t a magic shield but a clean foundation. By building on top of it, you ensure that your team spends time securing <em>your<\/em> application code, rather than fighting a never-ending battle against thousands of upstream vulnerabilities.<\/p>","protected":false},"excerpt":{"rendered":"<p>Customizing Docker Hardened Images In Part 1 and Part 2, we established the baseline. You migrated a service to a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3302,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-3301","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/3301","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=3301"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/3301\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/3302"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=3301"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=3301"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=3301"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}