[WIP] - 422 elb rotate (#493)

* Initial work on certificate rotation.

* Adding ability to get additional certificate info.

* - Adding endpoint rotation.
- Removes the g requirement from all services to enable easier testing.
This commit is contained in:
kevgliss
2016-11-18 11:27:46 -08:00
committed by GitHub
parent 6fd47edbe3
commit d45e7d6b85
27 changed files with 393 additions and 390 deletions

View File

@ -103,6 +103,7 @@ def describe_load_balancer_types(policies, **kwargs):
return kwargs['client'].describe_load_balancer_policy_types(PolicyTypeNames=policies)
@sts_client('elb')
def attach_certificate(account_number, region, name, port, certificate_id):
"""
Attaches a certificate to a listener, throws exception
@ -115,69 +116,3 @@ def attach_certificate(account_number, region, name, port, certificate_id):
:param certificate_id:
"""
return assume_service(account_number, 'elb', region).set_lb_listener_SSL_certificate(name, port, certificate_id)
# def create_new_listeners(account_number, region, name, listeners=None):
# """
# Creates a new listener and attaches it to the ELB.
#
# :param account_number:
# :param region:
# :param name:
# :param listeners:
# :return:
# """
# listeners = [is_valid(x) for x in listeners]
# return assume_service(account_number, 'elb', region).create_load_balancer_listeners(name, listeners=listeners)
#
#
# def update_listeners(account_number, region, name, listeners, ports):
# """
# We assume that a listener with a specified port already exists. We can then
# delete the old listener on the port and create a new one in it's place.
#
# If however we are replacing a listener e.g. changing a port from 80 to 443 we need
# to make sure we kept track of which ports we needed to delete so that we don't create
# two listeners (one 80 and one 443)
#
# :param account_number:
# :param region:
# :param name:
# :param listeners:
# :param ports:
# """
# # you cannot update a listeners port/protocol instead we remove the only one and
# # create a new one in it's place
# listeners = [is_valid(x) for x in listeners]
#
# assume_service(account_number, 'elb', region).delete_load_balancer_listeners(name, ports)
# return create_new_listeners(account_number, region, name, listeners=listeners)
#
#
# def delete_listeners(account_number, region, name, ports):
# """
# Deletes a listener from an ELB.
#
# :param account_number:
# :param region:
# :param name:
# :param ports:
# :return:
# """
# return assume_service(account_number, 'elb', region).delete_load_balancer_listeners(name, ports)
#
#
# def get_listeners(account_number, region, name):
# """
# Gets the listeners configured on an elb and returns a array of tuples
#
# :param account_number:
# :param region:
# :param name:
# :return: list of tuples
# """
#
# conn = assume_service(account_number, 'elb', region)
# elbs = conn.get_all_load_balancers(load_balancer_names=[name])
# if elbs:
# return elbs[0].listeners

View File

@ -80,6 +80,20 @@ def get_cert_from_arn(arn):
return digest_aws_cert_response(response)
def create_arn_from_cert(account_number, region, certificate_name):
"""
Create an ARN from a certificate.
:param account_number:
:param region:
:param certificate_name:
:return:
"""
return "arn:aws:iam:{region}:{account_number}:{certificate_name}".format(
region=region,
account_number=account_number,
certificate_name=certificate_name)
def digest_aws_cert_response(response):
"""
Processes an AWS certifcate response and retrieves the certificate body and chain.

View File

@ -36,9 +36,7 @@ from flask import current_app
from boto.exception import BotoServerError
from lemur.plugins.bases import DestinationPlugin, SourcePlugin
from lemur.plugins.lemur_aws.ec2 import get_regions
from lemur.plugins.lemur_aws.elb import get_all_elbs, describe_load_balancer_policies, attach_certificate
from lemur.plugins.lemur_aws import iam, s3
from lemur.plugins.lemur_aws import iam, s3, elb, ec2
from lemur.plugins import lemur_aws as aws
@ -77,7 +75,10 @@ class AWSDestinationPlugin(DestinationPlugin):
e = self.get_option('elb', options)
if e:
attach_certificate(kwargs['accountNumber'], ['region'], e['name'], e['port'], e['certificateId'])
iam.attach_certificate(kwargs['accountNumber'], ['region'], e['name'], e['port'], e['certificateId'])
def deploy(self, elb_name, account, region, certificate):
pass
class AWSSourcePlugin(SourcePlugin):
@ -124,15 +125,15 @@ class AWSSourcePlugin(SourcePlugin):
regions = self.get_option('regions', options)
if not regions:
regions = get_regions(account_number=account_number)
regions = ec2.get_regions(account_number=account_number)
else:
regions = regions.split(',')
for region in regions:
elbs = get_all_elbs(account_number=account_number, region=region)
elbs = elb.get_all_elbs(account_number=account_number, region=region)
current_app.logger.info("Describing load balancers in {0}-{1}".format(account_number, region))
for elb in elbs:
for listener in elb['ListenerDescriptions']:
for e in elbs:
for listener in e['ListenerDescriptions']:
if not listener['Listener'].get('SSLCertificateId'):
continue
@ -140,21 +141,29 @@ class AWSSourcePlugin(SourcePlugin):
continue
endpoint = dict(
name=elb['LoadBalancerName'],
dnsname=elb['DNSName'],
type='elb',
name=e['LoadBalancerName'],
dnsname=e['DNSName'],
type='e',
port=listener['Listener']['LoadBalancerPort'],
certificate_name=iam.get_name_from_arn(listener['Listener']['SSLCertificateId'])
)
if listener['PolicyNames']:
policy = describe_load_balancer_policies(elb['LoadBalancerName'], listener['PolicyNames'], account_number=account_number, region=region)
policy = e.describe_load_balancer_policies(e['LoadBalancerName'], listener['PolicyNames'], account_number=account_number, region=region)
endpoint['policy'] = format_elb_cipher_policy(policy)
endpoints.append(endpoint)
return endpoints
def update_endpoint(self, options, endpoint, certificate):
account_number = self.get_option('accountNumber', options)
regions = self.get_option('regions', options)
for region in regions:
arn = iam.create_arn_from_cert(account_number, region, certificate.name)
elb.attach_certificate(account_number, region, certificate.name, endpoint.port, arn)
def clean(self, options, **kwargs):
account_number = self.get_option('accountNumber', options)
certificates = self.get_certificates(options)

View File

@ -15,7 +15,7 @@ def test_get_name_from_arn():
@mock_iam()
def test_get_all_server_certs(app):
from lemur.plugins.lemur_aws.iam import upload_cert, get_all_server_certs
upload_cert('123456789012', 'testCert', EXTERNAL_VALID_STR.decode('utf-8'), PRIVATE_KEY_STR.decode('utf-8'))
upload_cert('123456789012', 'testCert', EXTERNAL_VALID_STR, PRIVATE_KEY_STR)
certs = get_all_server_certs('123456789012')
assert len(certs) == 1
@ -24,6 +24,6 @@ def test_get_all_server_certs(app):
@mock_iam()
def test_get_cert_from_arn(app):
from lemur.plugins.lemur_aws.iam import upload_cert, get_cert_from_arn
upload_cert('123456789012', 'testCert', EXTERNAL_VALID_STR.decode('utf-8'), PRIVATE_KEY_STR.decode('utf-8'))
upload_cert('123456789012', 'testCert', EXTERNAL_VALID_STR, PRIVATE_KEY_STR)
body, chain = get_cert_from_arn('arn:aws:iam::123456789012:server-certificate/testCert')
assert body.replace('\n', '') == EXTERNAL_VALID_STR.decode('utf-8').replace('\n', '')
assert body.replace('\n', '') == EXTERNAL_VALID_STR.replace('\n', '')