adding regex filtering
This commit is contained in:
@ -12,6 +12,8 @@ from lemur.plugins.base import Plugin, plugins
|
||||
class DestinationPlugin(Plugin):
|
||||
type = 'destination'
|
||||
requires_key = True
|
||||
sync_as_source = False
|
||||
sync_as_source_name = ''
|
||||
|
||||
def upload(self, name, body, private_key, cert_chain, options, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
@ -459,7 +459,10 @@ class ACMEIssuerPlugin(IssuerPlugin):
|
||||
"pending_cert": entry["pending_cert"],
|
||||
})
|
||||
except (PollError, AcmeError, Exception) as e:
|
||||
current_app.logger.error("Unable to resolve pending cert: {}".format(pending_cert), exc_info=True)
|
||||
order_url = order.uri
|
||||
current_app.logger.error(
|
||||
"Unable to resolve pending cert: {}. "
|
||||
"Check out {} for more information.".format(pending_cert, order_url), exc_info=True)
|
||||
certs.append({
|
||||
"cert": False,
|
||||
"pending_cert": entry["pending_cert"],
|
||||
|
@ -149,47 +149,6 @@ def get_elb_endpoints_v2(account_number, region, elb_dict):
|
||||
return endpoints
|
||||
|
||||
|
||||
class AWSDestinationPlugin(DestinationPlugin):
|
||||
title = 'AWS'
|
||||
slug = 'aws-destination'
|
||||
description = 'Allow the uploading of certificates to AWS IAM'
|
||||
version = aws.VERSION
|
||||
|
||||
author = 'Kevin Glisson'
|
||||
author_url = 'https://github.com/netflix/lemur'
|
||||
|
||||
options = [
|
||||
{
|
||||
'name': 'accountNumber',
|
||||
'type': 'str',
|
||||
'required': True,
|
||||
'validation': '[0-9]{12}',
|
||||
'helpMessage': 'Must be a valid AWS account number!',
|
||||
},
|
||||
{
|
||||
'name': 'path',
|
||||
'type': 'str',
|
||||
'default': '/',
|
||||
'helpMessage': 'Path to upload certificate.'
|
||||
}
|
||||
]
|
||||
|
||||
# 'elb': {
|
||||
# 'name': {'type': 'name'},
|
||||
# 'region': {'type': 'str'},
|
||||
# 'port': {'type': 'int'}
|
||||
# }
|
||||
|
||||
def upload(self, name, body, private_key, cert_chain, options, **kwargs):
|
||||
iam.upload_cert(name, body, private_key,
|
||||
self.get_option('path', options),
|
||||
cert_chain=cert_chain,
|
||||
account_number=self.get_option('accountNumber', options))
|
||||
|
||||
def deploy(self, elb_name, account, region, certificate):
|
||||
pass
|
||||
|
||||
|
||||
class AWSSourcePlugin(SourcePlugin):
|
||||
title = 'AWS'
|
||||
slug = 'aws-source'
|
||||
@ -266,6 +225,43 @@ class AWSSourcePlugin(SourcePlugin):
|
||||
iam.delete_cert(certificate.name, account_number=account_number)
|
||||
|
||||
|
||||
class AWSDestinationPlugin(DestinationPlugin):
|
||||
title = 'AWS'
|
||||
slug = 'aws-destination'
|
||||
description = 'Allow the uploading of certificates to AWS IAM'
|
||||
version = aws.VERSION
|
||||
sync_as_source = True
|
||||
sync_as_source_name = AWSSourcePlugin.slug
|
||||
|
||||
author = 'Kevin Glisson'
|
||||
author_url = 'https://github.com/netflix/lemur'
|
||||
|
||||
options = [
|
||||
{
|
||||
'name': 'accountNumber',
|
||||
'type': 'str',
|
||||
'required': True,
|
||||
'validation': '[0-9]{12}',
|
||||
'helpMessage': 'Must be a valid AWS account number!',
|
||||
},
|
||||
{
|
||||
'name': 'path',
|
||||
'type': 'str',
|
||||
'default': '/',
|
||||
'helpMessage': 'Path to upload certificate.'
|
||||
}
|
||||
]
|
||||
|
||||
def upload(self, name, body, private_key, cert_chain, options, **kwargs):
|
||||
iam.upload_cert(name, body, private_key,
|
||||
self.get_option('path', options),
|
||||
cert_chain=cert_chain,
|
||||
account_number=self.get_option('accountNumber', options))
|
||||
|
||||
def deploy(self, elb_name, account, region, certificate):
|
||||
pass
|
||||
|
||||
|
||||
class S3DestinationPlugin(ExportDestinationPlugin):
|
||||
title = 'AWS-S3'
|
||||
slug = 'aws-s3'
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
.. moduleauthor:: Christopher Jolley <chris@alwaysjolley.com>
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import hvac
|
||||
from flask import current_app
|
||||
@ -20,6 +21,14 @@ from lemur.plugins.bases import DestinationPlugin
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
class Error(Exception):
|
||||
"""Base exception class"""
|
||||
pass
|
||||
|
||||
class InvalidSanError(Error):
|
||||
"""Invlied SAN in SAN list as defined by regex in destination"""
|
||||
pass
|
||||
|
||||
class VaultDestinationPlugin(DestinationPlugin):
|
||||
"""Hashicorp Vault Destination plugin for Lemur"""
|
||||
title = 'Vault'
|
||||
@ -37,6 +46,17 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||
'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': 'vaultAuthTokenFile',
|
||||
'type': 'str',
|
||||
@ -80,8 +100,9 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||
{
|
||||
'name': 'sanFilter',
|
||||
'type': 'str',
|
||||
'value': '.*',
|
||||
'required': False,
|
||||
'validation': '^[0-9a-zA-Z\\\?\[\](){}^$+._-]+$',
|
||||
'validation': '^[0-9a-zA-Z\\\?\[\](){}|^$+*,._-]+$',
|
||||
'helpMessage': 'Valid regex filter'
|
||||
}
|
||||
]
|
||||
@ -105,25 +126,30 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||
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)
|
||||
for san in san_list:
|
||||
if not re.match(san_filter, san):
|
||||
current_app.logger.exception(
|
||||
"Exception uploading secret to vault: invalid SAN in certificate",
|
||||
exc_info=True)
|
||||
if san_filter:
|
||||
for san in san_list:
|
||||
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)
|
||||
os._exit(1)
|
||||
|
||||
with open(token_file, 'r') as file:
|
||||
token = file.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)
|
||||
else:
|
||||
path = '{0}/{1}'.format(path, cname)
|
||||
|
||||
secret = get_secret(url, token, mount, path)
|
||||
secret = get_secret(client, mount, path)
|
||||
secret['data'][cname] = {}
|
||||
|
||||
if bundle == 'Nginx' and cert_chain:
|
||||
@ -137,8 +163,9 @@ class VaultDestinationPlugin(DestinationPlugin):
|
||||
if isinstance(san_list, list):
|
||||
secret['data'][cname]['san'] = san_list
|
||||
try:
|
||||
client.secrets.kv.v1.create_or_update_secret(
|
||||
path=path, mount_point=mount, secret=secret['data'])
|
||||
client.secrets.kv.create_or_update_secret(
|
||||
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)
|
||||
@ -158,12 +185,14 @@ def get_san_list(body):
|
||||
return san_list
|
||||
|
||||
|
||||
def get_secret(url, token, mount, path):
|
||||
def get_secret(client, mount, path):
|
||||
""" retreiive existing data from mount path and return dictionary """
|
||||
result = {'data': {}}
|
||||
try:
|
||||
client = hvac.Client(url=url, token=token)
|
||||
result = client.secrets.kv.v1.read_secret(path=path, mount_point=mount)
|
||||
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)
|
||||
except ConnectionError:
|
||||
pass
|
||||
finally:
|
||||
|
Reference in New Issue
Block a user