123 lines
3.8 KiB
Python
123 lines
3.8 KiB
Python
#!/usr/bin/env python
|
|
|
|
import argparse
|
|
import base64
|
|
import json
|
|
import logging
|
|
import os
|
|
import re
|
|
import six
|
|
import subprocess
|
|
import sys
|
|
|
|
import pykube
|
|
|
|
GLOBALS_PATH = '/etc/ccp/globals/globals.json'
|
|
FERNET_DIR = '/etc/keystone/fernet-keys/'
|
|
|
|
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)
|
|
LOG = logging.getLogger(__name__)
|
|
LOG.setLevel(logging.INFO)
|
|
|
|
def get_config():
|
|
LOG.info("Getting global variables from %s", GLOBALS_PATH)
|
|
with open(GLOBALS_PATH) as f:
|
|
global_conf = json.load(f)
|
|
return global_conf
|
|
|
|
def get_pykube_client():
|
|
os.environ['KUBERNETES_SERVICE_HOST'] = 'kubernetes.default'
|
|
config = pykube.KubeConfig.from_service_account()
|
|
return pykube.HTTPClient(config)
|
|
|
|
def get_secret_definition(name):
|
|
client = get_pykube_client()
|
|
obj_dict = {
|
|
'metadata': {
|
|
'name': name,
|
|
'namespace': NAMESPACE
|
|
}
|
|
}
|
|
secret = pykube.Secret(client, obj_dict)
|
|
return secret
|
|
|
|
def read_from_files():
|
|
keys = filter(
|
|
lambda name: os.path.isfile(FERNET_DIR + name) and re.match("^\d+$", name),
|
|
os.listdir(FERNET_DIR)
|
|
)
|
|
data = {}
|
|
for key in keys:
|
|
with open(FERNET_DIR + key, 'r') as f:
|
|
data[key] = f.read()
|
|
if len(keys):
|
|
LOG.debug("Keys read from files: %s", keys)
|
|
else:
|
|
LOG.warn("No keys were read from files.")
|
|
return data
|
|
|
|
def get_keys_data():
|
|
keys = PROVIDED_KEYS or read_from_files()
|
|
return dict([(key, base64.b64encode(value.encode()).decode())
|
|
for (key, value) in six.iteritems(keys)])
|
|
|
|
def write_to_files(data):
|
|
for (key, value) in six.iteritems(data):
|
|
with open(FERNET_DIR + key, 'w') as f:
|
|
decoded_value = base64.b64decode(value).decode()
|
|
f.write(decoded_value)
|
|
LOG.debug("Key %s: %s", key, decoded_value)
|
|
LOG.info("%s keys were written", len(data))
|
|
|
|
def set_globals():
|
|
LOG.info("Setting up global variables")
|
|
global NAMESPACE, SECRET_NAME, PROVIDED_KEYS
|
|
config = get_config()
|
|
|
|
NAMESPACE = config['namespace']
|
|
LOG.debug("Namespace: %s", NAMESPACE)
|
|
|
|
SECRET_NAME = config['keystone']['fernet_secret_name']
|
|
LOG.debug("Secret name: %s", SECRET_NAME)
|
|
|
|
PROVIDED_KEYS = None
|
|
if 'fernet_keys' in config['keystone']:
|
|
PROVIDED_KEYS = config['keystone']['fernet_keys']
|
|
LOG.debug("Fernet keys: %s", PROVIDED_KEYS)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('command', choices=['fernet_setup', 'fernet_rotate'])
|
|
args = parser.parse_args()
|
|
|
|
secret = get_secret_definition(SECRET_NAME)
|
|
if not secret.exists():
|
|
LOG.error("Secret '%s' does not exist.", SECRET_NAME)
|
|
sys.exit(1)
|
|
|
|
secret.reload()
|
|
if not PROVIDED_KEYS:
|
|
LOG.info("No fernet keys were provided in the config.")
|
|
if args.command == 'fernet_rotate':
|
|
LOG.info("Copying existing fernet keys from secret '%s' to %s.", SECRET_NAME, FERNET_DIR)
|
|
write_to_files(secret.obj['data'])
|
|
|
|
LOG.info("Executing 'keystone-manage %s --keystone-user=keystone --keystone-group=keystone' command.",
|
|
args.command)
|
|
subprocess.call(['keystone-manage', args.command, '--keystone-user=keystone', '--keystone-group=keystone'])
|
|
|
|
LOG.info("Updating data for '%s' secret.", SECRET_NAME)
|
|
updated_keys = get_keys_data()
|
|
secret.obj['data'] = updated_keys
|
|
secret.update()
|
|
LOG.info("%s fernet keys have been placed to secret '%s'", len(updated_keys), SECRET_NAME)
|
|
LOG.debug("Placed keys: %s", updated_keys)
|
|
LOG.info("Fernet keys %s has been completed", "rotation" if args.command == 'fernet_rotate' else "generation")
|
|
|
|
if __name__ == "__main__":
|
|
set_globals()
|
|
main()
|