[英]How to connect from node js to mongodb replica set using SSL
我試圖連接到mongodb副本集,該副本集設置為使用SSL對客戶端進行身份驗證。 我可以使用mongo shell進行連接,但是由於某些原因無法使用相同的鍵從node.js連接。
我正在使用在Mac上運行的mongodb版本3.2.6和node.js驅動程序版本2.1.18。
我遵循了這篇文章 ,並且能夠通過運行附加的腳本在本地計算機上設置集群:
# Prerequisites:
# a. Make sure you have MongoDB Enterprise installed.
# b. Make sure mongod/mongo are in the executable path
# c. Make sure no mongod running on 27017 port, or change the port below
# d. Run this script in a clean directory
##### Feel free to change following section values ####
# Changing this to include: country, province, city, company
dn_prefix="/C=CN/ST=GD/L=Shenzhen/O=MongoDB China"
ou_member="MyServers"
ou_client="MyClients"
mongodb_server_hosts=( "server1" "server2" "server3" )
mongodb_client_hosts=( "client1" "client2" )
mongodb_port=27017
# make a subdirectory for mongodb cluster
kill $(ps -ef | grep mongod | grep set509 | awk '{print $2}')
#rm -Rf db/*
mkdir -p db
echo "##### STEP 1: Generate root CA "
openssl genrsa -out root-ca.key 2048
# !!! In production you will want to use -aes256 to password protect the keys
# openssl genrsa -aes256 -out root-ca.key 2048
openssl req -new -x509 -days 3650 -key root-ca.key -out root-ca.crt -subj "$dn_prefix/CN=ROOTCA"
mkdir -p RootCA/ca.db.certs
echo "01" >> RootCA/ca.db.serial
touch RootCA/ca.db.index
echo $RANDOM >> RootCA/ca.db.rand
mv root-ca* RootCA/
echo "##### STEP 2: Create CA config"
# Generate CA config
cat >> root-ca.cfg <<EOF
[ RootCA ]
dir = ./RootCA
certs = \$dir/ca.db.certs
database = \$dir/ca.db.index
new_certs_dir = \$dir/ca.db.certs
certificate = \$dir/root-ca.crt
serial = \$dir/ca.db.serial
private_key = \$dir/root-ca.key
RANDFILE = \$dir/ca.db.rand
default_md = sha256
default_days = 365
default_crl_days= 30
email_in_dn = no
unique_subject = no
policy = policy_match
[ SigningCA ]
dir = ./SigningCA
certs = \$dir/ca.db.certs
database = \$dir/ca.db.index
new_certs_dir = \$dir/ca.db.certs
certificate = \$dir/signing-ca.crt
serial = \$dir/ca.db.serial
private_key = \$dir/signing-ca.key
RANDFILE = \$dir/ca.db.rand
default_md = sha256
default_days = 365
default_crl_days= 30
email_in_dn = no
unique_subject = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = CA:true
EOF
echo "##### STEP 3: Generate signing key"
# We do not use root key to sign certificate, instead we generate a signing key
openssl genrsa -out signing-ca.key 2048
# !!! In production you will want to use -aes256 to password protect the keys
# openssl genrsa -aes256 -out signing-ca.key 2048
openssl req -new -days 1460 -key signing-ca.key -out signing-ca.csr -subj "$dn_prefix/CN=CA-SIGNER"
openssl ca -batch -name RootCA -config root-ca.cfg -extensions v3_ca -out signing-ca.crt -infiles signing-ca.csr
mkdir -p SigningCA/ca.db.certs
echo "01" >> SigningCA/ca.db.serial
touch SigningCA/ca.db.index
# Should use a better source of random here..
echo $RANDOM >> SigningCA/ca.db.rand
mv signing-ca* SigningCA/
# Create root-ca.pem
cat RootCA/root-ca.crt SigningCA/signing-ca.crt > root-ca.pem
echo "##### STEP 4: Create server certificates"
# Now create & sign keys for each mongod server
# Pay attention to the OU part of the subject in "openssl req" command
# You may want to use FQDNs instead of short hostname
for host in "${mongodb_server_hosts[@]}"; do
echo "Generating key for $host"
openssl genrsa -out ${host}.key 2048
openssl req -new -days 365 -key ${host}.key -out ${host}.csr -subj "$dn_prefix/OU=$ou_member/CN=${host}"
openssl ca -batch -name SigningCA -config root-ca.cfg -out ${host}.crt -infiles ${host}.csr
cat ${host}.crt ${host}.key > ${host}.pem
done
echo "##### STEP 5: Create client certificates"
# Now create & sign keys for each client
# Pay attention to the OU part of the subject in "openssl req" command
for host in "${mongodb_client_hosts[@]}"; do
echo "Generating key for $host"
openssl genrsa -out ${host}.key 2048
openssl req -new -days 365 -key ${host}.key -out ${host}.csr -subj "$dn_prefix/OU=$ou_client/CN=${host}"
openssl ca -batch -name SigningCA -config root-ca.cfg -out ${host}.crt -infiles ${host}.csr
cat ${host}.crt ${host}.key > ${host}.pem
done
echo ""
echo "##### STEP 6: Start up replicaset in non-auth mode"
mport=$mongodb_port
for host in "${mongodb_server_hosts[@]}"; do
echo "Starting server $host in non-auth mode"
mkdir -p ./db/${host}
mongod --replSet set509 --port $mport --dbpath ./db/$host \
--fork --logpath ./db/${host}.log
let "mport++"
done
sleep 3
# obtain the subject from the client key:
client_subject=`openssl x509 -in ${mongodb_client_hosts[0]}.pem -inform PEM -subject -nameopt RFC2253 | grep subject | awk '{sub("subject= ",""); print}'`
echo "##### STEP 7: setup replicaset & initial user role\n"
myhostname=`hostname`
cat > setup_auth.js <<EOF
rs.initiate();
mport=$mongodb_port;
mport++;
rs.add("$myhostname:" + mport);
mport++;
rs.add("$myhostname:" + mport);
sleep(5000);
db.getSiblingDB("\$external").runCommand(
{
createUser: "$client_subject",
roles: [
{ role: "readWrite", db: 'test' },
{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "clusterAdmin", db:"admin"}
],
writeConcern: { w: "majority" , wtimeout: 5000 }
}
);
EOF
cat setup_auth.js
mongo localhost:$mongodb_port setup_auth.js
kill $(ps -ef | grep mongod | grep set509 | awk '{print $2}')
sleep 3
echo "##### STEP 8: Restart replicaset in x.509 mode\n"
mport=$mongodb_port
for host in "${mongodb_server_hosts[@]}"; do
echo "Starting server $host"
mongod --replSet set509 --port $mport --dbpath ./db/$host \
--sslMode requireSSL --clusterAuthMode x509 --sslCAFile root-ca.pem \
--sslAllowInvalidHostnames --fork --logpath ./db/${host}.log \
--sslPEMKeyFile ${host}.pem --sslClusterFile ${host}.pem
let "mport++"
done
# echo "##### STEP 9: Connecting to replicaset using certificate\n"
cat > do_login.js <<EOF
db.getSiblingDB("\$external").auth(
{
mechanism: "MONGODB-X509",
user: "$client_subject"
}
)
EOF
# mongo --ssl --sslPEMKeyFile client1.pem --sslCAFile root-ca.pem --sslAllowInvalidHostnames --shell do_login.js
運行集群后,我可以使用mongo shell通過以下命令連接到該集群(所有密鑰/證書均在./ssl目錄中生成):
mongo --ssl --sslPEMKeyFile ssl/client1.pem --sslCAFile ssl/root-ca.pem --sslAllowInvalidHostnames
並進行如下認證:
db.getSiblingDB("$external").auth(
{
mechanism: "MONGODB-X509",
user: "CN=client1,OU=MyClients,O=MongoDB China,L=Shenzhen,ST=GD,C=CN"
}
)
當我嘗試從node.js連接時,我一直失敗。 我正在運行以下代碼以使用本機mongo驅動程序連接到mongo:
'use strict';
const mongodb = require('mongodb');
const P = require('bluebird');
const fs = require('fs');
function connect_mongodb() {
let user = 'CN=client1,OU=MyClients,O=MongoDB China,L=Shenzhen,ST=GD,C=CN';
let uri = `mongodb://${encodeURIComponent(user)}@localhost:27017,localhost:27018,localhost:27019/test?replicaSet=set509&authMechanism=MONGODB-X509&ssl=true`;
var ca = [fs.readFileSync("./ssl/root-ca.pem")];
var cert = fs.readFileSync("./ssl/client1.pem");
var key = fs.readFileSync("./ssl/client1.pem");
let options = {
promiseLibrary: P,
server: {
ssl: true,
sslValidate: false,
checkServerIdentity: false,
sslCA: ca,
sslKey: key,
sslCert: cert,
},
replset: {
sslValidate: false,
checkServerIdentity: false,
ssl: true,
sslCA: ca,
sslKey: key,
sslCert: cert,
}
};
return mongodb.MongoClient.connect(uri, options);
}
connect_mongodb();
運行腳本時,出現以下錯誤:
Unhandled rejection MongoError: no valid seed servers in list
檢查mongodb日志時,我看到以下錯誤:
2017-01-17T22:48:54.191+0200 I NETWORK [initandlisten] connection accepted from 127.0.0.1:63881 #99 (5 connections now open)
2017-01-17T22:48:54.207+0200 E NETWORK [conn99] no SSL certificate provided by peer; connection rejected
2017-01-17T22:48:54.207+0200 I NETWORK [conn99] end connection 127.0.0.1:63881 (4 connections now open)
我嘗試了此處介紹的其他選項,但沒有成功。
謝謝您的幫助
升級到mongodb node js驅動程序2.2.22解決了該問題
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.