# CloudFormation to launch a demo PHP app and turn on specific TLS Ciphers
#
# Some useful references:
#
# http://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html
# http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-elbpolicies
# https://forums.aws.amazon.com/ann.jspa?annID=4475

AWSTemplateFormatVersion: 2010-09-09
Description: High Security TLS Amazon Elastic Beanstalk Application - Provides an
  application whose load balancer is configured to support only TLS 1.2 using an AWS
  managed protocol policy.
Mappings:
  # For DNS ZoneID mapping, see
  # http://docs.aws.amazon.com/general/latest/gr/rande.html#elb_region
  # Although it's documented for elasticloadbalancing.REGION.amazonaws.com, it is
  # also valid for REGION.elb.amazonaws.com as well.
  ELBtoR53map:
    "us-east-1":
      "HostedZoneId": "Z35SXDOTRQ7X7K"
    "us-east-2":
      "HostedZoneId": "Z3AADJGX6KTTL2"
    "us-west-1":
      "HostedZoneId": "Z368ELLRRE2KJ0"
    "us-west-2":
      "HostedZoneId": "Z1H1FL5HABSF5"
    "ca-central-1":
      "HostedZoneId": "ZQSVJUPU6J1EY"
    "ap-south-1":
      "HostedZoneId": "ZP97RAFLXTNZK"
    "ap-northeast-2":
      "HostedZoneId": "ZWKZPGTI48KDX"
    "ap-southeast-1":
      "HostedZoneId": "Z1LMS91P8CMLE5"
    "ap-southeast-2":
      "HostedZoneId": "Z1GM3OXH4ZPM65"
    "ap-northeast-1":
      "HostedZoneId": "Z14GRHDCWA56QT"
    "eu-central-1":
      "HostedZoneId": "Z215JYRZR1TBD5"
    "eu-west-1":
      "HostedZoneId": "Z32O12XQLNTSW2"
    "eu-west-2":
      "HostedZoneId": "ZHURV8PSTC4K8"
    "sa-east-1":
      "HostedZoneId": "Z2P70J7HTTTPLU"
Parameters:
  HostedDomainName:
    Type: String
    Default: example.com
    Description: "The DNS name of a hosted zone in Route 53. Must already exist."
  ELBHostName:
    Type: String
    Default: secure
    Description: "The host name to be created in Route 53. E.g., secure"
  CertificateARN:
    Type: String
    Default: arn:aws:acm:REGION:012345678901:certificate/12345678-abcd-1234-abcd-1234abcd1234
    Description: "The ARN of the certificate to use on the load balancer."
Resources:
  sampleApplication:
    Type: AWS::ElasticBeanstalk::Application
    Properties:
      Description: AWS Elastic Beanstalk Sample TLS Application
  sampleApplicationVersion:
    Type: AWS::ElasticBeanstalk::ApplicationVersion
    Properties:
      ApplicationName:
        Ref: sampleApplication
      Description: AWS ElasticBeanstalk Sample Application Version
      SourceBundle:
        S3Bucket: !Sub "elasticbeanstalk-samples-${AWS::Region}"
        S3Key: php-sample.zip
  sampleConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: sampleApplication
      Description: AWS ElasticBeanstalk Sample Configuration Template
      OptionSettings:
      - Namespace: aws:autoscaling:asg
        OptionName: MinSize
        Value: '2'
      - Namespace: aws:autoscaling:asg
        OptionName: MaxSize
        Value: '6'
      - Namespace: aws:elasticbeanstalk:environment
        OptionName: EnvironmentType
        Value: LoadBalanced
      - Namespace: aws:elasticbeanstalk:environment
        OptionName: LoadBalancerType
        Value: classic
      - Namespace: aws:elb:listener
        OptionName: ListenerEnabled
        Value: false
      - Namespace: aws:elb:listener:443
        OptionName: InstancePort
        Value: 80
      - Namespace: aws:elb:listener:443
        OptionName: ListenerProtocol
        Value: HTTPS
      - Namespace: aws:elb:listener:443
        OptionName: InstanceProtocol
        Value: HTTP
      # This connects to the custom policy we define below
      - Namespace: aws:elb:listener:443
        OptionName: PolicyNames
        Value: TLSHighPolicy
      - Namespace: aws:elb:policies
        OptionName: LoadBalancerPorts
        Value: :all
      - Namespace: aws:elb:policies
        OptionName: ConnectionDrainingEnabled
        Value: true
      - Namespace: aws:elb:policies
        OptionName: ConnectionDrainingTimeout
        Value: 20
      - Namespace: aws:elb:policies
        OptionName: ConnectionSettingIdleTimeout
        Value: 60
      - Namespace: aws:elb:policies
        OptionName: Stickiness Cookie Expiration
        Value: 86400
      - Namespace: aws:elb:policies
        OptionName: Stickiness Policy
        Value: false
      # This policy is what you modify to adjust the cipher choices and TLS protocol versions.
      - Namespace:  aws:elb:policies:TLSHighPolicy
        OptionName: SSLReferencePolicy
        Value:      ELBSecurityPolicy-TLS-1-2-2017-01
      - Namespace: aws:elb:listener:443
        OptionName: SSLCertificateId
        Value:  !Sub "${CertificateARN}"
      # Get solution stack names by running 'aws elasticbeanstalk list-available-solution-stacks'
      SolutionStackName: "64bit Amazon Linux 2016.09 v2.3.3 running PHP 7.0"
  sampleEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName:
        Ref: sampleApplication
      Description: Sample Environment
      TemplateName:
        Ref: sampleConfigurationTemplate
      VersionLabel:
        Ref: sampleApplicationVersion
  dnsAliasRecord:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      HostedZoneName: !Sub "${HostedDomainName}."
      Comment: Created for secure Elastic Beanstalk app.
      RecordSets:
      - Name: !Sub "${ELBHostName}.${HostedDomainName}"
        Type: A
        AliasTarget:
          HostedZoneId:
            Fn::FindInMap:
              - ELBtoR53map
              - Ref: AWS::Region
              - "HostedZoneId"
          DNSName: !GetAtt sampleEnvironment.EndpointURL
Outputs:
  LoadBalancerDNSName:
    Description: The public name of the load balancer
    Value: !Join [ "", [ "https://", !GetAtt sampleEnvironment.EndpointURL, "/" ] ]
  DNSAliasName:
    Description: Our TLS web site.
    Value: !Sub "https://${ELBHostName}.${HostedDomainName}/"
  TestOnSSLLabs:
    Description: Click this link to test the site at SSLLabs.
    Value: !Sub "https://www.ssllabs.com/ssltest/analyze.html?d=${ELBHostName}.${HostedDomainName}&hideResults=on&clearCache=on"
