Add SSL encryption to galera

Change-Id: I9e6d9ee439cab734eba02320d58ccfcd73e23106
This commit is contained in:
Proskurin Kirill 2017-01-12 13:43:00 +00:00
parent 909d165c5e
commit a760305ede
10 changed files with 132 additions and 11 deletions

1
service/files/ca.pem.j2 Normal file
View File

@ -0,0 +1 @@
{{ security.tls.ca_cert }}

View File

@ -16,6 +16,8 @@ configs:
node: null
port:
cont: 3306
tls:
enabled: true
url:
percona:
debian:

View File

@ -0,0 +1 @@
{{ security.tls.dhparam }}

View File

@ -33,11 +33,16 @@ PID_FILE = os.path.join(DATADIR, "mysqld.pid")
HOSTNAME = socket.getfqdn()
IPADDR = socket.gethostbyname(HOSTNAME)
CA_CERT = '/opt/ccp/etc/tls/ca.pem'
SERVER_CERT = '/opt/ccp/etc/tls/server-cert.pem'
SERVER_KEY = '/opt/ccp/etc/tls/server-key.pem'
MONITOR_PASSWORD = None
CLUSTER_NAME = None
ETCD_PATH = None
ETCD_HOST = None
ETCD_PORT = None
ETCD_TLS = None
def retry(f):
@ -64,11 +69,22 @@ def retry(f):
def get_etcd_client():
etcd_client = etcd.Client(host=ETCD_HOST,
port=ETCD_PORT,
allow_reconnect=True,
read_timeout=2)
return etcd_client
if ETCD_TLS:
protocol = 'https'
cert = (SERVER_CERT, SERVER_KEY)
ca_cert = CA_CERT
else:
protocol = 'http'
cert = None
ca_cert = None
return etcd.Client(host=ETCD_HOST,
port=ETCD_PORT,
allow_reconnect=True,
protocol=protocol,
cert=cert,
ca_cert=ca_cert,
read_timeout=2)
@retry
@ -297,7 +313,7 @@ def set_globals():
config = get_config()
global MONITOR_PASSWORD, CLUSTER_NAME
global ETCD_PATH, ETCD_HOST, ETCD_PORT
global ETCD_PATH, ETCD_HOST, ETCD_PORT, ETCD_TLS
CLUSTER_NAME = config['percona']['cluster_name']
MONITOR_PASSWORD = config['percona']['monitor_password']
@ -305,6 +321,7 @@ def set_globals():
ETCD_HOST = "etcd.%s.svc.%s" % (config['namespace'],
config['cluster_domain'])
ETCD_PORT = int(config['etcd']['client_port']['cont'])
ETCD_TLS = config['etcd']['tls']['enabled']
if __name__ == "__main__":

View File

@ -18,6 +18,10 @@ BACKEND_NAME = "galera-cluster"
SERVER_NAME = "primary"
GLOBALS_PATH = '/etc/ccp/globals/globals.json'
CA_CERT = '/opt/ccp/etc/tls/ca.pem'
SERVER_CERT = '/opt/ccp/etc/tls/server-cert.pem'
SERVER_KEY = '/opt/ccp/etc/tls/server-key.pem'
LOG_DATEFMT = "%Y-%m-%d %H:%M:%S"
LOG_FORMAT = "%(asctime)s.%(msecs)03d - %(levelname)s - %(message)s"
logging.basicConfig(format=LOG_FORMAT, datefmt=LOG_DATEFMT)
@ -29,6 +33,7 @@ CONNECTION_DELAY = None
ETCD_PATH = None
ETCD_HOST = None
ETCD_PORT = None
ETCD_TLS = None
# Haproxy constant for health checks
SRV_STATE_RUNNING = 2
@ -68,7 +73,7 @@ def set_globals():
config = get_config()
global CONNECTION_ATTEMPTS, CONNECTION_DELAY
global ETCD_PATH, ETCD_HOST, ETCD_PORT
global ETCD_PATH, ETCD_HOST, ETCD_PORT, ETCD_TLS
CONNECTION_ATTEMPTS = config['etcd']['connection_attempts']
CONNECTION_DELAY = config['etcd']['connection_delay']
@ -76,13 +81,26 @@ def set_globals():
ETCD_HOST = "etcd.%s.svc.%s" % (config['namespace'],
config['cluster_domain'])
ETCD_PORT = int(config['etcd']['client_port']['cont'])
ETCD_TLS = config['etcd']['tls']['enabled']
def get_etcd_client():
if ETCD_TLS:
protocol = 'https'
cert = (SERVER_CERT, SERVER_KEY)
ca_cert = CA_CERT
else:
protocol = 'http'
cert = None
ca_cert = None
return etcd.Client(host=ETCD_HOST,
port=ETCD_PORT,
allow_reconnect=True,
protocol=protocol,
cert=cert,
ca_cert=ca_cert,
read_timeout=2)

View File

@ -35,4 +35,16 @@ wsrep_provider = /usr/lib/galera3/libgalera_smm.so
wsrep_cluster_name = {{ percona.cluster_name }}
wsrep_sst_method = xtrabackup-v2
wsrep_sst_auth = "xtrabackup:{{ percona.xtrabackup_password }}"
wsrep_provider_options = "gcache.size={{ percona.gcache_size }};gcache.recover=yes"
wsrep_provider_options = "gcache.size={{ percona.gcache_size }};gcache.recover=yes{% if percona.tls.enabled %};socket.ssl=yes;socket.ssl_key=/opt/ccp/etc/tls/server-key.pem;socket.ssl_cert=/opt/ccp/etc/tls/server-cert.pem;socket.ssl_ca=/opt/ccp/etc/tls/ca.pem"{% endif %}
{% if percona.tls.enabled %}
ssl-ca = /opt/ccp/etc/tls/ca.pem
ssl-cert = /opt/ccp/etc/tls/server-cert.pem
ssl-key = /opt/ccp/etc/tls/server-key.pem
[sst]
encrypt = 4
ssl-ca = /opt/ccp/etc/tls/ca.pem
ssl-cert = /opt/ccp/etc/tls/server-cert.pem
ssl-key = /opt/ccp/etc/tls/server-key.pem
{% endif %}

View File

@ -24,8 +24,13 @@ INIT_FILE = os.path.join(DATADIR, 'init.ok')
PID_FILE = os.path.join(DATADIR, "mysqld.pid")
GRASTATE_FILE = os.path.join(DATADIR, 'grastate.dat')
SST_FLAG = os.path.join(DATADIR, "sst_in_progress")
DHPARAM = os.path.join(DATADIR, "dhparams.pem")
GLOBALS_PATH = '/etc/ccp/globals/globals.json'
CA_CERT = '/opt/ccp/etc/tls/ca.pem'
SERVER_CERT = '/opt/ccp/etc/tls/server-cert.pem'
SERVER_KEY = '/opt/ccp/etc/tls/server-key.pem'
LOG_DATEFMT = "%Y-%m-%d %H:%M:%S"
LOG_FORMAT = "%(asctime)s.%(msecs)03d - %(levelname)s - %(message)s"
logging.basicConfig(format=LOG_FORMAT, datefmt=LOG_DATEFMT)
@ -44,6 +49,8 @@ CONNECTION_DELAY = None
ETCD_PATH = None
ETCD_HOST = None
ETCD_PORT = None
ETCD_TLS = None
DHPARAM_CERT = None
class ProcessException(Exception):
@ -76,7 +83,8 @@ def get_config():
variables = {}
with open(GLOBALS_PATH) as f:
global_conf = json.load(f)
for key in ['percona', 'db', 'etcd', 'namespace', 'cluster_domain']:
for key in ['percona', 'db', 'etcd', 'namespace', 'cluster_domain',
'security']:
variables[key] = global_conf[key]
LOG.debug(variables)
return variables
@ -88,7 +96,7 @@ def set_globals():
global MYSQL_ROOT_PASSWORD, CLUSTER_NAME, XTRABACKUP_PASSWORD
global MONITOR_PASSWORD, CONNECTION_ATTEMPTS, CONNECTION_DELAY
global ETCD_PATH, ETCD_HOST, ETCD_PORT, EXPECTED_NODES
global FORCE_BOOTSTRAP, FORCE_BOOTSTRAP_NODE
global FORCE_BOOTSTRAP, FORCE_BOOTSTRAP_NODE, ETCD_TLS, DHPARAM_CERT
FORCE_BOOTSTRAP = config['percona']['force_bootstrap']['enabled']
FORCE_BOOTSTRAP_NODE = config['percona']['force_bootstrap']['node']
@ -103,6 +111,8 @@ def set_globals():
ETCD_HOST = "etcd.%s.svc.%s" % (config['namespace'],
config['cluster_domain'])
ETCD_PORT = int(config['etcd']['client_port']['cont'])
ETCD_TLS = config['etcd']['tls']['enabled']
DHPARAM_CERT = config['security']['tls']['dhparam']
def get_mysql_client(insecure=False):
@ -118,9 +128,21 @@ def get_mysql_client(insecure=False):
def get_etcd_client():
if ETCD_TLS:
protocol = 'https'
cert = (SERVER_CERT, SERVER_KEY)
ca_cert = CA_CERT
else:
protocol = 'http'
cert = None
ca_cert = None
return etcd.Client(host=ETCD_HOST,
port=ETCD_PORT,
allow_reconnect=True,
protocol=protocol,
cert=cert,
ca_cert=ca_cert,
read_timeout=2)
@ -134,6 +156,15 @@ def datadir_cleanup(path):
os.remove(fullpath)
def create_dhparam():
if not os.path.isfile(DHPARAM):
with open(DHPARAM, 'w') as f:
f.write(DHPARAM_CERT)
LOG.info("dhparam cert created in %s", DHPARAM)
else:
LOG.info("%s exists, not overriding it", DHPARAM)
def create_init_flag():
if not os.path.isfile(INIT_FILE):
@ -156,6 +187,7 @@ def run_cmd(cmd, check_result=False):
def run_mysqld(available_nodes, donors_list, etcd_client, lock):
create_dhparam()
cmd = ("mysqld --user=mysql --wsrep_cluster_name=%s"
" --wsrep_cluster_address=%s"
" --wsrep_sst_method=xtrabackup-v2"
@ -476,7 +508,9 @@ def wait_for_mysqld(proc):
def wait_for_mysqld_to_start(proc, insecure):
LOG.info("Waiting mysql to start...")
time.sleep(5)
# Sometimes initial mysql start could take some time, especialy with SSL
# enabled. FIXME - replace sleep with some additional checks.
time.sleep(30)
while True:
if check_if_sst_running():
LOG.debug("SST sync detected, waiting...")

View File

@ -0,0 +1 @@
{{ security.tls.server_cert }}

View File

@ -0,0 +1 @@
{{ security.tls.server_key }}

View File

@ -15,6 +15,11 @@ service:
daemon:
files:
- galera-checker
# {% if percona.tls.enabled %}
- ca.pem
- server-key.pem
- server-cert.pem
# {% endif %}
dependencies:
- etcd
command: "/opt/ccp/bin/galera_checker.py"
@ -31,6 +36,11 @@ service:
files:
- haproxy-conf
- haproxy_entrypoint
# {% if percona.tls.enabled %}
- ca.pem
- server-key.pem
- server-cert.pem
# {% endif %}
dependencies:
- etcd
command: "/opt/ccp/bin/haproxy_entrypoint.py daemon"
@ -67,6 +77,11 @@ service:
- entrypoint
- mycnf
- galera-checker
# {% if percona.tls.enabled %}
- ca.pem
- server-key.pem
- server-cert.pem
# {% endif %}
dependencies:
- etcd
command: /opt/ccp/bin/entrypoint.py
@ -90,3 +105,22 @@ files:
path: /opt/ccp/bin/haproxy_entrypoint.py
content: haproxy_entrypoint.py
perm: "0755"
# {% if percona.tls.enabled %}
ca.pem:
path: /opt/ccp/etc/tls/ca.pem
content: ca.pem.j2
perm: "0400"
server-key.pem:
path: /opt/ccp/etc/tls/server-key.pem
content: server-key.pem.j2
perm: "0400"
server-cert.pem:
path: /opt/ccp/etc/tls/server-cert.pem
content: server-cert.pem.j2
perm: "0400"
# Cant use it right now, 'cos of the file creation order
dhparams.pem:
path: /var/lib/mysql/dhparams.pem
content: dhparams.pem.j2
perm: "0400"
# {% endif %}