在 Swarm 集群中管理敏感数据
在 Docker Swarm 服务中, Secret 是一种 BLOB(二进制大对象) 数据, 就像密码、SSH 私钥、 SSL 证书或那些不应该未加密就直接存储在 Dockerfile 或应用程序代码中的数据。在 Docker 1.13 及更高版本中,可以使用 Docker Secrets 集中管理这些数据,并将其安全地传输给需要访问的容器。 一个给定的 Secret 只能被那些已被授予明确访问权限的服务使用,并且只能在这些服务任务正在运行的情况下。
不想在镜像或代码中管理的任何敏感数据,都可以使用 Secret 来管理,比如:
- 用户名和密码
- TLS certificates and keys
- SSH keys
- 其他重要数据:比如数据库名、内部服务器信息
- 通用的字符串或二进制内容 (最大可达 500 Kb)
注意: Docker Secret 仅对 Swarm service有效,对独立的容器是无用的。如需使用,可以启动 1 个副本的service来使用 Docker Secret。
另一个使用 Secert 的场景是在容器和一组证书之间提供一个抽象层。考虑一种场景:有开发、测试和生产三套环境,同一个应用程序在不同的环境中都可以拥有不同的凭证,并且以相同的 Secret Name 存储在开发、测试和生产集群中。这样容器只需要知道 Secret Name,就可以在不同的环境中正常工作。
当然,你也可以使用 Docker Secret 管理非敏感数据,比如配置文件。但是,非敏感数据还是建议使用 Docker Config 来管理。
通过案例学习 Secret
我们将创建一个 Mysql Service ,将密码保存到secret 中。我们还会创建一个 WordPress service ,他将使用 secret 连接Mysql 。这个例子将展示如何使用secret避免在image中存放敏感信息,或者在命令行中直接传递敏感信息。
1 、创建 secret
我们使用 docker secret create
命令以管道符的形式创建 secret
存放 MySQL 的密码。
一般情况下,应用不会直接用 root 密码访问 MySQL。我们会创建一个单独的用户 wordpress
,密码存放到 secret mysql_password
中。
[root@node1 ~]$ openssl rand -base64 20 | docker secret create mysql_password -
lmlpd2qxi7lzvdf993udgqn6b
返回的是新创建的 secret的 ID,不是密码
再创建 secret 存放 MySQL 的root密码
[root@node1 ~]$ openssl rand -base64 20 | docker secret create mysql_root_password -
5f1i7uj8b8f6gxac54z5blsyo
上面这种方式是从标准输入读取 secret 的内容,也可以指定从文件中读取,例如:
[root@node1 ~]$ openssl rand -base64 20 > password.txt
[root@node1 ~]$ docker secret create mysql_root_password_file ./password.txt
jqwde9g4nlxdzbydmg91gy6k2
2、查看 secret
使用 docker secret ls
命令来查看 secret
[root@node1 ~]$ docker secret ls
ID NAME DRIVER CREATED UPDATED
lmlpd2qxi7lzvdf993udgqn6b mysql_password 12 minutes ago 12 minutes ago
5f1i7uj8b8f6gxac54z5blsyo mysql_root_password 11 minutes ago 11 minutes ago
jqwde9g4nlxdzbydmg91gy6k2 mysql_root_password_file 7 minutes ago 7 minutes ago
3、创建自定义 overlay 网络
用于mysql和WordPress service的网络通信,不需要把mysql service暴露出去
[root@node1 ~]$ docker network create -d overlay mysql_private
b5htbtr7dyy7o0g2i13n2415r
[root@node1 ~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
655033d70654 bridge bridge local
45b3b6c6bb0b docker_gwbridge bridge local
6b1a153f6fb9 host host local
dmmsdyma59i1 ingress overlay swarm
b5htbtr7dyy7 mysql_private overlay swarm
8417dc8e3faf none null local
4、创建 MySQL service
创建服务相关命令已经在前边章节进行了介绍,这里直接列出命令。
$ docker service create \
--name mysql \
--replicas 1 \
--network mysql_private \
--mount type=volume,source=mydata,destination=/var/lib/mysql \
--secret source=mysql_root_password,target=mysql_root_password \
--secret source=mysql_password,target=mysql_password \
-e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
-e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" \
-e MYSQL_USER="wordpress" \
-e MYSQL_DATABASE="wordpress" \
mysql:5.7
确认mysql 容器已经正常启动
[root@node1 ~]$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
m4g2uncfb0xo mysql replicated 1/1 mysql:5.7
5、创建 WordPress service
secret
默认通过 tmpfs
文件系统挂载到容器的 /run/secrets
目录中。
$ docker service create \
--name wordpress \
--replicas 1 \
--network mysql_private \
--publish published=30000,target=80 \
--mount type=volume,source=wpdata,destination=/var/www/html \
--secret source=mysql_password,target=wp_db_password,mode=0400 \
-e WORDPRESS_DB_USER="wordpress" \
-e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \
-e WORDPRESS_DB_HOST="mysql:3306" \
-e WORDPRESS_DB_NAME="wordpress" \
wordpress:latest
查看服务,确保2个service 都正常启动
$ docker service ls
ID NAME MODE REPLICAS IMAGE
wvnh0siktqr3 mysql replicated 1/1 mysql:latest
nzt5xzae4n62 wordpress replicated 1/1 wordpress:latest
现在浏览器访问 IP:30000
,即可开始 WordPress
的安装与使用。
通过以上方法,我们没有像以前通过设置环境变量来设置 MySQL 密码, 而是采用 docker secret
来设置密码,防范了密码泄露的风险。
轮换rotate
这里用修改mysql密码来示例
1、创建新的mysql密码并用secret 存储
$ openssl rand -base64 20 | docker secret create mysql_password_v2 -
2、修改mysql service
修改mysql service ,让它能同时使用新旧2个secret,因为update service 会导致容器重启,这时WordPress 可以访问旧的secret 持续提供服务
$ docker service update \
--secret-rm mysql_password mysql
$ docker service update \
--secret-add source=mysql_password,target=old_mysql_password \
--secret-add source=mysql_password_v2,target=mysql_password \
mysql
3、修改WordPress 用户密码
通过mysqladmin 修改wordpress 的mysql密码
$ docker container exec $(docker ps --filter name=mysql -q) \
bash -c 'mysqladmin --user=wordpress --password="$(< /run/secrets/old_mysql_password)" password "$(< /run/secrets/mysql_password)"'
4、更新WordPress service 使用新密码
$ docker service update \
--secret-rm mysql_password \
--secret-add source=mysql_password_v2,target=wp_db_password,mode=0400 \
wordpress
5、确认WordPress是否正常
访问WordPress验证网站是否正常
6、移除旧的secret
$ docker service update \
--secret-rm mysql_password \
mysql
$ docker secret rm mysql_password
在 docker stack 中的使用
version: '3.1'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_root_password
- db_password
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: db_password.txt
db_root_password:
file: db_root_password.txt
volumes:
db_data: