在微服务架构应用中,众多组件在集群中动态地创建、伸缩、更新。在如此动态和大规模的分布式系统上,管理和分发密码、证书等敏感信息将会是非常具有挑战性的工作。对于容器应用,传统的秘密分发方式,如将秘钥存放在容器镜像中,或是利用环境变量,volume动态挂载方式动态传入都存在着潜在的安全风险。
为了应对这个问题,在Docker 1.13及更高版本中,Docker推出了Secrets管理,可以在Swarm mode集群中安全地管理密码、密钥证书等敏感信息,并允许在多个Docker容器实例之间共享访问指定的秘密信息。
Docker secret 基本功能与典型场景
Docker命令行工具提供了docker secret
命令来管理敏感信息,
注: docker secret
只能从Docker Swarm模式的manager节点调用,如果你在本机进行试验,请先执行 docker swarm init
命令
$ docker secret --help
Usage: docker secret COMMAND
Manage Docker secrets
Options:
--help Print usage
Commands:
create Create a secret from a file or STDIN as content
inspect Display detailed information on one or more secrets
ls List secrets
rm Remove one or more secrets
Run 'docker secret COMMAND --help' for more information on a command.
其中 docker secret create
支持从标准输入读取信息,并且存入指定的secret:
首先我们创建两个 secrets
$ echo "Password4DB" | docker secret create db_password -
$ echo "Password4Root" | docker secret create root_password -
然后我们创建一个“db”服务并引用所创建的secret作为,数据库密码和root密码
$ docker service create --name db \
-d \
--secret db_password \
--secret root_password \
-e MYSQL_USER=dbtest \
-e MYSQL_DATABASE=dbtest \
-e MYSQL_PASSWORD_FILE=/run/secrets/db_password \
-e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/root_password \
mariadb
创建完毕之后,我们可以检查服务的状态
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
ouq2xbuu3jrp db replicated 1/1 mariadb:latest
$ docker service logs --tail 100 db
...
db.1.zjmymi0goca0@moby | 2017-05-28 23:35:25 140451437311936 [Warning] 'proxies_priv' entry '@% root@32ab97f50413' ignored in --skip-name-resolve mode.
db.1.zjmymi0goca0@moby | 2017-05-28 23:35:25 140451437311936 [Note] mysqld: ready for connections.
db.1.zjmymi0goca0@moby | Version: '10.1.23-MariaDB-1~jessie' socket: '/var/run/mysqld/mysqld.sock' port: 3306 mariadb.org binary distribution
我们可以通过 docker exec
命令来进入容器内部,查看挂载到/run/secrets/目录下的秘密文件
$ docker exec -ti 32ab97f50413 bash
root@32ab97f50413:/# cat /run/secrets/db_password
Password4DB
root@32ab97f50413:/# cat /run/secrets/root_password
Password4Root
容器编排中使用 docker secret
从 Docker Compose V3.1开始,支持在容器编排文件中使用 secret,这可以方便地在不同容器中分享所需的敏感信息。下面我们将使用 Compose 模板来构建一个Wordpress应用,通过 secret 实现 “wordpress”服务容器和“db”服务容器*享数据库密码。
docker-compose.yml
文件如下
version: "3.1"
services:
wordpress:
image: wordpress:latest
secrets:
- wp_db_password
ports:
- 8080:80
environment:
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_DB_PASSWORD_FILE=/run/secrets/wp_db_password
- WORDPRESS_DB_HOST=mariadb
deploy:
replicas: 3
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
mariadb:
image: mariadb
secrets:
- wp_db_password
- root_db_password
environment:
- MYSQL_USER=wordpress
- MYSQL_DATABASE=wordpress
- MYSQL_PASSWORD_FILE=/run/secrets/wp_db_password
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/root_db_password
deploy:
replicas: 1
restart_policy:
condition: on-failure
secrets:
wp_db_password:
external: true
root_db_password:
external: true
通过模板中的 secrets
部分,我们创建和引用 Docker Secrtes,而且在Service 定义中可以非常方便地引用这些秘密信息,实现安全的容器编排。
首先,我们利用命令行创建秘密
$ echo "Password4DB" | docker secret create wp_db_password -
$ echo "Password4Root" | docker secret create root_db_password -
然后利用命令行部署compose模板
$ docker stack deploy -c docker-compose.yml wordpress
Creating network wordpress_default
Creating service wordpress_wordpress
Creating service wordpress_mariadb
由于我们为 “wordpress” 服务定义了 routing mesh 的端口映射,将8080端口暴露为服务的访问端口。我们可以打开浏览器,输入 http://127.0.0.1:8080 之后,就可以看到 WordPress 著名的配置页面了。
关于更多关于 Docker 编排能力的说明,请参见Docker 1.13 编排能力进化
阿里云容器服务中使用 Docker Secrets
首先,我们需要创建一个Docker Swarm Mode集群。注意在集群模式中选择 Docker Swarm Mode。目前它还在 Beta 公测阶段,在华东2、美西1等地域开放。
创建集群之后,它会自动构成一个 Docker Swarm集群。
选择集群,点击 “管理” >> “秘钥管理” >> “创建”,来创建新的secret
然后退回容器服务控制台,创建Docker Compose V3模板。
选择 “镜像与方案” >> “编排模板” >> “创建”,使用如下内容创建模板 “wordpressv3-secret”
version: "3.1"
services:
wordpress:
image: wordpress:latest
secrets:
- wp_db_password
environment:
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_DB_PASSWORD_FILE=/run/secrets/wp_db_password
- WORDPRESS_DB_HOST=mariadb
labels:
aliyun.routing.port_80: wordpress
deploy:
replicas: 3
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
mariadb:
image: mariadb
secrets:
- wp_db_password
- root_db_password
environment:
- MYSQL_USER=wordpress
- MYSQL_DATABASE=wordpress
- MYSQL_PASSWORD_FILE=/run/secrets/wp_db_password
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/root_db_password
deploy:
replicas: 1
restart_policy:
condition: on-failure
secrets:
wp_db_password:
external: true
root_db_password:
external: true
和上面示例模板一致,它会使用集群中的 secret “wp_db_password” 和 “root_db_password” 来配置数据库密码和root密码。
与之前示例唯一不同的地方在于,在本模板中使用 aliyun.routing.port_80: wordpress
标签来指明:将虚拟域名 “wordpress” 的请求路由到容器的 80 端口进行处理。这样无需在集群上暴露额外的端口,就可以直接通过7层负载均衡来访问应用了。容器服务内置了7层负载均衡和路由能力。
选择“创建应用”,输入应用名称和部署集群,点击“下一步”
在“应用配置”页面,选择“创建并部署”,
创建完毕,在应用页面就可以看见新的容器应用,在其部署就绪之后,我们可以点击应用名称进入应用管理界面,查看服务和容器信息。
在路由列表,我们可以发现应用注册过的路由地址,
点击之后,可以进入“WordPress”的配置页面了,是不是很方便呢:-)
关于更多关于阿里云容器服务支持Swarm Mode的信息,请阅读相应文章。
Docker secret 实现原理
Docker 在Swarm mode集群设计中采用了系统化的安全设计。 用户创建的 Secrets,会以加密的方式存储在集群中 Manager节点的 Raft Store中。在创建服务时,Secrets 会下发到服务任务所处的 Worker 节点,并以 tmpfs 的形式挂载在容器内部。从而保证了秘钥等敏感信息可以安全地在分布式集群上分发。通过这样的措施,即使集群中一台Worker节点被攻破,没有容器访问权限的人是无法获取相应秘密信息的。
在其他容器编排技术中,如Kubernetes也有类似的 Secrets 机制,然而在安全性上还存在较多的问题,期待在未来能够解决。
总结
安全无小事,微服务架构的应用对容器集群中安全地管理和分发秘密提出了更大的挑战。通过Docker Secret和Docker编排可以非常简洁、优雅地解决这个问题,帮助您打造安全的云原生应用执行环境。
容器服务的Swarm mode还在公测之中,陆续会有更多更酷的功能发布出来,也欢迎大家多提宝贵意见。
了解更多阿里云容器服务内容,请访问 https://www.aliyun.com/product/containerservice