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

Set password and other options via ENV variable #46

Closed
phlegx opened this issue Feb 11, 2016 · 53 comments
Closed

Set password and other options via ENV variable #46

phlegx opened this issue Feb 11, 2016 · 53 comments
Labels
Request Request for image modification or feature

Comments

@phlegx
Copy link

phlegx commented Feb 11, 2016

It would be awesome if it would be possible to set the Password via an ENV variable. Is this planned any time soon or maybe even already possible?

Of course it would even more awesome when we could set other parameters as well 👍

@Starefossen
Copy link

In the mean time you could check out tutumcloud/redis which supports this, and much much more.

@yosifkit
Copy link
Contributor

We don't supply a config file, so that would be up to you to just COPY or mount in a config and set whatever options you need. Using your own config is described on the Docker Hub or a more direct link to the source.

@oryband
Copy link

oryband commented Mar 29, 2016

@yosifkit copying a config file at build time isn't dynamic. Many scenarios involve creating a config template, passing environment variables and generating a configuration file in the entrypoint. This isn't a good solution.

@oryband
Copy link

oryband commented Mar 29, 2016

tutumcloud/redis is going to be deprecated soon. This alternative looks interesting: https://github.com/bitnami/bitnami-docker-redis

@phlegx
Copy link
Author

phlegx commented Mar 29, 2016

@oryband That is a nice one, thank you very much! Going to test this out

@tianon
Copy link
Contributor

tianon commented Apr 18, 2016

I'm still not sure I'm understanding what the need here for additional complexity is, given that Redis itself supports supplying any of the configuration file options directly via the command-line, which I've just verified:

$ docker run --name some-redis -d redis redis-server --requirepass foobared
896132042afb124aae06ea855e02da2a211bd0540a862f1d785b586a3bbc4479
$ docker run -it --link some-redis:redis --rm redis redis-cli -h redis -p 6379
redis:6379> AUTH test
(error) ERR invalid password
redis:6379> AUTH foobared
OK
redis:6379> 

This could be abstracted to an environment variable trivially via something like:

$ docker run --name some-redis -d -e REDIS_PASSWORD=foobared redis sh -c 'exec redis-server --requirepass "$REDIS_PASSWORD"'

@tianon
Copy link
Contributor

tianon commented Apr 18, 2016

Additionally to bake an image that supports that usage:

FROM redis

ENV REDIS_PASSWORD default-password

CMD ["sh", "-c", "exec redis-server --requirepass \"$REDIS_PASSWORD\""]

Combine that with automated builds (https://docs.docker.com/docker-hub/builds/) and repository links (https://docs.docker.com/docker-hub/builds/#repository-links) and it's reasonably easy to have an up-to-date image built FROM this one which supports supplying REDIS_PASSWORD for setting a password, if that's necessary.

@josegonzalez
Copy link

Just for a bit of context, Dokku integrates with the "official" images provided by docker to give developers access to various popular datastores. We use internal networking by default - safer on infra where there isn't private networking, like DigitalOcean - requiring that users manually expose the datastores for remote access.

In the case where a user wants to expose a service publicly, even a bit of protection is nice, and where possible we default to requiring a password for a datastore anyhow. Redis is the only one where we can't do that without:

  • Modifying a file on disk (eh)
  • Setting the password in the clear for the docker run command (ew)

It would be nice if we could set an environment variable for the password, as then we can easily integrate password protection and provide our users a modicum of security.

See dokku/dokku-redis#58 for (a lot less) detail.

@yosifkit
Copy link
Contributor

@josegonzalez, It would not have to be in the clear on the command line. 😄

$ # export your password env or run some script that exports the password to $SUPER_PASS
$ docker run --name some-redis -d redis redis-server --requirepass "$SUPER_PASS"
$ # bash will evaluate the env var before it is passed to docker

$ # which would be basically the same as if we implemented the desired env
$ docker run --name some-redis -d -e REDIS_PASSWORD="$SUPER_PASS" redis redis-server

@josegonzalez
Copy link

Wouldn't that show up in the output of docker inspect? I suppose providing an env file would be the same, but at least it wouldn't be in the command inspect output.

@tianon
Copy link
Contributor

tianon commented Aug 29, 2016 via email

@anthonyrisinger
Copy link

FWIW, both the postgres and mysql images support doing several common initialization tasks via ENV.

I think this makes for a nicer evaluation experience. It's simple to plug a redis container to an existing app this way because the container can configure itself to whatever the app expects. I'm trying to do this right now to localize our platform, and am working around the lack of ENV configuration in pretty much the ways stated above (intercept ENTRYPOINT or COMMAND), but it's a chore nonetheless.

When I first look at an available docker image, one of the next things I do is look at how flexible it is and what it can do via ENV, since that's the primary container config mechanism. If you require the user to extend your image and publish their own variant to some registry, for even basic/simple configuration, I feel the bar was raised quite a bit without any pragmatic benefit.

I've seen images accept an entire config via ENV, or use some convention to translate ENV keys into config assignments. Neither is too difficult to do in a custom ENTRYPOINT, and neither adds any overhead aside from a few extra bytes. I think expecting people to unconditionally extend the redis image for anything beyond toy usage results in a weaker DX/developer-experience.

@yosifkit
Copy link
Contributor

@anthonyrisinger, postgres and mysql both require the server to be running to create users, which is why they have environment variables. None of their configuration is done via env vars and both databases can take most settings that could be set via a config file, through a flag:

$ # postgres
$ docker run --name pg -d postgres -c max_connections=200 -c shared_buffers=1GB -c effective_cache_size=3GB -c work_mem=5242kB -c maintenance_work_mem=256MB -c min_wal_size=1GB -c max_wal_size=2GB -c checkpoint_completion_target=0.7 -c wal_buffers=16MB -c default_statistics_target=100

$ # mysql
$ docker run --name sql -d -e MYSQL_ROOT_PASSWORD=my-secret-pw mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

Redis is basically the same but allows all of its config via flags, including password.

$ docker run --name red -d redis --slaveof 10.0.0.2 6379 --requirepass secret

Doing the same via docker-compose:

version: "2"

services:
  postgres:
    image: postgres
    command: >
      -c max_connections=200
      -c shared_buffers=1GB
      -c effective_cache_size=3GB
      -c work_mem=5242kB
      -c maintenance_work_mem=256MB
      -c min_wal_size=1GB
      -c max_wal_size=2GB
      -c checkpoint_completion_target=0.7
      -c wal_buffers=16MB
      -c default_statistics_target=100
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
  redis:
    image: redis
    command: >
     --slaveof 10.0.0.2 6379
     --requirepass secret 

How are flags to CMD any different than setting environment variables or even different from the mysql and postgres images?

@anthonyrisinger
Copy link

@yosifkit I acknowledge you can get there with COMMAND, and that's a fair point about the other databases requiring online configuration. mysql does allow other config, like MYSQL_ONETIME_PASSWORD or *_FILE, and postgres gets fancy with POSTGRES_INITDB_XLOGDIR. To some degree this whole thing is probably subjective and preference-driven, stemming from the dichotomy of containers being both CLI-like and appliance-like.

I like the declarative aspect of ENV. I am instructing this black box thinger what I need from it, as opposed to executing a tool/binary and knowing its rules and idiosyncrasies. I also like that it's key/value, which makes it straightforward to CRUD individual items from docker inspect or consume/generate from shell.

I might be old-fashioned or in the minority here, I'm not sure. ENV was always the way the config a system/OS container, since the way before time, long long ago! Hard to pass args to good ol' init after all. Docker became ubiquitous and lowered the bar to the point images now successfully compete directly with native binaries, which I think is super. Nonetheless, I generally still find ENV more pleasant to use and mechanically process on the daily, especially for apps I don't know very well or am just trying to get usable for whatever reason.

What say you? (whynotboth)?

@christrewin
Copy link

christrewin commented Jun 20, 2017

It would be nice to have a way to use Docker secrets to read from /run/secrets/redis-pass and set the redis --requirepass flag.

For example:

On a swarm manager set the redis-pass, then use docker stack deploy -c docker-compose-prod.yml appname

version: '3.1'

secrets:
    redis-pass:
        external: true

redis:
    build: ./redis
    image: redis:3.2.9
    networks:
        - frontend
    ports:
        - "6379"
    deploy:
        replicas: 2
        update_config:
            parallelism: 2
            delay: 10s
        restart_policy:
            condition: on-failure
    secrets:
        - redis-pass:
    environment:
        REDIS_PASS_FILE: /run/secrets/redis-pass

@amq
Copy link

amq commented Oct 8, 2017

We need some more love for Redis :) MariaDB has this since almost a year: MariaDB/mariadb-docker@6452a88
@tianon

@yosifkit
Copy link
Contributor

I am still against adding env vars for config since a) it is easy to add to COMMAND or docker run and b) adding just one will open the avalanche for all of them and we don't want to maintain a list of all possible redis config options for each version of redis.

@amq, here is a solution for using a secret with the cli flag. I did it with a volume, but a secret should be the same by swapping out the volume and adding in the yaml for the secret.

version: '3.1'

services:
  redis:
    image: redis:4.0.2
    volumes:
      - './secret:/run/secrets/redis-pass'
    environment:
        REDIS_PASS_FILE: /run/secrets/redis-pass
    command: [
      "bash", "-c",
      '
       docker-entrypoint.sh
       --requirepass "$$(cat $$REDIS_PASS_FILE)"
      '
    ]

@amq
Copy link

amq commented Oct 10, 2017

@yosifkit I'm only asking for the secret support of the password env var. I agree that using secrets for all env configuration is unnecessary.

shusugmt added a commit to shusugmt/st2-docker that referenced this issue Nov 23, 2017
@MariaWf
Copy link

MariaWf commented Jan 22, 2018

@yosifkit thank you ,great!

redis:
    image: redis
    ports:
      - "6379:6379"
    environment:
        REDIS_PASS_FILE: /run/secrets/redis-password
    command: [
      "bash", "-c",
      '
       docker-entrypoint.sh
       --requirepass "$$(cat $$REDIS_PASS_FILE)"
      '
    ]
    volumes:
      - ./db/redis/etc/redis.conf:/usr/local/etc/redis/redis.conf 
      - ./db/redis/data:/data 
      - ./db/redis/etc/redis-password:/run/secrets/redis-password 
    networks:
      - code-network 

@feluxe
Copy link

feluxe commented Feb 5, 2018

In case anyone wonders if tianon's solution would work with kubernetes secrets as well... It works. I just tested it. You can use a password for redis from a secret like this:

redis-dockerfile:

FROM redis

CMD ["sh", "-c", "exec redis-server --requirepass \"$REDIS_PASSWORD\""]

redis-secret.yaml:

...
metadata:
  name: my-secret
...
data:
  redis-password: my_redis_pw_string

redis-deployment.yaml:

        ...
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: redis-password

@t3ran13
Copy link

t3ran13 commented Feb 11, 2018

i think the best way for docker-compose set .env
https://docs.docker.com/compose/environment-variables/#the-env-file

$ cat .env
PSWD=123

$ cat docker-compose.yml
version: "3"
services:
  redis:
    image: redis:3.2
    ports:
      - "6379:6379"
    command: [
          "bash", "-c",
          '
           docker-entrypoint.sh
           --requirepass ${REDIS_PSWD}
          '
    ]

check with

docker-compose config

@adampl
Copy link

adampl commented Feb 11, 2018

Inspired by @yosifkit I've ended up with something more robust:

services:
  redis:
    image: redis
    environment:
      REDIS_PASS_FILE: /run/secrets/redis-pass
    command: bash -c '[ "$$REDIS_PASS_FILE" ] &&
      ( cat "$$REDIS_PASS_FILE" | xargs -0 redis-server --requirepass ) || redis-server'

This allows you to use all characters in the secret file (except null), or to not set the password when the environment variable is empty or unset (useful for development).

@davesmits
Copy link

so i now what to use redis on my kubernetes cluster and first need to build my own image to be able to get the password in it via kubernetes secrets? really? this should be in the box by default

@AnatolyRugalev
Copy link

AnatolyRugalev commented Mar 21, 2018

@davesmits there is possibility to override command in pod manifest, see https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/

You could inject secret to environment variable and then pass it to command option

My custom example may not apply to you:

containers:
- name: redis
  image: my-custom-redis-image
  command: ["redis-server", "/etc/redis.conf", "--requirepass", "$(REDIS_PASSWORD)"]
  env:
    - name: REDIS_PASSWORD
      valueFrom:
        secretKeyRef:
          name: redis-password
          key: password

@wglambert wglambert added the Request Request for image modification or feature label Apr 24, 2018
@jeff1985
Copy link

Providing a password should be easy and documented directly in the README! Otherwise you risk thousands of lazy sysadmins exposing their images to the wild without any protection.

Please add this feature soon!

@duzun
Copy link

duzun commented Jun 14, 2019

I ended up extending this image and adding support for $REDIS_PASSWORD env:

FROM redis:5-alpine

RUN sed -e '3i\\nif [ -n "$REDIS_PASSWORD" ]; then set -- "$@" --requirepass "$REDIS_PASSWORD"; fi' -i /usr/local/bin/docker-entrypoint.sh

The main reason being the ability to use docker-composer.override.yml with its own 'command' key, and not having to wary about the password in this file.

xoen added a commit to ministryofjustice/analytics-platform-control-panel that referenced this issue Sep 3, 2019
Surprisingly the `redis` image doesn't have a nicer way of setting
the `redis-server` password and ignores the `REDIS_PASSWORD`
environment variable.

This was causing the `ERR Client sent AUTH, but no password is set`
error (as the client still passed the password correctly).

This change overrides the image command and set the password.

See open issue and solution: redis/docker-library-redis#46 (comment)
@shubhambhattar
Copy link

shubhambhattar commented Sep 29, 2019

@AnatolyRugalev isn't it the case that in k8s it is preferred to use args key for command args? I think the config should be as follows:

containers:
- name: redis
  image: my-custom-redis-image
  command: ["redis-server"]
  args: ["/etc/redis.conf", "--requirepass", "$(REDIS_PASSWORD)"]
  env:
  - name: REDIS_PASSWORD
    valueFrom:
      secretKeyRef:
        name: redis-password
        key: password

This works but I was so confused why $(ENV_VAR) is working and ${ENV_VAR} isn't because ENV_VAR is an environment variable and not a command. Then I found out that this is a Kubernetes specific feature that if you want to expand environment variable in command or args field, then you've to use $(ENV_VAR) syntax and not ${ENV_VAR} one.

Reference link: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#use-environment-variables-to-define-arguments

I believe since the option to set the password and other options as environment variable is already available (explained above), we can close this issue.

@Routhinator
Copy link

So I'm fine with the solutions in this, but request to the maintainers, can you put the CLI example in the README for the container?

@SuperSandro2000
Copy link

FYI I use this to fix this issue and support container with and without PW that extend from this common container:

common-redis:
    extends:
      service: common
    image: redis:5-alpine
    mem_limit: 1G
    sysctls:
      net.core.somaxconn: "511"
    command: |
      sh -c "\
        if [ -z $${REDISCLI_AUTH:-} ]; then
          redis-server
        else
           redis-server --requirepass $$REDISCLI_AUTH
        fi

@tianon
Copy link
Contributor

tianon commented Feb 5, 2020

For most cases, I'd suggest using a configuration file instead of the --requirepass command line parameter given that the default settings change slightly once any flags are specified (which could cause unexpected behavior):

$ docker pull redis
Using default tag: latest
latest: Pulling from library/redis
Digest: sha256:7b84b346c01e5a8d204a5bb30d4521bcc3a8535bbf90c660b8595fad248eae82
Status: Image is up to date for redis:latest
docker.io/library/redis:latest

$ docker run -dit --name test redis
0cea7b89a839e45e0f61bc887f2879bfdbb0bf6a974963a82560c433027d58e5

$ docker logs test
1:C 05 Feb 2020 20:33:47.217 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 05 Feb 2020 20:33:47.217 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 05 Feb 2020 20:33:47.217 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
...

$ docker exec -i test redis-cli config get '*' > before.txt

$ docker rm -vf test

$ docker run -dit --name test redis --requirepass test
19805af3d5f4c4129d80606820030222dc6e627c5fde622c9399ee8715a55cd0

$ docker logs test
1:C 05 Feb 2020 20:35:35.670 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 05 Feb 2020 20:35:35.670 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 05 Feb 2020 20:35:35.670 # Configuration loaded
...

$ docker exec -i test redis-cli -a test config get '*' > after.txt
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.

$ diff -u before.txt after.txt
--- before.txt	2020-02-05 12:35:09.375349180 -0800
+++ after.txt	2020-02-05 12:36:20.157339827 -0800
@@ -1,7 +1,7 @@
 dbfilename
 dump.rdb
 requirepass
-
+test
 masterauth
 
 cluster-announce-ip
@@ -201,7 +201,7 @@
 dir
 /data
 save
-3600 1 300 100 60 10000
+
 client-output-buffer-limit
 normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60
 unixsocketperm

@SuperSandro2000
Copy link

Whats being configured with -3600 1 300 100 60 10000?

@yosifkit
Copy link
Contributor

yosifkit commented Feb 5, 2020

@SuperSandro2000, that is the save value (the key is just above it).

@SuperSandro2000
Copy link

Can we set the save value via the command line? I kinda want to avoid doing a config file.

@tianon
Copy link
Contributor

tianon commented Feb 6, 2020 via email

@paulcalabro
Copy link

paulcalabro commented Mar 26, 2020

@yosifkit Why is the environment variable REDIS_PASS_FILE required? Why will it not it just accept just the path in its place? I tried swapping its value in and it failed and I'm curious as to why it's failing.

version: '3.1'

services:
redis:
image: redis:4.0.2
volumes:
- './secret:/run/secrets/redis-pass'
environment:
REDIS_PASS_FILE: /run/secrets/redis-pass
command: [
"bash", "-c",
'
docker-entrypoint.sh
--requirepass "$$(cat $$REDIS_PASS_FILE)"
'
]

@yosifkit
Copy link
Contributor

@paulcalabro, --requirepass "$$(cat /run/secrets/redis-pass)" should work, but users wanted an environment variable similar to MYSQL_ROOT_PASSWORD_FILE.

I tried swapping its value in and it failed and I'm curious as to why it's failing

Did you also mount in a file with a single line of text or set up a secret to use?

@paulcalabro
Copy link

@yosifkit I did create a secret and associate it with the service. Sounds like it might be a bug on my end. I'll troubleshoot it further. Thanks for confirming it's not not subtlety I'm missing.

@danilopeixoto
Copy link

danilopeixoto commented Jun 29, 2020

This is a "Docker image" that does not support "Docker secrets" feature.

In the meantime, this should work for now:
command: ["sh", "-c", "redis-server --requirepass \"$$(cat /run/secrets/redis_password)\""]

@yosifkit
Copy link
Contributor

Given #46 (comment) (TLDR: adding any flag or config file loses the redis defaults), we will not be adding support for an ENV var that modifies the config file or adds flags.

It is relatively easy to add support for your own needs to use a file or direct env variable: #46 (comment) / #46 (comment)

@ccncristi
Copy link

ccncristi commented Jul 9, 2020

#46 is not a solution. It offers to map a volume and then read the password from that file.

The whole idea of docker secrets is to not save a password in a file on the host.
Docker secret saves the password encrypted, in it's internal database, and only presents it inside the containers, decrypted, in the RAM, using the path /run/secrets/[variable name] .

@thorrak
Copy link

thorrak commented Jan 3, 2021

Can this be revisited now that it sounds like the issue causing this behavior in Redis has been addressed since 6.2?

See: redis/redis#7092

@NitroCao
Copy link

Passing the password through the command line parameter is not secure, cause every user on the server can get the password through the ps command.

@tianon
Copy link
Contributor

tianon commented Jan 22, 2021 via email

@AlexMikhalev
Copy link

AlexMikhalev commented Jan 29, 2021

Can someone put forward recommended security configuration for Docker, Kubernetes and Consul/Vault?
Half of the recipes above no longer work or questionable - i.e. redis.conf with the password in it becomes unmanageable as can't follow infrastructure as code practices.

@itamarhaber
Copy link
Member

FWIW, as of Redis 6, the recommended approach to users' management is via the Access Control List mechanism and an external file with the defined permissions. In this context, the file can be stored on the host and mounted to the container.

@Uttam92477
Copy link

I'm still not sure I'm understanding what the need here for additional complexity is, given that Redis itself supports supplying any of the configuration file options directly via the command-line, which I've just verified:

$ docker run --name some-redis -d redis redis-server --requirepass foobared
896132042afb124aae06ea855e02da2a211bd0540a862f1d785b586a3bbc4479
$ docker run -it --link some-redis:redis --rm redis redis-cli -h redis -p 6379
redis:6379> AUTH test
(error) ERR invalid password
redis:6379> AUTH foobared
OK
redis:6379> 

This could be abstracted to an environment variable trivially via something like:

$ docker run --name some-redis -d -e REDIS_PASSWORD=foobared redis sh -c 'exec redis-server --requirepass "$REDIS_PASSWORD"'

@tianon , thanks for the comment. I think if documentation at https://hub.docker.com/_/redis could be updated, it would be nice. I usually just search in google "docker run <whatever i want (redis|mysql etc...)>" and first website that pops up is hub.docker.com. So, more documentation there (or a link to all supported configuration in redis website) will help.

transhapHigsn pushed a commit to DiligenceVault/st2-docker that referenced this issue Jun 8, 2021
@socketbox

This comment has been minimized.

@redis redis locked as resolved and limited conversation to collaborators Aug 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Request Request for image modification or feature
Projects
None yet
Development

No branches or pull requests