Linux で docker-compose を使用して MongoDB バージョン 6 以降のレプリカ セットをデプロイし、SSL/TLS プロトコルを構成する

1. 環境を準備する

MongoDB レプリカ セットは、少なくとも 3 つのノード (奇数番号のノード) をデプロイします。データ セキュリティを確保するために、MongoDB ノードは異なるホストに分散できます。この例では、1 つのホストを使用して 3 つの MongoDB インスタンスをデプロイします。

1. MongoDB クラスターのデータ関連ディレクトリを作成します。
# 创建 MongoDB 集群根目录及 3 个子目录
mkdir -p /mongodb-cluster/{
    
    mongo01, mongo02, mongo03}

# 创建 3 个 MongoDB 下子目录
mkdir -p /mongodb-cluster/mongo01/{
    
    certs, configdb, data, db, logs}
mkdir -p /mongodb-cluster/mongo02/{
    
    certs, configdb, data, db, logs}
mkdir -p /mongodb-cluster/mongo03/{
    
    certs, configdb, data, db, logs}

# 准备给上面 logs 目录赋予操作权限(注意:未赋予 logs 目录权限,运行会报错)
chmod 777 /mongodb-cluster/mongo01/logs
chmod 777 /mongodb-cluster/mongo01/logs
chmod 777 /mongodb-cluster/mongo01/logs
2. サーバー、クラスターの内部メンバー、およびクライアントに関連する証明書を生成します。

MongoDB レプリカ セットのデプロイメントにより、クラスター メンバーとクライアントは、通信の信頼性を確保するために認証を通じてサーバーと通信する必要があります。現在、MongoDB は通信認証に次の方法を提供します。

security.clusterAuthMode

タイプ: 文字列

デフォルト: キーファイル

クラスター認証に使用される方式。内部 x.509 認証を使用する場合は、ここで指定します。このオプションには次のいずれかの値を指定できます。

価値 説明
keyFile 認証にはキーファイルを使用します。キーファイルのみが受け入れられます。
sendKeyFile ローリング アップグレードの目的で使用されます。認証のためにキーファイルが送信されますが、キーファイルと x.509 証明書の両方を受け入れることができます。
sendX509 ローリング アップグレードの目的で使用されます。認証のために x.509 証明書を送信しますが、キーファイルと x.509 証明書の両方を受け入れることができます。
x509 尊敬される。認証のために x.509 証明書を送信し、x.509 証明書のみを受け入れます。

上記のいくつかの通信認証方法を通じて、デフォルトの keyFile キー ファイル認証方法も最も単純であり、テスト環境でのみ使用できます。通常、サーバーとクライアント間の通信セキュリティのために x509 を使用します。認証方法、以下 I x509 方式を使用して TLS プロトコル認証を構成します。

注: ほとんどの CA 証明書はサードパーティ ベンダーによって提供されており、課金する必要があります。(ここではopensslで自己署名CA証明書を生成し、通信認証を実現しています)。

自己署名証明書の生成
(1)、ルート証明書 ca.pem を生成します。
# 生成 CA 私钥(ca.key)(不加密)
openssl genrsa -out ca.key 2048
# 生成 CA 证书签名请求(ca.csr)
# 每个集群成员证书和服务端证书中必须具有相同的 O、OU 和 DC (具体可参考:https://www.mongodb.com/docs/manual/core/security-x.509)
openssl req -new -key ca.key -out ca.csr # 注意:在执行这条命令后,需要按要求填写内容,最后面两项可选,密码可不填
# 生成自签名 CA 证书(ca.pem), 直接免费 100 年有效
openssl x509 -req -days 36500 -in ca.csr -signkey ca.key -out ca.pem
(2)、サーバー証明書server.pemを生成します。
# 生成 server 端私钥 (server.key) 不加密
openssl genrsa -out server.key 2048
# 生成 server 证书签名请求 (server.csr)
openssl req -new -key server.key -out server.csr # 注意:输入内容和上面的保持一致
# 使用 ca 证书签署服务端 csr 以生成服务端证书 (server.crt) 
openssl ca -days 36500 -in server.csr -out server.crt -cert ca.pem -keyfile ca.key # 注意:执行这条命令会出现 2 处错误,按如下方式解决,再执行

# 第一个错误
/etc/pki/CA/index.txt No such file or directory
# 直接执行如下命令
touch /etc/pki/CA/index.txt

# 第二个错误
/etc/pki/CA/serial No such file or directory
# 直接执行如下命令后,文件里面输入数字,如:01,再保存 
vim /etc/pki/CA/serial

# 解决完问题后,再执行上面的命令对证书进行签名(后面输入区域,都输入 y 即可)
openssl ca -days 36500 -in server.csr -out server.crt -cert ca.pem -keyfile ca.key

# 删掉 server.crt 中的 certificate 信息,保留加密证书内容即可

# 合并证书和私钥成 PEM 文件, 构建命令如下:
cat server.key server.crt > server.pem

# 再验证自签名证书是否成功(返回,OK 代表成功)
openssl verify -CAfile ca.pem server.pem
(3) クライアント証明書 client.pem を生成します(手順はサーバーと同じですが、名前が少し変わります)
# 生成 client 端私钥 (client.key) 不加密
openssl genrsa -out client.key 2048
# 生成 client 证书签名请求 (client.csr)
openssl req -new -key client.key -out client.csr # 注意:输入内容和上面的保持一致
# 使用 ca 证书签署客户端 csr 以生成客户端证书 (client.crt) 
openssl ca -days 36500 -in client.csr -out client.crt -cert ca.pem -keyfile ca.key 
# 注意:这条命令运行后会出现 2 个错误,是因为之前签署了服务端证书,前面自己创建的两个文件已存在,所以,需要把 /etc/pki/CA 下的 index.txt 和 serial 文件删除,再重新执行该命令,再解决前面提到的错误就可以了

# 解决完问题后,再执行上面的命令对证书进行签名(后面输入区域,都输入 y 即可)
openssl ca -days 36500 -in client.csr -out client.crt -cert ca.pem -keyfile ca.key

# 删掉 client.crt 中的 certificate 信息,保留加密证书内容即可

# 合并证书和私钥成 PEM 文件, 构建命令如下:

cat client.key client.crt > client.pem

# 再验证自签名证书是否成功(返回,OK 代表成功)

openssl verify -CAfile ca.pem client.pem
(4) サーバー側のメンバー証明書cluster.pemを生成します(手順はクライアントと同じですが、名前が少し変わります)のでここでは書きません。
2. MongoDB クラスターのコア ファイルを作成し、構成します
1. 上記で生成されたすべての PEM 証明書を各 mongo の certs ディレクトリにコピーします。
# 执行如下命令
cp 文件路径 /mongodb-cluster/mongo01/certs
cp 文件路径 /mongodb-cluster/mongo02/certs
cp 文件路径 /mongodb-cluster/mongo03/certs

# 注意:确认包含如下 4 个文件
ca.pem  client.pem  cluster.pem  server.pem
2. 各サンプルの mongod.conf コア ファイルを作成し、設定します
# 创建 mongod.conf 配置文件
touch /mongodb-cluster/mongo01/configdb/mongod.conf
touch /mongodb-cluster/mongo02/configdb/mongod.conf
touch /mongodb-cluster/mongo03/configdb/mongod.conf

各サンプル mongod.conf ファイルに次の内容を書き込みます。

注: 各例で構成されているポート番号 27017 は、コンテナ内のポートであるため変更できませんが、要件に応じて変更することもできます。

net:
  bindIp: 0.0.0.0 # 配置允许所有主机连接,默认只能本地连接
  port: 27017 # 因为在一台主机中,三个示例的端口对应 27017、27018、27019 或者 其它不冲突的端口也可以
  tls:
    CAFile: /data/certs/ca.pem # 容器内映射路径,在本配置文件下,所有配置的路径都是容器路径,作为宿主机的映射路径
    certificateKeyFile: /data/certs/server.pem
    clusterFile: /data/certs/cluster.pem
    allowInvalidCertificates: true
    allowInvalidHostnames: true
    allowConnectionsWithoutCertificates: true
    mode: requireTLS # MongoDB 认证模型,使用 TLS, 默认不使用 TLS
processManagement:
  fork: false  # 是否开启以守护进程模式在后台运行
replication:
  replSetName: rs0 # 副本集名称
security:
  clusterAuthMode: x509  # 集群安全认证模型使用 x509
  authorization: enabled # 启用基于 RBAC 权限访问操作
storage:
  engine: wiredTiger # 6.0 以上版本默认使用 wiredTiger 引擎, 从 4.2 版本移除了 MMAPv1 存储引擎
  # 具体参数配置可参考:https://www.mongodb.com/docs/manual/reference/configuration-options/#storage-options
  wiredTiger:
      engineConfig:
         cacheSizeGB: 0.5
         journalCompressor: zstd # 默认使用 snappy 方式压缩,这里使用 zstd 高效压缩方式 
         zstdCompressionLevel: 6 # 设置 zstd 方式压缩级别,默认为 6, 范围:1-22, 级别越高,压缩率也越高
      collectionConfig:
         blockCompressor: zstd
      indexConfig:
         prefixCompression: true # 开启索引前缀压缩
systemLog:
  destination: file  # 日志存储方式为 file, 默认为 system_log 输出方式
  logAppend: true # 是否开启日志追加,默认为 false
  path: /data/logs/mongod.log  # 日志存储路径
3. docker-compose.yaml デプロイメント ファイルを作成する
# 创建 docker-compose.yaml 文件
touch /mongodb-cluster/docker-compose.yaml

次の内容を docker-compose.yaml ファイルに書き込みます。

version: "3.9"
services:
  mongo01:
    container_name: mongo01 # 容器名
    image: mongo # 拉取的镜像,未指定版本,默认 latest 最新版
    ports:
      - 27017:27017 # 容器内端口号映射,如:宿主机端口:容器端口
    environment:
      TZ: Asia/Shanghai # 配置时区信息
    volumes:
      - /etc/localtime:/etc/localtime
      - ./mongo01/db:/data/db  # 挂载数据 db 目录, 默认容器内是 /data/db, 因为前面没配置 storage.dbPath 路径
      - ./mongo01/configdb:/data/configdb # 挂载前面的 mongod.conf 配置文件, 默认容器内 /data/configdb
      - ./mongo01/certs:/data/certs # 这个是自定义挂载的 TLS 相关配置
      - ./mongo01/logs:/data/logs # 挂载容器内日志目录
    restart: always
    command: mongod --replSet rs0 -f /data/configdb/mongod.conf # 容器启动后,需要执行的命令
    networks:
      - mongo_network # 使用自定义网络
  mongo02:
    container_name: mongo02
    image: mongo
    ports:
      - 27018:27018
    environment:
      TZ: Asia/Shanghai
    volumes:
      - /etc/localtime:/etc/localtime
      - ./mongo02/db:/data/db
      - ./mongo02/configdb:/data/configdb
      - ./mongo02/certs:/data/certs
      - ./mongo02/logs:/data/logs
    restart: always
    command: mongod --replSet rs0 -f /data/configdb/mongod.conf
    networks:
      - mongo_network
  mongo03:
    container_name: mongo03
    image: mongo
    ports:
      - 27019:27019
    environment:
      TZ: Asia/Shanghai
    volumes:
      - /etc/localtime:/etc/localtime
      - ./mongo03/db:/data/db
      - ./mongo03/configdb:/data/configdb
      - ./mongo03/certs:/data/certs
      - ./mongo03/logs:/data/logs
    restart: always
    command: mongod --replSet rs0 -f /data/configdb/mongod.conf
    networks:
      - mongo_network 
# 创建容器网络
networks:
  mongo_network:
    name: mongo_network
3. MongoDB クラスターを起動し、クライアント認証を初期化および構成します。
1.MongoDBクラスターを起動します。
# 使用如下命令启动
docker-compose up -d

# 查看容器日志(未输出错误信息或没有日志信息则成功)
docker logs -f mongo01 -n 100

# 需要查看具体容器输出日志,可在前面配置的日志目录中查看
2. コンテナーの 1 つを入力し、クラスターを初期化します (3 つの例のいずれかを入力できますが、初期化する必要があるのは 1 つのコンテナーのみです)。
# 进入容器
docker exec -it mongo01 /bin/bash

# 进入 mongo 服务端, 需要指定客户端签名证书(注意:MongoDB 6.0 以上版本, 客户端命令为 mongosh)
# --host 是你前面生成签名证书时填的 Common Name 的值, 简称:CN, 可根据需求填写, 配置写错了, 会导致连接有问题
# 具体可参考:https://www.mongodb.com/docs/manual/core/security-x.509
mongosh --tls --tlsCertificateKeyFile /data/certs/client.pem --tlsCAFile /data/certs/ca.pem --host localhost --port 27017

# 进入 mongo 服务端后,需要先创建一个用户并赋予权限,不然,操作会出错
# 执行如下命令, 创建用户(注意:在执行命令之前,需要先 use admin 切换到 admin 库)
# 具体可参考:https://www.mongodb.com/docs/manual/reference/built-in-roles
db.createUser(
	{
    
    
		user:"root", # 用户名
		pwd:"123456", # 密码
		roles:[{
    
    role:"root",db:"admin"}] # 可配置多个角色, root 角色表示拥有超级用户角色, 作用于 admin 数据库
	}
);

# 使用刚创建的 root 用户登录认证, 进行执行接下来的操作
# root 用户登录认证(注意:需要在 admin 库执行, use admin 切换命令)
db.auth("root", "123456")
# 执行如下命令,初始化 mongo 副本集, 返回 ok 代表已初始化成功
rs.initiate( {
    
    
   _id : "rs0", # 副本集名称
   members: [
      {
    
     _id: 0, host: "172.21.0.3:27017" }, # mongo 实例 IP, 配置成宿主机 IP 即可
      {
    
     _id: 1, host: "172.21.0.4:27018" },
      {
    
     _id: 2, host: "172.21.0.2:27019" }
   ]
})

# 再执行 rs.status() 命令查看集群状态, 也可通过 rs.conf() 命令查看集群节点配置信息
3. x509 証明書を使用してクライアントを認証する

x.509 証明書をユーザーのサブジェクトとして追加する クライアント証明書を認証に使用するには、まずクライアント証明書の値サブジェクトを MongoDB ユーザーとして $external データベースに追加する必要があります。それぞれの一意の x.509 クライアント証明書は、MongoDB ユーザーに対応します。単一のクライアント証明書を使用して複数の MongoDB ユーザーを認証することはできません。詳細については、https: //www.mongodb.com/docs/manual/tutorial/configure-x509-client-authenticationを参照してください。

# 在宿主机上执行如下命令(注意:client.pem 是前面生成的客户端签名证书)
# 使用以下命令从客户端证书中检索 RFC2253 格式化:subject
openssl x509 -in client.pem -inform PEM -subject -nameopt RFC2253

# 该命令会返回 subject 字符串和证书:
subject= CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry
-----BEGIN CERTIFICATE-----
# ...
-----END CERTIFICATE-----

# 添加作为用户 RFC2253 的合规值, subject 根据需要省略空格。
# 首先, 需要进入主节点容器内 mongo 服务端, 执行如下操作:
# 进入容器
docker exec -it mongo01 /bin/bash
# 进入 mongo 服务端
mongosh --tls --tlsCertificateKeyFile /data/certs/client.pem --tlsCAFile /data/certs/ca.pem --host localhost --port 27017
# 需要切换为 admin 库, use admin 命令, 再执行 root 用户认证命令
db.auth("root", "123456")

# 以下添加一个用户并授予该用户 readWrite 在数据库中的角色 test 和 root 角色:
db.getSiblingDB("$external").runCommand(
  {
    
    
    createUser: "[email protected],CN=localhost,OU=BND,O=BN,ST=JS,C=CN",
    roles: [
         {
    
     role: "readWrite", db: "test" },
         {
    
     role: "root", db: "admin" }
    ],
    writeConcern: {
    
     w: "majority" , wtimeout: 5000 }
  }
)

# 客户端连接后认证, 使用如下命令:
db.getSiblingDB("$external").auth(
  {
    
    
    mechanism: "MONGODB-X509"
  }
)

# 客户端连接期间进行身份认证, 执行如下命令:
mongosh --tls --tlsCertificateKeyFile client.pem \
    --tlsCAFile ca.pem \
    --authenticationDatabase '$external' \
    --authenticationMechanism MONGODB-X509
4. MongoDB レプリカ セットのデータ同期をテストする
1. メインコンテナにデータを書き込み、スレーブコンテナに入ってクエリを実行します
# 进入主容器
docker exec -it mongo01 /bin/bash

# 进入 mongo 服务端
mongosh --tls --tlsCertificateKeyFile /data/certs/client.pem --tlsCAFile /data/certs/ca.pem --host localhost --port 27017

# 切换 admin 库, use admin 命令
use admin
# db 认证
db.auth("root", "123456")
# 插入一条数据在 test 库中, 文档不存在会自动创建
db.test.insertOne( {
    
     x: 1 } )
# 查询数据
db.test.find()

# 然后, 下面再从容器里面查看是否有数据
docker exec -it mongo02 /bin/bash # 进入从容器
mongosh --tls --tlsCertificateKeyFile /data/certs/client.pem --tlsCAFile /data/certs/ca.pem --host localhost --port 27018 # 进入 mongo 服务端

use admin # 切换 admin
db.auth("root", "123456") # db 认证
db.test.find() # 查询数据, 这里会出错, 默认是强制读主的, 不允许从节点进行读操作, 只能作为备份和高可用, 需要显示开启读操作

# 解决方案, 如下:
rs.secondaryOk() or db.getMongo().setReadPref("primaryPreferred")
# 这两条命令执行其中一条即可, 再次执行 db.test.find() 查询数据就能读到了
# 注意:rs.secondaryOk() 命令在新版本被弃用了, 建议使用:db.getMongo().setReadPref("primaryPreferred") 命令进行操作
5. Navicat クライアントを使用して MongoDB レプリカ セットに接続します
1. クライアント署名証明書と CA 証明書をサーバーにエクスポートします

含まれているもの: ca.pem および client.pem の 2 つのファイル

2. 以下の図に示すように、Navicat を使用して接続します。

ここに画像の説明を挿入

次の図に示すように、接続用の SSL モードの構成と有効化を続けます。

ここに画像の説明を挿入

次に、「接続のテスト」をクリックして正常に接続します。

6. その他
1. コピーを追加するには、マスター ノードへのログインの下に入力します。
rs.add("ip:port")
2. コピーを削除します
rs.remove("ip:port")
3. 新しい調停ノード
rs.addArb("ip:port")
4. レプリカ セット内のノード IP を変更します。
# 声明 cfg 变量
cfg = rs.conf()

# 执行修改各节点的 IP
cfg.members[0].host = "192.xxx.xxx.121:27017"
cfg.members[1].host = "192.xxx.xxx.121:27018"
cfg.members[2].host = "192.xxx.xxx.121:27019"

# 重新加载配置
rs.reconfig(cfg)

# 查询副本集状态
rs.status()

# 查询副本集配置
rs.conf()
7. SpringBoot は MongoDB レプリカ セットを統合します

次の記事に進む: SpringBoot は MongoDB バージョン 6 以降のレプリカ セットを統合し、SSL/TLS プロトコルを構成する

おすすめ

転載: blog.csdn.net/weixin_43322048/article/details/129190278