跳转到内容
搜索文档

MongoDB SSH

最后更新 查看 MarkdownAgent 设置

您可以使用 Cloudflare Access 和 Cloudflare Tunnel 构建 Zero Trust 规则,以保护到 MongoDB 部署的连接。Cloudflare Tunnel 需要一个轻量级守护程序 cloudflared 同时运行在部署端和客户端。

在本教程中,运行 cloudflared 的客户端通过 SSH 连接到运行在 Kubernetes 上的 MongoDB 部署。该部署示例旨在将 Compass 连接到 MongoDB 实例。MongoDB Kubernetes 部署将同时运行 MongoDB 数据库 service 和 cloudflared(作为类似于堡垒机的入站服务)。

本教程涵盖了如何:

  • 创建 Cloudflare Access 规则以保护 MongoDB 部署
  • 为部署配置 StatefulSet 和服务定义
  • 配置到 Cloudflare 边缘的 Cloudflare Tunnel 连接
  • 为客户端创建 SSH 配置文件

完成所需时间:

50 分钟


配置 Cloudflare Access

您可以在 Cloudflare Access 中构建一条规则,以控制谁可以连接到您的 MongoDB 部署。Cloudflare Access 规则围绕主机名构建;尽管可以通过 SSH 访问此部署,但在 Cloudflare 中该资源将被表示为主机名。例如,如果您的 Cloudflare 账户中拥有网站 app.com,则可以构建一条规则来保护 mongodb.app.com

  1. Cloudflare 仪表板中,转到 Zero Trust > Access controls(访问控制)> Applications(应用程序)

  2. 选择 Create new application(创建新应用程序)

  3. 选择 Self-hosted and private(自托管和私有)

  4. 选择 **Add public hostname(添加公共主机名)**并输入用户连接到您的部署的子域(例如 mongodb.app.com)。

  5. 添加 Access 策略以控制谁可以访问该部署。您可以构建一条允许组织中任何人连接的策略,或者您可以基于身份提供商组、多因素方法国家/地区等信号构建更细粒度的策略。

  6. 按照其余自托管应用程序创建步骤发布该应用程序。

配置 Kubernetes 部署

为了可以通过 SSH 访问,Kubernetes 部署应同时管理 MongoDB 独立服务和 SSH 代理服务。以下配置将部署 1 个数据库服务的副本(在端口 27017 上可用)以及一个 SSH 代理(在端口 22 上可用)。

StatefulSet Configuration

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb-standalone
  namespace: mongodb
spec:
  serviceName: database
  replicas: 1
  selector:
    matchLabels:
      app: database
  template:
    metadata:
      labels:
        app: database
        selector: mongodb-standalone
    spec:
      containers:
        - name: mongodb-standalone
          image: mongo
          command: ["mongod"]
          args: ["--config=/config/mongod.conf"]
          ports:
            - containerPort: 27017
              protocol: TCP
              name: mongod
          volumeMounts:
            - name: mongodb-conf
              mountPath: /config
              readOnly: true
            - name: mongodb-data
              mountPath: /data/db
            - name: tls
              mountPath: /etc/tls
            - name: mongodb-socket
              mountPath: /socket
        - name: ssh-proxy
          image: ubuntu:20.04
          command: ["/scripts/entrypoint.sh"]
          ports:
            - containerPort: 22
              protocol: TCP
              name: ssh-port
          volumeMounts:
            - name: mongodb-socket
              mountPath: /socket
            - name: scripts
              mountPath: /scripts
              readOnly: true
            - name: ssh-authorized-keys
              mountPath: /config/ssh
              readOnly: true
          resources:
            requests:
              cpu: 20m
              memory: 32Mi
      volumes:
        - name: mongodb-socket
          emptyDir: {}
        - name: mongodb-conf
          configMap:
            name: mongodb-standalone
            items:
              - key: mongod.conf
                path: mongod.conf
        - name: tls
          secret:
            secretName: tls
        - name: mongodb-data
          persistentVolumeClaim:
            claimName: mongodb-standalone
        - name: scripts
          configMap:
            name: scripts
            items:
              - key: entrypoint.sh
                path: entrypoint.sh
                mode: 0744
        - name: ssh-authorized-keys
          configMap:
            name: ssh-proxy-config
            items:
              - key: authorized_keys
                path: authorized_keys
                mode: 0400

相应的服务定义还应指定容器的端口和目标端口(在此情况下为数据库服务和 SSH 代理服务)。

Service Definition

apiVersion: v1
kind: Service
metadata:
  name: database
  namespace: mongodb
  labels:
    app: database
spec:
  clusterIP: None
  selector:
    app: database
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017
---
apiVersion: v1
kind: Service
metadata:
  name: ssh-proxy
  namespace: mongodb
  labels:
    app: database
spec:
  selector:
    app: database
  ports:
    - protocol: TCP
      port: 22
      targetPort: 22

MongoDB pod 和 SSH 堡垒机将通过空目录卷共享 Unix 套接字(socket)。堡垒机运行的 entrypoint.sh 文件(示例如下)将启动 OpenSSH 服务器。

#!/bin/sh
export TZ=America/Chicago
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
apt-get update -y && apt-get install -y openssh-server
mkdir /root/.ssh
cp /config/ssh/authorized_keys /root/.ssh/authorized_keys
chmod 400 /root/.ssh/authorized_keys
service ssh start
while true;
do sleep 30;
done;

配置 Cloudflare Tunnel

接下来,您可以使用 cloudflared 通过 Cloudflare Tunnel 连接到 Cloudflare 的边缘。首先下载并安装 Cloudflare Tunnel 守护程序 cloudflared

安装完成后,运行以下命令将 cloudflared 实例进行身份验证登录到您的 Cloudflare 账户。

cloudflared login

该命令将启动浏览器窗口并提示您登录您的 Cloudflare 账户。选择您已添加到账户中的网站。

在您选择账户中的一个网站后,Cloudflare 将下载一个名为 cert.pem 的证书文件以对该 cloudflared 实例进行身份验证。cert.pem 文件使用证书对您的 cloudflared 实例进行身份验证,并包含您账户的 API 密钥,用以执行诸如 DNS 记录修改等操作。

您现在可以使用 cloudflared 来控制您 Cloudflare 账户中的 Cloudflare Tunnel 连接。

下载证书

创建 Tunnel

您现在可以创建一个 Tunnel 以将 cloudflared 连接到 Cloudflare 的边缘。您将在下一步中配置该 Tunnel 的详细信息。

运行以下命令以创建一个 Tunnel。您可以将 mongodb 替换为任何您选择的名称。此命令需要 cert.pem 文件。

cloudflared tunnel create mongodb

Cloudflare 将以该名称创建 Tunnel,并为该 Tunnel 生成一个 ID 和凭证文件。

新建隧道

删除 cert.pem 文件

凭证文件与 cert.pem 文件是分开的。与 cert.pem 文件不同,凭证文件包含一个仅对您刚刚创建的命名 Tunnel 进行身份验证的令牌。该文件格式为 JSON,无法对您的 Cloudflare 账户进行更改,也无法创建其他 Tunnel。

如果您已完成 Tunnel 的创建,则可以删除 cert.pem 文件,仅保留凭证文件,并继续在 Cloudflare 仪表板或通过 API 直接管理 DNS 记录。有关这两个文件的不同功能的其他信息,请参阅常用术语列表。

JSON 文件存储为 Kubernetes 机密 (secret)。

配置 Cloudflare Tunnel

前面的步骤使用 cloudflared 为您的 Cloudflare 账户生成了凭证文件。当作为服务与 MongoDB Kubernetes 部署一起运行时,您将需要使用 cloudflared 的 Docker 镜像。Cloudflare 在 DockerHub 中提供了一个官方镜像

以下配置将运行 cloudflared 的单个副本作为与 MongoDB 和 SSH 代理服务并列的入站点。cloudflared 将把流量代理到 SSH 代理服务。cloudflared 实例将在不同的命名空间中作为其自身的 Deployment 运行,并且如果网络策略允许,将入站到 Kubernetes 节点中的任何服务。

cloudflared Configuration

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dashboard-tunnel
  namespace: argotunnel
  labels:
    app: dashboard-tunnel
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dashboard-tunnel
  template:
    metadata:
      labels:
        app: dashboard-tunnel
    spec:
      containers:
        - name: dashboard-tunnel
          # Image from https://hub.docker.com/r/cloudflare/cloudflared
          image: cloudflare/cloudflared:2020.11.11
          command: ["cloudflared", "tunnel"]
          args: ["--config", "/etc/tunnel/config.yaml", "run"]
          ports:
            - containerPort: 5000
          livenessProbe:
            tcpSocket:
              port: 5000
            initialDelaySeconds: 60
            periodSeconds: 60
          volumeMounts:
            - name: dashboard-tunnel-config
              mountPath: /etc/tunnel
            - name: tunnel-credentials
              mountPath: /etc/credentials
      volumes:
        - name: dashboard-tunnel-config
          configMap:
            name: dashboard-tunnel-config
        - name: tunnel-credentials
          secret:
            secretName: tunnel-credentials
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: dashboard-tunnel-config
  namespace: argotunnel
data:
  config.yaml: |
    tunnel: 9a00ef26-4997-4de2-83db-631efc74245c
    credentials-file: /etc/credentials/k8s-dashboard.json
    metrics: :5000
    protocol: http2
    no-autoupdate: true
    ingress:
    - hostname: mongodb.widgetcorp.tech
      originRequest:
        bastionMode: true
    - service: http_status:404

从客户端连接

部署完成后,您可以在客户端运行 cloudflared 以连接到 MongoDB 部署。将以下行添加到您的 SSH 配置文件中,并将示例替换为您的主机名和详细信息。--destination 的值应与先前配置的 SSH 代理服务的 URL 匹配。

Host mongodb
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname mongodb.widgetcorp.tech --destination ssh-proxy.mongodb.svc.cluster.local:22
  LocalForward 27000 /socket/mongodb-27017.sock
  User root
  IdentityFile /Users/username/.ssh/id_rsa

这是一次性步骤。当您下次尝试向该部署建立 SSH 连接时,cloudflared 将启动浏览器窗口并提示您进行身份验证。身份验证成功后,如果您拥有有效的会话,便可建立连接。一旦隧道建立,发送到您机器上 localhost:27000 的所有请求都将被转发到 SSH 代理容器上的 /socket/mongodb-27017.sock

您可以将 MongoDB Compass 设置为连接到 localhost:27000

这篇文档对您有帮助吗?