1. 程式人生 > >搭建mongodb副本叢集,keyfile和ssl方式,使用者認證模式

搭建mongodb副本叢集,keyfile和ssl方式,使用者認證模式

環境:

Microsoft Windows [版本 10.0.10586]

mongod 版本:

db version v3.2.1
git version: a14d55980c2cdc565d4704a7e3ad37e4e535c1b2
OpenSSL version: OpenSSL 1.0.1p-fips 9 Jul 2015
allocator: tcmalloc
modules: none
build environment:
    distmod: 2008plus-ssl
    distarch: x86_64
    target_arch: x86_64

1.建立3個資料夾1、2、3分別為主、備、備伺服器

2.使用keyFile進行授權連線replica sets

#隨機生成keyFile或者手動寫入,key的長度必須是6-1024的base64字元,unix下必須相同組許可權,windows下不需要
openssl rand -base64 1024 > mongodb.key
chmod 600 mongodb.key

3.配置檔案
{
    "storage":
    {
        "dbPath": "D:/MongoDB3/1/db"
    },
    "net":
    {
        "port": 27001,
        "http":
        {
            "enabled":true
        }
    },
    "replication":
    {
        "replSetName":"s1"
    },
    "security":
    {
        "authorization": "enabled",
        "clusterAuthMode":"keyFile",
        "keyFile":"D:/MongoDB3/settings/mongodb.key"
    }
}


4.啟動mongo

mongod --config="D:\MongoDB3\1\mongodb.cfg" 
mongod --config="D:\MongoDB3\2\mongodb.cfg" 	
mongod --config="D:\MongoDB3\3\mongodb.cfg"

5.連線主Mongo
mongo 127.0.0.1:27001

use admin
rs.initiate()
#確認
rs.conf()
#新增從庫,使用本機區域網ip地址,使用127.0.0.1會出錯
rs.add('192.168.10.105:27002')
rs.add('192.168.10.105:27003')

#或者一次性新增
rs.initiate({_id:"s1",members:[
{_id:0,host:"192.168.10.105:27001",priority:100},
{_id:1,host:"192.168.10.105:27002",priority:99},
{_id:2,host:"192.168.10.105:27003",priority:98},
]})

#檢視配置資訊
rs.status()

#移除庫
rs.remove('192.168.10.105:27002')

6.新增使用者及授權認證
db.createUser(
{
	user:"any", 
	pwd:"password",
	roles:[{role:"userAdminAnyDatabase",db:"admin"}]
}
);
db.auth("any","password")

7.連線副本
mongo 127.0.0.1:27001
#show dbs不可用
#設定可讀
rs.slaveOk() #Deprecated.
設定讀寫方式
#Primary                   #從主的讀,預設
#primaryPreferred      #基本上從主的讀,主不可用時,從從的讀
#secondary                #從從的讀
#secondaryPreferred   #基本上從從的讀,從不可用時,從主的讀
#nearest                    #從網路延遲最小的讀
db.getMongo().setReadPref('secondaryPreferred')

8.使用x509進行授權連線replica sets
9.生成CA證書和使用者證書
#建立CA目錄
mkdir -p ./demoCA/{private,newcerts}
touch ./demoCA/index.txt
echo 01 > ./demoCA/serial
#生成CA金鑰對
openssl genrsa -des3 -out ./demoCA/private/cakey.pem 2048 
#生成證書請求和證書
openssl req -new -x509 -days 3650 -key ./demoCA/private/cakey.pem -out ./demoCA/cacert.pem
#生成使用者金鑰對,userkey設定密碼userpempassword,clusterkey設定密碼clusterempassword
#生成user證書Common Name必須為127.0.0.1
openssl genrsa -des3 -out ./demoCA/private/userkey.pem 2048
openssl genrsa -des3 -out ./demoCA/private/clusterkey.pem 2048 
#生成使用者證書請求
openssl req -new -key ./demoCA/private/userkey.pem -out userreq.req
openssl req -new -key ./demoCA/private/clusterkey.pem -out clusterreq1.req
#使用 CA 簽發使用者證書
openssl ca -in userreq.req -out usercert.pem -days 3650
openssl ca -in clusterreq1.req -out clustercert1.pem -days 3650
#將key和cer打包成pem
cat ./demoCA/private/userkey.pem usercert.pem > user.pem
cat ./demoCA/private/clusterkey.pem clustercert1.pem > cluster1.pem 
openssl pkcs12 -export -clcerts -in usercert.pem -inkey ./demoCA/private/userkey.pem -out user.p12

10.上述生成的可能要用到檔案有:cacert.pem可重新命名為ca-cert.crt,user.pem,user.p12,cluster1.pem(參照生成cluster2.pem,cluster3.pem)

11.windows下ca證書管理,點選證書ca-cert.crt,安裝證書->將證書放入"受信任的根證書頒發機構",檢視windows下證書可執行certmgr.msc

12.配置檔案

{
    "storage":
    {
        "dbPath": "D:/MongoDB3/1/db"
    }, 
    "net":
    {
        "port": 27001,
        "http":
        {
            "enabled":false
        },
        "ssl":
        {
            "mode":"requireSSL",
            "CAFile":"D:/MongoDB3/settings/keys/ca-cert.crt",
			"PEMKeyFile":"D:/MongoDB3/settings/keys/user.pem",
			"PEMKeyPassword":"userpempassword",
			"clusterFile":"D:/MongoDB3/settings/keys/cluster1.pem",
			"clusterPassword":"clusterpempassword",
			"allowInvalidHostnames":true
        }
    },
	"replication":
    {
        "replSetName":"s1"
    },
    "security":
    {
        "authorization": "enabled",
		"clusterAuthMode":"x509"
    }
}
userpempassword為使用者金鑰對密碼, clusterpempassword為副本金鑰對密碼

13.啟動mongodb

mongod --config="D:\MongoDB3\1\mongodbs.cfg" 
mongod --config="D:\MongoDB3\2\mongodbs.cfg" 	
mongod --config="D:\MongoDB3\3\mongodbs.cfg"

14.連線mongo
mongo 127.0.0.1:27001  --ssl --sslPEMKeyFile "D:/MongoDB3/settings/keys/user.pem" --sslPEMKeyPassword "userpempassword" --sslAllowInvalidCertificates 
15.剩下步驟與keyfile設定一致

16.java驅動連線

import java.io.*; 
import java.net.Socket;
import java.security.*; 
import java.security.cert.*; 
import java.util.*; 

import javax.net.ssl.*; 

import org.bson.Document;

import com.mongodb.*; 
import com.mongodb.MongoClientOptions.*; 
import com.mongodb.client.*; 
import xiaogen.util.Logger;

/**
 * @author zhg
 * 創建於 2015年12月3日 上午11:14:07
 */

/**
 * @author zhg
 *
 */
public class Mains implements MongoDBHelper
{
	private static SSLSocketFactory sss;

	private static void initSSL() throws Exception
	{ 
		
		// 服務端證書
		TrustManager[] trust = new TrustManager[] { new EmptyX509TrustManager() };
		// 客戶端證書
		KeyManager[] key = createKeyManager(new FileInputStream("D:/MongoDB3/settings/keys/user.p12"), "sssss",
				null);
		SSLContext ssl = SSLContext.getInstance("SSL");

		ssl.init(key, trust, new java.security.SecureRandom());
		sss = ssl.getSocketFactory();
	}

	/**
	 * 服務端要求證書
	 * 
	 * @param stream
	 * @param password
	 * @param alias
	 * @return
	 */
	public static KeyManager[] createKeyManager(InputStream stream, String password, String alias)
	{
		try
		{
			if (stream != null)
			{
				// String type = KeyStore.getDefaultType();
				KeyStore ks = KeyStore.getInstance("PKCS12");
				ks.load(stream, password.toCharArray());
				if (alias != null)
				{
					return new KeyManager[] { new AliasKeyManager(ks, alias, password) };
				} else
				{
					KeyManagerFactory trustManagerFactory = KeyManagerFactory
							.getInstance(KeyManagerFactory.getDefaultAlgorithm());
					trustManagerFactory.init(ks, password.toCharArray());
					return trustManagerFactory.getKeyManagers();
				}
			}
		} catch (Exception e)
		{
			// TODO
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 檢驗伺服器
	 * 
	 * @param stream
	 * @param password
	 * @return
	 */
	public static TrustManager[] createTrustManager(InputStream stream, String password)
	{
		try
		{
			if (stream != null)
			{
				// String type = KeyStore.getDefaultType();
				// System.out.println(type);
				KeyStore ks = KeyStore.getInstance("PKCS12");
				ks.load(stream, password.toCharArray());
				TrustManagerFactory trustManagerFactory = TrustManagerFactory
						.getInstance(TrustManagerFactory.getDefaultAlgorithm());
				trustManagerFactory.init(ks);
				// Logger.d("Provider : " + ks.getProvider().getName());
				// Logger.d("Type : " + ks.getType());
				// Logger.d("Size : " + ks.size());
				//
				// Enumeration<String> en = ks.aliases();
				// while (en.hasMoreElements())
				// {
				// Logger.d("Alias: " + en.nextElement());
				// }
				return trustManagerFactory.getTrustManagers();
			} else
			{
				return new TrustManager[] { new EmptyX509TrustManager() };
			}
		} catch (Exception e)
		{
			// TODO
			e.printStackTrace();
		}
		return null;
	}

	private static class MyHostnameVerifier implements HostnameVerifier
	{
		@Override
		public boolean verify(String host, SSLSession arg1)
		{
			// Logger.d(host);
			return true;
		}

	}

	private static class EmptyX509TrustManager implements X509TrustManager
	{
		public EmptyX509TrustManager()
		{

		}

		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
		{
			// Logger.d(authType);
		}

		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
		{

			// Logger.d(Arrays.asList(chain)+"");
		}

		public X509Certificate[] getAcceptedIssuers()
		{
			return null;
		}

	}

	private static class AliasKeyManager implements X509KeyManager
	{
		private KeyStore _ks;
		private String _alias;
		private String _password;

		public AliasKeyManager(KeyStore ks, String alias, String password)
		{
			_ks = ks;
			_alias = alias;
			_password = password;
		}

		public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2)
		{
			return _alias;
		}

		public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2)
		{
			return _alias;
		}

		public String[] getClientAliases(String arg0, Principal[] arg1)
		{
			return new String[] { _alias };
		}

		public String[] getServerAliases(String arg0, Principal[] arg1)
		{
			return new String[] { _alias };
		}

		public X509Certificate[] getCertificateChain(String arg0)
		{
			try
			{
				java.security.cert.Certificate[] certificates = this._ks.getCertificateChain(_alias);
				X509Certificate[] x509Certificates = new X509Certificate[certificates.length];
				System.arraycopy(certificates, 0, x509Certificates, 0, certificates.length);
				return x509Certificates;
			} catch (Exception e)
			{
				e.printStackTrace();
				return null;
			}
		}

		public PrivateKey getPrivateKey(String arg0)
		{
			try
			{
				return (PrivateKey) _ks.getKey(_alias, _password == null ? null : _password.toCharArray());
			} catch (Exception e)
			{
				e.printStackTrace();
				return null;
			}
		}

	}

	final static String user = "all";
	final static char[] password = "xxxxxx".toCharArray();
	final static String auth = "admin";
	public static final String url = "192.168.10.105";

	public static MongoClient getClients()
	{
		try
		{
			initSSL();
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		Builder build = new MongoClientOptions.Builder();
		build.sslEnabled(true);
		build.sslInvalidHostNameAllowed(true);
		build.socketFactory(sss);
		MongoClient client = new MongoClient(Arrays.asList(new ServerAddress(url, 27001)),
				Arrays.asList(MongoCredential.createCredential(user, auth, password)), build.build());
		return client;
	}

	Mains()
	{
		//關閉Mongodb除錯輸出
		java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.OFF);
		try (MongoClient client = getClients())
		{
			
			showDBs(client);
			MongoDatabase db = client.getDatabase("admin");
			showCollections(db);
			// getRoles(db);
			db = client.getDatabase("my");
			MongoCollection<Document> col = db.getCollection("logs");
			ArrayList<Document> list = col.find().into(new ArrayList<Document>());
			if (list.isEmpty())
			{
				ArrayList<Document> documents = new ArrayList<>();
				for (int i = 0; i < 10; i++)
				{
					documents.add(new Document("index", i).append("uid", UUID.randomUUID().toString()));
				}
				col.insertMany(documents);
			} else
			{
				Logger.d("list size=" + list.size());
				Logger.d(new Document("res", list).toJson());
				if (list.size() < 10)
				{
					col.drop();
				}
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		new Mains();
	}

}