From 1ae1f94fcc51735cd90c2eae89ed988139572926 Mon Sep 17 00:00:00 2001 From: Benedetto Lo Giudice Date: Fri, 12 Jun 2015 15:20:03 +0100 Subject: [PATCH] Pindown the SSL cipher policy in CFN Add the current SSL cipher policy (Amazon default) via troposphere Pindown a policy either in the CFN YAML file or as an implicit default via troposphere Value of property PolicyNames must be of type List of String Updated tests Updated CHANGELOG and README --- CHANGELOG.md | 3 +++ README.rst | 49 +++++++++++++++++++++++++++++++++++++++++ bootstrap_cfn/config.py | 21 +++++++++++++++--- tests/test.py | 3 ++- tests/tests.py | 40 +++++++++++++++++++++++++++++++-- 5 files changed, 110 insertions(+), 6 deletions(-) mode change 100644 => 100755 tests/tests.py diff --git a/CHANGELOG.md b/CHANGELOG.md index af49471..444fd89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version 0.5.x +* Add an SSL cipher list policy pindown: implicit (no YAML entry needed) + or explicity (with YAML entry) ## Version 0.5.3 * Improve message content when cfn_create raises an exception and fails. diff --git a/README.rst b/README.rst index 127e8f2..b44c6e2 100644 --- a/README.rst +++ b/README.rst @@ -147,3 +147,52 @@ You can enable encryption for your DB by adding the following:: **NOTE:** AWS does not support RDS encryption for the *db.t2.** instance classes. More details on supported instance classes are available `here `_ + +SSL cipher list pindown (updated 27/06/2015) +============================================ +Amazon provides default policies for cipher lists: + +* Type: SSLNegotiationPolicyType +* Name: Reference-Security-Policy + +More info: + +https://aws.amazon.com/blogs/aws/elastic-load-balancing-perfect-forward-secrecy-and-other-security-enhancements/ + +http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-security-policy-options.html + +http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-ssl-security-policy.html + +http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-security-policy-table.html + +The policy in use currently by default is: ELBSecurityPolicy-2015-05 +This will be pinned down implicitely or explicitely with the following entry in CFN YAML, +part of elb -> listeners:: + + + PolicyNames: + - PinDownSSLNegotiationPolicy201505 + +Example:: + + elb: + - name: elbname + hosted_zone: something.dsd.io. + scheme: internet-facing + certificate_name: certificate-name + listeners: + - LoadBalancerPort: 80 + InstancePort: 80 + Protocol: HTTP + - LoadBalancerPort: 443 + InstancePort: 80 + Protocol: HTTPS + # following can be commented + PolicyNames: + - PinDownSSLNegotiationPolicy201505 + +To change the policy edit file:: + + bootstrap-cfn/bootstrap_cfn/config.py + + diff --git a/bootstrap_cfn/config.py b/bootstrap_cfn/config.py index f83c003..64a8534 100644 --- a/bootstrap_cfn/config.py +++ b/bootstrap_cfn/config.py @@ -9,7 +9,7 @@ from troposphere.autoscaling import LaunchConfiguration, \ AutoScalingGroup, BlockDeviceMapping, EBSBlockDevice, Tag from troposphere.elasticloadbalancing import LoadBalancer, HealthCheck, \ - ConnectionDrainingPolicy + ConnectionDrainingPolicy, Policy from troposphere.ec2 import SecurityGroup from troposphere.route53 import RecordSetGroup, RecordSet, AliasTarget from troposphere.ec2 import Route, Subnet, InternetGateway, VPC, \ @@ -25,7 +25,11 @@ class ProjectConfig: config = None def __init__(self, config, environment, passwords=None): - self.config = self.load_yaml(config)[environment] + try: + self.config = self.load_yaml(config)[environment] + except: + raise errors.BootstrapCfnError("Environment " + environment + " not found") + if passwords: passwords_dict = self.load_yaml(passwords)[environment] self.config = utils.dict_merge(self.config, passwords_dict) @@ -401,8 +405,14 @@ def elb(self): Enabled=True, Timeout=120, ), + Policies=[ + Policy( + Attributes=[{'Name': "Reference-Security-Policy", 'Value': "ELBSecurityPolicy-2015-05"}], + PolicyType='SSLNegotiationPolicyType', + PolicyName='PinDownSSLNegotiationPolicy201505' + ) + ] ) - if "health_check" in elb: load_balancer.HealthCheck = HealthCheck(**elb['health_check']) @@ -426,6 +436,11 @@ def elb(self): ":server-certificate/", "{0}-{1}".format(cert_name, self.stack_name)] ) + # if not present, add the default cipher policy + if 'PolicyNames' not in listener: + print "\n\n[INFO] ELB Listener for port 443 has no SSL Policy. " + \ + "Using default ELBSecurityPolicy-2015-05" + listener['PolicyNames'] = ['PinDownSSLNegotiationPolicy201505'] elb_list.append(load_balancer) diff --git a/tests/test.py b/tests/test.py index 3ad7b62..e72e47b 100644 --- a/tests/test.py +++ b/tests/test.py @@ -47,7 +47,8 @@ def setUp(self): 'Protocol': 'TCP'}, {'InstancePort': 443, 'LoadBalancerPort': 443, - 'Protocol': 'TCP'}], + 'Protocol': 'TCP', + 'PolicyNames': 'PinDownSSLNegotiationPolicy201505'}], 'name': 'test-dev-external', 'scheme': 'internet-facing'}, {'hosted_zone': 'kyrtest.pf.dsd.io.', diff --git a/tests/tests.py b/tests/tests.py old mode 100644 new mode 100755 index 23f8e0d..90663b3 --- a/tests/tests.py +++ b/tests/tests.py @@ -11,7 +11,7 @@ from troposphere.route53 import RecordSetGroup from troposphere.elasticloadbalancing import LoadBalancer, HealthCheck,\ - ConnectionDrainingPolicy + ConnectionDrainingPolicy, Policy from troposphere.iam import PolicyType import bootstrap_cfn.errors as errors @@ -233,6 +233,13 @@ def test_elb(self): SecurityGroups=[Ref("DefaultSGtestdevinternal")], LoadBalancerName="ELB-test-dev-internal", Scheme="internal", + Policies=[ + Policy( + Attributes=[{'Name': "Reference-Security-Policy", 'Value': "ELBSecurityPolicy-2015-05"}], + PolicyType='SSLNegotiationPolicyType', + PolicyName='PinDownSSLNegotiationPolicy201505' + ) + ] ) pt1 = PolicyType( @@ -333,6 +340,13 @@ def test_elb(self): SecurityGroups=[Ref("DefaultSGtestdevexternal")], LoadBalancerName="ELB-test-dev-external", Scheme="internet-facing", + Policies=[ + Policy( + Attributes=[{'Name': "Reference-Security-Policy", 'Value': "ELBSecurityPolicy-2015-05"}], + PolicyType='SSLNegotiationPolicyType', + PolicyName='PinDownSSLNegotiationPolicy201505' + ) + ], ) known = [lb, lb2, pt1, pt2, rs, rsg] expected_sgs = [ @@ -653,10 +667,18 @@ def test_elb_with_ssl(self): {"InstancePort": 443, "SSLCertificateId": Join( "", ["arn:aws:iam::", Ref("AWS::AccountId"), ":server-certificate/", "my-cert-my-stack-name"]), - "LoadBalancerPort": 443, "Protocol": "HTTPS"}], + "LoadBalancerPort": 443, "Protocol": "HTTPS", + "PolicyNames": ["PinDownSSLNegotiationPolicy201505"]}], SecurityGroups=[Ref("DefaultSGdockerregistryservice")], LoadBalancerName="ELB-docker-registryservice", Scheme="internet-facing", + Policies=[ + Policy( + Attributes=[{'Name': "Reference-Security-Policy", 'Value': "ELBSecurityPolicy-2015-05"}], + PolicyType='SSLNegotiationPolicyType', + PolicyName='PinDownSSLNegotiationPolicy201505' + ) + ], ) Policydockerregistryservice = PolicyType( @@ -755,6 +777,13 @@ def test_elb_with_healthcheck(self): SecurityGroups=[Ref("DefaultSGdockerregistryservice")], LoadBalancerName="ELB-docker-registryservice", Scheme="internet-facing", + Policies=[ + Policy( + Attributes=[{'Name': "Reference-Security-Policy", 'Value': "ELBSecurityPolicy-2015-05"}], + PolicyType='SSLNegotiationPolicyType', + PolicyName='PinDownSSLNegotiationPolicy201505' + ) + ], ) Policydockerregistryservice = PolicyType( @@ -831,6 +860,13 @@ def test_elb_with_reserved_chars(self): SecurityGroups=[Ref("DefaultSGdevdockerregistryservice")], LoadBalancerName="ELB-dev_docker-registryservice", Scheme="internet-facing", + Policies=[ + Policy( + Attributes=[{'Name': "Reference-Security-Policy", 'Value': "ELBSecurityPolicy-2015-05"}], + PolicyType='SSLNegotiationPolicyType', + PolicyName='PinDownSSLNegotiationPolicy201505' + ) + ], ) DNSdevdockerregistryservice = RecordSetGroup(