compose icon indicating copy to clipboard operation
compose copied to clipboard

Secrets fail to set the `uid`, `gid` and `mode` specified in `docker-compose.yml`

Open sanchitbapat opened this issue 3 years ago • 1 comments

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:

  1. 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"]
  1. 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
  1. Create a text file for secrets (somefile.txt)
❯ cat somefile.txt
Text from a secret file
  1. 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:

  1. Without creating the tester user
  2. With same source and target names for the file in docker-compose.yml
  3. Using the uid and gid for root
  4. Using random values for uid and gid
  5. 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:

sanchitbapat avatar Jul 13 '22 19:07 sanchitbapat

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

ev-adias avatar Sep 05 '22 17:09 ev-adias

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?

markkrj avatar Oct 25 '22 14:10 markkrj

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...

rijnhard avatar Nov 15 '22 12:11 rijnhard

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.

mario-gravel avatar Dec 15 '22 01:12 mario-gravel

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.

ndeloof avatar Dec 15 '22 11:12 ndeloof

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.

mario-gravel avatar Dec 15 '22 13:12 mario-gravel

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.

ndeloof avatar Dec 15 '22 14:12 ndeloof

Oh, my bad ! Sorry 'bout that !

mario-gravel avatar Dec 15 '22 14:12 mario-gravel

So if a secret change, we need to restart the container. Am I right ?

mario-gravel avatar Dec 15 '22 14:12 mario-gravel

yes indeed

ndeloof avatar Dec 15 '22 14:12 ndeloof

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.

mario-gravel avatar Dec 15 '22 14:12 mario-gravel

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

ndeloof avatar Dec 15 '22 14:12 ndeloof

As long as the secret file can be updated on the fly and still have the good uid, gid and mode, I'm good !

mario-gravel avatar Dec 15 '22 14:12 mario-gravel

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: @.***>

rijnhard avatar Dec 16 '22 05:12 rijnhard

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.

cu avatar Jan 11 '23 22:01 cu

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

ndeloof avatar Jan 12 '23 12:01 ndeloof

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.

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 avatar Jan 25 '23 11:01 peterge1998

@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

noahehall avatar Jan 25 '23 14:01 noahehall

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.

AnderssonPeter avatar Mar 12 '23 18:03 AnderssonPeter

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.

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 avatar May 15 '23 19:05 con-f-use

@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

ndeloof avatar May 15 '23 20:05 ndeloof

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.

con-f-use avatar May 15 '23 20:05 con-f-use

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 avatar May 19 '23 20:05 ianhinder

@ianhinder yes indeed

ndeloof avatar May 20 '23 05:05 ndeloof

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.

ianhinder avatar May 22 '23 10:05 ianhinder

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)

con-f-use avatar May 22 '23 10:05 con-f-use

using bind mount for local files indeed doesn't work with a remote docker host, and is a significant limitation for this use-case

ndeloof avatar May 22 '23 10:05 ndeloof

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.

con-f-use avatar May 22 '23 10:05 con-f-use

actually you can docker cp into a container before after it has been created and before it get started

ndeloof avatar May 22 '23 11:05 ndeloof

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.

ianhinder avatar May 22 '23 11:05 ianhinder