如何使用OpenVPN和Docker在Ubuntu 16.04上运行安全的MongoDB服务器

MongoDB是一个开源的NoSQL数据库。传统的MongoDB设置缺少一些您担心数据安全性的安全功能。有几种方法来保护运行数据库的服务器。首先,您可以设置VPN并限制...

MongoDB是一个开源的NoSQL数据库。传统的MongoDB设置缺少一些您担心数据安全性的安全功能。 有几种方法来保护运行数据库的服务器。首先,您可以设置VPN,并限制只对连接到VPN的客户端的访问。然后,您可以使用证书加密客户端和服务器之间的传输层。您将在本教程中同时执行。此外,您将使用Docker来运行MongoDB实例,因此您可以确保您的MongoDB配置和证书在多个服务器上的可重用性。

先决条件

要完成本教程,您需要:
  • 一个OpenVPN服务器,您可以通过以下教程设置如何在Ubuntu 16.04上设置OpenVPN服务器 。 确保在创建服务器时检查“ 专用网络 ”框。
  • 安装了Docker的Ubuntu 16.04机器。 您将在此创建您的MongoDB Docker映像,以及在容器中运行MongoDB的位置。 要创建它,请在DigitalOcean管理控制台中单击Create Droplet ,然后选择一键应用 ,然后在16.04上选择Docker 1.x。启用此服务器上的私有网络。
  • 在两台服务器上都具有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
您应该看到类似以下的输出:
10.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
然后添加两个新规则,允许SSH和MongoDB仅从连接到VPN的计算机访问。为此,请使用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
您应该看到以下输出:
To                         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目录。 在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
同样在网段中,设置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解析器 。 然后, 使用我们的加密DNS挑战来验证新创建的内部网域,并为其颁发证书。 首先,转到~/mongoconf/config/ssl目录并生成服务器证书 - 密钥对。 填写您选择的信息提示。 注意Common NamePEM Passphrase字段。
cd ~/mongoconf/config/ssl
openssl req -new -x509 -days 365 -out server.crt -keyout server.key
您将看到以下输出,并将被要求提供一些细节:
. . .
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通行短语可以是您想要的这一步。
. . .
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 ,请将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 .
一旦图像建立,请根据图像运行容器。我们将把容器目录作为一个容器装载到容器中,这样我们可以在容器内的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有关于创建用户的更多信息,并且是一个向生产就绪安装程序迈出的重要一步。