【问题标题】:Python flask application access to docker secrets in a swarmPython烧瓶应用程序访问群中的docker秘密
【发布时间】:2020-12-25 09:55:30
【问题描述】:

我想部署一个烧瓶+gunicorn 项目,我是 Docker 的新手。到目前为止,我有一个 Dockerfile 如下。

# Pull official base image
FROM python:3.7-slim-buster

# Set work directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Set environment variables
ENV REDIS_HOST [...omit here...]
ENV REDIS_PORT [...omit here...]
ENV REDIS_DB_WHITELIST [...omit here...]
ENV MYSQL_HOST [...omit here...]
ENV MYSQL_PORT [...omit here...]
ENV MYSQL_DB_DUMMY [...omit here...]

# Copy project
COPY . /usr/src/app/

# Install dependencies
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN pip install gunicorn

EXPOSE 5000

RUN chmod +x ./entrypoint.sh
ENTRYPOINT ["sh", "entrypoint.sh"]

还有一个 docker-compose.yml 如下。

version: "3.9"

secrets:
  FLASK_SECRET_KEY:
    external: true
  MYSQL_USER:
    external: true
  MYSQL_PASSWORD:
    external: true

services:
  web:
    image: flask-app:v0.1.0
    environment:
      FLASK_SECRET_KEY_FILE: /run/secrets/FLASK_SECRET_KEY
      MYSQL_USER_FILE: /run/secrets/MYSQL_USER
      MYSQL_PASSWORD_FILE: /run/secrets/MYSQL_PASSWORD
    ports:
      - "5000:5000"
    secrets:
      - FLASK_SECRET_KEY
      - MYSQL_USER
      - MYSQL_PASSWORD

在我搜索完之后,似乎访问 docker 机密的唯一方法是使用 docker stack deploy --compose-file=docker-compose.yml flask-app 命令。显然,我有三个敏感数据 FLASK_SECRET_KEYMYSQL_USERMYSQL_PASSWORD 需要存储在 Docker 机密中。原来app一直无法运行,我假设python脚本中的mysql_user = os.environ['MYSQL_USER']等无法访问环境变量。

我不知道通过 Dockerfile 或 docker-compose.yml 从 Docker 机密访问敏感数据的正确方法,如果我有错误,请纠正我。

【问题讨论】:

    标签: python docker-compose dockerfile docker-swarm


    【解决方案1】:

    我确实找到了一种从 docker secret 访问敏感数据的方法,使用 python-dotenv。这是我的项目级 config.py 模块的一些 sn-p。

    import os
    from dotenv import load_dotenv
    
    dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
    if os.path.exists(dotenv_path):
        load_dotenv(dotenv_path=dotenv_path)
    
    
    def manage_sensitive(name):
        v1 = os.getenv(name)
        
        secret_fpath = f'/run/secrets/{name}'
        existence = os.path.exists(secret_fpath)
        
        if v1 is not None:
            return v1
        
        if existence:
            v2 = open(secret_fpath).read().rstrip('\n')
            return v2
        
        if all([v1 is None, not existence]):
            return KeyError(f'{name}')
    
    
    class ConfigRabbitMQ:
        AMQP_USER = manage_sensitive(name='amqp_user')
        AMQP_PASSWORD = manage_sensitive(name='amqp_password')
        
        AMQP_HOST = manage_sensitive(name='amqp_host')
        AMQP_PORT = manage_sensitive(name='amqp_port')
    

    所以在与此 config.py 模块相同的目录中有一个 .env 文件。该模块可以从 Docker 机密和.env 文件中访问敏感数据,因为在.dockerignore 文件中列出.env 是一种常见的做法。因此,例如,docker-compose.yml 如下。

    version: "3.9"
    
    services:
      web:
        ...
        secrets:
          - amqp_user
          - amqp_password
        ...
    
    secrets:
      amqp_user:
        external: true
      amqp_password:
        external: true
    

    对更好的做法有什么建议吗?

    【讨论】:

    【解决方案2】:

    您使用简短语法在服务上声明机密。默认情况下,此类机密将挂载在容器内的 /run/secrets/{secretname} 中。

    长语法甚至允许指定目标位置(尽管 v3 compose 参考声称它只会挂载到 /run/secrets/):

    创建一个秘密:

    echo "mysecret" | docker secret create mysecret -
    

    注意:秘密也可以在 docker-compose.yml 中创建,并带有文件引用。为简单起见,我在示例中选择手动创建它。

    使用 swarm stack 中的秘密:

    version: '3.8'
    services:
      testsecret:
        image: ubuntu
        deploy:
          replicas: 1
        tty: true
        secrets:
          - source: mysecret
            target: /path/in/container/mysecret
            mode: 0444
    
    secrets:
      mysecret:
        external: true
    

    然后在您的应用程序中读取文件 /path/in/container/mysecret 以获取其内容。

    请记住,秘密始终以只读方式安装。增加的安全性是秘密在 swarm 节点之间加密分布,并加密存储在 raft 日志中(~=集群状态)。一旦秘密被挂载到容器中,它将是 tempfs 上的未加密文件。另一个优点是细节不会暴露为环境变量,因此不太可能被意外泄露。

    似乎 docker-compose 与 compose 文件规范的 v3.x 版本存在定义差距,允许在 docker-compose 部署中使用机密。但是:那时很多低级功能将不可用。

    几天以来,v3 compose 文件参考页面似乎被破坏了:除了页眉和页脚,描述的整个正文都丢失了......

    【讨论】:

    • 对不起,我的回复可能过期了。我确实找到了v3 version of the compose file spec,我选择从其默认路径访问 Docker 机密,如您所见my answer。我仍然不确定这是否是一个好习惯。如果有任何建议,我将不胜感激。
    猜你喜欢
    • 2018-03-21
    • 2017-10-18
    • 1970-01-01
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 2016-03-09
    • 2020-09-30
    • 1970-01-01
    相关资源
    最近更新 更多