如何解决Python Flask 应用程序访问集群中的 docker 机密
我想部署一个 Flask+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_KEY、MYSQL_USER、MYSQL_PASSWORD 需要存储在 Docker 机密中。事实证明,应用程序一直无法运行,我假设 python 脚本中的 mysql_user = os.environ['MYSQL_USER']
等无法访问环境变量。
我不知道通过 Dockerfile 或 docker-compose.yml 从 Docker 机密访问敏感数据的正确方法,如果我有任何错误,请纠正我。
解决方法
您使用了简短的语法来声明服务的秘密。默认情况下,此类机密将安装在容器内的 /run/secrets/{secretname} 中。
长语法甚至允许指定目标位置(即使 v3 compose 引用声称它只会挂载到 /run/secrets/):
创建一个秘密:
echo "mysecret" | docker secret create mysecret -
注意:秘密也可以在 docker-compose.yml 中创建,并带有文件引用。为简单起见,我选择在我的示例中手动创建它。
在群体堆栈中消费秘密:
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 日志中(~=集群状态)。一旦一个秘密被装载到一个容器中,它就会是一个临时文件上的未加密文件。另一个优点是细节不会暴露为环境变量,因此不太可能被意外泄露。
似乎 docker-compose 与 v3.x 版本的 compose 文件规范存在定义差距,该版本允许在 docker-compose 部署中使用机密。但是:那时许多低级功能将不可用。
几天以来,v3 撰写文件参考页面似乎已损坏:从页眉和页脚来看,整个描述都丢失了...
,我确实找到了一种使用 python-dotenv 从 docker secret 访问敏感数据的方法。这是我的项目级 config.py
模块的一些片段。
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')
因此在与此 .env
模块相同的目录中有一个 config.py
文件。此模块可以访问来自 Docker 机密和 .env
文件的敏感数据,因为在 .env
文件中列出 .dockerignore
是一种常见做法。因此,例如,docker-compose.yml
如下所示。
version: "3.9"
services:
web:
...
secrets:
- amqp_user
- amqp_password
...
secrets:
amqp_user:
external: true
amqp_password:
external: true
对于更好的做法有什么建议吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。