Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
sanchitbapat opened this issue Jul 13, 2022 · 49 comments
Closed
Assignees

Comments

@sanchitbapat
Copy link

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:

@ev-adias
Copy link

ev-adias commented Sep 5, 2022

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

@markkrj
Copy link

markkrj commented Oct 25, 2022

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?

@rijnhard
Copy link

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

@mario-gravel
Copy link

mario-gravel commented Dec 15, 2022

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.

@ndeloof ndeloof self-assigned this Dec 15, 2022
@ndeloof
Copy link
Contributor

ndeloof commented Dec 15, 2022

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.

@mario-gravel
Copy link

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.

@ndeloof
Copy link
Contributor

ndeloof commented Dec 15, 2022

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.

@mario-gravel
Copy link

Oh, my bad ! Sorry 'bout that !

@mario-gravel
Copy link

mario-gravel commented Dec 15, 2022

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

@ndeloof
Copy link
Contributor

ndeloof commented Dec 15, 2022

yes indeed

@mario-gravel
Copy link

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.

@ndeloof
Copy link
Contributor

ndeloof commented Dec 15, 2022

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

@mario-gravel
Copy link

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

@rijnhard
Copy link

rijnhard commented Dec 16, 2022 via email

@cu
Copy link

cu commented Jan 11, 2023

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.

@ndeloof
Copy link
Contributor

ndeloof commented Jan 12, 2023

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 ndeloof removed the kind/bug label Jan 12, 2023
@peterge1998
Copy link

peterge1998 commented Jan 25, 2023

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.

@noahehall
Copy link

@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

@AnderssonPeter
Copy link

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.

jaydrogers added a commit to serversideup/docker-ssh that referenced this issue Apr 19, 2023
@ianhinder
Copy link

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.

@ndeloof
Copy link
Contributor

ndeloof commented May 22, 2023

sure, I'm not suggesting here to write your own hack-ish script to use docker cp, just saying we have an opportunity here to replace bind mounts for secrets/config with copy to better control permissions and ownership within container's filesystem

@ianhinder
Copy link

Exactly, my hope as well!

@ndeloof
Copy link
Contributor

ndeloof commented May 23, 2023

unfortunately this approach is currently blocked by moby/moby#34142

@nicholastulach
Copy link

I assume the cp work around will not work for build-time secrets…?

@ndeloof
Copy link
Contributor

ndeloof commented May 26, 2023

@nicholastulach exact, build time secrets are implemented by buildkit

@bodograumann
Copy link

@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

That was totally unclear to me. Can we make more explicit which features are only supported with docker swarm?

@marcpa00
Copy link

@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 The docs quoted is present in Services top-level element where clearly the word services refers to the children of services root element in the compose file, as stated in second paragraph of "Services top-level element" page.

Therefore, I would argue that service's task in that document naturally refers to a service in a compose file rather than a swarm container.

As @bodograumann says, if this is really a feature exclusive to docker swarm, it should be stated explicitly, or even removed from the document "Services top-level element" until it is actually something supported by docker compose.

@ndeloof
Copy link
Contributor

ndeloof commented Jul 17, 2023

@marcpa00 the compose specification is not intended to only cover docker compose features, that's fine some feature only apply to an alternative tool (whenever docker swarm doesn't use the compose specification) as long as docker compose warn users about unsupported features. Also, docker compose may be able to implement this feature once docker engine allows setting uid/gid on mounts, which has been discussed already. In the meantime, this is already available for environment-based secrets.

@nathanweeks
Copy link

unfortunately this approach is currently blocked by moby/moby#34142

@ndeloof Would it be possible to utilize a tmpfs mount, which allows some control of the mountpoint ownership (#3425 (comment)), in conjunction with the "volume with some initial content" idea that was mentioned for configs (#8707 (comment))?

Somewhat of a naive question, as I'm not familiar with how Docker Compose is implemented at a systems level, or if a tmpfs would cause issues with scenarios like, e.g., host/container restarts.

@sabs21
Copy link

sabs21 commented Nov 19, 2023

Any updates? I am running into this issue with Docker version 24.0.6, build ed223bc.
compose.yml

services:
  dev:
    secrets:
      - source: ssh_key
        mode: 0400
secrets:
  ssh_key:
    file: ~/.ssh/id_ed25519

Executing commands within container

root@a0b9f2920f01:/usr/local/proj# ssh-add /run/secrets/ssh_key
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0777 for '/run/secrets/ssh_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.

@stalb
Copy link

stalb commented Nov 22, 2023

The permissions of the initial file are used in the container.
So changing the permissions of the ~/.ssh/id_ed25519 would do the trick.

The problem is when you need to mount the secret in two container which want non compatible permissions eg. 400 in one and 440 in the other.

@ndeloof
Copy link
Contributor

ndeloof commented Nov 23, 2023

latest docker compose release warn you about this feature not being supported

WARN[0000] secrets `uid`, `gid` and `mode` are not supported, they will be ignored 

the reason is that secrets are implemented as bind mounts, which comes with this limlitation.

@ndeloof ndeloof closed this as not planned Won't fix, can't repro, duplicate, stale Nov 23, 2023
@quarky42
Copy link

The documentation says mode, uid, and gid all work for compose services for both configs and secrets:
https://docs.docker.com/compose/compose-file/05-services/#long-syntax
and
https://docs.docker.com/compose/compose-file/05-services/#long-syntax-4

Why is this issue being closed as "not planned". It is critical that files be loaded into the container with controlled / explicit permissions. Go try running filebeat with a custom filebeat.yml file loaded in without setting the permissions on the file correctly and see how far you get.

What possible excuse can there be for this commitment to be backed out on?

Loading files into the service without control of permissions is absurd.

@ndeloof
Copy link
Contributor

ndeloof commented Dec 12, 2023

@quarky42 compose specification is a vendor-neutral definition of the compose file format, it doesn't define implementation details and limitation by Docker Compose.
This feature can't be implemented by Docker Compose as the docker engine has no support for config or secret (only when ran in swarm mode), and it uses a bind mount hack as a workaround, which can't offer such options.

@isujtauke
Copy link

@quarky42 compose specification is a vendor-neutral definition of the compose file format, it doesn't define implementation details and limitation by Docker Compose. This feature can't be implemented by Docker Compose as the docker engine has no support for config or secret (only when ran in swarm mode), and it uses a bind mount hack as a workaround, which can't offer such options.

I feel like the confusion around this is warranted. The documentation that one would use for building a docker-compose.yaml doesn't indicate anywhere that there's a split in how secrets work when you use docker compose vs swarm. It's defined in the specification, and seemingly works partially in docker compose because of the aforementioned "bind mount hack"....though there's no indication via the documentation that any such hack is why it works in docker compose.

@ndeloof
Copy link
Contributor

ndeloof commented Dec 13, 2023

That's indeed a major challenge we have to address regarding inclusion of the Compose Specification in Docker docs, as then we miss "implementation details"

@sunnyphp
Copy link

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.

I'm found solution:

services:
  test:
    container_name: test
    image: busybox
    volumes:
      - ./source/.ssh:/root/ssh-copy
    tmpfs:
      - /root/.ssh
    command: sh -c "cp /root/ssh-copy/* /root/.ssh/ && chmod 0400 /root/.ssh/* && ls -la /root/.ssh"

Dirty hack, but acceptable for me.

@zorgoz
Copy link

zorgoz commented Apr 25, 2024

Is there any roadmap for this feature (I needed this with configs, not secrets)?
Just wondering: why is it not in the docs, that this is actually not supported?

@andrewvaughan
Copy link

@ndeloof

latest docker compose release warn you about this feature not being supported

WARN[0000] secrets `uid`, `gid` and `mode` are not supported, they will be ignored 

the reason is that secrets are implemented as bind mounts, which comes with this limlitation.

This error actually was more confusing than helpful to me, and is what led me to finding this discussion. It is seemingly counter to the Compose documentation, which makes it seem like they are supported.

Only reading through this entire discucssion did I learn that the Docker team uses the term service as both a swarm-only term and as a top-level mapping in the Compose documentation. There's no way users are just going to "know" that this is the case, and, at minimum, warrants an asterisk on the documentation explaining so. Requiring your users to understand how Swarm works should not be a dependency for being successful with Compose.

I'll add my $0.02 that this seems to be a severe limitation to Docker Compose Secrets and implementation should be reconsidered. This leaves the use of secrets at the whim of the image maintainer as to whether they build in a fashion that allows for access or not.

For example, in the formal Postgres docker container, they run all entrypoints as a 999:999 (postgres) user, meaning secrets become inaccessible during entrypoint and beyond. This severely limits the ability to extend that image's functionality with any use of secrets or add any dynamic capabilities through a Docker Compose configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.