NethermindEth / nethermind

A robust execution client for Ethereum node operators.
https://nethermind.io/nethermind-client
GNU General Public License v3.0
1.19k stars 401 forks source link

Towards deterministic builds. #886

Open MicahZoltu opened 4 years ago

MicahZoltu commented 4 years ago

In the docker images, instead of pointing at something like https://github.com/NethermindEth/nethermind/blob/383df00694f3ffd884a4d277977521f06efe9d10/Dockerfile#L1 change it to point at something like:

# <digest> is `microsoft/dotnet:2.2-sdk`
FROM microsoft/dotnet@<digest> AS build

This would ensure that anyone who wanted to rebuild the exact Dockerfile to ensure nothing sneaking was included could do so. As it is now, such a user would need to try every published version of the particular base image until they found the one that resulted in a matching layer.

spetz commented 4 years ago

I do understand your point, yet I think that it's easier to rely on tags, assuming that e.g. 2.2 version is always stable and does not introduce any breaking changes. By doing so, you always have up to date image (containing the latest patches etc.) and I can't really think about something "sneaking" that would cause the application to break or so - that would mean that dotnet image was not tested correctly and should not be published at all.

MicahZoltu commented 4 years ago

Sorry, the "something sneaky" is a malicious actor introducing a vulnerability into the dotnet:2.2-sdk build pipeline or into the Nethermind build pipeline.


By using a digest, upgrades to base images are always intentional, and you'll never end up in a situation where an attacker can compromise the dotnet build pipeline and then trigger an official nethermind build (or just time the attack to coincide with nethermind builds). Instead, the attacker would need to compromise the dotnet:2.2-sdk build pipeline and then convince the nethermind team to update the digest, which is significantly more complicated.

While this may be a relatively unlikely attack vector, it is one that is trivially addressed by using digests instead of tags, and in a space where people are dealing with large amounts of money, small changes that don't have a negative impact on usability can be worth it.

Note: There is value in Nethermind regularly updating the dotnet digest to latest, I just believe that these should be intentional events, not something that happens automatically without no human input as part of CI.


The other reason to use digests is that it allows a third party auditor to easily verify the CI builds. Once verified, they can assert to everyone "this build of Nethermind checks out, I verified the hash against a build I ran locally and it matches". With no digest, the auditor cannot easiely validate that the image contains what Nethermind team says it contains, so all users have to implicitly trust Nethermind to not do anything "sneaky". Something "sneaky" here would be to say that you are building with Dockerfile x, but in reality build with Dockerfile y which contains some backdoor code.

tkstanczak commented 4 years ago

I tend to agree due to the very nature of the systems that we deal with. Probably better to set everything in stone.

tkstanczak commented 4 years ago

@spetz could we change the docker images to be predictable and to have verifiable digests?

kamilchodola commented 1 month ago

@matilote Is there still something we should do here?