AWSTemplateFormatVersion: 2010-09-09
Description: Launch two FortiGates within an existing VPC in A-P cluster running in dual AZs with combined HA sync and mgmt on single ENI
Metadata:
  'AWS::CloudFormation::Interface':
    ParameterGroups:
      - Label:
          default: VPC Configuration
        Parameters:
          - VPCID
          - VPCCIDR
          - PublicSubnet1
          - PublicSubnet1RouterIP
          - PrivateSubnet1
          - PrivateSubnet1RouterIP
          - HASyncMgmtSubnet1
          - HASyncMgmtSubnet1RouterIP
          - PublicSubnet2
          - PublicSubnet2RouterIP
          - PrivateSubnet2
          - PrivateSubnet2RouterIP
          - HASyncMgmtSubnet2
          - HASyncMgmtSubnet2RouterIP
      - Label:
          default: FortiGate Instance Configuration
        Parameters:
          - AZForFGTA
          - AZForFGTB
          - FGTInstanceType
          - FortiOSVersion
          - LicenseType
          - CIDRForFGTAccess
          - KeyPair
          - HAsecret
      - Label:
          default: FortiGate IP Configuration
        Parameters:
          - IPAPublicSubnet1
          - IPAPrivateSubnet1
          - IPAHASyncMgmtSubnet1
          - IPBPublicSubnet2
          - IPBPrivateSubnet2
          - IPBHASyncMgmtSubnet2
Parameters:
  VPCID:
    Type: 'AWS::EC2::VPC::Id'
    Description: Select the existing VPC for deployment
  VPCCIDR:
    Type: String
    Description: 'Enter the VPC CIDR of the above VPC. Ex: 10.0.0.0/16'
  AZForFGTA:
    Type: 'AWS::EC2::AvailabilityZone::Name'
    Description: Select the first AZ for FortiGateA
  AZForFGTB:
    Type: 'AWS::EC2::AvailabilityZone::Name'
    Description: Select the second AZ for FortiGateB
  PublicSubnet1:
    Type: 'AWS::EC2::Subnet::Id'
    Description: Select the Public1 subnet
  IPAPublicSubnet1:
    Type: String
    Description: >-
      Indicate the IP of the interface of FGTA attached to public subnet1. Ex:
      10.0.1.12/24
  PublicSubnet1RouterIP:
    Type: String
    Default: 10.0.1.1
    Description: Provide the IP of the gateway for the public subnet1
  PrivateSubnet1:
    Type: 'AWS::EC2::Subnet::Id'
    Description: Select the private subnet1
  IPAPrivateSubnet1:
    Type: String
    Description: >-
      Indicate the IP of the interface of FGTA attached to private subnet1. Ex:
      10.0.2.12/24
  PrivateSubnet1RouterIP:
    Type: String
    Default: 10.0.2.1
    Description: Provide the IP of the gateway for the private subnet1
  HASyncMgmtSubnet1:
    Type: 'AWS::EC2::Subnet::Id'
    Description: Select the HA sync/management subnet1
  IPAHASyncMgmtSubnet1:
    Type: String
    Description: >-
      Indicate the IP of the interface of FGTA attached to HA sync/mgmt subnet1. 
      Ex: 10.0.3.12/24
  HASyncMgmtSubnet1RouterIP:
    Type: String
    Default: 10.0.3.1
    Description: Provide the IP of the gateway for the HA sync/mgmt subnet1
  PublicSubnet2:
    Type: 'AWS::EC2::Subnet::Id'
    Description: Select the public subnet2
  IPBPublicSubnet2:
    Type: String
    Description: >-
      Indicate the IP of the interface of FGTB attached to public subnet2. Ex:
      10.0.10.12/24
  PublicSubnet2RouterIP:
    Type: String
    Default: 10.0.10.1
    Description: Provide the IP of the gateway for the public subnet2
  PrivateSubnet2:
    Type: 'AWS::EC2::Subnet::Id'
    Description: Select the private subnet2
  IPBPrivateSubnet2:
    Type: String
    Description: >-
      Indicate the IP of the interface of FGTB attached to private subnet2. Ex:
      10.0.20.12/24
  PrivateSubnet2RouterIP:
    Type: String
    Default: 10.0.20.1
    Description: Provide the IP of the gateway for the private subnet2
  HASyncMgmtSubnet2:
    Type: 'AWS::EC2::Subnet::Id'
    Description: Select the HA sync/management subnet2
  IPBHASyncMgmtSubnet2:
    Type: String
    Description: >-
      Indicate the IP of the interface of FGTB attached to HA sync/mgmt subnet2.
      Ex: 10.0.30.12/24
  HASyncMgmtSubnet2RouterIP:
    Type: String
    Default: 10.0.30.1
    Description: Provide the IP of the gateway for the HA sync/mgmt subnet2
  FGTInstanceType:
    Type: String
    Default: c6in.xlarge
    Description: Select the instance type for the FortiGates
    AllowedValues:
      - t3.medium
      - t3.xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
      - c5.18xlarge
      - c5n.large
      - c5n.xlarge
      - c5n.2xlarge
      - c5n.4xlarge
      - c5n.9xlarge
      - c5n.18xlarge
      - c6i.large
      - c6i.xlarge
      - c6i.2xlarge
      - c6i.4xlarge
      - c6i.8xlarge
      - c6i.16xlarge
      - c6i.24xlarge
      - c6in.large
      - c6in.xlarge
      - c6in.2xlarge
      - c6in.4xlarge
      - c6in.8xlarge
      - c6in.16xlarge
      - c7g.medium
      - c7g.large
      - c7g.xlarge
      - c7g.2xlarge
      - c7g.4xlarge
      - c7g.8xlarge
      - c7g.16xlarge
      - c7gn.large
      - c7gn.xlarge
      - c7gn.2xlarge
      - c7gn.4xlarge
      - c7gn.8xlarge
  FortiOSVersion:
    Type: String
    Default: 7.6.x
    Description: Select the version of FortiOS to use (latest GA AMI will be used)
    AllowedValues:
      - 7.0.x
      - 7.2.x
      - 7.4.x
      - 7.6.x
  LicenseType:
    Type: String
    Description: Select the license type for the FortiGates
    AllowedValues:
      - BYOL
      - PAYG
  CIDRForFGTAccess:
    Type: String
    Default: 0.0.0.0/0
    Description: Enter the CIDR from which FortiGate instances need to be accessed from
  KeyPair:
    Type: 'AWS::EC2::KeyPair::KeyName'
    Description: Select the keypair for the FortiGates
  HAsecret:
    Type: String
    Description: Secret for HA peer identification
Mappings:
  FortiOSIntelAMISearchString:
    6.4.x:
      BYOL: FortiGate-VM64-AWS *(6.4.*)*|dlaioq277sglm5mw1y1dmeuqa
      PAYG: FortiGate-VM64-AWSONDEMAND *(6.4.*)*|2wqkpek696qhdeo7lbbjncqli
    7.0.x:
      BYOL: FortiGate-VM64-AWS *(7.0.*)*|dlaioq277sglm5mw1y1dmeuqa
      PAYG: FortiGate-VM64-AWSONDEMAND *(7.0.*)*|2wqkpek696qhdeo7lbbjncqli
    7.2.x:
      BYOL: FortiGate-VM64-AWS *(7.2.*)*|dlaioq277sglm5mw1y1dmeuqa
      PAYG: FortiGate-VM64-AWSONDEMAND *(7.2.*)*|2wqkpek696qhdeo7lbbjncqli
    7.4.x:
      BYOL: FortiGate-VM64-AWS *(7.4.*)*|dlaioq277sglm5mw1y1dmeuqa
      PAYG: FortiGate-VM64-AWSONDEMAND *(7.4.*)*|2wqkpek696qhdeo7lbbjncqli
    7.6.x:
      BYOL: FortiGate-VM64-AWS *(7.6.*)*|dlaioq277sglm5mw1y1dmeuqa
      PAYG: FortiGate-VM64-AWSONDEMAND *(7.6.*)*|2wqkpek696qhdeo7lbbjncqli
  FortiOSArmAMISearchString:
    6.4.x:
      BYOL: FortiGate-VMARM64-AWS *(6.4.*)*|33ndn84xbrajb9vmu5lxnfpjq
      PAYG: FortiGate-VMARM64-AWSONDEMAND *(6.4.*)*|8gc40z1w65qjt61p9ps88057n
    7.0.x:
      BYOL: FortiGate-VMARM64-AWS *(7.0.*)*|33ndn84xbrajb9vmu5lxnfpjq
      PAYG: FortiGate-VMARM64-AWSONDEMAND *(7.0.*)*|8gc40z1w65qjt61p9ps88057n
    7.2.x:
      BYOL: FortiGate-VMARM64-AWS *(7.2.*)*|33ndn84xbrajb9vmu5lxnfpjq
      PAYG: FortiGate-VMARM64-AWSONDEMAND *(7.2.*)*|8gc40z1w65qjt61p9ps88057n
    7.4.x:
      BYOL: FortiGate-VMARM64-AWS *(7.4.*)*|33ndn84xbrajb9vmu5lxnfpjq
      PAYG: FortiGate-VMARM64-AWSONDEMAND *(7.4.*)*|8gc40z1w65qjt61p9ps88057n
    7.6.x:
      BYOL: FortiGate-VMARM64-AWS *(7.6.*)*|33ndn84xbrajb9vmu5lxnfpjq
      PAYG: FortiGate-VMARM64-AWSONDEMAND *(7.6.*)*|8gc40z1w65qjt61p9ps88057n
Conditions:
  Graviton: !Or
    - !Equals
      - !Select
        - '0'
        - !Split
          - .
          - !Ref FGTInstanceType
      - c6g
    - !Equals
      - !Select
        - '0'
        - !Split
          - .
          - !Ref FGTInstanceType
      - c6gn
    - !Equals
      - !Select
        - '0'
        - !Split
          - .
          - !Ref FGTInstanceType
      - c7g
    - !Equals
      - !Select
        - '0'
        - !Split
          - .
          - !Ref FGTInstanceType
      - c7gn
Resources:
  InstanceRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: FGCPPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'ec2:Describe*'
                  - 'ec2:AssociateAddress'
                  - 'ec2:AssignPrivateIpAddresses'
                  - 'ec2:UnassignPrivateIpAddresses'
                  - 'ec2:ReplaceRoute'
                  - 's3:GetObject'
                Resource: '*'
  InstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref InstanceRole
  FGTSecGrpBase:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPCID
      GroupDescription: FGTSecGrp
      SecurityGroupIngress:
        - Description: Allow remote access to FGT
          IpProtocol: '-1'
          FromPort: 0
          ToPort: 65535
          CidrIp: !Ref CIDRForFGTAccess
        - Description: Allow local VPC access to FGT
          IpProtocol: '-1'
          FromPort: 0
          ToPort: 65535
          CidrIp: !Ref VPCCIDR
  FGTSecGrpFGTRule:
    Type: 'AWS::EC2::SecurityGroupIngress'
    Properties:
      GroupId: !Ref FGTSecGrpBase
      Description: Allow FGTs to access each other
      IpProtocol: '-1'
      FromPort: 0
      ToPort: 65535
      SourceSecurityGroupId: !Ref FGTSecGrpBase
  FgtA:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !GetAtt RunImageFunction.ami
      InstanceType: !Ref FGTInstanceType
      IamInstanceProfile: !Ref InstanceProfile
      KeyName: !Ref KeyPair
      NetworkInterfaces:
        - NetworkInterfaceId: !Ref FGTAENI0
          DeviceIndex: '0'
        - NetworkInterfaceId: !Ref FGTAENI1
          DeviceIndex: '1'
        - NetworkInterfaceId: !Ref FGTAENI2
          DeviceIndex: '2'
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - '-FgtA'
      UserData: !Base64 
        'Fn::Join':
          - |+

          - - config system vdom-exception
            - edit 0
            - set object router.static
            - next
            - edit 0
            - set object system.interface
            - end
            - config system global
            - set hostname FGTA
            - end
            - config system interface
            - edit port1
            - set alias public
            - set mode static
            - !Join 
              - ''
              - - 'set ip '
                - !Ref IPAPublicSubnet1
            - set allowaccess ping https ssh
            - set mtu-override enable
            - set mtu 9001
            - next
            - edit port2
            - set alias private
            - set mode static
            - !Join 
              - ''
              - - 'set ip '
                - !Ref IPAPrivateSubnet1
            - set allowaccess ping https ssh
            - set mtu-override enable
            - set mtu 9001
            - next
            - edit port3
            - set alias hasync-hamgmt
            - set mode static
            - !Join 
              - ''
              - - 'set ip '
                - !Ref IPAHASyncMgmtSubnet1
            - set allowaccess ping https ssh
            - set mtu-override enable
            - set mtu 9001
            - next
            - end
            - config router static
            - edit 1
            - set device port1
            - !Join 
              - ''
              - - 'set gateway '
                - !Ref PublicSubnet1RouterIP
            - next
            - edit 2
            - !Join 
              - ''
              - - 'set dst '
                - !Ref VPCCIDR
            - set device port2
            - !Join 
              - ''
              - - 'set gateway '
                - !Ref PrivateSubnet1RouterIP
            - next
            - end
            - config firewall policy
            - edit 1
            - set name outbound-all
            - set srcintf port2
            - set dstintf port1
            - set srcaddr all
            - set dstaddr all
            - set action accept
            - set schedule always
            - set service ALL
            - set logtraffic all
            - set nat enable
            - next
            - end
            - config system ha
            - set group-name "fortinet"
            - set group-id 1
            - !Join 
              - ''
              - - 'set password '
                - !Ref HAsecret
            - set mode a-p
            - set hbdev port3 50
            - set session-pickup enable
            - set ha-mgmt-status enable
            - config ha-mgmt-interface
            - edit 1
            - set interface port3
            - !Join 
              - ''
              - - 'set gateway '
                - !Ref HASyncMgmtSubnet1RouterIP
            - next
            - end
            - set override disable
            - set priority 255
            - set unicast-hb enable
            - !Join 
              - ''
              - - 'set unicast-hb-peerip '
                - !Select 
                  - '0'
                  - !Split 
                    - /
                    - !Ref IPBHASyncMgmtSubnet2
            - end
  FgtB:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !GetAtt RunImageFunction.ami
      InstanceType: !Ref FGTInstanceType
      IamInstanceProfile: !Ref InstanceProfile
      KeyName: !Ref KeyPair
      NetworkInterfaces:
        - NetworkInterfaceId: !Ref FGTBENI0
          DeviceIndex: '0'
        - NetworkInterfaceId: !Ref FGTBENI1
          DeviceIndex: '1'
        - NetworkInterfaceId: !Ref FGTBENI2
          DeviceIndex: '2'
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - '-FgtB'
      UserData: !Base64 
        'Fn::Join':
          - |+

          - - config system global
            - set hostname FGTB
            - end
            - config system interface
            - edit port1
            - set alias public
            - set mode static
            - !Join 
              - ''
              - - 'set ip '
                - !Ref IPBPublicSubnet2
            - set allowaccess ping https ssh
            - set mtu-override enable
            - set mtu 9001
            - next
            - edit port2
            - set alias private
            - set mode static
            - !Join 
              - ''
              - - 'set ip '
                - !Ref IPBPrivateSubnet2
            - set allowaccess ping https ssh
            - set mtu-override enable
            - set mtu 9001
            - next
            - edit port3
            - set alias hasync-hamgmt
            - set mode static
            - !Join 
              - ''
              - - 'set ip '
                - !Ref IPBHASyncMgmtSubnet2
            - set allowaccess ping https ssh
            - set mtu-override enable
            - set mtu 9001
            - next
            - end
            - config router static
            - edit 1
            - set device port1
            - !Join 
              - ''
              - - 'set gateway '
                - !Ref PublicSubnet2RouterIP
            - next
            - edit 2
            - !Join 
              - ''
              - - 'set dst '
                - !Ref VPCCIDR
            - set device port2
            - !Join 
              - ''
              - - 'set gateway '
                - !Ref PrivateSubnet2RouterIP
            - next
            - end
            - config firewall policy
            - edit 1
            - set name outbound-all
            - set srcintf port2
            - set dstintf port1
            - set srcaddr all
            - set dstaddr all
            - set action accept
            - set schedule always
            - set service ALL
            - set logtraffic all
            - set nat enable
            - next
            - end
            - config system ha
            - set group-name "fortinet"
            - set group-id 1
            - !Join 
              - ''
              - - 'set password '
                - !Ref HAsecret
            - set mode a-p
            - set hbdev port3 50
            - set session-pickup enable
            - set ha-mgmt-status enable
            - config ha-mgmt-interface
            - edit 1
            - set interface port3
            - !Join 
              - ''
              - - 'set gateway '
                - !Ref HASyncMgmtSubnet2RouterIP
            - next
            - end
            - set override disable
            - set priority 100
            - set unicast-hb enable
            - !Join 
              - ''
              - - 'set unicast-hb-peerip '
                - !Select 
                  - '0'
                  - !Split 
                    - /
                    - !Ref IPAHASyncMgmtSubnet1
            - end
  FGTAENI0:
    Type: 'AWS::EC2::NetworkInterface'
    Properties:
      Description: port1
      GroupSet:
        - !Ref FGTSecGrpBase
      SourceDestCheck: false
      SubnetId: !Ref PublicSubnet1
      PrivateIpAddress: !Select 
        - '0'
        - !Split 
          - /
          - !Ref IPAPublicSubnet1
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - FgtAENI0
        - Key: Interface
          Value: eth0
  FGTBENI0:
    Type: 'AWS::EC2::NetworkInterface'
    Properties:
      Description: port1
      GroupSet:
        - !Ref FGTSecGrpBase
      SourceDestCheck: false
      SubnetId: !Ref PublicSubnet2
      PrivateIpAddress: !Select 
        - '0'
        - !Split 
          - /
          - !Ref IPBPublicSubnet2
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - FgtBENI0
        - Key: Interface
          Value: eth0
  FGTAENI1:
    Type: 'AWS::EC2::NetworkInterface'
    Properties:
      Description: port2
      GroupSet:
        - !Ref FGTSecGrpBase
      SourceDestCheck: false
      SubnetId: !Ref PrivateSubnet1
      PrivateIpAddress: !Select 
        - '0'
        - !Split 
          - /
          - !Ref IPAPrivateSubnet1
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - FgtAENI1
  FGTBENI1:
    Type: 'AWS::EC2::NetworkInterface'
    Properties:
      Description: port2
      GroupSet:
        - !Ref FGTSecGrpBase
      SourceDestCheck: false
      SubnetId: !Ref PrivateSubnet2
      PrivateIpAddress: !Select 
        - '0'
        - !Split 
          - /
          - !Ref IPBPrivateSubnet2
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - FgtBENI1
  FGTAENI2:
    Type: 'AWS::EC2::NetworkInterface'
    Properties:
      Description: port3
      GroupSet:
        - !Ref FGTSecGrpBase
      SourceDestCheck: false
      SubnetId: !Ref HASyncMgmtSubnet1
      PrivateIpAddresses:
        - PrivateIpAddress: !Select 
            - '0'
            - !Split 
              - /
              - !Ref IPAHASyncMgmtSubnet1
          Primary: true
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - FgtAENI2
  FGTBENI2:
    Type: 'AWS::EC2::NetworkInterface'
    Properties:
      Description: port3
      GroupSet:
        - !Ref FGTSecGrpBase
      SourceDestCheck: false
      SubnetId: !Ref HASyncMgmtSubnet2
      PrivateIpAddresses:
        - PrivateIpAddress: !Select 
            - '0'
            - !Split 
              - /
              - !Ref IPBHASyncMgmtSubnet2
          Primary: true
      Tags:
        - Key: Name
          Value: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - FgtBENI2
  ClusterEIP:
    Type: 'AWS::EC2::EIP'
    Properties:
      Domain: vpc
    DependsOn: FgtA
  FgtAMgmtEIP:
    Type: 'AWS::EC2::EIP'
    Properties:
      Domain: vpc
    DependsOn: FgtA
  FgtBMgmtEIP:
    Type: 'AWS::EC2::EIP'
    Properties:
      Domain: vpc
    DependsOn: FgtB
  ClusterAEIPASSOCIATION:
    Type: 'AWS::EC2::EIPAssociation'
    Properties:
      AllocationId: !GetAtt 
        - ClusterEIP
        - AllocationId
      NetworkInterfaceId: !Ref FGTAENI0
  FgtAMgmtEIPASSOCIATION:
    Type: 'AWS::EC2::EIPAssociation'
    Properties:
      AllocationId: !GetAtt 
        - FgtAMgmtEIP
        - AllocationId
      NetworkInterfaceId: !Ref FGTAENI2
  FgtBMgmtEIPASSOCIATION:
    Type: 'AWS::EC2::EIPAssociation'
    Properties:
      AllocationId: !GetAtt 
        - FgtBMgmtEIP
        - AllocationId
      NetworkInterfaceId: !Ref FGTBENI2
  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: S3AccessRole
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ec2:DescribeImages
                  - s3:PutObject
                Resource: '*'
              - Effect: Allow
                Action:
                  - logs:*
                Resource: '*'
  ImageFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: !Join
          - |+

          - - import boto3
            - import cfnresponse
            - import logging
            - import json
            - logger = logging.getLogger()
            - logger.setLevel(logging.INFO)
            - client = boto3.client('ec2')
            - ''
            - 'def handler(event, context):'
            - '    if event[''RequestType''] == ''Create'':'
            - '        logger.info(''<-- event received: {}''.format(json.dumps(event)))'
            - '        searchString = event[''ResourceProperties''][''SearchString'']'
            - '        productCode =  event[''ResourceProperties''][''ProductCode'']'
            - '    else:'
            - '        responseData = {''msg'':''200''}'
            - '        cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)'
            - '        return None'
            - ''
            - '    try:'
            - '        resp = client.describe_images('
            - '            Filters=[{''Name'': ''name'', ''Values'': [searchString]}, {''Name'': ''product-code'', ''Values'': [productCode]}],'
            - '            Owners=[''aws-marketplace'']'
            - '        )'
            - '    except Exception as error:'
            - '        logger.error(''<--!! Exception: {}''.format(error))'
            - '        responseData = {''msg'':''Exception: {}''.format(error)}'
            - '        cfnresponse.send(event, context, cfnresponse.FAILED, responseData)'
            - ''
            - '    if resp[''ResponseMetadata''][''HTTPStatusCode''] == 200 and resp[''Images''] != []:'
            - '        ami_dict = {}'
            - '        ami_list = []'
            - '        for entry in resp[''Images'']:'
            - '            key = entry[''CreationDate'']'
            - '            ami_dict[key] = entry[''ImageId'']'
            - '        ami_list = sorted(ami_dict, reverse = True)'
            - '        logger.info(''--> found latest AMI: {}, {}, {} {}''.format(ami_dict[ami_list[0]], ami_list[0], searchString, productCode))'
            - '        responseData = {''ami'': ami_dict[ami_list[0]]}'
            - '        cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)'
            - '    else:'
            - '        logger.error(''!!--> Unable to find AMI {} {} in describe_images response! {}''.format(searchString, productCode, resp))'
            - '        responseData = {''msg'':''Unable to find AMI {} {} in describe_images response! {}''.format(searchString, productCode,resp)}'
            - '        cfnresponse.send(event, context, cfnresponse.FAILED, responseData)'
            - ''
      Role: !GetAtt LambdaRole.Arn
      Timeout: 120
      Handler: index.handler
      Runtime: python3.9
      MemorySize: 128
  RunImageFunction:
    Type: Custom::ImageFunction
    Properties:
      ServiceToken: !GetAtt ImageFunction.Arn
      SearchString: !If
        - Graviton
        - !Select
          - '0'
          - !Split
            - '|'
            - !FindInMap
              - FortiOSArmAMISearchString
              - !Ref FortiOSVersion
              - !Ref LicenseType
        - !Select
          - '0'
          - !Split
            - '|'
            - !FindInMap
              - FortiOSIntelAMISearchString
              - !Ref FortiOSVersion
              - !Ref LicenseType
      ProductCode: !If
        - Graviton
        - !Select
          - '1'
          - !Split
            - '|'
            - !FindInMap
              - FortiOSArmAMISearchString
              - !Ref FortiOSVersion
              - !Ref LicenseType
        - !Select
          - '1'
          - !Split
            - '|'
            - !FindInMap
              - FortiOSIntelAMISearchString
              - !Ref FortiOSVersion
              - !Ref LicenseType
Outputs:
  FGTAURL:
    Value: !Join 
      - ''
      - - 'https://'
        - !Ref FgtAMgmtEIP
    Description: URL to access FortigateA
  FGTUsername:
    Value: admin
    Description: Username to access Fortigates
  FGTAPassword:
    Value: !Ref FgtA
    Description: Password to access FortigateA
  FGTBURL:
    Value: !Join 
      - ''
      - - 'https://'
        - !Ref FgtBMgmtEIP
    Description: URL to access FortigateB
  FGTBPassword:
    Value: !Ref FgtB
    Description: Password to access FortigateB