compose
compose copied to clipboard
Secrets fail to set the `uid`, `gid` and `mode` specified in `docker-compose.yml`
Description
Docker secrets specified using the long syntax for the docker-compose.yml file fail to set the specified uid, gid and mode.
Also, from the docs, the default value of the uid and gid fields should be the user that runs the container however the value remains whatever was set on the host machine.
Steps to reproduce the issue:
- Create a
Dockerfile
❯ cat Dockerfile
FROM ubuntu:20.04
RUN adduser tester -u 1005 --disabled-password
CMD ["/bin/bash", "-c", "ls -al /run/secrets/target_secret_file.txt"]
- Create a
docker-compose.yml
❯ cat docker-compose.yml
services:
secrets-tester:
build: .
secrets:
- source: some_secret_file
target: target_secret_file.txt
uid: "1005"
gid: "1005"
mode: 0440
secrets:
some_secret_file:
file: somefile.txt
- Create a text file for secrets (
somefile.txt)
❯ cat somefile.txt
Text from a secret file
- Run the service
docker compose run secrets-tester
Describe the results you received: Received Output:
❯ docker compose run secrets-tester
-rw-r--r-- 1 1000 1000 24 Jul 13 16:47 /run/secrets/target_secret_file.txt
Describe the results you expected: Expected Output:
❯ docker compose run secrets-tester
-r--r----- 1 1005 1005 24 Jul 13 16:47 /run/secrets/target_secret_file.txt
Additional information you deem important (e.g. issue happens only occasionally): Same behavior is observed in these cases:
- Without creating the
testeruser - With same
sourceandtargetnames for the file indocker-compose.yml - Using the
uidandgidforroot - Using random values for
uidandgid - Different values for
mode
Output of docker compose version:
❯ docker --version
Docker version 20.10.17, build 100c701
❯ docker compose version
Docker Compose version v2.6.0
Output of docker info:
❯ docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.8.2-docker)
compose: Docker Compose (Docker Inc., v2.6.0)
scan: Docker Scan (Docker Inc., v0.17.0)
Server:
Containers: 2
Running: 0
Paused: 0
Stopped: 2
Images: 1
Server Version: 20.10.14
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc io.containerd.runc.v2 io.containerd.runtime.v1.linux
Default Runtime: runc
Init Binary: docker-init
containerd version: 3df54a852345ae127d1fa3092b95168e4a88e2f8
runc version: v1.1.2-0-ga916309
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 5.10.102.1-microsoft-standard-WSL2
Operating System: Ubuntu 20.04.4 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 7.763GiB
Name: DESKTOP-IGS6AOM
ID: MBVL:76QX:UWDQ:AK7Z:BNGW:PYGL:EXFG:ZHGD:JM53:RBFZ:4SQV:5I7Z
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
WARNING: No blkio throttle.read_bps_device support
WARNING: No blkio throttle.write_bps_device support
WARNING: No blkio throttle.read_iops_device support
WARNING: No blkio throttle.write_iops_device support
Additional environment details:
Same thing happens to me. I'm trying to use secrets to workaround having to set the permissions on the host file, by setting the mode in the secret, but it end up with the exact same permissions of the host.
This issues comes up for me when using a keyfile for MongoDB replica authentication. The keyfile must not be world-readable, and in *nix this is easy to fix, in Windows (docker-desktop) it's not, so I was hoping that using secrets might fix the problem. It seems not
As bind mounts do not support different permissions (uid, gid and mode), I suspect that in order to support this, the content of such secrets must be copied into the container (as in #9553), or, use POSIX ACLs (more complex). Am I right @ndeloof? But why does the compose documentation mention such options if they are not supported in the first place?
well secrets and configs arent writeable (as per specification) so no reason why the implementation cant actually be a copy. unless the idea is that they can change during runtime...
I'm using a secret for a SSH Private Key that must have a 0400 mode. Setting the uid, gid and mode is a requirement.
secrets:
- source: ssh_host_ecdsa_key
target: /etc/ssh/ssh_host_ecdsa_key
mode: 0400
2022-12-14 20:41:23 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2022-12-14 20:41:23 @ WARNING: UNPROTECTED PRIVATE KEY FILE! @
2022-12-14 20:41:23 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2022-12-14 20:41:23 Permissions 0777 for '/etc/ssh/ssh_host_ed25519_key' are too open.
2022-12-14 20:41:23 It is required that your private key files are NOT accessible by others.
2022-12-14 20:41:23 This private key will be ignored.
2022-12-14 20:41:23 sshd: no hostkeys available -- exiting.
Same issue applies both to Compose v1 and v2 the root cause is that both use a bind mount to "inject" secret inside container, but bind mount doesn't allow a distinct UID/GID/mode to be exposed inside container.
A possible alternative I can imagine is to replace this approach with a copy (just like we do with support for secret set by environment). The sole drawback is that, doing so, changes to secret on host won't apply to secret inside container. Doesn't seem to be a major issue to me, but let me know if this would be a blocker for your usage.
In my own opinion, having to rebuild the image to change a secret isn't an option. Major issue? Not now because we haven't reach the production, we're still developing. But once in production, it will be a security concern.
The access to the container repository isn't as secure as the access to the production host. Somebody pulling the image will have access to the private keys. Not a good thing at all !
There must be control over the uid, gid and mode for a secret file.
having to rebuild the image to change a secret isn't an option
This is not my proposal: compose would copy the secret into the container (not image) after creation, and before start. This is how secret based on environment is implemented already.
Oh, my bad ! Sorry 'bout that !
So if a secret change, we need to restart the container. Am I right ?
yes indeed
Does it implies a redeploy of the container or just the starting phase will be enough ?
It would be great if a refresh can be triggered manually (ex: docker compose refresh-secrets) to redo the copy in the container. Having a watchdog to do this automatically may consume resources unnecessary. Secrets don't change often but being able to update them without a restart can be a good solution.
we could copy secret again at any time, or have a dedicated command for this purpose, but the more obvious one would be to trigger a container restart
As long as the secret file can be updated on the fly and still have the good uid, gid and mode, I'm good !
I agree with the suggestion on a copy implementation, my use case is local development since I want to align local dev with a production swarm and a quick restart on local is totally acceptable to me.
On Thu, Dec 15, 2022, 16:14 Mario Gravel @.***> wrote:
As long as the secret file can be updated on the fly and still have the good uid, gid and mode, I'm good !
— Reply to this email directly, view it on GitHub https://github.com/docker/compose/issues/9648#issuecomment-1353160053, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABAXP2FJAB2TJB5D2UDM2BDWNMRVRANCNFSM53PZWJBQ . You are receiving this because you commented.Message ID: @.***>
I was testing out the secrets functionality using docker compose version 2.14.1 today and was surprised to learn that they don't work the way the docs say they should.
$ cat docker-compose.yaml
services:
bb:
image: busybox
command: sleep infinity
secrets:
- source: my_secret
target: /secret_file_target
uid: "1234"
gid: "5678"
mode: 0400
secrets:
my_secret:
file: ./secret_file_source
$ echo "this is my secret file" > secret_file_source
$ docker compose up -d
$ docker compose exec bb ls -l secret_file_target
-rw-rw-r-- 1 1000 1000 23 Jan 11 22:38 secret_file_target
This also seems to affect configs as well.
Marking this issue as "kind/enhancement" as secrets never have supported having uid/gid set by compose (v1 or v2), this feature was introduced and only supported by docker swarm
I'm using a secret for a SSH Private Key that must have a 0400 mode. Setting the uid, gid and mode is a requirement.
secrets: - source: ssh_host_ecdsa_key target: /etc/ssh/ssh_host_ecdsa_key mode: 04002022-12-14 20:41:23 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2022-12-14 20:41:23 @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ 2022-12-14 20:41:23 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2022-12-14 20:41:23 Permissions 0777 for '/etc/ssh/ssh_host_ed25519_key' are too open. 2022-12-14 20:41:23 It is required that your private key files are NOT accessible by others. 2022-12-14 20:41:23 This private key will be ignored. 2022-12-14 20:41:23 sshd: no hostkeys available -- exiting.
Can confirm this failing behavior (setting mode, uid & gid) which is not working for me too.
$ docker --version
Docker version 20.10.23, build 7155243
$ docker compose version
Docker Compose version v2.15.1
I came across this when I wanted to mount a private ssh key to the checkmk/check-mk-raw container via docker compose secrets and specify uid, gid & mode for the key, when I got the same UNPOTECTED KEY warning when executing ssh manually. According to the docs, this should be possible but did not work for me too.
@peterge1998 the key thing about the docs is the explicit wording
uid and gid: The numeric UID or GID that owns the file within /run/secrets/ in the service’s task containers. Default value is USER running container.
a service task explictly refers to swarm containers
It would be nice if this was supported when using docker compose I run the a container where the process runs as nobody.
So o give it access to the secret I have to give nobody read access to it on the host.
So if anyone gains access they can read the secrets in question without gaining root access.
A possible alternative I can imagine is to replace this approach with a
copy(just like we do with support for secret set byenvironment). The sole drawback is that, doing so, changes to secret on host won't apply to secret inside container. Doesn't seem to be a major issue to me, but let me know if this would be a blocker for your usage.
IMPORTANT
A regular Dockerfile COPY directive for secrets is a bad idea, because the secret ends up in the image. It is not localized to the running container. The second someone accidentally uploads the image to a public docker repository, the secret is public knowledge.
I know https://github.com/docker/compose/pull/10498 is fine, because it does the copy at container-runtime, just wanted to state that copying a secret via COPY in a dockerfile is dangerous.
@con-f-use I'm not talking about a Dockerfile COPY but about using docker cp after the container has been created. It won't be stored inside an image
Yes, I know. I wrote that, just wanted to be abundantly clear, so that inexperienced folk stumbling upon this issue don't do something they'll regret.
Will this allow us to use file-based secrets with a remote docker host, which is not currently possible with the bind-mount implementation?
@ianhinder yes indeed
Could this also be extended to configs? Currently I have to build a new image with the config files baked in, as docker configs in compose don't work with a remote docker host. If they were copied, similar to the secrets here, this would enable the use of local config files which appeared as standard configs on a remote host.
as docker configs in compose don't work with a remote docker host
What are you refering to here, can you give an example? (also I wish github issues had threads, as this is kinda offtopic to the original issue)
using bind mount for local files indeed doesn't work with a remote docker host, and is a significant limitation for this use-case
Ah, now I get it, yes especially if you need the files on container startup, because then you can't docker copy or scp them.
actually you can docker cp into a container before after it has been created and before it get started
Indeed - you can copy, but then your project configuration can't be expressed purely from a declarative compose file, and needs to be "booted" from a shell script or equivalent. This makes it less easy to transfer it between environments.