|
| 1 | +# 🔐 Securing our image |
| 2 | + |
| 3 | +In the last section, we created a container image. But, did we create a _good_ container image? |
| 4 | + |
| 5 | +## What defines a good image? |
| 6 | + |
| 7 | +The definition for a good image will vary by team, organization, and company. But, most will agree that the following criteria apply: |
| 8 | + |
| 9 | +- **Minimal vulnerabilities.** Ideally, there will be _no_ critical or high vulnerabilities. Others are kept to a minimum. |
| 10 | +- **Trusted image sources.** The base images (those specified in the `FROM` statement) are trusted and authorized base images |
| 11 | +- **Non-root users by default.** When a container starts, is it going to run as a non-root user? Doing so helps minimize issues if a compromise occurs. |
| 12 | +- **Open-source license issues.** When using open-source libraries, the associated licenses can sometimes cause complications when used in enterprise settings. Keeping track of these is important. |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | +## 🔍 Analyzing our image |
| 17 | + |
| 18 | +With Docker Scout, we can easily analyze our image using the policies specified by organization. |
| 19 | + |
| 20 | +1. If you are part of an organization, run the following command, replacing "ORGANIZATION' with the name of your org: |
| 21 | + |
| 22 | + ```bash |
| 23 | + docker scout config organization ORGANIZATION |
| 24 | + ``` |
| 25 | + |
| 26 | +2. Use `docker scout quickview` to perform a quick analysis of your container image: |
| 27 | + |
| 28 | + ```bash |
| 29 | + docker scout quickview $DOCKER_USERNAME/memes-r-us |
| 30 | + ``` |
| 31 | + |
| 32 | + In the analysis procedure, you should see indications that the SBOM and provenance were "found", meaning they were attached to the image. |
| 33 | + |
| 34 | + If you have an organization configured, you're likely to see output similar to the following: |
| 35 | +
|
| 36 | + ```plaintext |
| 37 | + Policy status FAILED (6/7 policies met) |
| 38 | +
|
| 39 | + Status │ Policy │ Results |
| 40 | + ─────────┼─────────────────────────────────────────────┼────────────────────────────── |
| 41 | + ! │ No default non-root user found │ |
| 42 | + ✓ │ No AGPL v3 licenses │ 0 packages |
| 43 | + ✓ │ No fixable critical or high vulnerabilities │ 0C 0H 0M 0L |
| 44 | + ✓ │ No high-profile vulnerabilities │ 0C 0H 0M 0L |
| 45 | + ✓ │ No outdated base images │ |
| 46 | + ✓ │ No unapproved base images │ 0 deviations |
| 47 | + ✓ │ Supply chain attestations │ 0 deviations |
| 48 | + ``` |
| 49 | +
|
| 50 | + This is highlighting that we do not have a non-root user by default. Let's fix that! |
| 51 | + |
| 52 | +3. In your `Dockerfile`, add the following before the `EXPOSE` statement: |
| 53 | + |
| 54 | + ```dockerfile |
| 55 | + RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser |
| 56 | + USER appuser |
| 57 | + ``` |
| 58 | + |
| 59 | +4. Perform a new build using the following command: |
| 60 | + |
| 61 | + ```bash |
| 62 | + docker build -t $DOCKER_USERNAME/memes-r-us:updated --sbom=true --provenance=mode=max --load . |
| 63 | + ``` |
| 64 | + |
| 65 | +5. Perform an analysis of the newly built image: |
| 66 | + |
| 67 | + ```bash |
| 68 | + docker scout quickview $DOCKER_USERNAME/memes-r-us:updated |
| 69 | + ``` |
| 70 | + |
| 71 | + The output should now show: |
| 72 | + |
| 73 | + ```plaintext |
| 74 | + Policy status SUCCESS (7/7 policies met) |
| 75 | + ``` |
| 76 | + |
| 77 | + Hooray! 🎉 |
| 78 | + |
| 79 | + |
| 80 | + |
| 81 | +## 🔐 Docker Hardened Images |
| 82 | + |
| 83 | +While our image is now compliant, we still run the risk of new vulnerabilities being discovered. How can we remediate them as quickly as possible? And can we use base images that are slimmer to further reduce that risk? |
| 84 | + |
| 85 | +Docker Hardened Images provide near-zero CVE base images that help produce up to 95% smaller images and come with enterprise-grade SLAs for rapid remediation. |
| 86 | + |
| 87 | +Fortunately, migrating to them isn't that difficult! |
| 88 | +
|
| 89 | +One adjustment is that the "prod" version of an image doesn't include the tools required to install packages and other dependencies. Therefore, we need to use a multi-stage approach. |
| 90 | + |
| 91 | +Our previous Dockerfile, after being migrated, will look like this: |
| 92 | + |
| 93 | +```dockerfile |
| 94 | +# === Build stage: Install dependencies === |
| 95 | +FROM docker/dhi-node:24-alpine3.22-dev AS builder |
| 96 | +
|
| 97 | +WORKDIR /usr/local/app |
| 98 | +COPY package*.json ./ |
| 99 | +RUN npm ci --production |
| 100 | +
|
| 101 | +# === Runtime stage: Minimal image === |
| 102 | +FROM docker/dhi-node:24-alpine3.22 |
| 103 | +
|
| 104 | +WORKDIR /usr/local/app |
| 105 | +ENV NODE_ENV=production |
| 106 | +
|
| 107 | +COPY --from=builder /usr/local/app/node_modules ./node_modules |
| 108 | +COPY src/ ./src/ |
| 109 | +EXPOSE 3000 |
| 110 | +CMD ["src/index.js"] |
| 111 | +``` |
| 112 | + |
| 113 | +## 🐳 Docker Recap |
| 114 | + |
| 115 | +Let's take a step back and focus on what we learned. |
| 116 | +
|
| 117 | +- **Docker makes image analysis easy with Scout.** With Scout, developers have the tools required to analysis container images, identify issues, and receive guidance on how to fix the issues they are facing. |
| 118 | +- **Docker Hardened Images provide enterprise-grade base images.** With Docker Hardened Images, enterprises can ensure they are building their images from solid foundations. |
0 commit comments