Black lint all the things

This commit is contained in:
Curtis Castrapel
2019-05-16 07:57:02 -07:00
parent 3680d523d4
commit 68fd1556b2
226 changed files with 9340 additions and 5940 deletions

View File

@ -1,5 +1,4 @@
try:
VERSION = __import__('pkg_resources') \
.get_distribution(__name__).version
VERSION = __import__("pkg_resources").get_distribution(__name__).version
except Exception as e:
VERSION = 'unknown'
VERSION = "unknown"

View File

@ -25,59 +25,57 @@ from cryptography.hazmat.backends import default_backend
class VaultSourcePlugin(SourcePlugin):
""" Class for importing certificates from Hashicorp Vault"""
title = 'Vault'
slug = 'vault-source'
description = 'Discovers all certificates in a given path'
author = 'Christopher Jolley'
author_url = 'https://github.com/alwaysjolley/lemur'
title = "Vault"
slug = "vault-source"
description = "Discovers all certificates in a given path"
author = "Christopher Jolley"
author_url = "https://github.com/alwaysjolley/lemur"
options = [
{
'name': 'vaultUrl',
'type': 'str',
'required': True,
'validation': '^https?://[a-zA-Z0-9.:-]+$',
'helpMessage': 'Valid URL to Hashi Vault instance'
"name": "vaultUrl",
"type": "str",
"required": True,
"validation": "^https?://[a-zA-Z0-9.:-]+$",
"helpMessage": "Valid URL to Hashi Vault instance",
},
{
'name': 'vaultKvApiVersion',
'type': 'select',
'value': '2',
'available': [
'1',
'2'
],
'required': True,
'helpMessage': 'Version of the Vault KV API to use'
"name": "vaultKvApiVersion",
"type": "select",
"value": "2",
"available": ["1", "2"],
"required": True,
"helpMessage": "Version of the Vault KV API to use",
},
{
'name': 'vaultAuthTokenFile',
'type': 'str',
'required': True,
'validation': '(/[^/]+)+',
'helpMessage': 'Must be a valid file path!'
"name": "vaultAuthTokenFile",
"type": "str",
"required": True,
"validation": "(/[^/]+)+",
"helpMessage": "Must be a valid file path!",
},
{
'name': 'vaultMount',
'type': 'str',
'required': True,
'validation': r'^\S+$',
'helpMessage': 'Must be a valid Vault secrets mount name!'
"name": "vaultMount",
"type": "str",
"required": True,
"validation": r"^\S+$",
"helpMessage": "Must be a valid Vault secrets mount name!",
},
{
'name': 'vaultPath',
'type': 'str',
'required': True,
'validation': '^([a-zA-Z0-9_-]+/?)+$',
'helpMessage': 'Must be a valid Vault secrets path'
"name": "vaultPath",
"type": "str",
"required": True,
"validation": "^([a-zA-Z0-9_-]+/?)+$",
"helpMessage": "Must be a valid Vault secrets path",
},
{
'name': 'objectName',
'type': 'str',
'required': True,
'validation': '[0-9a-zA-Z:_-]+',
'helpMessage': 'Object Name to search'
"name": "objectName",
"type": "str",
"required": True,
"validation": "[0-9a-zA-Z:_-]+",
"helpMessage": "Object Name to search",
},
]
@ -85,38 +83,38 @@ class VaultSourcePlugin(SourcePlugin):
"""Pull certificates from objects in Hashicorp Vault"""
data = []
cert = []
body = ''
url = self.get_option('vaultUrl', options)
token_file = self.get_option('vaultAuthTokenFile', options)
mount = self.get_option('vaultMount', options)
path = self.get_option('vaultPath', options)
obj_name = self.get_option('objectName', options)
api_version = self.get_option('vaultKvApiVersion', options)
cert_filter = '-----BEGIN CERTIFICATE-----'
cert_delimiter = '-----END CERTIFICATE-----'
body = ""
url = self.get_option("vaultUrl", options)
token_file = self.get_option("vaultAuthTokenFile", options)
mount = self.get_option("vaultMount", options)
path = self.get_option("vaultPath", options)
obj_name = self.get_option("objectName", options)
api_version = self.get_option("vaultKvApiVersion", options)
cert_filter = "-----BEGIN CERTIFICATE-----"
cert_delimiter = "-----END CERTIFICATE-----"
with open(token_file, 'r') as tfile:
token = tfile.readline().rstrip('\n')
with open(token_file, "r") as tfile:
token = tfile.readline().rstrip("\n")
client = hvac.Client(url=url, token=token)
client.secrets.kv.default_kv_version = api_version
path = '{0}/{1}'.format(path, obj_name)
path = "{0}/{1}".format(path, obj_name)
secret = get_secret(client, mount, path)
for cname in secret['data']:
if 'crt' in secret['data'][cname]:
cert = secret['data'][cname]['crt'].split(cert_delimiter + '\n')
elif 'pem' in secret['data'][cname]:
cert = secret['data'][cname]['pem'].split(cert_delimiter + '\n')
for cname in secret["data"]:
if "crt" in secret["data"][cname]:
cert = secret["data"][cname]["crt"].split(cert_delimiter + "\n")
elif "pem" in secret["data"][cname]:
cert = secret["data"][cname]["pem"].split(cert_delimiter + "\n")
else:
for key in secret['data'][cname]:
if secret['data'][cname][key].startswith(cert_filter):
cert = secret['data'][cname][key].split(cert_delimiter + '\n')
for key in secret["data"][cname]:
if secret["data"][cname][key].startswith(cert_filter):
cert = secret["data"][cname][key].split(cert_delimiter + "\n")
break
body = cert[0] + cert_delimiter
if 'chain' in secret['data'][cname]:
chain = secret['data'][cname]['chain']
if "chain" in secret["data"][cname]:
chain = secret["data"][cname]["chain"]
elif len(cert) > 1:
if cert[1].startswith(cert_filter):
chain = cert[1] + cert_delimiter
@ -124,8 +122,10 @@ class VaultSourcePlugin(SourcePlugin):
chain = None
else:
chain = None
data.append({'body': body, 'chain': chain, 'name': cname})
return [dict(body=c['body'], chain=c.get('chain'), name=c['name']) for c in data]
data.append({"body": body, "chain": chain, "name": cname})
return [
dict(body=c["body"], chain=c.get("chain"), name=c["name"]) for c in data
]
def get_endpoints(self, options, **kwargs):
""" Not implemented yet """
@ -135,81 +135,74 @@ class VaultSourcePlugin(SourcePlugin):
class VaultDestinationPlugin(DestinationPlugin):
"""Hashicorp Vault Destination plugin for Lemur"""
title = 'Vault'
slug = 'hashi-vault-destination'
description = 'Allow the uploading of certificates to Hashi Vault as secret'
author = 'Christopher Jolley'
author_url = 'https://github.com/alwaysjolley/lemur'
title = "Vault"
slug = "hashi-vault-destination"
description = "Allow the uploading of certificates to Hashi Vault as secret"
author = "Christopher Jolley"
author_url = "https://github.com/alwaysjolley/lemur"
options = [
{
'name': 'vaultUrl',
'type': 'str',
'required': True,
'validation': '^https?://[a-zA-Z0-9.:-]+$',
'helpMessage': 'Valid URL to Hashi Vault instance'
"name": "vaultUrl",
"type": "str",
"required": True,
"validation": "^https?://[a-zA-Z0-9.:-]+$",
"helpMessage": "Valid URL to Hashi Vault instance",
},
{
'name': 'vaultKvApiVersion',
'type': 'select',
'value': '2',
'available': [
'1',
'2'
],
'required': True,
'helpMessage': 'Version of the Vault KV API to use'
"name": "vaultKvApiVersion",
"type": "select",
"value": "2",
"available": ["1", "2"],
"required": True,
"helpMessage": "Version of the Vault KV API to use",
},
{
'name': 'vaultAuthTokenFile',
'type': 'str',
'required': True,
'validation': '(/[^/]+)+',
'helpMessage': 'Must be a valid file path!'
"name": "vaultAuthTokenFile",
"type": "str",
"required": True,
"validation": "(/[^/]+)+",
"helpMessage": "Must be a valid file path!",
},
{
'name': 'vaultMount',
'type': 'str',
'required': True,
'validation': r'^\S+$',
'helpMessage': 'Must be a valid Vault secrets mount name!'
"name": "vaultMount",
"type": "str",
"required": True,
"validation": r"^\S+$",
"helpMessage": "Must be a valid Vault secrets mount name!",
},
{
'name': 'vaultPath',
'type': 'str',
'required': True,
'validation': '^([a-zA-Z0-9_-]+/?)+$',
'helpMessage': 'Must be a valid Vault secrets path'
"name": "vaultPath",
"type": "str",
"required": True,
"validation": "^([a-zA-Z0-9_-]+/?)+$",
"helpMessage": "Must be a valid Vault secrets path",
},
{
'name': 'objectName',
'type': 'str',
'required': False,
'validation': '[0-9a-zA-Z:_-]+',
'helpMessage': 'Name to bundle certs under, if blank use cn'
"name": "objectName",
"type": "str",
"required": False,
"validation": "[0-9a-zA-Z:_-]+",
"helpMessage": "Name to bundle certs under, if blank use cn",
},
{
'name': 'bundleChain',
'type': 'select',
'value': 'cert only',
'available': [
'Nginx',
'Apache',
'PEM',
'no chain'
],
'required': True,
'helpMessage': 'Bundle the chain into the certificate'
"name": "bundleChain",
"type": "select",
"value": "cert only",
"available": ["Nginx", "Apache", "PEM", "no chain"],
"required": True,
"helpMessage": "Bundle the chain into the certificate",
},
{
'name': 'sanFilter',
'type': 'str',
'value': '.*',
'required': False,
'validation': '.*',
'helpMessage': 'Valid regex filter'
}
"name": "sanFilter",
"type": "str",
"value": ".*",
"required": False,
"validation": ".*",
"helpMessage": "Valid regex filter",
},
]
def __init__(self, *args, **kwargs):
@ -225,14 +218,14 @@ class VaultDestinationPlugin(DestinationPlugin):
"""
cname = common_name(parse_certificate(body))
url = self.get_option('vaultUrl', options)
token_file = self.get_option('vaultAuthTokenFile', options)
mount = self.get_option('vaultMount', options)
path = self.get_option('vaultPath', options)
bundle = self.get_option('bundleChain', options)
obj_name = self.get_option('objectName', options)
api_version = self.get_option('vaultKvApiVersion', options)
san_filter = self.get_option('sanFilter', options)
url = self.get_option("vaultUrl", options)
token_file = self.get_option("vaultAuthTokenFile", options)
mount = self.get_option("vaultMount", options)
path = self.get_option("vaultPath", options)
bundle = self.get_option("bundleChain", options)
obj_name = self.get_option("objectName", options)
api_version = self.get_option("vaultKvApiVersion", options)
san_filter = self.get_option("sanFilter", options)
san_list = get_san_list(body)
if san_filter:
@ -240,58 +233,67 @@ class VaultDestinationPlugin(DestinationPlugin):
try:
if not re.match(san_filter, san, flags=re.IGNORECASE):
current_app.logger.exception(
"Exception uploading secret to vault: invalid SAN: {}".format(san),
exc_info=True)
"Exception uploading secret to vault: invalid SAN: {}".format(
san
),
exc_info=True,
)
os._exit(1)
except re.error:
current_app.logger.exception(
"Exception compiling regex filter: invalid filter",
exc_info=True)
exc_info=True,
)
with open(token_file, 'r') as tfile:
token = tfile.readline().rstrip('\n')
with open(token_file, "r") as tfile:
token = tfile.readline().rstrip("\n")
client = hvac.Client(url=url, token=token)
client.secrets.kv.default_kv_version = api_version
if obj_name:
path = '{0}/{1}'.format(path, obj_name)
path = "{0}/{1}".format(path, obj_name)
else:
path = '{0}/{1}'.format(path, cname)
path = "{0}/{1}".format(path, cname)
secret = get_secret(client, mount, path)
secret['data'][cname] = {}
secret["data"][cname] = {}
if bundle == 'Nginx':
secret['data'][cname]['crt'] = '{0}\n{1}'.format(body, cert_chain)
secret['data'][cname]['key'] = private_key
elif bundle == 'Apache':
secret['data'][cname]['crt'] = body
secret['data'][cname]['chain'] = cert_chain
secret['data'][cname]['key'] = private_key
elif bundle == 'PEM':
secret['data'][cname]['pem'] = '{0}\n{1}\n{2}'.format(body, cert_chain, private_key)
if bundle == "Nginx":
secret["data"][cname]["crt"] = "{0}\n{1}".format(body, cert_chain)
secret["data"][cname]["key"] = private_key
elif bundle == "Apache":
secret["data"][cname]["crt"] = body
secret["data"][cname]["chain"] = cert_chain
secret["data"][cname]["key"] = private_key
elif bundle == "PEM":
secret["data"][cname]["pem"] = "{0}\n{1}\n{2}".format(
body, cert_chain, private_key
)
else:
secret['data'][cname]['crt'] = body
secret['data'][cname]['key'] = private_key
secret["data"][cname]["crt"] = body
secret["data"][cname]["key"] = private_key
if isinstance(san_list, list):
secret['data'][cname]['san'] = san_list
secret["data"][cname]["san"] = san_list
try:
client.secrets.kv.create_or_update_secret(
path=path, mount_point=mount, secret=secret['data']
path=path, mount_point=mount, secret=secret["data"]
)
except ConnectionError as err:
current_app.logger.exception(
"Exception uploading secret to vault: {0}".format(err), exc_info=True)
"Exception uploading secret to vault: {0}".format(err), exc_info=True
)
def get_san_list(body):
""" parse certificate for SAN names and return list, return empty list on error """
san_list = []
try:
byte_body = body.encode('utf-8')
byte_body = body.encode("utf-8")
cert = x509.load_pem_x509_certificate(byte_body, default_backend())
ext = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
ext = cert.extensions.get_extension_for_oid(
x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME
)
san_list = ext.value.get_values_for_type(x509.DNSName)
except x509.extensions.ExtensionNotFound:
pass
@ -301,12 +303,14 @@ def get_san_list(body):
def get_secret(client, mount, path):
""" retreive existing data from mount path and return dictionary """
result = {'data': {}}
result = {"data": {}}
try:
if client.secrets.kv.default_kv_version == '1':
if client.secrets.kv.default_kv_version == "1":
result = client.secrets.kv.v1.read_secret(path=path, mount_point=mount)
else:
result = client.secrets.kv.v2.read_secret_version(path=path, mount_point=mount)
result = client.secrets.kv.v2.read_secret_version(
path=path, mount_point=mount
)
except ConnectionError:
pass
finally: