AWSTemplateFormatVersion: '2010-09-09'
Description: "This templates sets up standalone Ignition in a new AWS VPC (qs-ign00lbf4)"
Metadata:
  LICENSE: Apache License Version 2.0
  cfn-lint:
    config:
      ignore_checks:
        - E9101
        - W9002
        - W9003
        - W3005
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: Network Configuration
      Parameters:
      - KeyPairName
      - AvailabilityZones
      - WebAccessCIDR
    - Label:
        default: Linux bastion configuration
      Parameters:
       - EnableBastion
       - RemoteAccessCIDR
       - EnableTCPForwarding
    - Label:
        default: Database Configuration
      Parameters:
      - DBName
      - DBAutoMinorVersionUpgrade
      - DBBackupRetentionPeriod
      - DBEngineVersion
      - DBInstanceClass
      - DBMasterUsername
      - DBMasterUserPassword
      - DBMasterUserPassword2
      - DBPort
      - DBMultiAZ
      - DBAllocatedStorageEncrypted
      - DBExportLogToCloudwatch
      - EnableEventSubscription
      - NotificationList
    - Label:
        default: Ignition configuration
      Parameters:
      - LicenseAgreement
      - IgnitionInstanceType
      - IgnitionGatewayName
      - IgnitionRootUsername
      - IgnitionRootPassword
      - IgnitionRootPassword2
      - EnableIgnitionBackup
    - Label:
        default: Quick Start configuration
      Parameters:
      - QSS3BucketName
      - QSS3BucketRegion
      - QSS3KeyPrefix
    ParameterLabels:
      AvailabilityZones:
        default: Availability Zones
      EnableBastion:
        default: Create bastion stack
      EnableTCPForwarding:
        default: Enable TCP forwarding
      RemoteAccessCIDR:
        default: Permitted IP range
      DBEngineVersion:
        default: Database engine version
      DBName:
        default: Database name
      DBAllocatedStorageEncrypted:
        default: Enable database encryption
      DBExportLogToCloudwatch:
        default: Export database logs to Amazon Cloudwatch
      DBAutoMinorVersionUpgrade:
        default: Automatic minor database version upgrades
      DBBackupRetentionPeriod:
        default: Database backup retention period
      DBInstanceClass:
        default: Database instance class
      DBMasterUsername:
        default: Database administrator user name
      DBMasterUserPassword:
        default: Database administrator password
      DBMasterUserPassword2:
        default: Database administrator password (verification)
      DBPort:
        default: Database port
      DBMultiAZ:
        default: Multi-AZ deployment
      QSS3BucketName:
        default: Partner Solution S3 bucket name
      QSS3BucketRegion:
        default: Partner Solution S3 bucket region
      QSS3KeyPrefix:
        default: Partner Solution S3 key prefix
      EnableEventSubscription:
        default: Enable event subscription
      NotificationList:
        default: Amazon SNS notification email
      KeyPairName:
        default: Key name
      WebAccessCIDR:
        default: Web access CIDR
      LicenseAgreement:
        default: Inductive Automation Software License Agreement
      IgnitionInstanceType:
        default: Ignition instance type
      IgnitionGatewayName:
        default: Ignition Gateway name
      IgnitionRootUsername:
        default: Ignition root account username
      IgnitionRootPassword:
        default: Ignition root account password
      IgnitionRootPassword2:
        default: Ignition root account password (verification)
      EnableIgnitionBackup:
        default: Enable Ignition redundancy
Parameters:
  AvailabilityZones:
    Description: >-
      List of Availability Zones to use for the subnets in the VPC. Only two
      Availability Zones are used for this deployment, and the logical order of
      your selections is preserved.
    Type: 'List<AWS::EC2::AvailabilityZone::Name>'
  KeyPairName:
    ConstraintDescription: "Name of an existing EC2 key pair."
    Description: Name of an existing public/private key pair, for connecting to your instance.
    Type: "AWS::EC2::KeyPair::KeyName"
  WebAccessCIDR:
    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])(\/(0|1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x
    Description: CIDR block to allow web access to the load balancer.
    Type: String
  QSS3BucketName:
    AllowedPattern: ^[0-9a-z]+([0-9a-z-\.]*[0-9a-z])*$
    ConstraintDescription: >-
      The S3 bucket name can include numbers, lowercase letters,
      and hyphens (-), but it cannot start or end with a hyphen.
    Default: aws-ia
    Description: >-
      Name of the S3 bucket for your copy of the deployment assets. Keep the default
      name unless you are customizing the template. Changing the name updates code
      references to point to a new location.
    MinLength: 3
    MaxLength: 63
    Type: String
  QSS3BucketRegion:
    Default: us-east-1
    Description: >-
      AWS Region where the S3 bucket (QSS3BucketName) is hosted. Keep
      the default Region unless you are customizing the template. Changing the Region
      updates code references to point to a new location. When using your own bucket,
      specify the Region.
    Type: String
  QSS3KeyPrefix:
    AllowedPattern: ^([0-9a-zA-Z!-_\.\*'\(\)/]+/)*$
    ConstraintDescription: >-
      The S3 key prefix can include numbers, lowercase letters, uppercase letters,
      hyphens (-), underscores (_), periods (.), asterisks (*), single quotes ('),
      open parenthesis ((), close parenthesis ()), and forward slashes (/). End the
      prefix with a forward slash.
    Default: cfn-ps-inductive-automation-ignition/
    Description: >-
      S3 key prefix that is used to simulate a folder for your copy of the
      deployment assets. Keep the default prefix unless you are customizing
      the template. Changing the prefix updates code references to point to
      a new location.
    Type: String
  EnableBastion:
    AllowedValues:
      - "true"
      - "false"
    Default: "false"
    Description: Choose "false" if you don't want to deploy the optional bastion host stack.
    Type: String
  EnableTCPForwarding:
    Type: String
    Description: Choose "true" to enable TCP forwarding.
    Default: 'false'
    AllowedValues:
      - 'true'
      - 'false'
  RemoteAccessCIDR:
    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])(\\/([0-9]|[1-2][0-9]|3[0-2]))$"
    ConstraintDescription: "CIDR block parameter must be in the form x.x.x.x/x"
    Description: CIDR block to allow external SSH access.
    Type: String
  DBAllocatedStorageEncrypted:
    Default: "true"
    AllowedValues:
      - "true"
      - "false"
    Description: Choose "false" if you don't want to encrypt the database.
    Type: String
  DBExportLogToCloudwatch:
    Default: "true"
    AllowedValues:
      - "true"
      - "false"
    Description: Choose "false" if you don't want to export database logs to Amazon CloudWatch.
    Type: String
  DBAutoMinorVersionUpgrade:
    AllowedValues:
      - "true"
      - "false"
    Default: "false"
    Description: Choose "true" to enable automatic minor database version upgrades.
    Type: String
  DBBackupRetentionPeriod:
    Default: "35"
    Description: Number of days to retain automatic database snapshots.
    Type: String
  DBEngineVersion:
    Description: Database engine version.
    Type: String
    Default: 14.5
    AllowedValues:
      - 11.17
      - 12.12
      - 13.8
      - 14.5
  DBInstanceClass:
    AllowedPattern: "db\\.[a-z0-9]*\\.[a-z0-9]*"
    ConstraintDescription: "Must select a valid database instance type."
    Default: db.r5.large
    Description: Name of the class that determines the computation and memory capacity of the database instance.
    Type: String
  DBMasterUserPassword:
    AllowedPattern: "(?=^.{6,255}$)((?=.*\\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*"
    ConstraintDescription: "Min 8 chars."
    Description: Database administrator account password.
    MaxLength: "64"
    MinLength: "8"
    NoEcho: "True"
    Type: String
  DBMasterUserPassword2:
    AllowedPattern: >-
      ^(?=^.{8,255}$)(?=.*[a-z])(?=.*[A-Z])(?=.*\d)((?=.*[^A-Za-z0-9])(?!.*[@/"'])).*$
    ConstraintDescription: >-
      Must have a minimum of 8 characters. Must include 1 uppercase letter, 1 lowercase letter, 1 number, and 1 symbol (not including / @ " ').
    Description: Verify the database administrator account password.
    MaxLength: "64"
    MinLength: "8"
    NoEcho: "True"
    Type: String
  DBMasterUsername:
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
    ConstraintDescription: "Must begin with a letter and contain only alphanumeric characters."
    Default: pgadmin
    Description: Database administrator account user name.
    MaxLength: "16"
    MinLength: "1"
    Type: String
  DBPort:
    Default: 5432
    Description: Database instance listener port.
    Type: Number
    ConstraintDescription: Must be in the range 1150–65535.
    MinValue: 1150
    MaxValue: 65535
  DBMultiAZ:
    AllowedValues:
      - "true"
      - "false"
    Default: "true"
    Description: Choose "false" if you don't want the database instance deployed to multiple Availability Zones for high availability.
    Type: String
  DBName:
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
    Default: 'AuroraPostgresDB'
    Description: Amazon Aurora database name.
    MaxLength: "64"
    MinLength: "5"
    Type: String
  EnableEventSubscription:
    AllowedValues:
      - "true"
      - "false"
    Default: "true"
    Description: Choose "false" if you don't want to enable SNS topic subscription.
    Type: String
  NotificationList:
    Type: String
    Description: Email address to subscribe to the SNS topic, to receive CloudWatch alarm and Amazon RDS event notifications.
    AllowedPattern: '^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
    ConstraintDescription: provide a valid email address.
  LicenseAgreement:
    Description: I have read and accept the terms of the Inductive Automation Software License Agreement (https://inductiveautomation.com/ignition/license).
    Type: String
    Default: '-'
    AllowedValues:
    - I agree
    - '-'
    ConstraintDescription: You must choose "I agree" to complete the deployment.
  IgnitionInstanceType:
    AllowedValues:
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.nano
      - t3.micro
      - t3.small
      - t3.medium
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
    ConstraintDescription: You must choose a valid instance type.
    Default: m5.large
    Description: Amazon EC2 instance type for Ignition instances.
    Type: String
  IgnitionGatewayName:
    AllowedPattern: "[a-zA-Z0-9]*"
    Default: Ignition
    Description: Ignition Gateway system name.
    Type: String
  IgnitionRootUsername:
    Default: admin
    Description: Ignition root account user name.
    Type: String
  IgnitionRootPassword:
    AllowedPattern: >-
      ^(?=^.{8,255}$)(?=.*[a-z])(?=.*[A-Z])(?=.*\d)((?=.*[^A-Za-z0-9])(?!.*[@/"'])).*$
    ConstraintDescription: >-
      Must have a minimum of 8 characters. Must include 1 uppercase letter, 1 lowercase letter, 1 number, and 1 symbol (not including / @ " ').
    Description: Ignition root account password.
    MaxLength: 64
    MinLength: 8
    NoEcho: True
    Type: String
  IgnitionRootPassword2:
    AllowedPattern: >-
      ^(?=^.{8,255}$)(?=.*[a-z])(?=.*[A-Z])(?=.*\d)((?=.*[^A-Za-z0-9])(?!.*[@/"'])).*$
    ConstraintDescription: >-
      Must have a minimum of 8 characters. Must include 1 uppercase letter, 1 lowercase letter, 1 number, and 1 symbol (not including / @ " ').
    Description: Verify the Ignition root account password.
    MaxLength: 64
    MinLength: 8
    NoEcho: True
    Type: String
  EnableIgnitionBackup:
    AllowedValues:
      - "true"
      - "false"
    Default: "true"
    Description: Choose "false" if you don't want to deploy a backup Ignition instance.
    Type: String
Rules:
  LicenseAgreementRule:
    Assertions:
    - Assert:
        Fn::Contains:
        - - I agree
        - Ref: LicenseAgreement
      AssertDescription: User must agree to the terms of the license agreement.
  DBPasswordRule:
    Assertions:
    - Assert:
        Fn::Equals:
        - Ref: DBMasterUserPassword
        - Ref: DBMasterUserPassword2
      AssertDescription: Database master user passwords do not match.
  IgnitionRootPasswordRule:
    Assertions:
    - Assert:
        Fn::Equals:
        - Ref: IgnitionRootPassword
        - Ref: IgnitionRootPassword2
      AssertDescription: Ignition root user passwords do not match.
Conditions:
  EnableBastionAccess: !Equals
    - !Ref EnableBastion
    - "true"
  UseDatabaseEncryption:
    !Equals
    - !Ref DBAllocatedStorageEncrypted
    - "true"
  UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-ia']
Resources:
  VPCStack:
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL:
        !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/cfn-ps-aws-vpc/templates/aws-vpc.template.yaml'
        - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion]
          S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]
      Parameters:
        AvailabilityZones: !Join
          - ','
          - !Ref AvailabilityZones
        NumberOfAZs: '2'
        PrivateSubnet1ACIDR: 10.0.0.0/19
        PrivateSubnet2ACIDR: 10.0.32.0/19
        PublicSubnet1CIDR:  10.0.128.0/20
        PublicSubnet2CIDR: 10.0.144.0/20
        VPCCIDR: 10.0.0.0/16
  BastionStack:
    Condition: EnableBastionAccess
    Type: 'AWS::CloudFormation::Stack'
    Properties:
      TemplateURL:
        !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/cfn-ps-linux-bastion/templates/linux-bastion-entrypoint-existing-vpc.template.yaml'
        - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion]
          S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]
      Parameters:
        KeyPairName: !Ref KeyPairName
        PublicSubnet1ID: !GetAtt
          - VPCStack
          - Outputs.PublicSubnet1ID
        PublicSubnet2ID: !GetAtt
          - VPCStack
          - Outputs.PublicSubnet2ID
        EnableTCPForwarding: !Ref EnableTCPForwarding
        RemoteAccessCIDR: !Ref RemoteAccessCIDR
        VPCID: !GetAtt
          - VPCStack
          - Outputs.VPCID
        QSS3BucketName: !Ref QSS3BucketName
        QSS3BucketRegion: !Ref QSS3BucketRegion
        QSS3KeyPrefix: !Sub ${QSS3KeyPrefix}submodules/cfn-ps-linux-bastion/
  IgnitionStack:
    Type: 'AWS::CloudFormation::Stack'
    DependsOn: VPCStack
    Properties:
      TemplateURL:
        !Sub
        - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/ignition-standalone.template.yaml'
        - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion]
          S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]
      Parameters:
        ParentStackName: !Ref 'AWS::StackName'
        KeyPairName: !Ref KeyPairName
        VPCID: !GetAtt
          - VPCStack
          - Outputs.VPCID
        PrivateSubnet1ID:
          Fn::GetAtt:
            - VPCStack
            - Outputs.PrivateSubnet1AID
        PrivateSubnet2ID:
          Fn::GetAtt:
            - VPCStack
            - Outputs.PrivateSubnet2AID
        PublicSubnet1ID:
          Fn::GetAtt:
            - VPCStack
            - Outputs.PublicSubnet1ID
        PublicSubnet2ID:
          Fn::GetAtt:
            - VPCStack
            - Outputs.PublicSubnet2ID
        VPCCIDR: !GetAtt
          - VPCStack
          - Outputs.VPCCIDR
        WebAccessCIDR: !Ref WebAccessCIDR
        BastionSecurityGroupID: !If
          - EnableBastionAccess
          - !GetAtt 'BastionStack.Outputs.BastionSecurityGroupID'
          - ''
        PrimaryPrivateIPAddress: 10.0.128.10
        BackupPrivateIPAddress: 10.0.144.10
        DBName: !Ref DBName
        DBAutoMinorVersionUpgrade: !Ref DBAutoMinorVersionUpgrade
        DBAllocatedStorageEncrypted: !Ref DBAllocatedStorageEncrypted
        DBExportLogToCloudwatch: !Ref DBExportLogToCloudwatch
        DBBackupRetentionPeriod: !Ref DBBackupRetentionPeriod
        DBEngineVersion: !Ref DBEngineVersion
        DBInstanceClass: !Ref DBInstanceClass
        DBMasterUsername: !Ref DBMasterUsername
        DBMasterUserPassword: !Ref DBMasterUserPassword
        DBMasterUserPassword2: !Ref DBMasterUserPassword2
        DBPort: !Ref DBPort
        DBMultiAZ: !Ref DBMultiAZ
        EnableEventSubscription: !Ref EnableEventSubscription
        NotificationList: !Ref NotificationList
        QSS3BucketName: !Ref QSS3BucketName
        QSS3BucketRegion: !Ref QSS3BucketRegion
        QSS3KeyPrefix: !Ref QSS3KeyPrefix
        LicenseAgreement: !Ref LicenseAgreement
        IgnitionInstanceType: !Ref IgnitionInstanceType
        IgnitionGatewayName: !Ref IgnitionGatewayName
        IgnitionRootUsername: !Ref IgnitionRootUsername
        IgnitionRootPassword: !Ref IgnitionRootPassword
        IgnitionRootPassword2: !Ref IgnitionRootPassword2
        EnableIgnitionBackup: !Ref EnableIgnitionBackup
        EnablePublic: true
Outputs:
  DBName:
    Description: "Amazon Aurora database name."
    Value: !Ref DBName
  DBMasterUsername:
    Description: "Amazon Aurora database administrator username."
    Value: !GetAtt IgnitionStack.Outputs.DBMasterUsername
  RDSEndPointAddress:
    Description: "Amazon Aurora write endpoint."
    Value: !GetAtt IgnitionStack.Outputs.RDSEndPointAddress
  RDSReadEndPointAddress:
    Description: "Amazon Aurora read endpoint."
    Value: !GetAtt IgnitionStack.Outputs.RDSReadEndPointAddress
  RDSEndPointPort:
    Description: "Amazon Aurora port."
    Value: !GetAtt IgnitionStack.Outputs.RDSEndPointPort
  RDSEndPoints:
    Description: "Full Amazon Aurora write endpoint."
    Value: !GetAtt IgnitionStack.Outputs.RDSEndPoints
  RDSEncryptionKey:
    Condition: UseDatabaseEncryption
    Description: Alias of the encryption key created for Amazon RDS.
    Value: !GetAtt IgnitionStack.Outputs.RDSEncryptionKey
  IgnitionPrimaryPrivateDnsName:
    Description: Private DNS name for Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionPrimaryPrivateDnsName
  IgnitionPrimaryPrivateIP:
    Description: Private IP address for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionPrimaryPrivateIP
  IgnitionPrimaryPublicDnsName:
    Description: Public DNS name for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionPrimaryPublicDnsName
  IgnitionPrimaryPublicIP:
    Description: Public IP address for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionPrimaryPublicIP
  IgnitionBackupPrivateDnsName:
    Description: Private DNS name for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionBackupPrivateDnsName
  IgnitionBackupPrivateIP:
    Description: Private IP address for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionBackupPrivateIP
  IgnitionBackupPublicDnsName:
    Description: Public DNS name for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionBackupPublicDnsName
  IgnitionBackupPublicIP:
    Description: Public IP address for the Ignition EC2 instance.
    Value: !GetAtt IgnitionStack.Outputs.IgnitionBackupPublicIP
