docker / compose

Define and run multi-container applications with Docker
https://docs.docker.com/compose/
Apache License 2.0
33.92k stars 5.21k forks source link

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

Closed sanchitbapat closed 11 months ago

sanchitbapat commented 2 years ago

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"]


2. Create a `docker-compose.yml`

❯ cat docker-compose.yml services: secrets-tester: build: . secrets:

secrets: some_secret_file: file: somefile.txt

3. Create a text file for secrets (`somefile.txt`)

❯ cat somefile.txt Text from a secret file


4. 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 commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

Oh, my bad ! Sorry 'bout that !

mario-gravel commented 1 year ago

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

ndeloof commented 1 year ago

yes indeed

mario-gravel commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

cu commented 1 year ago

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 commented 1 year ago

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

peterge1998 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

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.

con-f-use commented 1 year ago

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.

ndeloof commented 1 year ago

@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

con-f-use commented 1 year ago

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.

ianhinder commented 1 year ago

Will this allow us to use file-based secrets with a remote docker host, which is not currently possible with the bind-mount implementation?

ndeloof commented 1 year ago

@ianhinder yes indeed

ianhinder commented 1 year ago

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.

con-f-use commented 1 year ago

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)

ndeloof commented 1 year ago

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

con-f-use commented 1 year ago

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.

ndeloof commented 1 year ago

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

ianhinder commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

Exactly, my hope as well!

ndeloof commented 1 year ago

unfortunately this approach is currently blocked by https://github.com/moby/moby/issues/34142

nicholastulach commented 1 year ago

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

ndeloof commented 1 year ago

@nicholastulach exact, build time secrets are implemented by buildkit

bodograumann commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

@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 commented 1 year ago

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 (https://github.com/docker/compose/issues/3425#issuecomment-423091370), in conjunction with the "volume with some initial content" idea that was mentioned for configs (https://github.com/docker/compose/issues/8707#issuecomment-1049919868)?

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 commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

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.

quarky42 commented 10 months ago

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 commented 10 months ago

@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 commented 10 months ago

@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 commented 10 months ago

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 commented 10 months ago

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 commented 6 months ago

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 commented 4 months ago

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

spectrapulse commented 2 months ago

I’m frustrated with the inadequate documentation and inconsistent support between Docker Swarm and Compose. This is the seventh instance I’ve encountered where Swarm lacks support for a feature that Compose offers, or vice versa.

It feels misleading to promote the capability of managing both environments with a single unified configuration in the documentation when, in reality, the latest version of Docker CE does not support the new Compose specification in Swarm. Unfortunately, Swarm lacks dedicated documentation that clearly delineates supported and unsupported features. This time, I’m struggling to mount secrets or configurations in a Compose environment because the application in the container expects specific file permissions, which necessitates a workaround. This issue likely stems from the decision to share a specification across two distinct tools with different levels of support for this spec, both of which are provided by the same vendor.

If the intention is for this to be a standalone specification, it should be renamed from “Compose File” to a more tool-agnostic term. The documentation should explicitly state when a feature is not supported by these tools—before developers encounter errors during the transition from development to a small production environment, not after, and certainly not through a GitHub Issue due to an unhelpful error message.

I can foresee further confusion with the introduction of Compose Bridge, particularly if it lacks comprehensive documentation. This oversight leads to significant time wasted especially when designing around functionality provided by these tools.