AWSTemplateFormatVersion: '2010-09-09'
Description: >-
  This template creates BIG-IP PAYG or BYOL High Availability WAF solution. The template
  uses nested templates for provisioning network, access, and compute resources for
  hosting BIG-IP Failover solution.
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Templates Location
        Parameters:
          - s3BucketName
          - s3BucketRegion
          - artifactLocation
      - Label:
          default: Network Configuration
        Parameters:
          - numAzs
          - numSubnets
          - subnetMask
          - vpcCidr
          - bigIpMgmtAddress01
          - bigIpExternalSelfIp01
          - bigIpExternalVip01
          - bigIpInternalSelfIp01
          - bigIpMgmtAddress02
          - bigIpExternalSelfIp02
          - bigIpExternalVip02
          - bigIpInternalSelfIp02
          - bigIpPeerAddr
      - Label:
          default: Amazon EC2 Configuration
        Parameters:
          - sshKey
          - bigIpInstanceProfile
      - Label:
          default: DAG / Ingress
        Parameters:
          - provisionPublicIpMgmt
          - restrictedSrcAddressMgmt
          - restrictedSrcAddressApp
      - Label:
          default: BIG-IP Configuration
        Parameters:
          - bigIpRuntimeInitPackageUrl
          - bigIpRuntimeInitConfig01
          - bigIpRuntimeInitConfig02
          - bigIpHostname01
          - bigIpHostname02
          - bigIpLicenseKey01
          - bigIpLicenseKey02
          - bigIpImage
          - bigIpCustomImageId
          - bigIpInstanceType
          - numNics
          - bigIpSecretArn
          - cfeS3Bucket
          - cfeVipTag
          - cfeTag
          - allowUsageAnalytics
      - Label:
          default: Application Configuration
        Parameters:
          - appDockerImageName
          - provisionExampleApp
      - Label:
          default: Resources Tags
        Parameters:
          - uniqueString
          - application
          - cost
          - environment
          - group
          - owner
    ParameterLabels:
      allowUsageAnalytics:
        default: Send anonymous statistics to F5
      appDockerImageName:
        default: Application docker image name
      application:
        default: Application
      artifactLocation:
        default: Path to directory where the modules folder is located. ex. "examples/"
      bigIpCustomImageId:
        default: Custom Image Id
      bigIpHostname01:
        default: Hostname for BIG-IP instance 01
      bigIpHostname02:
        default: Hostname for BIG-IP instance 02
      bigIpImage:
        default: F5 BIG-IP Image
      bigIpInstanceType:
        default: Enter valid instance type.
      bigIpInstanceProfile:
        default: Instance profile
      bigIpLicenseKey01:
        default: License key for BIG-IP instance 01
      bigIpLicenseKey02:
        default: License key for BIG-IP instance 02
      bigIpPeerAddr:
        default: Static self IP address for peer device.
      bigIpRuntimeInitConfig01:
        default: BIG-IP Runtime Init config used for BIGIP instance A
      bigIpRuntimeInitConfig02:
        default: BIG-IP Runtime Init config used for BIGIP instance B
      bigIpRuntimeInitPackageUrl:
        default: Runtime Init Package
      cfeS3Bucket:
        default: CFE S3 bucket
      cfeTag:
        default: CFE Deployment tag value
      cfeVipTag:
        default: CFE VIP tag value
      cost:
        default: Cost Center
      environment:
        default: Environment
      bigIpExternalSelfIp01:
        default: External private ip address for BIGIP instance A
      bigIpExternalSelfIp02:
        default: External private ip address for BIGIP instance B
      bigIpExternalVip01:
        default: External secondary ip address for BIGIP instance A
      bigIpExternalVip02:
        default: External secondary ip address for BIGIP instance B
      group:
        default: Group
      bigIpInternalSelfIp01:
        default: Internal private ip address for BIGIP instance A
      bigIpInternalSelfIp02:
        default: Internal private ip address for BIGIP instance B
      bigIpMgmtAddress01:
        default: Management private ip address for BIGIP instance A
      bigIpMgmtAddress02:
        default: Management private ip address for BIGIP instance B
      bigIpSecretArn:
        default: ARN of Secrets Manager secret
      numAzs:
        default: Number of Availability Zones
      numNics:
        default: Interfaces
      numSubnets:
        default: Number of Subnets
      owner:
        default: Owner
      provisionExampleApp:
        default: Provision Example App
      provisionPublicIpMgmt:
        default: Provision Public IP addresses for the BIG-IP management interface
      restrictedSrcAddressApp:
        default: Restricted Source Address to Application
      restrictedSrcAddressMgmt:
        default: Restricted Source Address to BIG-IP
      s3BucketName:
        default: S3 Bucket where Templates are Located
      s3BucketRegion:
        default: S3 Bucket Region where Templates are Located
      sshKey:
        default: Supply the public key that will be used for SSH authentication to
          the BIG-IP and application virtual machines
      subnetMask:
        default: Subnet Mask
      uniqueString:
        default: Unique string
      vpcCidr:
        default: VPC CIDR
  Version: 3.6.0.0
Outputs:
  amiId:
    Condition: noCustomImageId
    Description: Ami lookup returned ami id.
    Value: !GetAtt [AmiInfo, Id]
  bastionHostInstanceId:
    Condition: noPublicIp
    Description: bastion instance id
    Value: !GetAtt [Bastion, Outputs.bastionInstanceId]
  bastionPublicIp:
    Condition: noPublicIp
    Description: bastion's public IP address
    Value: !GetAtt [Bastion, Outputs.bastionPublicIp]
  bigIpInstance01:
    Description: BIGIP instance A nested stack name
    Value: !GetAtt [BigIpInstance01, Outputs.stackName]
  bigIpInstanceMgmtPrivateIp01:
    Description: private management ip for BIGIP instance A
    Value: !GetAtt [BigIpInstance01, Outputs.bigIpManagementInterfacePrivateIp]
  bigIpManagementPublicIp01:
    Condition: usePublicIpMgmt
    Description: bigip A public management address. WARNING - For eval purposes only.
      Production should never have the management interface exposed to Internet
    Value: !GetAtt [Dag, Outputs.bigIpManagementEipAddress01]
  bigIpManagementSsh01:
    Condition: usePublicIpMgmt
    Description: ssh login to bigip A management address. WARNING - For eval purposes
      only. Production should never have the management interface exposed to Internet
    Value: !Join
      - ''
      - - 'ssh admin@'
        - !GetAtt [Dag, Outputs.bigIpManagementEipAddress01]
  bigIpManagement01Url443:
    Condition: usePublicIpMgmt
    Description: url to bigip A management address. WARNING - For eval purposes only.
      Production should never have the management interface exposed to Internet
    Value: !Join
      - ''
      - - 'https://'
        - !GetAtt [Dag, Outputs.bigIpManagementEipAddress01]
  bigIpInstance02:
    Description: BIGIP instance B nested stack name
    Value: !GetAtt [BigIpInstance02, Outputs.stackName]
  bigIpInstanceMgmtPrivateIp02:
    Description: private management ip for BIGIP instance B
    Value: !GetAtt [BigIpInstance02, Outputs.bigIpManagementInterfacePrivateIp]
  bigIpKeyPairName:
    Condition: createKeyPair
    Description: SSH key pair name
    Value: !GetAtt [Access, Outputs.keyPairName]
  bigIpManagementPublicIp02:
    Condition: usePublicIpMgmt
    Description: bigip B public management address. WARNING - For eval purposes only.
      Production should never have the management interface exposed to Internet
    Value: !GetAtt [Dag, Outputs.bigIpManagementEipAddress02]
  bigIpManagementSsh02:
    Condition: usePublicIpMgmt
    Description: ssh login to bigip B management address. WARNING - For eval purposes
      only. Production should never have the management interface exposed to Internet
    Value: !Join
      - ''
      - - 'ssh admin@'
        - !GetAtt [Dag, Outputs.bigIpManagementEipAddress02]
  bigIpManagement02Url443:
    Condition: usePublicIpMgmt
    Description: url to bigip B management address. WARNING - For eval purposes only.
      Production should never have the management interface exposed to Internet
    Value: !Join
      - ''
      - - 'https://'
        - !GetAtt [Dag, Outputs.bigIpManagementEipAddress02]
  bigIpSecretArn:
    Condition: createSecret
    Description: Secret ARN
    Value: !GetAtt [Access, Outputs.secretArn]
  cfeS3Bucket:
    Description: cfe s3 bucket created and used for cloud-failover-extension
    Value: !If
      - useDefaultCfeS3Bucket
      - !Join
        - ''
        - - !Ref 'uniqueString'
          - '-bigip-high-availability-solution'
      - !Ref 'cfeS3Bucket'
  vipPublicUrl:
    Condition: usePublicIpVip
    Description: url to public vip address
    Value: !Join
      - ''
      - - 'https://'
        - !GetAtt [Dag, Outputs.bigIpExternalEipAddress03]
Parameters:
  allowUsageAnalytics:
    AllowedValues:
      - 'true'
      - 'false'
    Default: 'true'
    Description: This deployment can send anonymous statistics to F5 to help us determine
      how to improve our solutions. If you select **false** statistics are not sent.
    Type: String
  appDockerImageName:
    Default: 'f5devcentral/f5-demo-app:latest'
    Description: Application docker image name
    Type: String
  application:
    Default: f5app
    Description: Application Tag.
    Type: String
  artifactLocation:
    AllowedPattern: ^.*[0-9a-zA-Z]+/$
    ConstraintDescription: key prefix can include numbers, lowercase letters, uppercase
      letters, hyphens (-), and forward slash (/).
    Default: f5-aws-cloudformation-v2/v3.6.0.0/examples/
    Description: The path in the S3Bucket where the modules folder is located. Can
      include numbers, lowercase letters, uppercase letters, hyphens (-), and forward
      slash (/).
    Type: String
  bigIpCustomImageId:
    Default: ''
    Description: Provide BIG-IP AMI ID you wish to deploy.
    MaxLength: 255
    Type: String
  bigIpHostname01:
    ConstraintDescription: Must be a valid hostname containing fewer than 63 characters.
    Default: 'failover01.local'
    Description: Supply the hostname you would like to use for the BIG-IP instance.
      The hostname must contain fewer than 63 characters.
    MaxLength: 63
    Type: String
  bigIpHostname02:
    ConstraintDescription: Must be a valid hostname containing fewer than 63 characters.
    Default: 'failover02.local'
    Description: Supply the hostname you would like to use for the BIG-IP instance.
      The hostname must contain fewer than 63 characters.
    MaxLength: 63
    Type: String
  bigIpImage:
    ConstraintDescription: Must be a valid F5 BIG-IP market place image
    Default: '*17.1.1-0.2.6**PAYG-Best Plus 25Mbps*'
    Description: F5 BIG-IP market place image
    Type: String
  bigIpInstanceProfile:
    Default: ''
    Description: Enter the name of an existing IAM instance profile with applied IAM
      policy to be associated to the BIG-IP virtual machine(s). Leave default to create
      a new instance profile.
    Type: String
  bigIpInstanceType:
    ConstraintDescription: Must be a valid EC2 instance type for BIG-IP
    Default: m5.xlarge
    Description: Enter valid instance type.
    Type: String
  bigIpLicenseKey01:
    Default: ''
    Description: Supply the F5 BYOL license key for BIG-IP instance 01. Leave this
      parameter blank if deploying the PAYG solution.
    Type: String
  bigIpLicenseKey02:
    Default: ''
    Description: Supply the F5 BYOL license key for BIG-IP instance 02. Leave this
      parameter blank if deploying the PAYG solution.
    Type: String
  bigIpPeerAddr:
    Default: '10.0.1.11'
    Description: Provide the static address of the remote peer used for clustering.
      In this failover solution, clustering is initiated from the second instance
      (02) to the first instance (01) so you would provide the first instances Self
      IP address.
    Type: String
  bigIpRuntimeInitConfig01:
    Default: 'https://f5-cft-v2.s3.amazonaws.com/f5-aws-cloudformation-v2/v3.6.0.0/examples/failover/bigip-configurations/runtime-init-conf-3nic-payg-instance01-with-app.yaml'
    Description: 'REQUIRED - Supply a URL to the bigip-runtime-init configuration
      file in YAML or JSON format to use for f5-bigip-runtime-init configuration.'
    Type: String
  bigIpRuntimeInitConfig02:
    Default: 'https://f5-cft-v2.s3.amazonaws.com/f5-aws-cloudformation-v2/v3.6.0.0/examples/failover/bigip-configurations/runtime-init-conf-3nic-payg-instance02-with-app.yaml'
    Description: 'REQUIRED - Supply a URL to the bigip-runtime-init configuration
      file in YAML or JSON format to use for f5-bigip-runtime-init configuration.'
    Type: String
  bigIpRuntimeInitPackageUrl:
    Default: 'https://cdn.f5.com/product/cloudsolutions/f5-bigip-runtime-init/v2.0.3/dist/f5-bigip-runtime-init-2.0.3-1.gz.run'
    Description: URL for BIG-IP Runtime Init package.
    Type: String
  cfeS3Bucket:
    AllowedPattern: '^$|^(?=.{1,61}$)[0-9a-z]+([0-9a-z-.]*[0-9a-z])*$'
    ConstraintDescription: 'S3 bucket name must be unique, can be between 3 and 63
      characters long, and can contain only lower-case characters, numbers, periods,
      and dashes. It cannot contain underscores, end with a dash, have consecutive
      periods, or use dashes adjacent to periods.'
    Default: ''
    Description: 'Supply a unique name for a CFE S3 bucket created and used by Cloud
      Failover Extension.'
    Type: String
  cfeTag:
    Description: Cloud Failover deployment tag value.
    Type: String
    Default: bigip_high_availability_solution
  cfeVipTag:
    Description: Cloud Failover VIP tag value; provides private ip addresses to be
      assigned to VIP public ip.
    Type: String
    Default: '10.0.0.101,10.0.4.101'
  cost:
    Default: f5cost
    Description: Cost Center Tag.
    Type: String
  environment:
    Default: f5env
    Description: Environment Tag.
    Type: String
  bigIpExternalSelfIp01:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: External Private IP Address for BIGIP instance A.
    Default: 10.0.0.11
    Type: String
  bigIpExternalSelfIp02:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: External Private IP Address for BIGIP instance B.
    Default: 10.0.4.11
    Type: String
  bigIpExternalVip01:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: External Secondary Private IP Address for BIGIP instance A.
    Default: 10.0.0.101
    Type: String
  bigIpExternalVip02:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: External Secondary Private IP Address for BIGIP instance B.
    Default: 10.0.4.101
    Type: String
  group:
    Default: f5group
    Description: Group Tag.
    Type: String
  bigIpInternalSelfIp01:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: Internal Private IP Address for BIGIP instance A.
    Default: 10.0.2.11
    Type: String
  bigIpInternalSelfIp02:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: Internal Private IP Address for BIGIP instance B.
    Default: 10.0.6.11
    Type: String
  bigIpMgmtAddress01:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: Management Private IP Address for BIGIP instance A.
    Default: 10.0.1.11
    Type: String
  bigIpMgmtAddress02:
    AllowedPattern: '^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
    ConstraintDescription: IP address parameter must be in the form x.x.x.x
    Description: Management Private IP Address for BIGIP instance B.
    Default: 10.0.5.11
    Type: String
  bigIpSecretArn:
    Default: ''
    Description: The ARN of an existing AWS Secrets Manager secret where the BIG-IP
      password used for clustering is stored. If left empty, a secret will be created.
    Type: String
  numAzs:
    Default: 2
    Description: Number of Availability Zones to use in the VPC. Region must support
      number of availability zones entered. Min 1 Max 2.
    MaxValue: 2
    MinValue: 1
    Type: Number
  numNics:
    AllowedValues:
      - 2
      - 3
    Default: 3
    Description: Number of interfaces to create on BIG-IP instance. Maximum of 3 allowed.
      Minimum of 2 allowed.
    Type: Number
  numSubnets:
    Default: 4
    Description: Indicate the number of subnets to create. A minimum of 4 subnets
      required when provisionExampleApp = false
    MaxValue: 8
    MinValue: 2
    Type: Number
  owner:
    Default: f5owner
    Description: Owner Tag.
    Type: String
  provisionExampleApp:
    AllowedValues:
      - 'true'
      - 'false'
    Default: 'true'
    Description: Flag to deploy the demo web application.
    Type: String
  provisionPublicIpMgmt:
    AllowedValues:
      - 'true'
      - 'false'
    Default: 'true'
    Description: Whether or not to provision public IP addresses for the BIG-IP management
      network interfaces.
    Type: String
  restrictedSrcAddressMgmt:
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x.
    Description: REQUIRED - The IP address range used to SSH and access management
      GUI on the EC2 instances.
    MaxLength: '18'
    MinLength: '9'
    Type: String
  restrictedSrcAddressApp:
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x.
    Description: REQUIRED - The IP address range that can be used to access web traffic
      (80/443) to the EC2 instances.
    MaxLength: '18'
    MinLength: '9'
    Type: String
  s3BucketName:
    AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$
    ConstraintDescription: >-
      S3 bucket name can include numbers, lowercase letters, uppercase letters, and
      hyphens (-). It cannot start or end with a hyphen (-).
    Default: f5-cft-v2
    Description: >-
      REQUIRED - S3 bucket name for the modules. S3 bucket name can include numbers,
      lowercase letters, uppercase letters, and hyphens (-). It cannot start or end
      with a hyphen (-).
    Type: String
  s3BucketRegion:
    Default: us-east-1
    Description: The AWS Region where the Quick Start S3 bucket (s3BucketName) is
      hosted. When using your own bucket, you must specify this value.
    Type: String
  sshKey:
    Default: ''
    Description: Supply the public key that will be used for SSH authentication to
      the BIG-IP, application, and bastion virtual machines. If left empty, one will
      be created.
    Type: String
  subnetMask:
    ConstraintDescription: 'Subnet mask must be in value of 16-28. Total number of
      subnets created from VPC must be greater than or equal to number of regions
      multiplied by number of subnets. Example: 4 AZ with 8 subnets requires VPC supernetting
      support 32 subnets.'
    Default: 24
    Description: 'Mask for subnets. Valid values include 16-28. Note supernetting
      of VPC occurs based on mask provided; therefore, number of networks must be
      >= to the number of subnets created. Mask for subnets. Valid values include
      16-28.'
    MaxValue: 28
    MinValue: 16
    Type: Number
  uniqueString:
    ConstraintDescription: 'Must contain between 1 and 12 lowercase alphanumeric characters
      with first character as a letter.'
    AllowedPattern: ^[a-z][a-z0-9]{1,11}$
    Description: Unique String used when creating object names or Tags.
    Type: String
    Default: myuniqstr
  vpcCidr:
    AllowedPattern: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$'
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.0.0/16
    Description: CIDR block for the VPC.
    Type: String
Conditions:
  2nic: !Or
    - !Condition '3nic'
    - !Equals
      - 2
      - !Ref 'numNics'
  3nic: !Equals
    - 3
    - !Ref 'numNics'
  createBigIpInstanceProfile: !Equals
    - !Ref 'bigIpInstanceProfile'
    - ""
  createKeyPair: !Equals
    - ''
    - !Ref 'sshKey'
  createSecret: !Equals
    - ''
    - !Ref 'bigIpSecretArn'
  noCustomImageId: !Equals
    - ''
    - !Ref 'bigIpCustomImageId'
  noPublicIp: !Equals
    - 'false'
    - !Ref 'provisionPublicIpMgmt'
  sameAz: !Equals
    - '1'
    - !Ref 'numAzs'
  useDefaultCfeS3Bucket: !Equals
    - !Ref 'cfeS3Bucket'
    - ''
  usePublicIpMgmt: !Equals
    - 'true'
    - !Ref 'provisionPublicIpMgmt'
  usePublicIpVip: !Equals
    - 'true'
    - !Ref 'provisionExampleApp'
Resources:
  Access:
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/access/access.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        cfeTag: !Ref 'cfeTag'
        createAmiRole: 'true'
        createBigIpRoles: !If [createBigIpInstanceProfile, 'true', 'false']
        createSecret: !If [createSecret, 'true', 'false']
        createSshKey: !If [createKeyPair, 'true', 'false']
        s3Bucket: !If
          - useDefaultCfeS3Bucket
          - !Join
            - ''
            - - !Ref 'uniqueString'
              - '-bigip-high-availability-solution'
          - !Ref 'cfeS3Bucket'
        secretArn: !If [createSecret, !Ref 'AWS::NoValue', !Ref 'bigIpSecretArn']
        solutionType: failover
        uniqueString: !Ref 'uniqueString'
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  AmiInfo:
    Type: 'Custom::AMIInfo'
    Condition: noCustomImageId
    Properties:
      OSName: !Ref 'bigIpImage'
      OwnerId: 'aws-marketplace'
      Region: !Ref 'AWS::Region'
      ServiceToken: !GetAtt [Function, Outputs.lambdaARN]
  Application:
    Type: 'AWS::CloudFormation::Stack'
    Condition: usePublicIpVip
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/application/application.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        appContainerName: !Ref 'appDockerImageName'
        applicationSubnet: !If
          - usePublicIpVip
          - !Join
            - ','
            - - !Select
                - '3'
                - !Split
                  - ','
                  - !GetAtt
                    - Network
                    - Outputs.subnetsA
          - !Join
            - ','
            - - !Select
                - '4'
                - !Split
                  - ','
                  - !GetAtt
                    - Network
                    - Outputs.subnetsA
        appSecurityGroupId: !GetAtt [Dag, Outputs.appSecurityGroupId]
        sshKey: !If [createKeyPair, !GetAtt [Access, Outputs.keyPairName], !Ref 'sshKey']
        restrictedSrcAddress: !Ref 'restrictedSrcAddressApp'
        uniqueString: !Ref 'uniqueString'
        vpc: !GetAtt
          - Network
          - Outputs.vpcId
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  Bastion:
    Type: 'AWS::CloudFormation::Stack'
    Condition: noPublicIp
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/bastion/bastion.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        mgmtSubnet: !Join
          - ','
          - - !Select
              - '0'
              - !Split
                - ','
                - !GetAtt
                  - Network
                  - Outputs.subnetsA
        bastionSecurityGroupId: !GetAtt
          - Dag
          - Outputs.bastionSecurityGroupId
        sshKey: !If [createKeyPair, !GetAtt [Access, Outputs.keyPairName], !Ref 'sshKey']
        restrictedSrcAddress: !Ref 'restrictedSrcAddressMgmt'
        uniqueString: !Ref 'uniqueString'
        vpc: !GetAtt
          - Network
          - Outputs.vpcId
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  BigIpInstance01:
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/bigip-standalone/bigip-standalone.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        allowUsageAnalytics: !Ref 'allowUsageAnalytics'
        bigIpPeerAddr: !Ref 'bigIpPeerAddr'
        bigIpPeerHostname: !Ref 'bigIpHostname02'
        bigIpRuntimeInitPackageUrl: !Ref 'bigIpRuntimeInitPackageUrl'
        bigIpRuntimeInitConfig: !Ref 'bigIpRuntimeInitConfig01'
        cfeS3Bucket: !If
          - useDefaultCfeS3Bucket
          - !Join
            - ''
            - - !Ref 'uniqueString'
              - '-bigip-high-availability-solution'
          - !Ref 'cfeS3Bucket'
        cfeTag: !Ref 'cfeTag'
        externalSelfPublicIpId: !GetAtt [Dag, Outputs.bigIpExternalEipAllocationId01]
        externalServicePublicIpIds: !If [usePublicIpVip, !GetAtt [Dag, Outputs.bigIpExternalEipAllocationId03],
          '']
        externalSecurityGroupId: !GetAtt [Dag, Outputs.bigIpExternalSecurityGroup]
        externalSelfIp: !Ref 'bigIpExternalSelfIp01'
        externalServiceIps: !If [usePublicIpVip, !Ref 'bigIpExternalVip01', '']
        externalSubnetId: !If
          - usePublicIpVip
          - !Join
            - ','
            - - !Select
                - '0'
                - !Split
                  - ','
                  - !GetAtt
                    - Network
                    - Outputs.subnetsA
          - !Join
            - ','
            - - !Select
                - '3'
                - !Split
                  - ','
                  - !GetAtt
                    - Network
                    - Outputs.subnetsA
        hostname: !Ref 'bigIpHostname01'
        imageId: !If
          - noCustomImageId
          - !GetAtt
            - AmiInfo
            - Id
          - !Ref 'bigIpCustomImageId'
        instanceIndex: '01'
        instanceProfile: !If
          - createBigIpInstanceProfile
          - !GetAtt
            - Access
            - Outputs.bigIpInstanceProfile
          - !Ref 'bigIpInstanceProfile'
        instanceType: !Ref 'bigIpInstanceType'
        internalSecurityGroupId: !If [3nic, !GetAtt [Dag, Outputs.bigIpInternalSecurityGroup],
          !Ref 'AWS::NoValue']
        internalSelfIp: !If [3nic, !Ref 'bigIpInternalSelfIp01', !Ref 'AWS::NoValue']
        internalSubnetId: !If
          - 3nic
          - !Join
            - ','
            - - !Select
                - '2'
                - !Split
                  - ','
                  - !GetAtt
                    - Network
                    - Outputs.subnetsA
          - !Ref 'AWS::NoValue'
        licenseKey: !Ref 'bigIpLicenseKey01'
        mgmtPublicIpId: !If [usePublicIpMgmt, !GetAtt [Dag, Outputs.bigIpManagementEipAllocationId01],
          '']
        mgmtSecurityGroupId: !GetAtt [Dag, Outputs.bigIpMgmtSecurityGroup]
        mgmtAddress: !Ref 'bigIpMgmtAddress01'
        mgmtSubnetId: !Join
          - ','
          - - !Select
              - '1'
              - !Split
                - ','
                - !GetAtt
                  - Network
                  - Outputs.subnetsA
        numExternalPublicIpAddresses: !If [usePublicIpVip, 2, 1]
        numSecondaryPrivateIpAddresses: !If [usePublicIpVip, 1, 0]
        secretArn: !If [createSecret, !GetAtt [Access, Outputs.secretArn], !Ref 'bigIpSecretArn']
        sshKey: !If [createKeyPair, !GetAtt [Access, Outputs.keyPairName], !Ref 'sshKey']
        uniqueString: !Ref 'uniqueString'
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  BigIpInstance02:
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/bigip-standalone/bigip-standalone.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        allowUsageAnalytics: !Ref 'allowUsageAnalytics'
        bigIpPeerAddr: !Ref 'bigIpPeerAddr'
        bigIpPeerHostname: !Ref 'bigIpHostname01'
        bigIpRuntimeInitPackageUrl: !Ref 'bigIpRuntimeInitPackageUrl'
        bigIpRuntimeInitConfig: !Ref 'bigIpRuntimeInitConfig02'
        cfeTag: !Ref 'cfeTag'
        externalSelfPublicIpId: !GetAtt [Dag, Outputs.bigIpExternalEipAllocationId02]
        externalServicePublicIpIds: ''
        externalSecurityGroupId: !GetAtt [Dag, Outputs.bigIpExternalSecurityGroup]
        externalSelfIp: !Ref 'bigIpExternalSelfIp02'
        externalServiceIps: !If [usePublicIpVip, !Ref 'bigIpExternalVip02', '']
        externalSubnetId: !If
          - usePublicIpVip
          - !Join
            - ','
            - - !Select
                - '0'
                - !Split
                  - ','
                  - !If [sameAz, !GetAtt [Network, Outputs.subnetsA], !GetAtt [Network,
                      Outputs.subnetsB]]
          - !Join
            - ','
            - - !Select
                - '3'
                - !Split
                  - ','
                  - !If [sameAz, !GetAtt [Network, Outputs.subnetsA], !GetAtt [Network,
                      Outputs.subnetsB]]
        hostname: !Ref 'bigIpHostname02'
        imageId: !If
          - noCustomImageId
          - !GetAtt
            - AmiInfo
            - Id
          - !Ref 'bigIpCustomImageId'
        instanceIndex: '02'
        instanceProfile: !If
          - createBigIpInstanceProfile
          - !GetAtt
            - Access
            - Outputs.bigIpInstanceProfile
          - !Ref 'bigIpInstanceProfile'
        instanceType: !Ref 'bigIpInstanceType'
        internalSecurityGroupId: !If [3nic, !GetAtt [Dag, Outputs.bigIpInternalSecurityGroup],
          !Ref 'AWS::NoValue']
        internalSelfIp: !If [3nic, !Ref 'bigIpInternalSelfIp02', !Ref 'AWS::NoValue']
        internalSubnetId: !If
          - 3nic
          - !Join
            - ','
            - - !Select
                - '2'
                - !Split
                  - ','
                  - !If [sameAz, !GetAtt [Network, Outputs.subnetsA], !GetAtt [Network,
                      Outputs.subnetsB]]
          - !Ref 'AWS::NoValue'
        licenseKey: !Ref 'bigIpLicenseKey02'
        mgmtPublicIpId: !If [usePublicIpMgmt, !GetAtt [Dag, Outputs.bigIpManagementEipAllocationId02],
          '']
        mgmtSecurityGroupId: !GetAtt [Dag, Outputs.bigIpMgmtSecurityGroup]
        mgmtAddress: !Ref 'bigIpMgmtAddress02'
        mgmtSubnetId: !Join
          - ','
          - - !Select
              - '1'
              - !Split
                - ','
                - !If [sameAz, !GetAtt [Network, Outputs.subnetsA], !GetAtt [Network,
                    Outputs.subnetsB]]
        numExternalPublicIpAddresses: 1
        numSecondaryPrivateIpAddresses: !If [usePublicIpVip, 1, 0]
        secretArn: !If [createSecret, !GetAtt [Access, Outputs.secretArn], !Ref 'bigIpSecretArn']
        sshKey: !If [createKeyPair, !GetAtt [Access, Outputs.keyPairName], !Ref 'sshKey']
        uniqueString: !Ref 'uniqueString'
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  Dag:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub
        - https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/dag/dag.yaml
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        createAppSecurityGroup: true
        createFailoverIngress: true
        createInternalSecurityGroup: !If [3nic, 'true', 'false']
        createExternalSecurityGroup: true
        createBastionSecurityGroup: !If [usePublicIpMgmt, false, true]
        cfeTag: !Ref 'cfeTag'
        cfeVipTag: !Ref 'cfeVipTag'
        numberPublicExternalIpAddresses: !If [usePublicIpVip, 3, 2]
        numberPublicMgmtIpAddresses: !If [usePublicIpMgmt, 2, 0]
        provisionExternalBigipLoadBalancer: false
        provisionInternalBigipLoadBalancer: false
        restrictedSrcAddressApp: !Ref 'restrictedSrcAddressApp'
        restrictedSrcAddressMgmt: !Ref 'restrictedSrcAddressMgmt'
        restrictedSrcPort: 443
        uniqueString: !Ref 'uniqueString'
        vpc: !GetAtt
          - Network
          - Outputs.vpcId
        vpcCidr: !Ref 'vpcCidr'
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  Function:
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/function/function.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        amiLookupRole: !GetAtt
          - Access
          - Outputs.lambdaAmiExecutionRole
        createAmiLookupFunction: 'true'
        uniqueString: !Ref 'uniqueString'
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
  Network:
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL: !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.amazonaws.com/${artifactLocation}modules/network/network.yaml'
        - S3Region: !Ref 's3BucketRegion'
          S3Bucket: !Ref 's3BucketName'
      Parameters:
        numAzs: !Ref 'numAzs'
        numSubnets: !Ref 'numSubnets'
        setPublicSubnet1: !Ref 'provisionPublicIpMgmt'
        subnetMask: !Ref 'subnetMask'
        uniqueString: !Ref 'uniqueString'
        vpcCidr: !Ref 'vpcCidr'
        vpcTenancy: default
        application: !Ref 'application'
        cost: !Ref 'cost'
        environment: !Ref 'environment'
        group: !Ref 'group'
        owner: !Ref 'owner'
