-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not re-tag non-distributable blob descriptors #2561
Conversation
1aa279e
to
e531f69
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if one blob has URLs and another access of same blob does not. I guess the same issue is with the mediatype as well. Current combinations avoid ambiguity by setting the correct mediatype from compression+oci/docker exporter options. Would you be ok with making this exporter option as well? Either just a bool or a more advanced variant would be to set the URL prefixes.
Is it correct that this does not affect the pusher? These blobs would still be pushed to the registry atm.
Could you expand more on your concerns and what the exporter option is for?
Correct, this only changes the data we use to create new manifests, does not affect the behavior of pusher. |
So for example there is one build that accesses blob So one way to solve it would be with a similar opt-in like I see in that containerd PR. There could of course be more complicated cases with 2 blobs with different sets of URLs or cases where user wants only some blobs to be non-distributable but at least it should not break the default case for anyone. Another way would be to namespace these cases to separate refs on disk. That's somewhat tricky probably as current equality checks are digest-based. |
I see. |
No, there is no such concept as "base/from image" in llb and there can't be. Buildkit only tracks chains of snapshot-blob pairs. |
@tonistiigi Thinking about this, this seems like an advanced use case which is already unsupported anyway and requires manually updating the manifest. re: the containerd pr |
This seems like "not immediately on fire" form of "What if we get two unrelated blobs with the same hash?". In the latter case, if we don't prevent this then you end up feeding a watermelon into Perhaps they should catch fire immediately? When pulling a blob into the content store, is it possible to recognise a "same hash, different content type" conflict and fail there? (This might be a containerd-level problem to solve, on reflection). For the use-cases of the non-distributable layers, I don't think there's any expectation that there will be the same objects floating around with different media types? If someone changes the mediatype and uploads it somewhere else (or unpacks it and repacks it via tooling), that's almost certainly in violation of whatever distribution restrictions are applicable. |
Yeah I don't really see a good way to deal with the problem of different metadata (mediatype, urls) for the same blob other than build it on a different machine or clear the cache. |
38dee8d
to
e521b63
Compare
We look the contents when creating new blobs to see if they match the expected mediatype. Eg. if user exports image and requests zstd we look what is in the disk. If it is zstd then it is used, if it is uncompressed then it gets compressed. If it is gzip then we decompress and compress again. This was mainly added for estargz that uses the same mediatype as gzip but we need to understand if a blob is already stargz or not and we need to look the disk for that. Theoretically, I'm not against doing some basic validation on pull as well. If the mediatype is gzip but blob isn't actually gzip I think it is fair to just error right away. For the other components of mediatype than compression, they don't stick with the blob. Eg. if you pulled with docker mediatypes it doesn't mean you export with them as well. You export with the types that user set on |
a990713
to
c9ab798
Compare
Per our discussion, I've updated the PR: This still always stores the original media type and urls (and always appends urls if new ones are found) in buildkit's cache. |
c9ab798
to
38ae30b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer if GetRemotes()
already returned the descriptor that is guaranteed to be either only distributable(default) or foreign if URLs exist. It means need to pass more arguments but atm none of the callers can make assumptions about the result, so they all need to try to convert mediatypes and clear the URLs. That is more duplicated code and eventually one of these callers will forget to run these cleanup routines.
In the future same should be done for the oci vs. docker mediatypes as well, but that is old code and can be fixed later.
If you can, would be good to also get an integration test for it as well that tests that URLs are kept if opt-in and discarded otherwise. You can just push a small public image with a URL and add it to the mirrored image list in the beginning of integration tests. A more complicated way would be to make manifest manually and push it to the local registry but that probably gets too complex. |
Shouldn't the
Shouldn't it use the appropriate non-distributable layer type ( |
No buildkit user has accepted any license terms from the pulled image.
I think this is already happening. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall SGTM. Mostly comments about names and package structure. Still hoping for tests.
|
||
import "github.com/moby/buildkit/util/compression" | ||
|
||
type RefConfig struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a use case that required a separate packages for this definition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import cycle from cache->solver->cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let's figure this out later. It's more about what the dependency between solver and cache pkg should be.
@@ -46,7 +48,7 @@ type ImmutableRef interface { | |||
Finalize(context.Context) error | |||
|
|||
Extract(ctx context.Context, s session.Group) error // +progress | |||
GetRemotes(ctx context.Context, createIfNeeded bool, compressionopt compression.Config, all bool, s session.Group) ([]*solver.Remote, error) | |||
GetRemotes(ctx context.Context, createIfNeeded bool, cfg config.RefConfig, all bool, s session.Group) ([]*solver.Remote, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe functional options?
83ce5c6
to
c3ef527
Compare
Before this change buildkit was changing the media type for non-distributable layers to normal layers. It was also clearing out the urls to get those blobs. Now the layer mediatype and URL's are preserved. If a layer blob is seen more than once, if it has extra URL's they will be appended to the stored value. On export there is now a new exporter option to preserve the non-distributable data values. All URL's seen by buildkit will be added to the exported content. Signed-off-by: Brian Goff <[email protected]>
This just makes sure the logic for the layer conversion is all in one place and settable by a common option. Signed-off-by: Brian Goff <[email protected]>
Signed-off-by: Brian Goff <[email protected]>
Signed-off-by: Brian Goff <[email protected]>
c3ef527
to
fb9c022
Compare
Green CI, also added the new integration tests. |
You need a license to pull the image, as described at, e.g., https://hub.docker.com/_/microsoft-windows-nanoserver. You could probably try and haggle over the meaning of "use" here, but if none of BuildKit's activities are part of "using the image", then there's no license grant for that, so it becomes less allowed. At the very least, I have used |
What you are describing here is basically equivalent of me pushing something to foobar.com and then going to the maintainers of |
Foreign layers are only kept as foreign at this point if the user requested it to be. Since foreign layers are not meant to be pushed, automatically skip those layers. Signed-off-by: Brian Goff <[email protected]>
fb9c022
to
c332148
Compare
Your characterising is if if I was saying Buildkit is failing the license. I meant "you" in the generic sense, i.e. "one", not you, @tonistiigi, the author of BuildKit. Sorry if that wasn't clear. If I download the thing you put on foobar.com, and I wasn't allowed to by the license, then by doing so I've broken the license. Not curl or the authors of curl. It's very possible I don't notice I've done that, as there's no indication within HTTP that this has happened. If there was a flag or something built into HTTP that told me I wasn't licensed to download that file, then I think curl would be remiss as a HTTP client implementation if the default was "Ignore that flag", any more than it would be remiss if the default was "accept expired TLS certificates". Being able to override either is quite reasonable, as in both cases, I am saying "I know what I'm doing". In this case, the only flag available for OCI registries that says "You are not allowed to download this" is authentication, and so MS have gone with a permissive approach "We assume you are licensed to download this" rather than a restrictive approach "You must log in and prove you are permitted to download this", which I think was the correct choice. However, there is a specific flag in this ecosystem for "You're not allowed to upload this", so I would apply the same logic that tooling is remiss to ignore the flag. So I would argue:
Anyway, the OCI spec is pretty clear, that irrespective of the specific legal details:
and automatically changing the media type to ignore this specification term doesn't really seem to fit the spirit of the spec. |
I tend to agree with @TBBle. |
I noticed the release note
suggests that presence or absence of URLs is being used to determine if a layer is non-distributable, and a quick check of the PR's changes to cache/refs.go confirms this. (And I note that the reason why is given there, and was also touched upon above). That's inconsistent with the OCI Image spec directions on this topic:
A use-case for this behaviour is that the non-distributable layer may not have a URL entry because it's not a publicly-usable base layer, so it's only expected to be referenced in images pushed to the same registry that already holds that layer. An example of this would be the layer in a CI image that contains an MS Visual Studio installation; last year a whole bunch of public images were noticed to be pushing such a layer to public Docker Hub images, where the license for MS VS Build Tools does not allow this, but allowed pushing to private images for use by other members of the same licensee, e.g., company-internal registries. It would be reasonable (but not currently tool-supported, I think) to mark the layers containing the non-distributable content as non-distributable; and specify that internal developers building containers that need to use those tools must base it on the existing image, rather than rolling their own, to support/ensure license compliance. (In the specific case of MS VS Build Tools, I've suggested that MS could make this less-painful, but have not had any useful response). The mentioned edge case where some descriptor for a given layer includes URLs, and some other descriptor doesn't, and both are marked non-distributable also hits this point. I've never seen this use-case in the wild, but it's not the sort of use-case I'd expect to see often in-the-wild anyway, as it'd be of more value in closed, controlled environments than on public container registries. And lack of tooling support (MS uses a custom tool to roll their Windows base container images) means it's not going to be a common sight either. So I think future work on this area should address this situation. I still think the best solution is to not lose the content type of a layer at any point during the process, and fail pulls where a blob's content type does not match what's in the store already, with an explicit matrix of "known-compatible content types" to override this. But I recognise that's not necessarily a trivial change. |
How common this case isn't really relevant for this case. Eg. we could say that it isn't very common that an image will try to attack the user system. 99.99% of images don't do that, so why implement a security sandbox at all? The possibility that someone builds an image and unexpectedly gets a broken image that can't be pulled or contains leaked information from other registries that were not part of this build at all is just something that can't happen. Even if it happens only one time or seems theoretical, it would be a bug that needs to be fixed.
iiuc this was true before and after this PR.
One of the differences to me is that buildkit is a tool for building new images. It is not a tool for manipulating existing manifests or moving existing manifests between different storage. All the manifests it creates are 100% new. So when the user is putting together a manifest that points to |
Creating a new image that contains existing layers does not change the type or content of those layers, even when the resulting image is new. That's a pretty fundamental piece of the OCI ecosystem, since it allows As far as I know, BuildKit doesn't yet support tagging new layers as non-distributable, so for this discussion, we're only talking about pre-existing layers pulled from elsewhere. |
Before this change buildkit was changing the media type for
non-distributable layers to normal layers.
It was also clearing out the urls to get those blobs.
This keeps those layers as non-distributable and stores the urls so we can
keep those values when building the new manifest.
Fixes part of #2555
As a note, I don't have a full understanding of the internals here.
I got to this point pretty much by spraying some changes in and seeing what gave me the desired output.