
Added configuration parameter, verify_ca, to magnum.conf with default value of True. This parameter is passed to the heat templates to indicate whether the cluster nodes validate the Certificate Authority when making requests to the OpenStack APIs (Keystone, Magnum, Heat). This configuration parameter can be set to False to disable CA validation. Co-Authored-By: Vijendar Komalla <vijendar.komalla@rackspace.com> Change-Id: Iab02cb1338b811dac0c147378dbd0e63c83f0413 Partial-Bug: #1663757
185 lines
5.3 KiB
Python
185 lines
5.3 KiB
Python
#!/usr/bin/python
|
|
|
|
# Copyright 2015 Rackspace, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
import requests
|
|
|
|
HEAT_PARAMS_PATH = '/etc/sysconfig/heat-params'
|
|
PUBLIC_IP_URL = 'http://169.254.169.254/latest/meta-data/public-ipv4'
|
|
CERT_DIR = '/etc/docker'
|
|
CERT_CONF_DIR = '%s/conf' % CERT_DIR
|
|
CA_CERT_PATH = '%s/ca.crt' % CERT_DIR
|
|
SERVER_CONF_PATH = '%s/server.conf' % CERT_CONF_DIR
|
|
SERVER_KEY_PATH = '%s/server.key' % CERT_DIR
|
|
SERVER_CSR_PATH = '%s/server.csr' % CERT_DIR
|
|
SERVER_CERT_PATH = '%s/server.crt' % CERT_DIR
|
|
|
|
CSR_CONFIG_TEMPLATE = """
|
|
[req]
|
|
distinguished_name = req_distinguished_name
|
|
req_extensions = req_ext
|
|
x509_extensions = req_ext
|
|
prompt = no
|
|
copy_extensions = copyall
|
|
[req_distinguished_name]
|
|
CN = swarm.invalid
|
|
[req_ext]
|
|
subjectAltName = %(subject_alt_names)s
|
|
extendedKeyUsage = clientAuth,serverAuth
|
|
"""
|
|
|
|
|
|
def _parse_config_value(value):
|
|
parsed_value = value
|
|
if parsed_value[-1] == '\n':
|
|
parsed_value = parsed_value[:-1]
|
|
return parsed_value[1:-1]
|
|
|
|
|
|
def load_config():
|
|
config = dict()
|
|
with open(HEAT_PARAMS_PATH, 'r') as fp:
|
|
for line in fp.readlines():
|
|
key, value = line.split('=', 1)
|
|
config[key] = _parse_config_value(value)
|
|
return config
|
|
|
|
|
|
def create_dirs():
|
|
os.makedirs(CERT_CONF_DIR)
|
|
|
|
|
|
def _get_public_ip():
|
|
return requests.get(PUBLIC_IP_URL).text
|
|
|
|
|
|
def _build_subject_alt_names(config):
|
|
subject_alt_names = [
|
|
'IP:%s' % _get_public_ip(),
|
|
'IP:%s' % config['API_IP_ADDRESS'],
|
|
'IP:%s' % config['SWARM_NODE_IP'],
|
|
'IP:%s' % config['SWARM_API_IP'],
|
|
'IP:127.0.0.1'
|
|
]
|
|
return ','.join(subject_alt_names)
|
|
|
|
|
|
def write_ca_cert(config, verify_ca):
|
|
cluster_cert_url = '%s/certificates/%s' % (config['MAGNUM_URL'],
|
|
config['CLUSTER_UUID'])
|
|
headers = {'X-Auth-Token': config['USER_TOKEN'],
|
|
'OpenStack-API-Version': 'container-infra latest'}
|
|
ca_cert_resp = requests.get(cluster_cert_url,
|
|
headers=headers,
|
|
verify=verify_ca)
|
|
|
|
with open(CA_CERT_PATH, 'w') as fp:
|
|
fp.write(ca_cert_resp.json()['pem'])
|
|
|
|
|
|
def write_server_key():
|
|
subprocess.call(['openssl', 'genrsa',
|
|
'-out', SERVER_KEY_PATH,
|
|
'4096'])
|
|
|
|
|
|
def _write_csr_config(config):
|
|
with open(SERVER_CONF_PATH, 'w') as fp:
|
|
params = {
|
|
'subject_alt_names': _build_subject_alt_names(config)
|
|
}
|
|
fp.write(CSR_CONFIG_TEMPLATE % params)
|
|
|
|
|
|
def create_server_csr(config):
|
|
_write_csr_config(config)
|
|
subprocess.call(['openssl', 'req', '-new',
|
|
'-days', '1000',
|
|
'-key', SERVER_KEY_PATH,
|
|
'-out', SERVER_CSR_PATH,
|
|
'-reqexts', 'req_ext',
|
|
'-extensions', 'req_ext',
|
|
'-config', SERVER_CONF_PATH])
|
|
|
|
with open(SERVER_CSR_PATH, 'r') as fp:
|
|
return {'cluster_uuid': config['CLUSTER_UUID'], 'csr': fp.read()}
|
|
|
|
|
|
def write_server_cert(config, csr_req, verify_ca):
|
|
cert_url = '%s/certificates' % config['MAGNUM_URL']
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'X-Auth-Token': config['USER_TOKEN'],
|
|
'OpenStack-API-Version': 'container-infra latest'
|
|
}
|
|
csr_resp = requests.post(cert_url,
|
|
data=json.dumps(csr_req),
|
|
headers=headers,
|
|
verify=verify_ca)
|
|
|
|
with open(SERVER_CERT_PATH, 'w') as fp:
|
|
fp.write(csr_resp.json()['pem'])
|
|
|
|
|
|
def get_user_token(config, verify_ca):
|
|
creds_str = '''
|
|
{
|
|
"auth": {
|
|
"identity": {
|
|
"methods": [
|
|
"password"
|
|
],
|
|
"password": {
|
|
"user": {
|
|
"id": "%(trustee_user_id)s",
|
|
"password": "%(trustee_password)s"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
params = {
|
|
'trustee_user_id': config['TRUSTEE_USER_ID'],
|
|
'trustee_password': config['TRUSTEE_PASSWORD'],
|
|
}
|
|
creds = creds_str % params
|
|
headers = {'Content-Type': 'application/json'}
|
|
url = config['AUTH_URL'] + '/auth/tokens'
|
|
r = requests.post(url, headers=headers, data=creds, verify=verify_ca)
|
|
config['USER_TOKEN'] = r.headers['X-Subject-Token']
|
|
return config
|
|
|
|
|
|
def main():
|
|
config = load_config()
|
|
if config['TLS_DISABLED'] == 'False':
|
|
verify_ca = True if config['VERIFY_CA'] == 'True' else False
|
|
create_dirs()
|
|
config = get_user_token(config, verify_ca)
|
|
write_ca_cert(config, verify_ca)
|
|
write_server_key()
|
|
csr_req = create_server_csr(config)
|
|
write_server_cert(config, csr_req, verify_ca)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|