从 postgres docker 容器中的环境变量中删除敏感信息

Remove sensitive information from environment variables in postgres docker container

我想制作一个 postgres 数据库映像,但不想公开使用 docker-compose.yml 文件生成时存储为环境变量的密码和用户名。基本上,我不希望任何人执行到容器中并找出变量。

一种方法是使用 docker-secrets,但我不想使用 docker swarm,因为我的容器会 运行 在单个主机上。

我的docker-编写文件-

    version: "3"
    services:
       db:
         image: postgres:10.0-alpine
      environment:
         POSTGRES_USER: 'user'
         POSTGRES_PASSWORD: 'pass'
         POSTGRES_DB: 'db'

我尝试过的东西 -

1) 取消设置入口点末尾的环境变量-entrypoint.sh

        for f in /docker-entrypoint-initdb.d/*; do
            case "$f" in
            *.sh)     echo "[=12=]: running $f"; . "$f" ;;
            *.sql)    echo "[=12=]: running $f"; "${psql[@]}" -f "$f"; echo ;;
            *.sql.gz) echo "[=12=]: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
            *)        echo "[=12=]: ignoring $f" ;;
            esac
            echo
        done
        unset POSTGRES_USER

不过什么也没发生。 :(

2) init.sql inside docker-entrypoint-initdb.d,创建数据库,用户并在不使用环境的情况下通过。 我分享了音量,因为 -

```
   volumes:
       - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
```

并且,在我的主机上,在 docker-入口点-initdb.d 内,我将 init.sql 保存为 -

CREATE DATABASE docker_db;CREATE USER docker_user with encrypted password 'pass';GRANT ALL PRIVILEGES ON DATABASE docker_db TO docker_user;

我移动到 运行 容器中,这个文件在那里,但是没有创建文件中提到的用户或数据库。

过去两天我一直坚持这个问题,非常感谢任何帮助。

使用不带值的参数在您的 Dockerfile 中构建图像:

ARG PASSWORD 

并使用

构建它
export PASSWORD="MYPASS" && docker build ...

以这种方式 ARG 在 运行 宁 container

时不存在

这是一个完整的例子:

dockerfile:

FROM postgres:10.0-alpine

ARG my_user
ARG my_pass

Compose:

version: "3"
services:
       db:
         build:
           context: .
           args:
            - my_user
            - my_pass       
         environment:
           - POSTGRES_USER=${my_user}
           - POSTGRES_PASSWORD=${my_pass}
           - POSTGRES_DB=db

运行它:

export my_user=test && export my_pass=test1cd && docker-compose up -d --build

现在,如果您登录 container 并尝试 echo $my_pass,您会得到一个空字符串

结果:

docker exec -ti 3b631d907153 bash

bash-4.3# psql -U test db
psql (10.0)
Type "help" for help.

db=#

I don't want anyone to exec into the container and find out the variables.

这不现实,我不担心。

这里的根本问题是 Docker 没有特别针对某人可以 运行 执行哪些 docker 命令的任何访问控制。 如果您可以 运行 任何 docker 命令,那么您对主机具有不受限制的根级访问权限。 例如,您可以

docker run --rm -it -v /:/host busybox vi /host/etc/sudoers
docker exec -it myapp_db env
docker inspect myapp_dbadmin
docker exec -it myapp_app cat ./db_config.yml
docker run --rm -it -v /:/host busybox cat /host/$PWD/db_config.yml

这里最简单的做法是完全不让任何您不信任的用户访问系统。 (如果您在云环境中,两个一半大小的云实例通常与一个更大的实例具有相同的成本,因此以这种方式划分用户可能很简单。)

理论上,您可以通过确保 docker 访问受到限制(例如,在 sudo 之后)、仅在文件中传递凭据并确保相应的主机文件也具有适当的权限来限制事情文件权限,因此无法读取。这通常涉及将此配置移出 docker-compose.yml 文件。它不是 "usual" Docker 配置,但它确实解决了环境变量并不是那么安全的问题。

对于任何其他环境变量,您可以查看@LinPy 的答案。它巧妙地使用 Docker Image Build-time Variables 来覆盖这些值。但至少,我无法在这种情况下受益,可能是因为这些是 postgres 的一些 "special" 变量并且无法覆盖它们(欢迎在评论部分进行任何解释)。

所以,现在开始解决方案 -

问题 - 不希望 postgres 的 username/password 作为环境变量可见。

解决方案 - 不要在 compose 的环境变量部分指定它们。

相反,使用脚本制作 user/database。 Postgres 的映像 运行 是一个入门级脚本,它会在 docker-entrypoint-initdb.d 目录和 运行 中查找任何 .sh/.sql 文件它。

示例,

目录结构 -

-docker-compose.yml
-docker-entrypoint-initdb.d
  -init.sql

我的docker-撰写文件-

version: "3"

services:
    db:
      image: postgres:10.0-alpine
      ports:
        - 8765:5432
      volumes:
        - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d

init.sql 文件

CREATE DATABASE docker_db;CREATE USER docker_user with encrypted password 'pass';GRANT ALL PRIVILEGES ON DATABASE docker_db TO docker_user;
docker-compose up
docker exec -it container-id bash
psql -U docker_user docker_db
psql (10.0)
Type "help" for help.

docker_db=>

现在,从您的主机中删除 init.sql,因为它是共享卷,它也会从您的容器中删除。

更新

在 Compose 中使用 docker 秘密之前,请考虑此 and that github answer


您可以使用 docker secrets in Compose.

docker postgresql docs 的相关部分所述:

As an alternative to passing sensitive information via environment variables, _FILE may be appended to some of the previously listed environment variables, causing the initialization script to load the values for those variables from files present in the container. In particular, this can be used to load passwords from Docker secrets stored in /run/secrets/<secret_name> files.

因此您的撰写文件可以读取:

version: "3"
services:
  db:
    image: postgres:10.0-alpine
  environment:
    POSTGRES_USER_FILE: /run/secrets/user
    POSTGRES_PASSWORD_FILE: /run/secrets/pass
    POSTGRES_DB_FILE: /run/secrets/db
  secrets:
    - user
    - pass
    - db

secrets:
  user:
    file: user.txt
  pass:
    file: pass.txt
  db: 
    file: db.txt

您在 DockerHub 的 Postgres 页面上描述了这种方式。

"Docker 秘密

作为通过环境变量传递敏感信息的替代方法,可以将 _FILE 附加到之前列出的一些环境变量,从而导致初始化脚本从容器中存在的文件中加载这些变量的值。特别是,这可用于从存储在 /run/secrets/ 文件中的 Docker 秘密中加载密码。例如:

$ docker run --name some-postgres -e POSTGRES_PASSWORD_FILE=/run/secrets/postgres-passwd -d postgres

目前,仅支持 POSTGRES_INITDB_ARGS、POSTGRES_PASSWORD、POSTGRES_USER 和 POSTGRES_DB。

检查服务时可以看到的内容: