如何在Ubuntu16.04上使用OpenVPN和Docker运行安全的MongoDB服务器
MongoDB 是一个开源的 NoSQL 数据库。 如果您担心数据安全,传统的 MongoDB 设置缺少一些您想要的安全功能。
有几种方法可以保护运行数据库的服务器。 首先,您可以设置 VPN 并将访问限制为仅连接到 VPN 的那些客户端。 然后您可以使用证书加密客户端和服务器之间的传输层。 您将在本教程中同时进行这两项操作。 此外,您将使用 Docker 来运行 MongoDB 实例,因此您可以确保 MongoDB 配置和证书在多个服务器上的可重用性。
先决条件
要完成本教程,您需要:
- 一个 OpenVPN 服务器,您可以按照教程 How To Set Up an OpenVPN Server on Ubuntu 16.04 进行设置。 确保在创建服务器时选中 私有网络 框。
- 安装了 Docker 的 Ubuntu 16.04 机器。 您将在这里创建 MongoDB Docker 映像,并在容器中运行 MongoDB。 要创建它,在DigitalOcean管理控制台中点击创建Droplet,选择一键式应用程序,然后选择Docker 1.x on 16.04。 也在此服务器上启用专用网络。
- 在两台服务器上都具有 sudo 权限的非 root 用户。 Ubuntu 16.04 的 初始设置指南解释了如何设置它。
- MongoDB 安装在您的本地机器上。 您将使用它来测试您与 MongoDB 服务器的连接。
第 1 步 — 配置 VPN 以转发到专用 IP 地址
如果您遵循先决条件 OpenVPN 文章,您很可能将服务器配置为将请求转发到公共网络接口,而不是专用网络接口。 在本教程中,我们将配置 MongoDB 服务器,使其只能在其私有接口上访问,我们只能通过我们的 VPN 连接进行访问。 我们需要修改 VPN 服务器上的 IP 转发规则,以便来自 VPN 客户端的流量也被路由到专用网络。
连接到您的 OpenVPN 服务器。
ssh sammy@vpn_server_public_ip
然后转到 DigitalOcean 仪表板,选择您的 VPN Droplet,并找到它的私有 IP 地址。
获得私有 IP 地址后,在 VPN Droplet 上执行此命令以识别使用该 IP 地址的网络接口:
sudo nano /etc/ufw/before.rules ip route | grep vpn_server_private_ip
您应该会看到类似于以下内容的输出:
Output10.132.0.0/16 dev eth1 proto kernel scope link src vpn_server_private_ip
记下输出中的网络接口。 在本例中,接口为 eth1
,但您的可能不同。
确定专用网络接口后,编辑文件 /etc/ufw/before.rules
:
sudo nano /etc/ufw/before.rules
找到您在先决条件教程中定义的部分,如下所示:
/etc/ufw/before.rules
# START OPENVPN RULES # NAT table rules *nat :POSTROUTING ACCEPT [0:0] # Allow traffic from OpenVPN client to eth0 -A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE COMMIT # END OPENVPN RULES
为专用网络接口添加新规则:
/etc/ufw/before.rules
# START OPENVPN RULES # NAT table rules *nat :POSTROUTING ACCEPT [0:0] # Allow traffic from OpenVPN client to eth0 -A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE -A POSTROUTING -s 10.8.0.0/8 -o eth1 -j MASQUERADE COMMIT # END OPENVPN RULES
请务必将 eth1
替换为专用网络的接口。 然后保存文件并退出编辑器。
禁用并重新启用防火墙:
sudo ufw disable sudo ufw enable
然后退出您的 VPN 服务器。
exit
现在建立从本地计算机到 VPN 服务器的 VPN 连接。 在本教程中保持此连接。
现在让我们使用它的私有 IP 地址连接到 MongoDB 服务器并配置它的防火墙。
第 2 步 – 设置 MongoDB 服务器的防火墙
我们将使用其私有 IP 地址连接到 MongoDB 服务器。 如果没有,请返回 DigitalOcean 仪表板并找到 MongoDB Docker Droplet 的私有 IP 地址。 您将在此处使用它连接到服务器,随后您将使用它直接连接到 MongoDB,因为我们即将对数据库服务器的访问限制为 VPN 客户端。 这样可以避免公开暴露数据库,这是必须具备的安全措施。
确保您已连接到您的 VPN,并使用其私有 IP SSH 到 MongoDB 服务器:
ssh sammy@mongodb_server_private_ip
登录后,删除所有现有的防火墙规则以防止外界访问:
sudo ufw delete limit ssh sudo ufw delete allow 2375/tcp sudo ufw delete allow 2376/tcp
然后添加两个新规则,只允许从连接到您的 VPN 的计算机上进行 SSH 和 MongoDB 访问。 为此,请使用您的 VPN 服务器的私有 IP 地址作为源 IP:
sudo ufw allow from vpn_server_private_ip to any port 22 proto tcp sudo ufw allow from vpn_server_private_ip to any port 28018 proto tcp
确保这些是配置的仅有的两个规则:
sudo ufw status
您应该看到以下输出:
OutputTo Action From -- ------ ---- 22/tcp ALLOW vpn_server_private_ip 28018/tcp ALLOW vpn_server_private_ip
启用防火墙并注销服务器:
sudo ufw enable exit
然后重新登录到 MongoDB 服务器,以确保在启用 IP 过滤器后您仍然可以访问服务器。
ssh sammy@mongodb_server_private_ip
如果您无法建立 SSH 连接,请确保您已连接到 VPN,并且您已设置 VPN 服务器以转发专用网络上的流量。 如果这不起作用,请使用 DigitalOcean Console 登录并检查防火墙规则。 确保您在规则中指定了 VPN 服务器的私有 IP,而不是 MongoDB 服务器的私有 IP。
要了解有关 UFW 的更多信息,请探索 这个 DigitalOcean UFW 教程 。
现在您已经配置了基本的安全措施,继续配置 MongoDB。
第 3 步 - 创建 MongoDB 配置文件
在这一步中,我们将创建一个自定义 MongoDB 配置,将 MongoDB 配置为使用 SSL 证书。
让我们创建一个目录结构来保存我们的配置和相关文件。 我们将创建一个名为 mongoconf
的目录,然后在其中为我们的配置文件创建一个 config
目录。 在 config
目录中,我们将创建一个名为 ssl
的目录,我们将在其中存储证书。
使用以下命令创建结构:
mkdir -p ~/mongoconf/config/ssl
然后切换到~/mongoconf/config
文件夹:
cd ~/mongoconf/config
使用文本编辑器打开一个名为 mongod.conf
的新文件:
nano mongod.conf
首先,将数据库设置为绑定到端口 28018
上的每个网络接口。 在这种情况下,绑定到 0.0.0.0
不是安全问题,因为防火墙无论如何都不允许来自外部世界的连接。 但我们确实需要允许来自 VPN 内部客户端的连接。 将以下内容添加到文件中:
mongodb.conf
net: bindIp: 0.0.0.0 port: 28018
同样在 net
部分,设置 SSL 证书的路径并指定证书密码。 我们将很快创建实际的证书文件和密码。
mongodb.conf
net: . . . ssl: CAFile: /etc/mongo/ssl/client.pem PEMKeyFile: /etc/mongo/ssl/server.pem PEMKeyPassword: test mode: requireSSL
最后,设置默认存储目录并启用日志。
mongodb.conf
. . . storage: dbPath: /mongo/db journal: enabled: true
要了解所有可用的配置选项,阅读 MongoDB 的文档。
现在,保存文件并退出编辑器。 是时候生成我们将使用的 SSL 证书了。
第 4 步 — 生成 SSL 证书
为了保证数据传输的安全,您需要为 MongoDB 生成两个 SSL 证书——一个用于服务器,一个用于将访问数据库的客户端。
注意: 我们在本教程中创建自签名证书。 在生产环境中,您将使用受信任的证书颁发机构来生成它们。
为此,您需要 设置私有 DNS 解析器 。 然后,使用 Let's Encrypt DNS challenge 来验证新创建的 Intranet 域并为它们颁发证书。
首先,切换到 ~/mongoconf/config/ssl
目录并生成服务器证书-密钥对。 在提示中填写您选择的信息。 注意 Common Name
和 PEM Passphrase
字段。
cd ~/mongoconf/config/ssl openssl req -new -x509 -days 365 -out server.crt -keyout server.key
您将看到以下输出,并在此过程中要求您提供一些详细信息:
Server certificate-key generation. . . Enter PEM pass phrase: test Verifying - Enter PEM pass phrase: test . . . Common Name (e.g. server FQDN or YOUR name) []: mongodb_server_private_ip . . .
当系统要求您输入 PEM 密码短语时,请确保您使用的值与您在上一步中的 MongoDB 配置文件中使用的值相同。
MongoDB 不接受单独的密钥和证书文件,因此将它们组合成一个 .pem
文件:
cat server.crt server.key >> server.pem
接下来,为客户端生成证书密钥对:
openssl req -new -x509 -days 365 -out client.crt -keyout client.key
您将遵循与以前相同的过程,但这次使用 VPN 服务器的私有 IP。 PEM 密码短语可以是您在此步骤中想要的任何内容。
Client certificate-key generation. . . Enter PEM pass phrase: secret_password Verifying - Enter PEM pass phrase: secret_password . . . Common Name (e.g. server FQDN or YOUR name) []: vpn_server_private_ip . . .
将您刚刚生成的文件连接成一个 .pem
文件:
cat client.crt client.key >> client.pem
接下来,将两个证书文件复制到本地计算机,以便您可以远程连接到 MongoDB 服务器。 您可以在本地计算机上使用 scp
命令执行此操作:
scp sammy@mongodb_server_private_ip:/home/sammy/mongoconf/config/ssl/\{client.pem,server.pem\} .
或者,您可以按照教程 如何使用 SFTP 通过远程服务器安全传输文件 将 client.pem
和 server.pem
文件传输到本地计算机。
现在让我们创建 Docker 映像并在容器中运行数据库引擎,以便此配置更便于移植。
第 5 步 — 创建 MongoDB Docker 映像并运行容器
您已经创建了一个安全的 MongoDB 配置并生成了证书。 现在让我们让它与 Docker 一起移植。 我们将为 MongoDB 创建一个自定义映像,但我们将在运行容器时传入我们的配置文件和证书。
要构建映像,您需要一个 Dockerfile。
注意:要在没有 sudo
的情况下运行 docker
,请将 sammy 添加到 docker 组:
sudo usermod -aG docker sammy
然后注销服务器并重新登录,以便新的组权限生效。
切换到项目的根目录并在编辑器中打开一个空的 Dockerfile:
cd ~/mongoconf nano Dockerfile
将以下内容添加到新文件中:
Dockerfile
FROM ubuntu:xenial RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 RUN echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.4.list RUN apt-get update && apt-get install -y mongodb-org RUN mkdir -p /mongo/db /etc/mongo EXPOSE 28018 ENTRYPOINT ["mongod", "--config", "/etc/mongo/mongod.conf"]
这个文件告诉 Docker 创建一个基于 Ubuntu 16.04 Xenial 的镜像,下载最新的 MongoDB 二进制文件,并创建一些目录来存储配置文件和数据库。 它使容器的端口 28018
对主机可用,并在每次用户重新启动容器时运行 Mongo。
注:为简单起见,我们的镜像是基于Ubuntu的。 但是,基于 Alpine Linux 等轻量级发行版构建的容器使用的磁盘空间更少。
保存文件并退出编辑器。 然后构建镜像:
docker build -t mongo .
构建镜像后,运行基于镜像的容器。 我们将 config
目录挂载为容器内的卷,以便我们的自定义配置和键对容器内的 MongoDB 实例可见:
docker run \ --detach \ --publish 28018:28018 \ --volume $PWD/config:/etc/mongo \ --name mongodb \ mongo
现在您有一个正在运行的 MongoDB 实例,可以从本地计算机访问它。
第 6 步 - 访问 MongoDB
在本地机器上的新终端中,使用 MongoDB 服务器的私有 IP 地址连接到数据库。 您将提供下载到本地计算机的 client.pem 和 server.pem 文件,以及创建客户端证书时使用的密码。 执行这个命令:
mongo \ --ssl \ --sslCAFile path_to_server_pem \ --sslPEMKeyFile path_to_client_pem \ --sslPEMKeyPassword pem_key_passphrase \ --host mongodb_server_private_ip \ --port 28018
如果一切正常,您应该会看到 MongoDB 提示符。
如果出现错误,请仔细检查您连接的是 MongoDB 服务器的私有 IP,而不是 VPN 服务器的 IP 地址。 还要验证密钥位置和密码是否正确,以及您与 VPN 的连接是否仍在运行。
结论
现在您有一个在 Docker 容器中运行的自定义配置的 MongoDB。 其安全性由 SSL 客户端-服务器身份验证和传输加密授予。 通过将防火墙配置为限制与连接到 VPN 服务器的客户端的数据库连接,您增加了额外的安全性。
尽管此设置最适合测试,但请记住,在生产环境中,您应该使用受信任的证书颁发机构和签名证书。 此外,您必须分析您的安全需求并采取相应措施。 例如,您可能希望在数据库中设置用户、密码和角色。 教程 如何在 Ubuntu 16.04 上安装和保护 MongoDB 提供了有关创建用户的更多信息,并且是迈向生产就绪设置的一个很好的下一步。