geant_acme_uploader.py 7.06 KiB
#!/usr/bin/env python3
#
"""Geant Acme - Uploader
Usage:
geant_acme_uploader.py --domain DOMAIN (--provider <PROVIDER> | \
--wildcard) (--client <CLIENT>... | --wildcard)
geant_acme_uploader.py (-h | --help)
Options:
-h --help Show this screen
-d DOMAIN --domain=DOMAIN Domain
-c CLIENT --client=CLIENT Client
-u UNIT --unit=UNIT Unit, entity or team
-p PROVIDER --provider=PROVIDER Provider
-w --wildcard Wildcard
"""
import os
import configparser
import OpenSSL.crypto
from docopt import docopt
import hvac
import redis
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning #pylint: disable=E0401
def check_expiration(certificate):
""" check certificate expiration """
st_cert = open(certificate, 'rt').read()
ssl_crypto = OpenSSL.crypto
cert = ssl_crypto.load_certificate(ssl_crypto.FILETYPE_PEM, st_cert)
return cert.has_expired()
def check_key(priv_key):
""" check certificate expiration """
try:
st_key = open(priv_key, 'rt').read()
except Exception: #pylint: disable=w0703
return None
ssl_crypto = OpenSSL.crypto
try:
key = ssl_crypto.load_privatekey(ssl_crypto.FILETYPE_PEM, st_key)
except: #pylint: disable=w0702
return None
try:
key.check()
except Exception: #pylint: disable=w0703
return None
return True
def redis_download(redis_host, redis_token, key):
""" download a key """
r_client = redis.StrictRedis(
host=redis_host, password=redis_token, port=6379, db=0)
try:
redis_value = r_client.get(key).decode('utf-8')
except Exception as err: #pylint: disable=w0703
redis_value = err
return redis_value
def vault_dowload(vault_host, vault_token, key_name):
""" upload key to vault """
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) #pylint: disable=E1101
client = hvac.Client(
url='https://{}'.format(vault_host),
token=vault_token,
verify=False
)
try:
vault_value = client.read(key_name)['data']['value']
except Exception as err: #pylint: disable=w0703
vault_value = err
return vault_value
def redis_upload(redis_host, redis_token, key, value):
""" upload a key """
r_client = redis.StrictRedis(
host=redis_host, password=redis_token, port=6379, db=0)
try:
_ = r_client.set(key, value)
except Exception as err: #pylint: disable=w0703
print('could not write key {} to Redis {}: {}'.format(key, redis_host, err))
print('giving up...')
os.sys.exit(1)
def redis_save(redis_host, redis_token):
""" run save DB """
r_client = redis.StrictRedis(
host=redis_host, password=redis_token, port=6379, db=0)
try:
_ = r_client.save()
except Exception as err: #pylint: disable=w0703
print('could not save to disk on Redis {}: {}'.format(redis_host, err))
print('giving up...')
os.sys.exit(1)
def vault_upload(vault_host, vault_token, key_name, key_value):
""" upload key to vault """
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) #pylint: disable=E1101
client = hvac.Client(
url='https://{}'.format(vault_host),
token=vault_token,
verify=False
)
try:
_ = client.write(key_name, value=key_value)
except Exception as err: #pylint: disable=w0703
print('could not write key {} to Vault {}: {}'.format(
key_name, vault_host, err))
print('giving up...')
os.sys.exit(1)
# Here we Go.
if __name__ == "__main__":
ARGS = docopt(__doc__)
DOMAIN = ARGS['--domain']
UNIT = ARGS['--unit']
PROVIDER = ARGS['--provider']
if ARGS['--wildcard']:
CLIENT = ['common']
WILDCARD = 'wildcard_'
PROVIDER_PREFIX = '{}_'.format(PROVIDER)
else:
CLIENT = ARGS['--client']
WILDCARD = PROVIDER_PREFIX = ''
CONFIG = configparser.RawConfigParser()
CONFIG.read_file(open('/root/.geant_acme.ini'))
REDIS_TOKEN = CONFIG.get('geant_acme', 'redis_token')
VAULT_TOKEN = CONFIG.get('geant_acme', 'vault_token_{}'.format(UNIT))
REDIS_HOST = CONFIG.get('geant_acme', 'redis_host')
VAULT_HOST = CONFIG.get('geant_acme', 'vault_host')
BASEDIR = '/etc/{}/live'.format(PROVIDER)
KEYPATH = os.path.join(BASEDIR, DOMAIN, 'privkey.pem')
LOG_FILE = '/var/log/acme_{}/geant_acme.log'.format(PROVIDER)
os.sys.stdout = os.sys.stderr = open(LOG_FILE, 'a', 1)
# check certificates validity and accessibility
for certname in ['cert.pem', 'chain.pem', 'fullchain.pem']:
certpath = os.path.join(BASEDIR, DOMAIN, certname)
if os.access(certpath, os.R_OK):
if check_expiration(certpath):
print('{} has expired: giving up...'.format(certpath))
os.sys.exit(1)
else:
print('could not access {}: giving up...'.format(certpath))
os.sys.exit(1)
# check key validity and accessibility
if os.access(KEYPATH, os.R_OK):
if not check_key(KEYPATH):
print('{} is not a valid key: giving up...'.format(certpath))
os.sys.exit(1)
else:
print('could not access {}: giving up...'.format(KEYPATH))
os.sys.exit(1)
for CLIENT_ITEM in CLIENT:
# upload certificates to Redis
for certname in ['cert.pem', 'chain.pem', 'fullchain.pem']:
certpath = os.path.join(BASEDIR, DOMAIN, certname)
with open(certpath, 'r') as certfile:
certdata_local = certfile.read()
domain_underscored = DOMAIN.replace('.', '_')
certname_renamed = certname.replace(
'cert.pem', 'pem').replace('.', '_')
REDIS_FULL_PATH = '{}:{}:redis_{}{}_{}'.format(
UNIT, CLIENT_ITEM, PROVIDER_PREFIX, domain_underscored, certname_renamed)
certdata_upstream = redis_download(REDIS_HOST, REDIS_TOKEN, REDIS_FULL_PATH)
if certdata_local != certdata_upstream:
print('uploading to Redis: {}'.format(REDIS_FULL_PATH))
redis_upload(REDIS_HOST, REDIS_TOKEN, REDIS_FULL_PATH, certdata_local)
else:
print('redis key {} did not change: skipping'.format(REDIS_FULL_PATH))
# upload key to Vault
with open(KEYPATH, 'r') as keyfile:
KEYDATA_LOCAL = keyfile.read()
DOMAIN_UNDERSCORED = DOMAIN.replace('.', '_')
VAULT_FULL_PATH = '{}/{}/vault_{}{}{}_key'.format(
UNIT, CLIENT_ITEM, PROVIDER_PREFIX, WILDCARD, DOMAIN_UNDERSCORED)
KEYDATA_UPSTREAM = vault_dowload(VAULT_HOST, VAULT_TOKEN, VAULT_FULL_PATH)
if KEYDATA_LOCAL != KEYDATA_UPSTREAM:
print('uploading to Vault: {}'.format(VAULT_FULL_PATH))
vault_upload(VAULT_HOST, VAULT_TOKEN, VAULT_FULL_PATH, KEYDATA_LOCAL)
else:
print('vault key {} did not change: skipping'.format(VAULT_FULL_PATH))
redis_save(REDIS_HOST, REDIS_TOKEN)