!72 创建ssl所需相关文件

Merge pull request !72 from 薛蒙恩/split_ssl
This commit is contained in:
opengauss-bot
2022-12-06 08:34:40 +00:00
committed by Gitee
5 changed files with 224 additions and 11 deletions

View File

@ -61,14 +61,12 @@ def checkXMLFile(xmlFile):
if not os.access(xmlFile, os.R_OK): if not os.access(xmlFile, os.R_OK):
CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50100"] % (xmlFile, "current user")) CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50100"] % (xmlFile, "current user"))
def checkHostsTrust(hosts, localhost = ""): def checkHostsTrust(hosts):
""" """
check trust between current host and the given hosts check trust between current host and the given hosts
""" """
hostsWithoutTrust = [] hostsWithoutTrust = []
for host in hosts: for host in hosts:
if host == localhost:
continue
checkTrustCmd = "ssh -o ConnectTimeout=3 -o ConnectionAttempts=5 -o PasswordAuthentication=no " \ checkTrustCmd = "ssh -o ConnectTimeout=3 -o ConnectionAttempts=5 -o PasswordAuthentication=no " \
"-o StrictHostKeyChecking=no %s 'pwd > /dev/null'" % host "-o StrictHostKeyChecking=no %s 'pwd > /dev/null'" % host
status, output = subprocess.getstatusoutput(checkTrustCmd) status, output = subprocess.getstatusoutput(checkTrustCmd)

82
tool/cm_tool/CreateCMCACert.sh Executable file
View File

@ -0,0 +1,82 @@
#!/bin/bash
#############################################################################
# Copyright (c) 2022 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description : CreateCMCACert.sh
#############################################################################
set -e
envfile=$1
if [ "$envfile" = "" ]; then
echo "Envfile is needed."
exit 1
fi
activePeriod=$2
if [ "$activePeriod" == "" ]; then
activePeriod=10950
fi
read -s passwd
source $envfile
certPath=$GAUSSHOME/share/sslcert/cm
if [ ! -f "$certPath/openssl.cnf" ]; then
echo "CM ssl conf does not exist."
exit 1
fi
export OPENSSL_CONF=$GAUSSHOME/share/sslcert/gsql/openssl.cnf
if [ ! -f "$OPENSSL_CONF" ]; then
echo "ssl config file does not exist."
exit 1
fi
# generate root cert
## cakey.pem
echo "$passwd" | openssl genrsa -aes256 -f4 -passout stdin -out $certPath/cakey.pem 2048
## cacert.pem
echo "$passwd" | openssl req -new -x509 -passin stdin -days $activePeriod -key $certPath/cakey.pem -out $certPath/cacert.pem -subj "/C=CN/ST=NULL/L=NULL/O=NULL/OU=NULL/CN=CA"
# generate server and client cert
for role in "server" "client";
do
## key
echo "$passwd" | openssl genrsa -aes256 -passout stdin -out $certPath/$role.key 2048
## csr
echo "$passwd" | openssl req -new -key $certPath/$role.key -passin stdin -out $certPath/$role.csr -subj "/C=CN/ST=NULL/L=NULL/O=NULL/OU=NULL/CN=$role"
## crt
echo "$passwd" | openssl x509 -req -days $activePeriod -in $certPath/$role.csr -CA $certPath/cacert.pem -CAkey $certPath/cakey.pem -passin stdin -CAcreateserial -out $certPath/$role.crt -extfile $certPath/openssl.cnf
done
# generate server cipher and rand
expect -c "
spawn cm_ctl encrypt -M server -D $certPath;
expect {
\"*password*\" { send \"$passwd\r\"; exp_continue }
}
"
# generate client cipher and rand
expect -c "
spawn cm_ctl encrypt -M client -D $certPath;
expect {
\"*password*\" { send \"$passwd\r\"; exp_continue }
}
"
# set the password to null and unset it
passwd=""
unset passwd
# change to readonly
chmod 400 $certPath/*

View File

@ -18,13 +18,13 @@
# Description : InstallImpl.py # Description : InstallImpl.py
############################################################################# #############################################################################
from curses.ascii import isdigit, islower, isupper
import os import os
import re import re
import subprocess import subprocess
import xml.etree.cElementTree as ETree import getpass
from ErrorCode import ErrorCode from ErrorCode import ErrorCode
from Common import executeCmdOnHost from Common import executeCmdOnHost
from CMLog import CMLog
class InstallImpl: class InstallImpl:
def __init__(self, install): def __init__(self, install):
@ -139,7 +139,6 @@ class InstallImpl:
cmd = """ cmd = """
cp {gaussHome}/share/config/cm_server.conf.sample {cmdir}/cm_server/cm_server.conf cp {gaussHome}/share/config/cm_server.conf.sample {cmdir}/cm_server/cm_server.conf
sed 's#log_dir = .*#log_dir = {gaussLog}/cm/cm_server#' {cmdir}/cm_server/cm_server.conf -i sed 's#log_dir = .*#log_dir = {gaussLog}/cm/cm_server#' {cmdir}/cm_server/cm_server.conf -i
sed 's/enable_ssl.*=.*on/enable_ssl = off/g' {cmdir}/cm_server/cm_server.conf -i
""".format(gaussHome=self.gaussHome, gaussLog=self.gaussLog, cmdir=cmdir) """.format(gaussHome=self.gaussHome, gaussLog=self.gaussLog, cmdir=cmdir)
status, output = self.executeCmdOnHost(host, cmd) status, output = self.executeCmdOnHost(host, cmd)
if status != 0: if status != 0:
@ -154,7 +153,6 @@ class InstallImpl:
cp {gaussHome}/share/config/cm_agent.conf.sample {cmdir}/cm_agent/cm_agent.conf && cp {gaussHome}/share/config/cm_agent.conf.sample {cmdir}/cm_agent/cm_agent.conf &&
sed 's#log_dir = .*#log_dir = {gaussLog}/cm/cm_agent#' {cmdir}/cm_agent/cm_agent.conf -i && sed 's#log_dir = .*#log_dir = {gaussLog}/cm/cm_agent#' {cmdir}/cm_agent/cm_agent.conf -i &&
sed 's#unix_socket_directory = .*#unix_socket_directory = {gaussHome}#' {cmdir}/cm_agent/cm_agent.conf -i sed 's#unix_socket_directory = .*#unix_socket_directory = {gaussHome}#' {cmdir}/cm_agent/cm_agent.conf -i
sed 's/enable_ssl.*=.*on/enable_ssl = off/g' {cmdir}/cm_agent/cm_agent.conf -i
""".format(gaussHome=self.gaussHome, gaussLog=self.gaussLog, cmdir=cmdir) """.format(gaussHome=self.gaussHome, gaussLog=self.gaussLog, cmdir=cmdir)
status, output = self.executeCmdOnHost(host, cmd) status, output = self.executeCmdOnHost(host, cmd)
if status != 0: if status != 0:
@ -201,7 +199,6 @@ class InstallImpl:
# set crontab on other hosts # set crontab on other hosts
setCronCmd = "crontab %s" % cronContentTmpFile setCronCmd = "crontab %s" % cronContentTmpFile
cleanTmpFileCmd = "rm %s -f" % cronContentTmpFile cleanTmpFileCmd = "rm %s -f" % cronContentTmpFile
import getpass
username = getpass.getuser() username = getpass.getuser()
killMonitorCmd = "pkill om_monitor -u %s; " % username killMonitorCmd = "pkill om_monitor -u %s; " % username
for host in self.hostnames: for host in self.hostnames:
@ -299,6 +296,139 @@ class InstallImpl:
if status != 0: if status != 0:
self.logger.logExit("Failed to refresh static file." + output) self.logger.logExit("Failed to refresh static file." + output)
@staticmethod
def checkPassword(passwordCA):
minPasswordLen = 8
maxPasswordLen = 15
kinds = [0, 0, 0, 0]
specLetters = "~!@#$%^&*()-_=+\\|[{}];:,<.>/?"
if len(passwordCA) < minPasswordLen:
print("Invalid password, it must contain at least eight characters.")
return False
if len(passwordCA) > maxPasswordLen:
print("Invalid password, it must contain at most fifteen characters.")
return False
for c in passwordCA:
if isdigit(c):
kinds[0] += 1
elif isupper(c):
kinds[1] += 1
elif islower(c):
kinds[2] += 1
elif c in specLetters:
kinds[3] += 1
else:
print("The password contains illegal character: %s." % c)
return False
kindsNum = 0
for k in kinds:
if k > 0:
kindsNum += 1
if kindsNum < 3:
print("The password must contain at least three kinds of characters.")
return False
return True
def _getPassword(self):
passwordCA = ""
passwordCA2 = ""
tryCount = 0
while tryCount < 3:
passwordCA = getpass.getpass("Please input the password for ca cert:")
passwordCA2 = getpass.getpass("Please input the password for ca cert again:")
if passwordCA != passwordCA2:
tryCount += 1
self.logger.printMessage("The password enterd twice do not match.")
continue
if not InstallImpl.checkPassword(passwordCA):
tryCount += 1
continue
break
if tryCount == 3:
self.logger.logExit("Maximum number of attempts has been reached.")
return passwordCA
def _createCMSslConf(self, certPath):
"""
Generate config file.
"""
self.logger.debug("OPENSSL: Create config file.")
v3CaL = [
"[ v3_ca ]",
"subjectKeyIdentifier=hash",
"authorityKeyIdentifier=keyid:always,issuer:always",
"basicConstraints = CA:true",
"keyUsage = keyCertSign,cRLSign",
]
v3Ca = os.linesep.join(v3CaL)
# Create config file.
with open(os.path.join(certPath, "openssl.cnf"), "w") as fp:
# Write config item of Signature
fp.write(v3Ca)
self.logger.debug("OPENSSL: Successfully create config file.")
def _cleanUselessFile(self):
"""
Clean useless files
:return: NA
"""
certPath = os.path.join(self.gaussHome, "share/sslcert/cm")
keyFiles = ["cacert.pem", "server.crt", "server.key", "client.crt", "client.key",
"server.key.cipher", "server.key.rand", "client.key.cipher", "client.key.rand"]
for fileName in os.listdir(certPath):
filePath = os.path.join(certPath, fileName)
if fileName not in keyFiles:
os.remove(filePath)
def _createCMCALocal(self):
self.logger.debug("Creating Cm ca files locally.")
certPath = os.path.join(self.gaussHome, "share/sslcert/cm")
mkdirCmd = "rm %s -rf; mkdir %s" % (certPath, certPath)
status, output = subprocess.getstatusoutput(mkdirCmd)
if status != 0:
self.logger.debug("Command: %s\nStatus: %sOutput: %s" % (mkdirCmd, status, output))
self.logger.logExit("Failed to create cert path.")
self._createCMSslConf(certPath)
curPath = os.path.split(os.path.realpath(__file__))[0]
createCMCACert = os.path.realpath(os.path.join(curPath, "CreateCMCACert.sh"))
passwd = self._getPassword()
cmd = "echo \"%s\" | sh %s %s" % (passwd, createCMCACert, self.envFile)
# once used, set password to null and release it
passwd = ""
del passwd
status, output = subprocess.getstatusoutput(cmd)
cmd = ""
del cmd
if status != 0:
self.logger.logExit("Failed to create cm ca cert file.\n" + output)
self._cleanUselessFile()
def _distributeCA(self):
self.logger.debug("Distributing CM ca files to other hosts.")
certPath = os.path.join(self.gaussHome, "share/sslcert/cm")
createCertPathCmd = "rm {certPath} -rf; mkdir {certPath}; chmod 700 {certPath}".format(
certPath=certPath)
for host in self.hostnames:
if host == self.localhostName:
continue
status, output = self.executeCmdOnHost(host, createCertPathCmd)
if status != 0:
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" (createCertPathCmd, status, output)
self.logger.debug(errorDetail)
self.logger.logExit("Failed to create path of CA for CM on host %s." % host)
scpCmd = "scp {certPath}/* {host}:{certPath}".format(certPath=certPath, host=host)
status, output = subprocess.getstatusoutput(scpCmd)
if status != 0:
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" (scpCmd, status, output)
self.logger.debug(errorDetail)
self.logger.logExit("Failed to create CA for CM.")
def createCMCA(self):
self.logger.log("Creating CM ca files.")
self._createCMCALocal()
self._distributeCA()
def run(self): def run(self):
self.logger.log("Start to install cm tool.") self.logger.log("Start to install cm tool.")
self.prepareCMPath() self.prepareCMPath()
@ -306,6 +436,7 @@ class InstallImpl:
self.createManualStartFile() self.createManualStartFile()
self.initCMServer() self.initCMServer()
self.initCMAgent() self.initCMAgent()
self.createCMCA()
self._refreshStaticFile() self._refreshStaticFile()
self.setMonitorCrontab() self.setMonitorCrontab()
self.startCluster() self.startCluster()

View File

@ -114,6 +114,8 @@ General options:
CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % '-cmpkg' + ".") CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % '-cmpkg' + ".")
if not os.path.exists(self.cmpkg): if not os.path.exists(self.cmpkg):
CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % self.cmpkg) CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % self.cmpkg)
if not os.path.isfile(self.cmpkg):
CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50210"] % ("cmpkg " + self.cmpkg))
if self.envFile == "": if self.envFile == "":
self.envFile = os.path.join(os.environ['HOME'], ".bashrc") self.envFile = os.path.join(os.environ['HOME'], ".bashrc")
@ -235,7 +237,7 @@ General options:
self.logger.logExit("\"cmDir\" of all nodes must be provided.") self.logger.logExit("\"cmDir\" of all nodes must be provided.")
def checkHostTrust(self): def checkHostTrust(self):
checkHostsTrust(self.hostnames, self.localhostName) checkHostsTrust(self.hostnames)
def initLogger(self): def initLogger(self):
logPath = os.path.join(self.gaussLog, "cm", "cm_tool") logPath = os.path.join(self.gaussLog, "cm", "cm_tool")

View File

@ -249,7 +249,7 @@ General options:
if host == self.localhostName: if host == self.localhostName:
isLocal = True isLocal = True
cmd = "source %s; cd $GAUSSHOME/bin; rm -f om_monitor* cm_agent* cm_server* " \ cmd = "source %s; cd $GAUSSHOME/bin; rm -f om_monitor* cm_agent* cm_server* " \
"cm_ctl* cm_persist* *manual*start*; cd -" % self.envFile "cm_ctl* cm_persist* *manual*start* promote_mode_cms; cd -" % self.envFile
status, output = executeCmdOnHost(host, cmd, isLocal) status, output = executeCmdOnHost(host, cmd, isLocal)
if status != 0: if status != 0:
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (cmd, status, output) errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (cmd, status, output)
@ -267,7 +267,7 @@ General options:
CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"]) CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"])
def checkHostTrust(self): def checkHostTrust(self):
checkHostsTrust(self.hostnames, self.localhostName) checkHostsTrust(self.hostnames)
def run(self): def run(self):
self.checkExeUser() self.checkExeUser()