Skip to content
Snippets Groups Projects
geant_acme_uploader.py 5.25 KiB
#!/usr/bin/env python3
#
"""Geant Acme - Uploader

Usage:
  geant_acme_uploader.py --domain DOMAIN (-c CLIENT | -w)
  geant_acme_uploader.py (-h | --help)

Options:
  -h --help                   Show this screen.
  -d DOMAIN --domain=DOMAIN   Domain
  -c CLIENT --client=CLIENT   Client
  -w --wildcard               Wildcard
"""
import os
import configparser
from docopt import docopt
import hvac
import redis
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning #pylint: disable=E0401


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:
        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:
        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:
        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:
        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:
        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']
    if ARGS['--wildcard']:
        CLIENT = 'common'
        WILDCARD = 'wildcard_'
    else:
        CLIENT = ARGS['--client']
        WILDCARD = ''

    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')
    REDIS_HOST = CONFIG.get('geant_acme', 'redis_host')
    VAULT_HOST = CONFIG.get('geant_acme', 'vault_host')
    BASEDIR = '/etc/letsencrypt/live'
    os.sys.stdout = os.sys.stderr = open('/var/log/acme/acme.log', 'a', 1)

    # upload certificates to Redis
    for certname in ['cert.pem', 'chain.pem', 'fullchain.pem']:
        certpath = os.path.join(BASEDIR, DOMAIN, certname)
        if os.access(certpath, os.R_OK):
            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(
                    CLIENT, 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))
        else:
            print('could not access {}: giving up...'.format(certpath))
            os.sys.exit(1)

    # upload key to Vault
    KEYPATH = os.path.join(BASEDIR, DOMAIN, 'privkey.pem')
    if os.access(KEYPATH, os.R_OK):
        with open(KEYPATH, 'r') as keyfile:
            KEYDATA_LOCAL = keyfile.read()
            DOMAIN_UNDERSCORED = DOMAIN.replace('.', '_')
            VAULT_FULL_PATH = 'puppet/{}/vault_{}{}_key'.format(
                CLIENT, 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))
    else:
        print('could not access {}: giving up...'.format(KEYPATH))
        os.sys.exit(1)

    redis_save(REDIS_HOST, REDIS_TOKEN)