使用 MYSQL_ALLOW_EMPTY_PASSWORD=yes 运行 docker mariadb/mysql 的安全风险

这是互联网上常见的 docker-compose.yml 的一部分

docker-compose.yml
services:
  mariadb:
    image: 'mariadb:latest'
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
      - MYSQL_DATABASE=redmine
    volumes:
      - './mariadb_data:/var/lib/mysql'
 [...]

简单且安全,对吧?一个无 root 密码的 MariaDB 实例运行在单独的容器中,并且没有暴露其端口 3306 - 因此只有来自相同 docker-compose.yml 的服务可以访问它,因为 docker-compose 将所有这些服务放在单独的网络中。

错误。

虽然 MariaDB 实例无法从互联网访问,因为它可以通过其内部 IP 地址被任何进程访问。

为了理解发生了什么,我们来看看 docker 的网络。在这种情况下,我的 docker-compose 配置名为 redmine

docker_network_ls.txt
$ docker network ls | grep redmine
ea7ed38f469b        redmine_default           bridge              local

这是 docker-compose 在没有任何显式网络配置的情况下创建的网络。让我们 inspect 网络以显示主机:

docker_network_inspect.json
[
    // [...]
        "Containers": {
            "2578fc65b4dab9f204d0a252e421dd4ddd9f41c35642d48350f4e59370581757": {
                "Name": "redmine_mariadb_1",
                "EndpointID": "1e6d81acc096a12fc740173f4e107090333c42e8a86680ac5c9886c148d578e7",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "7867f71d2a36265c34c133b70aea487b90ea68fcf30ecb42d6e7e9a376cf8e07": {
                "Name": "redmine_redmine_1",
                "EndpointID": "f5ac7b3325aa9bde12f0c625c4881f9a6fc9957da4965767563ec9a3b76c19c3",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
    // [...]
]

我们可以看到 redmine_mariadb_1 容器的 IP 地址是 172.18.0.2

使用内部 IP 172.18.0.2,你可以访问 MySQL 服务器。

主机上的任何进程(甚至来自非特权用户)都可以无密码连接到容器,例如

mysqldump_no_password.sh
$ mysqldump -uroot -h172.18.0.2 --all-databases
// 这将显示整个 MariaDB 数据库的转储

如何缓解此安全风险?

缓解相当容易,因为我们只需要为 MariaDB 实例设置 root 密码

我推荐的最佳实践是避免重复密码。为此,在 docker-compose.yml 所在的目录中创建一个 .env 文件。

mariadb.env
MARIADB_ROOT_PASSWORD=aiPaipei6ookaemue4voo0NooC0AeH

记住将密码替换为随机密码或使用此 shell 脚本自动创建:

generate_mariadb_env.sh
echo MARIADB_ROOT_PASSWORD=$(pwgen 30) > .env

现在我们可以在 docker-compose.yml 中需要 MariaDB root 密码的任何地方使用 ${MARIADB_ROOT_PASSWORD},例如:

docker-compose.yml
services:
  mariadb:
    image: 'mariadb:latest'
    environment:
      - MYSQL_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
      - MYSQL_DATABASE=redmine
    volumes:
      - './mariadb_data:/var/lib/mysql'
  redmine:
    image: 'redmine:latest'
    environment:
      - REDMINE_USERNAME=admin
      - REDMINE_PASSWORD=redmineadmin
      - REDMINE_EMAIL=ukoehler@techoverflow.net
      - REDMINE_DB_MYSQL=mariadb
      - REDMINE_DB_USERNAME=root
      - REDMINE_DB_PASSWORD=${MARIADB_ROOT_PASSWORD}
    ports:
      - '3718:3000'
    volumes:
      - './redmine_data/conf:/usr/src/redmine/conf'
      - './redmine_data/files:/usr/src/redmine/files'
      - './redmine_themes:/usr/src/redmine/public/themes'
    depends_on:
      - mariadb

Check out similar posts by category: Databases, Docker, Linux