Search code examples
amazon-web-servicesamazon-elbtroposphere

How to update the SSL negotiation policy in using the Troposhpere framework for an AWS classic load balancer 443 listener


I have a working Troposphere template that brings up my environment with a classic load balancer. I am modifying it to have the load balancer port 443 listener come up using the SSL Negotiation policy(cypher) ELBSecurityPolicy-TLS-1-2-2017-01.

It will let me generate the cloudformation yaml but when I try to create the stack using the generated yaml I get the error "Encountered unsupported property PolicyType" while it is trying to create the load balancer.

PolicyType is supported by Troposphere but not in AWS CF??

Any clues as to what I am doing wrong? Is there a better way?

I can not find any examples of updating the SSL negotiation using the Troposphere framework.

Here is the snippet of my Troposphere ELB listener code section that I think should do the magic -

            LoadBalancerPort="443",
            InstancePort="443",
            Protocol="https",
            InstanceProtocol="https",
            PolicyNames=["StickyPolicy", "My-SSLNegotiation-Policy"],
            #todo - need valid cert
            SSLCertificateId=params.CA_SSL_CERT,
        ),
        elb.Policy(
            LoadBalancerPorts=["443"],
            InstancePorts=["443"],
            PolicyType="SSLNegotiationPolicyType",
            PolicyName="My-SSLNegotiation-Policy",
            Attributes=[{
            "Name": "Reference-Security-Policy",
            "Value": "ELBSecurityPolicy-TLS-1-2-2017-01"
            }]
        )`

Here is the policy class for the Troposphere elasticloadbalancing.py(https://github.com/cloudtools/troposphere/blob/master/troposphere/elasticloadbalancing.py)

class Policy(AWSProperty):
    props = {
        'Attributes': ([dict], False),
        'InstancePorts': (list, False),
        'LoadBalancerPorts': (list, False),
        'PolicyName': (basestring, True),
        'PolicyType': (basestring, True),
    }

Here is my entire Troposphere load balancer code :

LoadBalancer = t.add_resource(LoadBalancer(
#https://github.com/cloudtools/troposphere/blob/master/examples/Autoscaling.py
    "LoadBalancer",
    ConnectionDrainingPolicy=elb.ConnectionDrainingPolicy(
        Enabled=True,
        Timeout=120,
    ),
    ConnectionSettings=elb.ConnectionSettings(
        IdleTimeout=600
    ),
    Subnets=[DMZSubnet1a, DMZSubnet1b],
    LBCookieStickinessPolicy=[elb.LBCookieStickinessPolicy(
        PolicyName="StickyPolicy",
        CookieExpirationPeriod="28800"
        ),
    ],
    #AvailabilityZones=[Join("", [Ref("AWS::Region"), "a"]), Join("", [Ref("AWS::Region"), "b"])],
    HealthCheck=elb.HealthCheck(
        #Target="HTTPS:443/index.html",
        Target="TCP:80",
        HealthyThreshold="5",
        UnhealthyThreshold="5",
        Interval="30",
        Timeout="15",
    ),
    # Redirect http to https on classic load balancer   -  https://aws.amazon.com/premiumsupport/knowledge-center/redirect-http-https-elb/
    Listeners=[
        elb.Listener(
            LoadBalancerPort="80",
            InstancePort="80",
            Protocol="TCP",
            InstanceProtocol="TCP",
            #SSLCertificateId=Ref(SSLCertificateId)
            #SSLCertificateId=params.CA_SSL_CERT,
        ),
        elb.Listener(
            LoadBalancerPort="443",
            InstancePort="443",
            Protocol="https",
            InstanceProtocol="https",
            PolicyNames=["StickyPolicy", "My-SSLNegotiation-Policy"],
            #todo - need valid cert
            SSLCertificateId=params.CA_SSL_CERT,
        ),
        elb.Policy(
            LoadBalancerPorts=["443"],
            InstancePorts=["443"],
            PolicyType="SSLNegotiationPolicyType",
            PolicyName="My-SSLNegotiation-Policy",
            Attributes=[{
            "Name": "Reference-Security-Policy",
            "Value": "ELBSecurityPolicy-TLS-1-2-2017-01"
            }]
        )
    ],
    CrossZone=True,
    SecurityGroups=[LoadBalancerSG],
    LoadBalancerName=Join("-", [Ref("AWS::StackName"), "LdBlncr"]),
    Scheme="internet-facing",
))

Here is the AWS CloudFormation yaml it creates for the load balancer :

  LoadBalancer:
    Properties:
      ConnectionDrainingPolicy:
        Enabled: true
        Timeout: 120
      ConnectionSettings:
        IdleTimeout: 600
      CrossZone: 'true'
      HealthCheck:
        HealthyThreshold: '5'
        Interval: '30'
        Target: TCP:80
        Timeout: '15'
        UnhealthyThreshold: '5'
      LBCookieStickinessPolicy:
        - CookieExpirationPeriod: '28800'
          PolicyName: StickyPolicy
      Listeners:
        - InstancePort: '80'
          InstanceProtocol: TCP
          LoadBalancerPort: '80'
          Protocol: TCP
        - InstancePort: '443'
          InstanceProtocol: https
          LoadBalancerPort: '443'
          PolicyNames:
            - StickyPolicy
            - My-SSLNegotiation-Policy
          Protocol: https
          SSLCertificateId: arn:aws:acm:us-east-1:000000000:certificate/d79e336-dd51-4cac-ba3
        - Attributes:
            - Name: Reference-Security-Policy
              Value: ELBSecurityPolicy-TLS-1-2-2017-01
          InstancePorts:
            - '443'
          LoadBalancerPorts:
            - '443'
          PolicyName: My-SSLNegotiation-Policy
          PolicyType: SSLNegotiationPolicyType
      LoadBalancerName: !Join
        - '-'
        - - !Ref 'AWS::StackName'
          - LdBlncr
      Scheme: internet-facing
      SecurityGroups:
        - !ImportValue
          Fn::Join:
            - '-'
            - - ernie
              - LoadBalancerSG
      Subnets:
        - !ImportValue
          Fn::Join:
            - '-'
            - - ernie
              - DMZSubnet1a
        - !ImportValue
          Fn::Join:
            - '-'
            - - ernie
              - DMZSubnet1b
    Type: AWS::ElasticLoadBalancing::LoadBalancer

Solution

  • The Classic Load Balancer Policies should be specified under the Policies property, not the Listeners property. https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-elb.html#cfn-ec2-elb-policies

    Remove the elb.Policy( ... ) from the Listerners=[ ...] property and add the Policies = [ elb.Policy( ... ), ... ] property to the LoadBalancer resource / object.