Conversation
You can pass a map of filename -> data to nsinit.Exec() and the files will be created in the container, without being stored to disk outside the container. Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
This adds support for private files, i.e. files in /run/private/* that
are only visible in the container and are not stored outside them. For
example you can do something like:
docker run --private-file api.key:/secret/key image
Which will upload the contents of the local /secret/key and create a
file called /run/private/api.key in the container with that contents.
You can also place a file called /etc/docker/private.d/api.key on
the machine running the docker daemon to achieve the same thing.
Private files also work for docker start and docker build, and
previous private keys are inherited on docker restart.
Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
|
Docs? |
|
Yeah, docs are obviously missing. |
|
/cc @ktintc |
|
@alexlarsson Okay. Docs are never a waste of time IMHO. :P But understand. I am personally a +0. I think making docker cp bi-directional would resolve this use case for me but I understand the desire. |
|
Why does this functionality have to be specific to private files? Instead, if you just created a generic "--add" argument that had the same semantics as the Dockerfile ADD but just allows you to add files on run, that could be used for this also. You'd just do "--add my.key:/run/private/". |
|
@jamtur01 docker cp wouldn't really work for most of the usecases here, as it inherently works on the copy-on-write parts of the docker container. I.e. the part that will be commited to an image. It never lets you copy from e.g. a volume or a tmpfs like /run. So, its generally no different from just having the file in the base image, i.e. all private data will be leaked with the image. Additionally, even if you could copy a file into a tmpfs like /run, that would only be for the instance of /run for the cp, and it will be gone the next time you start the container, which means this would not be useful in e.g. a Dockerfile where each line is a new container. @ibuildthecloud I've intentionally tried to limit the capabilities for this because it doesn't really match with the desire to make docker build fully repeatable and host independent. This is by design of course, the goal is of course to only let you build if you have the right key, etc. However, we want to avoid this being misused for other things. Also, the way the code works (holding data in memory, encoding it, etc) makes it not really work well for e.g. large files. |
|
You do not want all third party containers running on your host get access to those private files. So I think it is not a good idea to put the private files from |
|
@djmaze Well, if you want container specific files you can just just --add-private-files, and ignore |
|
@alexlarsson From what I gather the private files is not persisted in the container *.json config files so you have to do How bad would it be to just persist the data in the json config files? Basically only root can see those files, if you're root on the box you can get to the data in the container /run/private anyhow. |
|
@ibuildthecloud Well, it wouldn't be hard to persist it, in fact it would be easier code-wise than what the current code is doing. However, how bad would it be from a security/risk perspective? Thats really hard to say, as it depends on all sorts of details. I just erred on the side of caution. If we add it to the config file the main difference is a) its a bit easier to get at when you're root, and b) its possible to get the secrets from non-running containers, and the advantage is that you can start a container that dies without knowing the secret. Is it worth it? I don't really know. |
|
@alexlarsson If you don't persist it then I think there needs to be something that would prevent restarting a container that was previously launched with The only security issue I can think of if you persist it it is that the contents of the private files is accessible through the API which may be accessible by non-root. Maybe you just don't return the contents in a |
|
I agree with @ibuildthecloud that runconfig will cause containers to fail to restart cleanly. Also, I'd like to remind @alexlarsson that security doesn't come from "it might be more secure, I'll err on the side of caution". Security comes from actually being secure, and keeping a file path secret isn't security at all. runconfig in my opinion complicates the code base while providing no security benefit at all. In fact, it makes security worse: The key is held in a file owned by root, presumably a file that is labeled with SELinux to be accessible only to docker. If you store the path to the key in the docker config(also labeled by SELinux as belonging to docker and docker alone) then the information about where the secret file is is confined to the same security context as the secret itself(the docker security context). However, if the user has to type in the path to the file using |
|
@timthelion Its not the path, its the actual data, which may have been uploaded from another host (and thus not exist anywhere else on the host but inside the tmpfs of the container). |
|
That said, if you're root on the host you can still nsenter the container and extract the data from the tmpfs, so its not technically safer there. The main real difference is whether the secret data is fully gone when the container exits, or not. |
|
It seems to me, that it would be more useful and flexible to: A) make volumes work at build time. and B) use a wrapper script to create and destroy the tempfs |
|
@timthelion volumes at buildtime was nak:ed by @shykes due to not wanting host-dependent builds. This pr is the direct result of that, as for these usecases we conceptually need to be somewhat host-dependent, but we try to do it in a minimal way. |
|
Hmph, I don't see this re-branding of volumes to be any less host-dependent.... When you think about it from RedHat's point of view, it doesn't make much sense to keep the product key secret while allowing the product itself to be easily copied. So why not keep the key in the image ;) It just occurred to me that a generally useful command would be
For example, if your build requires You've just build your program with the linux headers, but these headers are not stored in the final image, thus bloat is reduced.
For example to install proprietary redhat software into your image without adding your rhel key to the final image you can do: |
|
@timthelion The |
|
@djmaze you're right that the |
|
@djmaze Yes, it is just a temporary ADD... |
|
@djmaze actually there is a good use case in which the file should not be deleted. Compare the disk usage of the following two snippets(given that and ;) |
|
Though admittedly if WITHFILE did always delete the file after the command was run one could also do: |
|
@timthelion Finally I get what you imagined. You want WITHFILE to automatically remove the file after the last line in the Dockerfile has been eval'd, right? I do not think this fits the syntax you are proposing. That should rather be called ADD_TEMPORARY (or similar) and stand on its own line in the Dockerfile, just like ADD. |
|
No, WITHFILE will should add the file and run the command BEFORE saving a layer. If we removed the file after the last line in the docker file then the file would still be there, just marked as removed in the COW(Copy on write) file system. |
|
@djmaze If the docker binary weighs 20 megabytes and we |
|
@djmaze in the case of the private key files, we never want them to be written into a layer at all, so that they stay private. Which is why WITHFILE is useful for that case as well. |
|
Persisting the private files in the docker config would be nice because it would allow restarts, especially in the context of maintenance because the operator restarting docker and its container will most like not be able to restore the missing private files. Having said that, I see it would also be nice that in the current approach if you were to use the API to start a container theoretically the private files will never be persisted to disk. For the extra paranoid that could be a nice feature. What if we could do both, for example Side note, I ran this PR before and I swear the arguments were actually reversed so that its |
|
@ibuildthecloud This is a huge amount of added complexity for a very narrow use case. And completely unnecessary, because the same functionality can be implemented more simply. Image 6 months from now when everyone will be coming across the I am not the maintainer, but if I was, I'd never let this through. |
|
@timthelion I think everyone has understood your point of view. |
|
@unclejack I don't think that makes my critique less helpful. I'm not just ranting I'm making specific critiques and I'm trying to find solutions as well. Perhaps renaming |
|
The Run in RunConfig means "per-Run", as the HostConfig means "per-Host" config and "Config" is global Config. Its possible that a better name can be found, in particular since the package is named runconfig this becomes a bit confusing. RuntimeConfig? |
There was a problem hiding this comment.
So that ParseRunConfig() can read it
|
So what's the conclusion then? Are we saying that if you use |
|
@alexlarsson Are you sure you don't want to flip the syntax to be |
|
@ibuildthecloud Really, this feature is meant for short term tasks like software installation. If you need the file to be in the container permanently and you need it to survive docker daemon restarts than this isn't the feature for you. |
|
According to https://gist.github.com/alexlarsson/c8e3277d2678c1061319 this is not necessarily just short term build operations. For example, I may need an x509 client cert to communicate to some HTTPS service. If we are limiting the scope of this to short term build operations, then I'd remove |
|
Long discussion at todays meeting lead to a slightly different design. I will re-do this with the new approach. |
|
I made a new PR for the new approach to get a fresh start on the discussions: |
|
closing this in favour of #6075 |
This implements the private files proposal from:
https://gist.github.com/alexlarsson/c8e3277d2678c1061319
Private files are files stored in
/run/privatein the container. That is a tmpfs that is only visible in the container and the private files are never stored outside the container. For example you can do something like:Which will upload the contents of the local /secret/key and create a file called /run/private/api.key in the container with that contents.
You can also place a file called
/etc/docker/private.d/api.keyon the machine running the docker daemon to achieve the same thing. This is very useful for host-specific private file, like product entitlements.Private files also work for docker start and docker build, and previous private keys are inherited on docker restart.