An Interest In:
Web News this Week
- April 23, 2024
- April 22, 2024
- April 21, 2024
- April 20, 2024
- April 19, 2024
- April 18, 2024
- April 17, 2024
Advanced Docker: how to use secrets the right way
Secrets are one of the sneakiest vulnerability issues you can have in a Docker image if you don't know how to handle them.
If you need to clone a private repository or to download a private package you must use sensitive data during your docker build
, there's no easy way around that.
In this tutorial on the advanced usage of Docker series, I'll explain how to use a build secret in a safe way.
What is Buildkit
I explained last week what is the Buildkit build engine, how to set it up, and how you can use Buildkit to speed up docker build
.
Never use COPY
and rm
If you are dealing with secrets during your development, I'm sure the first thing you've tried is to COPY
a file with credentials from your Dockerfile and then remove it with rm
when you don't need it anymore...
This is so wrong
because you are just deleting the file from that layer but the credentials are still in the layer above!
Unsafe code example
Let's use this Dockerfile.
FROM ubuntu:bionicCOPY .netrc /RUN rm .netrc
And let's build it.
$ docker build -t unsafe . -f Dockerfile.not-safeSending build context to Docker daemon 4.096kBStep 1/3 : FROM ubuntu:bionic ---> c14bccfdea1cStep 2/3 : COPY .netrc / ---> 18d1eb74c6daStep 3/3 : RUN rm .netrc ---> Running in fafd31acf728Removing intermediate container fafd31acf728 ---> d7d4315738a6Successfully built d7d4315738a6Successfully tagged unsafe:latest
Now we want to use the command docker history
to list all the layers of the image.
$ docker history d7d4315738a6IMAGE CREATED CREATED BY SIZE COMMENTd7d4315738a6 10 seconds ago /bin/sh -c rm .netrc 0B18d1eb74c6da 14 seconds ago /bin/sh -c #(nop) COPY file:a0fa732884be950b 19Bc14bccfdea1c 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B<missing> 4 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do 7B<missing> 4 weeks ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 0B<missing> 4 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > / 745B<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:84f8ddc4d76e1e867 63.2MB
Here we can see the latest layer created, d7d4315738a6
, but you don't care about it.
The best part is the previous layer, 18d1eb74c6da
, which we can analyze deeper.
$ docker run -it 18d1eb74c6daroot@09fb719ec3dc:/# cat .netrcmy secret password
This is the deal: every layer of your image is available, including the ones with your secrets!
Think about it next time you do COPY
and rm
.
Buildkit to the rescue with --secret
Buildkit adds a new flag called --secret
for the docker build command. You can use it to provide safely a secret to your Dockerfile at build time! Buildkit mounts the secret using tmpfs
in a temporary file located in /run/secrets
that we can use to access a secret in the Dockerfile.
Using this feature we are sure that no secrets will remain in the image!
Safe code example
Dockerfile
Let's use the following Dockerfile
# syntax = docker/dockerfile:1.0-experimentalFROM ubuntu:bionicRUN --mount=type=secret,id=mynetrc,dst=/.netrc cat /.netrcRUN cat /.netrc
The first thing to notice is # syntax = docker/dockerfile:1.0-experimental
, we tell Docker to use the new syntax to exploit the new Buildkit functionality.
Then, with the first RUN
command, the magic happens. We tell Docker to mount
a secret
with the id mynetrc
to the destination /.netrc
and in the same line, we execute the cat
command just for the sake of the example.
Then we RUN
again the cat command on the same file.
Build command
To build our Dockerfile this is the command:
$ DOCKER_BUILDKIT=1 docker build --secret id=mynetrc,src=.netrc --progress=plain --no-cache -f Dockerfile.safe -t safe .
You can notice here the flag --secret
which tells Docker the secret name and location. We also need to set DOCKER_BUILDKIT=1
to use the Buildkit build engine.
OK, let's build it.
$ DOCKER_BUILDKIT=1 docker build --secret id=mynetrc,src=.netrc --progress=plain --no-cache -f Dockerfile.safe -t safe .#...#8 [1/3] FROM docker.io/library/ubuntu:bionic#8 CACHED#9 [2/3] RUN --mount=type=secret,id=mynetrc,dst=/.netrc cat /.netrc#9 0.808 my secret password#9 DONE 1.7s#10 [3/3] RUN cat /.netrc#10 DONE 2.0s#11 exporting to image#11 exporting layers#11 exporting layers 0.7s done#11 writing image sha256:b86ed6e0585c2f2e5cb14796b896dae0004f75004ccece0949a3de0ca600b113 0.0s done#11 naming to docker.io/library/safe 0.0s done#11 DONE 1.0s
As you can see, in the RUN --mount=type=secret,id=mynetrc,dst=/.netrc cat /.netrc
we can access the content of the file, instead on the following RUN
there's no output.
The .netrc
file, in fact, is present in the final layer of the image but it's empty.
Let's use the command docker history
to list all the layers of this new image.
$ docker history b86ed6e0585cIMAGE CREATED CREATED BY SIZE COMMENTb86ed6e0585c 5 hours ago RUN /bin/sh -c cat /.netrc # buildkit 0B buildkit.dockerfile.v0<missing> 5 hours ago RUN /bin/sh -c cat /.netrc # buildkit 0B buildkit.dockerfile.v0<missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 4 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do 7B <missing> 4 weeks ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 0B <missing> 4 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > / 745B <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:84f8ddc4d76e1e867 63.2MB
As you can see, it's not possible now to load an older layer to read the secret.
This is it!
I hope this was useful for you, now go and refactor your old Dockerfile!
Reach me on Twitter @gasparevitta and let me know how you use manage secrets.
You can find the code snippets on Github.
This article was originally published on my blog. Head over there if you like this post and want to read others like it!
Original Link: https://dev.to/gasparev/advanced-docker-how-to-use-secrets-the-right-way-1l67
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To