AWSTemplateFormatVersion: 2010-09-09
Description: Deploys either a manually configurable or a Check Point CloudGuard IaaS
  Security Gateway & Management (Standalone) instance into an existing VPC (20230801)
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: VPC Network Configuration
        Parameters:
          - VPC
          - PublicSubnet
          - PrivateSubnet
          - InternalRouteTable
      - Label:
          default: EC2 Instance Configuration
        Parameters:
          - StandaloneName
          - StandaloneInstanceType
          - KeyName
          - AllocatePublicAddress
          - VolumeSize
          - VolumeType
          - VolumeEncryption
          - EnableInstanceConnect
          - TerminationProtection
      - Label:
          default: Check Point Settings
        Parameters:
          - StandaloneVersion
          - Shell
          - StandalonePasswordHash
      - Label:
          default: Advanced Settings
        Parameters:
          - ResourcesTagName
          - StandaloneHostname
          - AllowUploadDownload
          - CloudWatch
          - StandaloneBootstrapScript
          - NTPPrimary
          - NTPSecondary
          - AdminCIDR
          - GatewaysAddresses
    ParameterLabels:
      VPC:
        default: VPC
      PublicSubnet:
        default: Public subnet
      PrivateSubnet:
        default: Private subnet
      InternalRouteTable:
        default: Internal route table
      StandaloneName:
        default: Standalone Name
      StandaloneInstanceType:
        default: Standalone Instance type
      KeyName:
        default: Key name
      AllocatePublicAddress:
        default: Allocate an Elastic IP
      VolumeSize:
        default: Root volume size (GB)
      VolumeType:
        default: Volume Type
      VolumeEncryption:
        default: Volume encryption KMS key identifier
      EnableInstanceConnect:
        default: Enable AWS Instance Connect
      TerminationProtection:
        default: Termination Protection
      StandaloneVersion:
        default: License
      Shell:
        default: Admin shell
      StandalonePasswordHash:
        default: Standalone Password hash
      ResourcesTagName:
        default: Resources prefix tag
      StandaloneHostname:
        default: Standalone Hostname
      AllowUploadDownload:
        default: Allow upload & download
      CloudWatch:
        default: CloudWatch metrics
      StandaloneBootstrapScript:
        default: Bootstrap Script
      NTPPrimary:
        default: Primary NTP server
      NTPSecondary:
        default: Secondary NTP server
      AdminCIDR:
        default: Administrator addresses
      GatewaysAddresses:
        default: Gateways addresses
Parameters:
  VPC:
    Type: AWS::EC2::VPC::Id
    MinLength: 1
  PublicSubnet:
    Description: The public subnet of the Security Gateway.
    Type: AWS::EC2::Subnet::Id
    MinLength: 1
  PrivateSubnet:
    Description: The private subnet of the Security Gateway.
    Type: AWS::EC2::Subnet::Id
    MinLength: 1
  InternalRouteTable:
    Description: The route table id in which to set 0.0.0.0/0 route to the Security Gateway instance in this route table (e.g. rtb-12a34567). Route table cannot have an existing 0.0.0.0/0 route. If empty - traffic will not be routed through the Security Gateway, this requires manual configuration in the route table. (optional)
    Type: String
    Default: ''
  StandaloneName:
    Type: String
    Default: Check-Point-Instance
  StandaloneInstanceType:
    Description: The instance type of the Security Gateway & Management (Standalone) instance.
    Type: String
    Default: c5.xlarge
    AllowedValues:
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
      - c5.12xlarge
      - c5.18xlarge
      - c5.24xlarge
      - c5n.large
      - c5n.xlarge
      - c5n.2xlarge
      - c5n.4xlarge
      - c5n.9xlarge
      - c5n.18xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.8xlarge
      - m5.12xlarge
      - m5.16xlarge
      - m5.24xlarge
      - m6i.large
      - m6i.xlarge
      - m6i.2xlarge
      - m6i.4xlarge
      - m6i.8xlarge
      - m6i.12xlarge
      - m6i.16xlarge
      - m6i.24xlarge
      - m6i.32xlarge
      - c6i.large
      - c6i.xlarge
      - c6i.2xlarge
      - c6i.4xlarge
      - c6i.8xlarge
      - c6i.12xlarge
      - c6i.16xlarge
      - c6i.24xlarge
      - c6i.32xlarge
      - c6in.large
      - c6in.xlarge
      - c6in.2xlarge
      - c6in.4xlarge
      - c6in.8xlarge
      - c6in.12xlarge
      - c6in.16xlarge
      - c6in.24xlarge
      - c6in.32xlarge
      - r5.large
      - r5.xlarge
      - r5.2xlarge
      - r5.4xlarge
      - r5.8xlarge
      - r5.12xlarge
      - r5.16xlarge
      - r5.24xlarge
      - r5a.large
      - r5a.xlarge
      - r5a.2xlarge
      - r5a.4xlarge
      - r5a.8xlarge
      - r5a.12xlarge
      - r5a.16xlarge
      - r5a.24xlarge
      - r5b.large
      - r5b.xlarge
      - r5b.2xlarge
      - r5b.4xlarge
      - r5b.8xlarge
      - r5b.12xlarge
      - r5b.16xlarge
      - r5b.24xlarge
      - r5n.large
      - r5n.xlarge
      - r5n.2xlarge
      - r5n.4xlarge
      - r5n.8xlarge
      - r5n.12xlarge
      - r5n.16xlarge
      - r5n.24xlarge
      - r6i.large
      - r6i.xlarge
      - r6i.2xlarge
      - r6i.4xlarge
      - r6i.8xlarge
      - r6i.12xlarge
      - r6i.16xlarge
      - r6i.24xlarge
      - r6i.32xlarge
      - m6a.large
      - m6a.xlarge
      - m6a.2xlarge
      - m6a.4xlarge
      - m6a.8xlarge
      - m6a.12xlarge
      - m6a.16xlarge
      - m6a.24xlarge
      - m6a.32xlarge
      - m6a.48xlarge
    ConstraintDescription: Must be a valid EC2 instance type
  KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance.
    Type: AWS::EC2::KeyPair::KeyName
    MinLength: 1
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  AllocatePublicAddress:
    Default: true
    Type: String
    AllowedValues:
      - true
      - false
  VolumeSize:
    Type: Number
    MinValue: 100
    Default: 100
  VolumeType:
    Description: General Purpose SSD Volume Type
    Type: String
    Default: gp3
    AllowedValues:
      - gp3
      - gp2
  VolumeEncryption:
    Description: KMS or CMK key Identifier - Use key ID, alias or ARN. Key alias should be prefixed with 'alias/' (e.g. for KMS default alias 'aws/ebs' - insert 'alias/aws/ebs').
    Type: String
    Default: alias/aws/ebs
  EnableInstanceConnect:
    Description: Ec2 Instance Connect is not supported with versions prior to R80.40.
    Default: false
    Type: String
    AllowedValues:
      - true
      - false
  TerminationProtection:
    Description: Prevents an instance from accidental termination.
    Type: String
    Default: false
    AllowedValues:
      - true
      - false
  StandaloneVersion:
    Description: Standalone Version & License.
    Type: String
    Default: R81.20-BYOL-MGMT
    AllowedValues:
      - R82-BYOL-MGMT
      - R81.10-BYOL-MGMT
      - R81.20-BYOL-MGMT
  Shell:
    Description: Change the admin shell to enable advanced command line configuration.
    Type: String
    Default: /etc/cli.sh
    AllowedValues:
      - /etc/cli.sh
      - /bin/bash
      - /bin/csh
      - /bin/tcsh
  StandalonePasswordHash:
    Description: Admin user's password hash (use command "openssl passwd -6 PASSWORD"
      to get the PASSWORD's hash). (optional)
    Type: String
    Default: ''
    AllowedPattern: '[\$\./a-zA-Z0-9]*'
    NoEcho: true
  ResourcesTagName:
    Description: The name tag of the resources. (optional)
    Type: String
    Default: ''
  StandaloneHostname:
    Description: (optional)
    Type: String
    Default: ''
    AllowedPattern: '^([A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?|)$'
    ConstraintDescription: A valid hostname label or an empty string.
  AllowUploadDownload:
    Description: Automatically download updates and share statistical data for product improvement purpose.
    Type: String
    Default: true
    AllowedValues:
      - true
      - false
  CloudWatch:
    Description: Report Check Point specific CloudWatch metrics.
    Type: String
    Default: false
    AllowedValues:
      - true
      - false
  StandaloneBootstrapScript:
    Description: An optional script with semicolon (;) separated commands to run on the initial boot. (optional)
    Type: String
    Default: ''
    NoEcho: true
  NTPPrimary:
    Description: (optional)
    Type: String
    Default: 169.254.169.123
    AllowedPattern: '^[\.a-zA-Z0-9\-]*$'
  NTPSecondary:
    Description: (optional)
    Type: String
    Default: 0.pool.ntp.org
    AllowedPattern: '^[\.a-zA-Z0-9\-]*$'
  AdminCIDR:
    Description: Allow web, SSH, and graphical clients only from this network to communicate.
      with the Management Server.
    Type: String
    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]))$'
  GatewaysAddresses:
    Description: Allow gateways only from this network to communicate with the Management.
      Server. (optional)
    Type: String
    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])))?$'
Conditions:
  ProvidedResourcesTag: !Not [!Equals [!Ref ResourcesTagName, '']]
  AllocateAddress: !Equals [!Ref AllocatePublicAddress, true]
  EncryptedVolume: !Not [!Equals [!Ref VolumeEncryption, '']]
  ProvidedRouteTable: !Not [!Equals [!Ref InternalRouteTable, '']]
  EnableCloudWatch: !Equals [!Ref CloudWatch, true]
Resources:
  ReadyHandle:
    Type: AWS::CloudFormation::WaitConditionHandle
    Condition: AllocateAddress
    Properties: {}
  ReadyCondition:
    Type: AWS::CloudFormation::WaitCondition
    Condition: AllocateAddress
    DependsOn: StandaloneInstance
    Properties:
      Handle: !Ref ReadyHandle
      Timeout: 1800
  StandaloneIAMRole:
    Condition: EnableCloudWatch
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: [ ec2.amazonaws.com.cn ]
            Action: sts:AssumeRole
      Path: /
  StandaloneInstanceProfile:
    Condition: EnableCloudWatch
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles: [ !Ref StandaloneIAMRole ]
  CloudwatchPolicy:
    Condition: EnableCloudWatch
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://cgi-cfts.s3.cn-northwest-1.amazonaws.com.cn/iam/cloudwatch-policy.yaml
      Parameters:
        PolicyName: !If [ ProvidedResourcesTag, !Ref ResourcesTagName, !Ref 'AWS::StackName' ]
        PolicyRole: !Ref StandaloneIAMRole
  AMI:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://cgi-cfts.s3.cn-northwest-1.amazonaws.com.cn/utils/amis.yaml
      Parameters:
        Version: !Ref StandaloneVersion
  ExternalNetworkInterface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Tags:
        - Key: Name
          Value: !Join
            - _
            - - !If [ProvidedResourcesTag, !Ref ResourcesTagName, !Ref 'AWS::StackName']
              - ExternalNetworkInterface
      Description: eth0
      SourceDestCheck: false
      GroupSet:
        - !Ref PermissiveSecurityGroup
      SubnetId: !Ref PublicSubnet
  InternalNetworkInterface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Tags:
        - Key: Name
          Value: !Join
            - _
            - - !If [ProvidedResourcesTag, !Ref ResourcesTagName, !Ref 'AWS::StackName']
              - InternalNetworkInterface
      Description: eth1
      SourceDestCheck: false
      GroupSet:
        - !Ref PermissiveSecurityGroup
      SubnetId: !Ref PrivateSubnet
  PermissiveSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      Tags:
        - Key: Name
          Value: !Join
            - _
            - - !If [ProvidedResourcesTag, !Ref ResourcesTagName, !Ref 'AWS::StackName']
              - PermissiveSecurityGroup
      GroupDescription: Permissive security group.
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
  InternalDefaultRoute:
    Type: AWS::EC2::Route
    Condition: ProvidedRouteTable
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      NetworkInterfaceId: !Ref InternalNetworkInterface
      RouteTableId: !Ref InternalRouteTable
  StandaloneInstance:
    Type: AWS::EC2::Instance
    Properties:
      Tags:
        - Key: Name
          Value: !Ref StandaloneName
      ImageId: !GetAtt AMI.Outputs.ImageId
      InstanceType: !Ref StandaloneInstanceType
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            Encrypted: !If [EncryptedVolume, true, false]
            KmsKeyId: !If [EncryptedVolume, !Ref VolumeEncryption, !Ref 'AWS::NoValue']
            VolumeType: !Ref VolumeType
            VolumeSize: !Ref VolumeSize
      IamInstanceProfile: !If [EnableCloudWatch, !Ref StandaloneInstanceProfile, !Ref 'AWS::NoValue']
      DisableApiTermination: !Ref TerminationProtection
      UserData:
        'Fn::Base64':
          !Join
          - |+

          - - '#cloud-config'
            - 'runcmd:'
            - '  - |'
            - '    set -e'
            - !Sub '    admin_shell=${Shell} ; hostname=${StandaloneHostname} ; allow_info=${AllowUploadDownload} ; cw=${CloudWatch} ; ntp1=${NTPPrimary} ; ntp2=${NTPSecondary} ; eic=${EnableInstanceConnect} ; eip=${AllocatePublicAddress} ; admin_subnet=${AdminCIDR}'
            - !If [AllocateAddress, !Sub '    wait_handle=''${ReadyHandle}''',!Ref 'AWS::NoValue']
            - !Join ['', ['    bootstrap="$(echo ', 'Fn::Base64': !Ref StandaloneBootstrapScript, ')"']]
            - !Join ['', ['    pwd_hash="$(echo ', 'Fn::Base64': !Ref StandalonePasswordHash, ')"']]
            - !Sub ['    version=${Version}', {Version: !Select [0, !Split ['-', !Ref StandaloneVersion]]}]
            - '    python3 /etc/cloud_config.py enableCloudWatch=\"${cw}\" waitHandle=\"${wait_handle}\" installationType=\"standalone\" osVersion=\"${version}\" allowUploadDownload=\"${allow_info}\" templateVersion=\"20230801\" templateName=\"standalone\" shell=\"${admin_shell}\" enableInstanceConnect=\"${eic}\" hostName=\"${hostname}\" ntpPrimary=\"${ntp1}\" ntpSecondary=\"${ntp2}\" passwordHash=\"${pwd_hash}\" adminSubnet=\"${admin_subnet}\" allocatePublicAddress=\"${eip}\" bootstrapScript64=\"${bootstrap}\"'
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - DeviceIndex: 0
          NetworkInterfaceId: !Ref ExternalNetworkInterface
        - DeviceIndex: 1
          NetworkInterfaceId: !Ref InternalNetworkInterface
  PublicAddress:
    Type: AWS::EC2::EIP
    Condition: AllocateAddress
    Properties:
      Domain: vpc
  AddressAssoc:
    Type: AWS::EC2::EIPAssociation
    DependsOn: StandaloneInstance
    Condition: AllocateAddress
    Properties:
      NetworkInterfaceId: !Ref ExternalNetworkInterface
      AllocationId: !GetAtt PublicAddress.AllocationId
      PrivateIpAddress: !GetAtt ExternalNetworkInterface.PrimaryPrivateIpAddress
Outputs:
  PublicAddress:
    Condition: AllocateAddress
    Description: The public address of the Check Point instance.
    Value: !Ref PublicAddress
  SSH:
    Condition: AllocateAddress
    Description: SSH command to the Check Point instance.
    Value: !Join ['', ['ssh -i ', !Ref KeyName, ' admin@', !Ref PublicAddress]]
  URL:
    Condition: AllocateAddress
    Description: URL to the portal.
    Value: !Join ['', ['https://', !Ref PublicAddress ]]
