It is sometimes necessary to have files in a container that shouldn't ever end up in an image. These files are generally some form of private key or password that aren't allowed to be distributed. This document details a few usecases for such files and their requirements.
Not all package content is freely accessible on the network. For instance, using yum to download RHEL packages require that you provide x509 certificates and private keys to prove that you are entitled to download a particular product. In general such entitlements are tied to the computer running the program, and needs to somehow be transferred from the host to the container so that the yum instance in the container can access it.
In practice how this works is that a base image sets up a yum
repository configuration file, /etc/yum.repos.d/my-corp.repo
:
[my-corp-rpms]
name = Internal only RPMs for mycorp
baseurl = https://cdn.mycorp.com/content/rpms/
enabled = 1
gpgcheck = 1
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mycom
sslverify = 1
sslcacert = /etc/secret/mycom-ca.pem
sslclientkey = /etc/secret/mycom-private-key.key
sslclientcert = /etc/secret/mycom-cert.crt
In this example we have 3 secret files: the ca root, and the private key/certificate pair. They are typically tied to the machine that will execute the container (at least that is how e.g. RHEL licenses work), and are should ideally to be supplied to all containers running on that machine automatically.
A container, like e.g. a continuous integration mechanism, might need to access e.g. a git repository that is not publicly available. To authenticate to this container it would need to supply a ssh private key.
This involves a file like $HOME/.ssh/id_rsa
being available in the
container. Generally this key is tied either to the user starting the
container, or it is tied to the specific container instance. That
means the file is read either from the user's home directory, or is
manually specified when starting the container instance.
Many web services require API keys that identify a particular user. A container that uses such an api should ideally not ship the key with the container, as that makes distributing the image problematic. It is much better to ship the image without the key and then apply the specific key (e.g. you might have a different key for testing) when starting the container.
The private files can't be put in a base image, and in order avoid accidentally getting committed into an image they should not be stored in the normal container filesystem. They should instead work in a similar fashion to volumes.
In some cases the files come from the container host, but in other cases they come directly from the client, being uploaded via the REST api. We don't want to store these files unnecessarily long or unnecessarily make them available outside the container. Furthermore, volumes are not available during the build phase, which is required for some use cases.
This means using the existing volume feature as-is is not ideal, as they are not available during the build and require the files to be visible in the host filesystem.
-
PR#3070 Add support for certificates for registry
This is very similar to the above yum usecase, except it applies to the docker daemon itself when contacting a registry, rather than yum inside the container talking to a repo.
-
Index/registry authentication from
$HOME/.dockercfg
.This file contains login information that are automatically uploaded by the client to the docker daemon for all operations that may need to talk to the index, such as push/pull, etc. This is similar to e.g. the ssh key example above, except it applies to the daemon, and the authentication is not visible inside the container.
-
PR#5655 Always mount a /run tmpfs in the container
-
Issue#332 flatten images - merge multiple layers into a single one
First of all, each container gets a tmpfs mounted on /run that is not visible outside the container, and that dies with the container. This is similar to how /run works on a normal distribution, and forms the basis for allowing container files that are not part of any image.
Then during container initialization any registred host-specific private files are copied into a directory in /run, say /run/docker. Additionally any private data uploaded during docker run is placed in this directory, possibly overriding the host-specific files.
Another possibility to hide files is to put them in a image layer and then remove them at the end, then flattening the image to make sure the intermediate layers are not in the final image. This is not ideal though, as it puts the responsibility for not shipping the private files on the user, which can lead to accidental leaks.
For the host-specific private files the easiest solution is to have
some directory on the host, like /etc/docker/private.d
that gets
copied into /run/docker. This will allow use case nr 1 to work very
easy. We just put the repo config in the base layer, with the key
config pointing to e.g. /run/docker/yum/
and have the entitlement
setup mechanism create these files. Then anyone can just run docker build .
and have the dockerfile be able to do yum install
.
For user space files there are two alternatives, both of which would
be supported. First of all you can add references to files in the
$HOME/.dockercfg
file next to the current authentication
tokens. These would be automaticall uploaded on every docker run
or
docker build
call. The other alternative is to specify the files as
argument to the individual docker call, like docker run --private dir/foo-key-file:foo/api.key
which would upload this file to the
daemon for that container only.