Skip to content

Consider updating SHA checks to new SHA files #6495

Closed

Description

@richlander

Was just looking at https://github.com/dotnet/dotnet-docker/blob/d2401d0f2ae676c1dbd0d685ccfe917d2e406674/src/runtime/10.0/alpine3.22/amd64/Dockerfile.

The following now works:

$ curl -O https://builds.dotnet.microsoft.com/dotnet/Runtime/10.0.0-preview.5.25277.114/dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz
$ curl -O https://builds.dotnet.microsoft.com/dotnet/Runtime/10.0.0-preview.5.25277.114/dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz.sha512
$ cat dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz.sha512
716B01559B44320C124459C461DC9BE7A2391B680EC9BA46A22F77A737EB93C4E3323A73B1138DDD1574DCC50934C82ADF7ABE792D6BBD953B8AEA790619941F
$ dotnet_runtime_sha512=$(cat dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz.sha512)
$ echo "$dotnet_runtime_sha512 dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz" | sha512sum -c -
dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz: OK

This approach could significantly simplify the workflow for building .NET images. I always delete the SHA checking lines when I update these Dockerfiles. I am sure others do the same. It would be nice to not need to do so.

AFAIK, this only works for .NET 10, currently.

Activity

  1. lbussell commented on Jun 19, 2025

    @lbussell
    Member

    Amazing!!

    So in combination with Refactor how version numbers are specified after the introduction of installer stages (dotnet/dotnet-docker#6266), our new Dockerfile could look something like this:

    ARG REPO=mcr.microsoft.com/dotnet/runtime-deps
    ARG DOTNET_VERSION=10.0.0-preview.5.25277.114
    
    # Installer image
    FROM $REPO:10.0.0-preview.5-alpine3.22-amd64 AS installer
    ARG DOTNET_VERSION
    
    # Retrieve .NET Runtime
    RUN dotnet-filename=dotnet-runtime-${DOTNET_VERSION}-linux-musl-x64.tar.gz \
        && wget \
            https://builds.dotnet.microsoft.com/dotnet/Runtime/${DOTNET_VERSION}/${dotnet-filename} \
            https://builds.dotnet.microsoft.com/dotnet/Runtime/${DOTNET_VERSION}/${dotnet-filename}.sha512 \
        && sha512sum -c ${dotnet-filename}.sha512 \
        && mkdir -p /dotnet \
        && tar -oxzf ${dotnet-filename} -C /dotnet \
        && rm ${dotnet-filename} ${dotnet-filename}.sha512
    
    
    # .NET runtime image
    FROM $REPO:10.0.0-preview.5-alpine3.22-amd64
    ARG DOTNET_VERSION
    
    # .NET Runtime version
    ENV DOTNET_VERSION=${DOTNET_VERSION}
    
    COPY --from=installer ["/dotnet", "/usr/share/dotnet"]
    
    RUN ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

    However, the content of the .sha512 file is:

    716B01559B44320C124459C461DC9BE7A2391B680EC9BA46A22F77A737EB93C4E3323A73B1138DDD1574DCC50934C82ADF7ABE792D6BBD953B8AEA790619941F
    

    It is missing the file to check. I would expect it to be something like the following, which is what you get when you actually run sha512sum.

    716b01559b44320c124459c461dc9be7a2391b680ec9ba46a22f77a737eb93c4e3323a73b1138ddd1574dcc50934c82adf7abe792d6bbd953b8aea790619941f  dotnet-runtime-10.0.0-preview.5.25277.114-linux-musl-x64.tar.gz
    

    This means we can't actually use the sha512sum command as intended. We'll instead have to do something ugly like:

    # Retrieve .NET Runtime
    RUN wget -O dotnet.tar.gz https://builds.dotnet.microsoft.com/dotnet/Runtime/${DOTNET_VERSION}/dotnet-runtime-${DOTNET_VERSION}-linux-musl-x64.tar.gz \
        && wget -O dotnet.tar.gz.sha512 https://builds.dotnet.microsoft.com/dotnet/Runtime/${DOTNET_VERSION}/dotnet-runtime-${DOTNET_VERSION}-linux-musl-x64.tar.gz.sha512 \
        && echo "$(cat dotnet.tar.gz.sha512)  dotnet.tar.gz" | sha512sum -c - \
        ...

    Note that there is precedent for formatting .sha* files this way. See Chisel's .sha384 files for example: https://github.com/canonical/chisel/releases/tag/v1.1.0

    If this is really the first time that these files have been made public, we should really do this the right way.

  2. lbussell commented on Jun 19, 2025

    @lbussell
    Member

    Here are some examples

    I looked at the formats for those. They're all different.

    It strikes me that we may be able to use the --ignore-missing argument to use the combined checksum file for .NET 8/9. I'll work on a POC for that!

  3. richlander commented on Jun 19, 2025

    @richlander
    MemberAuthor

    Those were just the first three (and only) examples I checked. Yes, all different. I suspect if we did a more comprehensive survey that we'd see similar diversity. I think any option is good as long as we have a good way of describing what to do. I'm happy to see that we're progressing on this.

  4. lbussell commented on Jun 19, 2025

    @lbussell
    Member

    The following works:

    RUN dotnet_filename=dotnet-runtime-${DOTNET_VERSION}-linux-x64.tar.gz \
        && curl --fail --show-error --location --remote-name https://builds.dotnet.microsoft.com/dotnet/Runtime/${DOTNET_VERSION}/${dotnet_filename} \
        && curl --fail --show-error --location --remote-name https://builds.dotnet.microsoft.com/dotnet/checksums/${DOTNET_VERSION}-sha.txt \
        && sha512sum --ignore-missing --check ${DOTNET_VERSION}-sha.txt
  5. richlander commented on Jun 19, 2025

    @richlander
    MemberAuthor

    That looks pretty solid to me. Nice!

  6. mthalman commented on Jun 19, 2025

    @mthalman
    Member

    What is the goal with making this change? By having the SHA value hardcoded in the Dockerfile, it guarantees the integrity of the downloaded file as originally intended from the release. By downloading the SHA as its own file, it opens you up to security issues:

    • If an attacker made their way into the storage account, they could modify the installer file as well as its corresponding SHA file so that they are in sync. The Dockerfile build would think everything is fine.
    • A MITM attack could intercept the downloading of both files to deliver a malicious installer file along with a tampered SHA file.

    Both of these scenarios are mitigated by having a hardcoded SHA value in the Dockerfile.

  7. lbussell commented on Jun 19, 2025

    @lbussell
    Member

    /cc @blowdart on the security questions. I believe Rich has brought this up with him before. Some thoughts I had:

    If an attacker made their way into the storage account...

    This should be prevented by WORM policies in our storage accounts.

    A MITM attack could intercept the downloading of both files to deliver a malicious installer file along with a tampered SHA file.

    Are MITM attacks a significant concern since we are using HTTPS?

    Here are some of the pros for this approach:

    • .NET version is controllable entirely by Dockerfile build arguments. Someone could take our Dockerfiles and build images for any .NET version without changing the Dockerfiles.
    • manifest.versions.json can be greatly simplified since it no longer needs to contain checksums.
    • update-dependencies tooling can be greatly simplified since it no longer needs to fetch/calculate checksums.
    • Dockerfiles have much smaller diffs when changing .NET versions. In the best-case scenario, .NET updates only require updating the default ARG value in the Dockerfiles.

    Overall, I think it would be a big cost savings for maintaining this repo.

  8. blowdart commented on Jun 19, 2025

    @blowdart

    So yes, HTTPS is the mitigation for MITM. You should consider enabling OCSP/CRL checking by default, which is off by default in HttpClient et al as it can introduce failures if you can't reach the revocation servers. You could add an optional parameter to disable the online checks for those weird environments where this might happen.

    I have no real opinion versus hardcoded/downloadable. I leave that as PG rather than a security decision on whether the pros outweigh the cons

    (And go enable WORM on the storage account if it's not already)

  9. richlander commented on Jun 19, 2025

    @richlander
    MemberAuthor

    My take is that hard coding SHAs makes the Dockerfiles unusable for others and makes them less secure as a result. I also don't think of it as an industry best practice. Everyone else does what Logan (and I) is proposing to do. As Logan is suggesting, we're taking on significant cost and complexity for this extra validation.

    For example, if we ever get to a a model where we have a dotnet install command, it will do this same thing.

  10. lbussell commented on Jun 19, 2025

    @lbussell
    Member

    hard coding SHAs makes the Dockerfiles unusable for others and makes them less secure as a result

    +1, when prototyping with the current Dockerfiles the first thing I do is remove the sha checking commands, since it is so inflexible.

  11. self-assigned this
    on Jun 23, 2025
  12. added
    area-dockerfilesConcerns the official .NET Dockerfiles or Dockerfile templates
    and removed on Jun 23, 2025
  13. moved this from Backlog to Sprint in .NET Dockeron Jun 23, 2025
  14. added theissue type on Jun 23, 2025
  15. moved this from Sprint to In Progress in .NET Dockeron Jun 23, 2025
  16. richlander commented on Jun 27, 2025

    @richlander
    MemberAuthor

    We should do a writeup on this once we're done, both to explain/describe the change and to encourage DIY users to adopt it (and why).

  17. lbussell commented on Jul 15, 2025

    @lbussell
    Member

    As of Preview 6, .NET 10 Dockerfiles use the new format:

    # Retrieve .NET Runtime
    RUN dotnet_version=10.0.0-preview.6.25358.103 \
    && curl --fail --show-error --location \
    --remote-name https://builds.dotnet.microsoft.com/dotnet/Runtime/$dotnet_version/dotnet-runtime-$dotnet_version-linux-x64.tar.gz \
    --remote-name https://builds.dotnet.microsoft.com/dotnet/Runtime/$dotnet_version/dotnet-runtime-$dotnet_version-linux-x64.tar.gz.sha512 \
    && sha512sum -c dotnet-runtime-$dotnet_version-linux-x64.tar.gz.sha512 \

    Fixed with #6521

  18. moved this from In Progress to Done in .NET Dockeron Jul 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area-dockerfilesConcerns the official .NET Dockerfiles or Dockerfile templates

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions