文章目錄
- 自定義證書
- 生成CA證書
- 生成服務器之間的證書
- 生成集群證書
- 生成用戶證書
- MongoDB配置
- java使用x.509證書連接MongoDB
- MongoShell使用證書連接
8.0版本的mongodb開啟復制集,配置證書認證
自定義證書
生成CA證書
生成ca私鑰: openssl genrsa -out ca.key 4096
# 生成RSA 4096位私鑰
生成ca證書: openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj "/CN=MongoDB Root CA/O=MyOrg/OU=Security"
驗證ca證書: openssl x509 -in ca.crt -text -noout
生成pkcs12格式的p12文件:后續用于java代碼認證
cat ca.crt ca.key > ca.pem
openssl pkcs12 -export -in ca.pem -out ca.p12 -password pass:123456
生成服務器之間的證書
生成服務器私鑰: openssl genrsa -out server.key 2048
生成證書簽名請求: openssl req -new -key server.key -out server.csr -subj "/CN=1.1.1.1/O=MyOrg/OU=Servers"
生成擴展配置文件(server.ext):
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage=digitalSignature, keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=DNS:mongodb-server.example.com,DNS:localhost,IP:192.168.1.100
用ca簽發證書: openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256 -extfile server.ext
合并證書與私鑰: cat server.crt server.key > server.pem
驗證服務器證書: openssl verify -CAfile ca.crt server.crt
# 應顯示 “OK”
生成集群證書
生成集群私鑰: openssl genrsa -out cluster.key 2048
生成CSR : openssl req -new -key cluster.key -out cluster.csr -subj "/CN=node1/O=MyOrg/OU=MongoDB-Cluster"
必須包含一致的 O(組織)或 OU(部門),否則集群節點無法相互認證。
生成擴展配置文件(cluster.ext):
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage=digitalSignature, keyEncipherment
extendedKeyUsage=clientAuth
ca簽發集群證書: openssl x509 -req -in cluster.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out cluster.crt -days 365 -sha256 -extfile cluster.ext
合并證書與私鑰: cat cluster.crt cluster.key > cluster.pem
驗證集群證書:
openssl x509 -in cluster.crt -text | grep "Subject:"
# 確認O/OU一致性
openssl verify -CAfile ca.crt cluster.crt
# 應顯示 “OK”
生成用戶證書
生成用戶私鑰: openssl genrsa -out zy1.key 2048
生成CSR : openssl req -new -key zy1.key -out zy1.csr -subj "/O=MyOrg/CN=zy1"
必須包含一致的 O(組織)或 OU(部門),否則集群節點無法相互認證。
生成擴展配置文件( zy1.ext):
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage=digitalSignature, keyEncipherment
extendedKeyUsage=clientAuth
ca簽發集群證書: openssl x509 -req -in zy1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out zy1.crt -days 365 -sha256 -extfile zy1.ext
合并證書與私鑰: cat zy1.crt zy1.key > zy1.pem
獲取subject : openssl x509 -in /usr/local/database/mongodb8.0.5/crt/zy1.pem -inform PEM -subject -nameopt RFC2253
生成pkcs12 格式的信任庫文件:
openssl pkcs12 -export -inkey zy1.pem -in zy1.pem -out zy1_pem.p12 -password pass:123456
測試PKCS12密碼正確性
keytool -list -v -keystore C:\Users\Administrator\Desktop\crt\zy1_pem.p12 -storetype pkcs12
MongoDB配置
mongodb配置:
# mongod.confnet:tls:mode: requireTLSCAFile: /path/to/ca.crtcertificateKeyFile: /path/to/server.pemclusterFile: /path/to/cluster.pemsecurity:clusterAuthMode: x509authorization: enabled
所有pem文件的權限都設為600 : chmod 600 ca.crt server.pem cluster.pem
客戶端的證書由同一CA簽發,并且在Mongodb中創建對應用戶,如下:用戶名為O=MyOrg,CN=zy
,需要與證書中的Subject保持一致。可以通過名命令獲取:
openssl x509 -in /usr/local/database/mongodb8.0.5/crt/zy1.pem -inform PEM -subject -nameopt RFC2253
db.getSiblingDB("$external").runCommand({createUser: "O=MyOrg,CN=zy",roles: [{ role: "readWrite", db: "test" },{ role: "userAdminAnyDatabase", db: "admin" }],writeConcern: { w: "majority" , wtimeout: 5000 }}
)
java使用x.509證書連接MongoDB
package com.zy.sslcontext;import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;/*** Connect to a MongoDB cluster with TLS connection.* Validate MongoDB server's certificate with the CA certificate. Present a Client certificate to be validated by* the MongoDB server.** Use X509 certificate to authenticate with the MongoDB server** Create a custom {@link javax.net.ssl.SSLContext} with the TrustStore holding the CA certificate and* the KeyStore holding the Client certificate and provide it to the MongoDB Driver.*/
public class ValidateServerPresentClientCertificateX509Auth {public static void main(String[] args) {// System.setProperty("javax.net.debug", "ssl:handshake:verbose");// Configure MongoDB Driver to use MONGODB-X509 as authentication mechanism// 此處url可以不用填寫用戶名密碼,則后續配置時采用credential(MongoCredential.createMongoX509Credential())使用證書在的用戶信息進行數據操作String connectionString = "mongodb://zy:123456@1.1.1.1:27017/?&ssl=true"; SSLContext sslContext;try {sslContext = getSSLContext();} catch (Exception e) {System.out.println("Failed to generate SSLContext. Error: " + e.getMessage());return;}MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(new ConnectionString(connectionString)) .applyToSslSettings(builder -> {builder.enabled(true); // 開啟sslbuilder.context(sslContext);})
// .credential(MongoCredential.createCredential("zy","admin","123456".toCharArray()))
// .credential(MongoCredential.createMongoX509Credential("O=MyOrg,CN=zy"))
// .credential(MongoCredential.createMongoX509Credential()).applyToConnectionPoolSettings(builder -> builder.maxSize(1) // 總最大連接數(所有實例總和).minSize(1) // 總最小空閑連接數.maxWaitTime(1500, TimeUnit.MILLISECONDS).maxConnectionIdleTime(10, TimeUnit.MINUTES)).applyToSocketSettings(b -> b.connectTimeout(3000, TimeUnit.MILLISECONDS).readTimeout(5000, TimeUnit.MILLISECONDS)).build();MongoClient client = MongoClients.create(settings);MongoDatabase test = client.getDatabase("test");MongoCollection<Document> coll = test.getCollection("collection1");// Retrieve the first document and print itSystem.out.println(coll.getNamespace());System.out.println(coll.find().first());MongoCollection<Document> collection = client.getDatabase("zy").getCollection("test1");collection.find().forEach(System.out::println);}/*** Load CA certificate from the file into the Trust Store.* Use PKCS12 keystore storing the Client certificate and read it into the {@link KeyStore}* Generate {@link SSLContext} from the Trust Store and {@link KeyStore}** @return SSLContext** @throws IOException* @throws CertificateException* @throws NoSuchAlgorithmException* @throws KeyStoreException* @throws KeyManagementException*/private static SSLContext getSSLContext() throws IOException, CertificateException,NoSuchAlgorithmException, KeyStoreException, KeyManagementException, UnrecoverableKeyException {// String certsPath = System.getProperty("cert_path");String certsPath = "C:\\Users\\Administrator\\Desktop\\crt\\";// Path to the CA certificate on diskString caCertPath = certsPath + "ca.crt";// 避坑:使用JKS認證失敗// openssl pkcs12 -export -inkey zy.key -in zy.pem -out zy.p12// Path to the PKCS12 Key Store holding the Client certificateString clientCertPath = certsPath + "zy1_pem.p12";String clientCertPwd = "123456";SSLContext sslContext;try (InputStream caInputStream = new FileInputStream(caCertPath);InputStream clientInputStream = new FileInputStream(clientCertPath)) {// Read Client certificate from PKCS12 Key StoreKeyStore clientKS = KeyStore.getInstance("PKCS12");clientKS.load(clientInputStream, clientCertPwd.toCharArray());// Retrieve Key Managers from the Client certificate Key StoreKeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());kmf.init(clientKS, clientCertPwd.toCharArray());KeyManager[] keyManagers = kmf.getKeyManagers();// Read CA certificate from file and convert it into X509CertificateCertificateFactory certFactory = CertificateFactory.getInstance("X509");X509Certificate caCert = (X509Certificate)certFactory.generateCertificate(caInputStream);KeyStore caKS = KeyStore.getInstance(KeyStore.getDefaultType());caKS.load(null);caKS.setCertificateEntry("caCert", caCert);// Initialize Trust ManagerTrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());tmf.init(caKS);// Create SSLContext. We need Trust Manager only in this use casesslContext = SSLContext.getInstance("TLS");sslContext.init(keyManagers, tmf.getTrustManagers(), null);}return sslContext;}
}
MongoShell使用證書連接
./mongosh --host 1.1.1.1 --tls --tlsCAFile /usr/local/database/mongodb8.0.5/crt/ca.crt --tlsCertificateKeyFile /usr/local/database/mongodb8.0.5/crt/zy.pem --authenticationDatabase '$external' --authenticationMechanism MONGODB-X509