如何在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 NamePEM 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.pemserver.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 提供了有关创建用户的更多信息,并且是迈向生产就绪设置的一个很好的下一步。