--- AWSTemplateFormatVersion: 2010-09-09 Description: Boomi Atom Installation Script. This stages a Boomi Molecule in the user selected VPC. (qs-1q1tds36n) Parameters: KeyPairName: Description: Key name for access to EC2 instances. Type: AWS::EC2::KeyPair::KeyName ConstraintDescription: Must be the name of an existing key name NodeInstanceType: Description: The Boomi host instance type. Type: String Default: m5.xlarge AllowedValues: - m4.xlarge - m5.xlarge - r4.xlarge - r5.xlarge MoleculeEBSVolume: Description: The size of the Amazon EBS volume attached to the Molecule instances. Size range is 1 GiB - 16 TiB (size listed in GiB). Type: Number Default: 100 MoleculeLocalTemp: Description: The local temporary path for the Molecule installation. Type: String Default: /mnt/tmp VPCID: Type: AWS::EC2::VPC::Id Description: The ID of your existing VPC. PublicSubnet1ID: Type: String Description: The ID of the public subnet in Availability Zone 1 in your existing VPC. Default: '' PublicSubnet2ID: Type: String Description: The ID of the public subnet in Availability Zone 2 in your existing VPC. Default: '' PrivateSubnet1ID: Type: AWS::EC2::Subnet::Id Description: The ID of the private subnet in Availability Zone 1 in your existing VPC. PrivateSubnet2ID: Type: AWS::EC2::Subnet::Id Description: The ID of the private subnet in Availability Zone 2 in your existing VPC. BoomiUsername: Description: The email account associated with the Boomi account. Type: String BoomiPassword: Description: The password associated with the Boomi account. Type: String NoEcho: true Default: '' BoomiInstallToken: Description: A Boomi Install Token generated from within the AtomSphere console. Type: String NoEcho: true Default: '' BoomiAccountID: Description: The Boomi account ID that you want to associate with the new Molecule cluster. Type: String BastionSecurityGroupID: Description: The ID of the bastion security group in your existing VPC. Used to provide access to the molecule (e.g., sg-1a2b3c4d). Type: String Default: '' MoleculeSharedDir: Description: A shared directory for Molecules. Type: String Default: /mnt/molecule MoleculeLocalPath: Description: The local path for the Molecule installation. Type: String Default: /opt/molecule/local/ MoleculeClusterName: Description: The name for the Boomi Molecule cluster. Type: String AllowedPattern: "[a-zA-Z0-9_]*" Default: molecule1 EFSEncryption: Description: EFS volumes can be encrypted. Choose either "true" or "false". Type: String Default: 'true' AllowedValues: - 'true' - 'false' EFSPerformanceMode: Description: The performance mode for the EFS volume. Type: String Default: generalPurpose AllowedValues: - generalPurpose - maxIO EFSProvisionedThroughput: Description: The provisioned throughput value for the EFS volume. Type: Number Default: 10 MaxValue: 1024 ConstraintDescription: "Value must be between 1-1024" EFSThroughputMode: Description: The throughput mode for the EFS volume. Type: String Default: bursting AllowedValues: - provisioned - bursting LBListenerPort: Type: String Description: The port of the LB Listener. Default: '9093' SSLCertificateArn: Description: The SSL Certificate ID used with the load balancer. Type: String Default: '' QSS3BucketName: AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ ConstraintDescription: Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: S3 bucket name for the Quick Start assets. This string can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String QSS3KeyPrefix: AllowedPattern: ^[0-9a-zA-Z-/]*$ ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Default: quickstart-boomi-molecule/ Description: S3 key prefix for the Quick Start assets. Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Type: String PrivateALB: Default: 'false' Description: "The ALB can be placed in the Private subnets. 'DeployALB' takes precedence. Choose either 'true' or 'false" Type: String AllowedValues: - 'true' - 'false' DeployALB: Default: 'true' Description: "Do you wish to deploy the ALB entirely? Choose either 'true' or 'false'" Type: String AllowedValues: - 'true' - 'false' Metadata: QuickStartDocumentation: EntrypointName: "Launch into an existing VPC" AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Network configuration" Parameters: - VPCID - PublicSubnet1ID - PublicSubnet2ID - PrivateSubnet1ID - PrivateSubnet2ID - BastionSecurityGroupID - Label: default: "Amazon EC2 configuration" Parameters: - KeyPairName - MoleculeEBSVolume - Label: default: "Boomi Molecule node sizing" Parameters: - NodeInstanceType - Label: default: "Boomi Molecule configuration" Parameters: - MoleculeClusterName - MoleculeLocalPath - MoleculeLocalTemp - BoomiAccountID - BoomiUsername - BoomiPassword - BoomiInstallToken - LBListenerPort - MoleculeSharedDir - PrivateALB - DeployALB - Label: default: "Amazon EFS configuration" Parameters: - EFSEncryption - EFSPerformanceMode - EFSThroughputMode - EFSProvisionedThroughput - Label: default: "SSL configuration" Parameters: - SSLCertificateArn - Label: default: AWS Quick Start configuration Parameters: - QSS3BucketName - QSS3KeyPrefix ParameterLabels: KeyPairName: default: SSH key name PrivateSubnet1ID: default: Private subnet 1 ID PrivateSubnet2ID: default: Private subnet 2 ID PublicSubnet1ID: default: Public subnet 1 ID PublicSubnet2ID: default: Public subnet 2 ID VPCID: default: VPC ID NodeInstanceType: default: Molecule node instance type MoleculeEBSVolume: default: Volume size for Boomi instances BoomiAccountID: default: Boomi account ID BoomiUsername: default: Boomi user name BoomiPassword: default: Boomi password BoomiInstallToken: default: Boomi installer token LBListenerPort: default: Load Balancer listener port MoleculeLocalTemp: default: Molecule local temp directory EFSEncryption: default: EFS encryption EFSPerformanceMode: default: EFS performance mode EFSProvisionedThroughput: default: EFS provisioned throughput EFSThroughputMode: default: EFS throughput mode MoleculeSharedDir: default: Molecule shared directory MoleculeLocalPath: default: Molecule local path MoleculeClusterName: default: Molecule cluster name SSLCertificateArn: default: SSL certificate ARN BastionSecurityGroupID: default: Bastion security group ID QSS3BucketName: default: Quick Start S3 bucket name QSS3KeyPrefix: default: Quick Start S3 key prefix PrivateALB: default: Private ALB DeployALB: default: DeployALB Rules: PasswordOrMFAToken: Assertions: - Assert: !Or - !And - !Equals [!Ref BoomiPassword, ''] - !Not [!Equals [!Ref BoomiInstallToken, '']] - !And - !Not [!Equals [!Ref BoomiPassword, '']] - !Equals [!Ref BoomiInstallToken, ''] AssertionDescription: You must supply either a password *or* an installation token. Conditions: APITokenProvided: !Not [!Equals [!Ref BoomiInstallToken, '']] PasswordProvided: !Equals [!Ref BoomiInstallToken, ''] EFSProvisionedThroughput: !Equals [!Ref EFSThroughputMode, 'provisioned'] EFSBurstingThroughput: !Equals [!Ref EFSThroughputMode, 'bursting'] ALBInPrivateSubnets: !Equals [!Ref PrivateALB, 'true'] ALBInPublicSubnets: !Equals [!Ref PrivateALB, 'false'] UsingALB: !Equals [!Ref DeployALB, 'true'] UsingALBAndPassword: !And [Condition: UsingALB, Condition: PasswordProvided] UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] Resources: LoadBalancerSecurityGroup: Condition: UsingALB Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: boomi-elb VpcId: !Ref VPCID Tags: - Key: Name Value: LoadBalancerSG SecurityGroupIngress: - FromPort: 9093 IpProtocol: tcp CidrIp: 0.0.0.0/0 ToPort: 9093 BoomiSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: "Boomi Molecule high-level SG" VpcId: !Ref VPCID Tags: - Key: Name Value: BoomiSG SecurityGroupIngress: - !If - ALBInPublicSubnets - FromPort: 22 IpProtocol: tcp SourceSecurityGroupId: !Ref BastionSecurityGroupID ToPort: 22 - !Ref AWS::NoValue - !If - UsingALB - FromPort: 22 IpProtocol: tcp SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup ToPort: 22 - !Ref AWS::NoValue - !If - UsingALB - FromPort: 9093 IpProtocol: tcp SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup ToPort: 9093 - !Ref AWS::NoValue BoomiUnicastSG: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Boomi-Unicast VpcId: !Ref VPCID Tags: - Key: Name Value: Boomi-Unicast-SG SecurityGroupIngress: - FromPort: 0 IpProtocol: 'tcp' SourceSecurityGroupId: !Ref BoomiSecurityGroup ToPort: 65535 MoleculeSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: moleculeSG VpcId: !Ref VPCID Tags: - Key: Name Value: MoleculeSG SecurityGroupIngress: - IpProtocol: 'tcp' FromPort: 0 ToPort: 65535 SourceSecurityGroupId: !Ref BoomiSecurityGroup MountTargetSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: MountTargetSecurityGroup VpcId: !Ref VPCID Tags: - Key: Name Value: MountTargetSecurityGroup SecurityGroupIngress: - IpProtocol: tcp FromPort: 2049 ToPort: 2049 SourceSecurityGroupId: !Ref BoomiSecurityGroup MountTarget1: Type: AWS::EFS::MountTarget Properties: FileSystemId: !If [EFSProvisionedThroughput, !Ref EFSFilesystemProvisioned, !Ref EFSFilesystemBursting] SubnetId: !Ref PrivateSubnet1ID SecurityGroups: - !Ref MountTargetSecurityGroup MountTarget2: Type: AWS::EFS::MountTarget Properties: FileSystemId: !If [EFSProvisionedThroughput, !Ref EFSFilesystemProvisioned, !Ref EFSFilesystemBursting] SubnetId: !Ref PrivateSubnet2ID SecurityGroups: - !Ref "MountTargetSecurityGroup" KMSKey: Type: 'AWS::KMS::Key' Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyResourceWildcard - EIAMPolicyActionWildcard - EIAMPolicyWildcardResource ignore_reasons: EIAMPolicyResourceWildcard: This is the default KMS key policy." EIAMPolicyActionWildcard: This is the default KMS key policy." EIAMPolicyWildcardResource: Circular dependecy. No AWS::KMS::KeyPolicy resource type exists, so its impossible to restict beyond calling service. Properties: Description: >- Used to encrypt/decrypt secure string parameters in AWS Systems manager parameter store EnableKeyRotation: true KeyPolicy: Version: 2012-10-17 Statement: - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root Action: kms:* Resource: '*' - Sid: AllowUseOfTheKey Effect: Allow Principal: AWS: '*' Action: - kms:Encrypt - kms:Decrypt - kms:ReEncrypt* - kms:GenerateDataKey* - kms:CreateGrant - kms:DescribeKey Resource: '*' Condition: StringEquals: kms:ViaService: !Sub efs.${AWS::Region}.amazonaws.com kms:CallerAccount: !Ref AWS::AccountId MoleculeNode1: CreationPolicy: ResourceSignal: Count: 1 Timeout: "PT15M" DependsOn: - MountTarget1 - MountTarget2 Type: "AWS::EC2::Instance" Metadata: AWS::CloudFormation::Init: configSets: head_molecule: - nfs_and_java_path - hostname_workaround - download_and_install_atom - java_symlink - start_atom molecule_workers: - hostname_workaround - nfs_and_java_path - java_symlink - start_atom last_molecule: - hostname_workaround - nfs_and_java_path - java_symlink - start_atom - set_container_id nfs_and_java_path: files: /tmp/molecule.service: content: !Sub | [Unit] Description=Boomi Molecule Cluster After=network.target RequiresMountsFor=/opt/boomi/Molecule_${MoleculeClusterName} [Service] Type=forking User=root Restart=always ExecStart=/opt/boomi/Molecule_${MoleculeClusterName}/bin/atom start ExecStop=/opt/boomi/Molecule_${MoleculeClusterName}/bin/atom stop ExecReload=/opt/boomi/Molecule_${MoleculeClusterName}/bin/atom restart [Install] WantedBy=multi-user.target mode: "000644" owner: "root" group: "root" /tmp/efs_mount_config.sh: content: !Sub - | #!/bin/bash CURRENT_AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) eth0_mac=$(ip link show dev eth0 | grep -i 'ether' | awk '{print $2}') VPC_CIDR=$(curl -s "http://169.254.169.254/latest/meta-data/network/interfaces/macs/${!eth0_mac}/vpc-ipv4-cidr-block") zone_dns=$(awk -F"." '{print $1"."$2"."$3".2"}'<<<$VPC_CIDR) efs_IP=$(dig +short ${!CURRENT_AZ}.${FilesystemID}.efs.${AWS::Region}.amazonaws.com @${!zone_dns}) if [ -z ${!efs_IP} ]; then exit 1; fi echo "${!efs_IP} ${!CURRENT_AZ}.${FilesystemID}.efs.${AWS::Region}.amazonaws.com" >> /etc/hosts echo "${!CURRENT_AZ}.${FilesystemID}.efs.${AWS::Region}.amazonaws.com:/ ${MoleculeSharedDir} nfs4 defaults,vers=4.1,rsize=1048576,wsize=1048576,hard,noatime 0 0" >> /etc/fstab mount -a - FilesystemID: !If - EFSProvisionedThroughput - !Ref EFSFilesystemProvisioned - !Ref EFSFilesystemBursting mode: '000755' owner: 'root' group: 'root' packages: yum: amazon-efs-utils: [] commands: 010_create_dirs: command: !Sub | mkdir -p ${MoleculeLocalPath} mkdir -p ${MoleculeSharedDir} mkdir -p ${MoleculeLocalTemp} chown ec2-user:ec2-user ${MoleculeLocalPath} ${MoleculeLocalTemp} 015_set_java_path_in_ec2user: command: | echo JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk.x86_64 /home/ec2-user/.bash_profile echo "export PATH=$JAVA_HOME/bin:$PATH" >> /home/ec2-user/.bash_profile 020_mount_nfs: command: - /tmp/efs_mount_config.sh java_symlink: commands: 010_create_symlink: command: !Sub "ln -sf ${MoleculeSharedDir}/${MoleculeClusterName}/jre/bin/java /usr/bin/java" start_atom: commands: 010_start_atom: command: !Sub | ${MoleculeSharedDir}/Molecule_${MoleculeClusterName}/bin/atom stop sudo -u ec2-user bash -c '${MoleculeSharedDir}/Molecule_${MoleculeClusterName}/bin/atom start' hostname_workaround: commands: 010_set_etc_hosts: command: | local_ip=$(ip addr show dev eth0 | egrep -oi 'inet.*brd' | cut -d '/' -f 1 | awk '{print $2}') ip_hostname=$(hostname -s) local_hostname=$(curl http://169.254.169.254/latest/meta-data/local-hostname) echo "${local_ip} ${local_hostname} ${ip_hostname}" >> /etc/hosts set_container_id: commands: 010_tell_boomi: command: !Sub | container_id=$(grep 'com.boomi.container.id' ${MoleculeSharedDir}/Molecule_${MoleculeClusterName}/conf/container.id | cut -c 24-59) chown -R ec2-user:ec2-user ${MoleculeLocalPath} sudo /opt/aws/bin/cfn-signal -s true -d "{\"container_id\": \"${!container_id}\"}" '${Node4WaitHandle}' download_and_install_atom: files: /tmp/molecule_install.sh: source: https://platform.boomi.com/atom/molecule_install64.sh mode: '000755' owner: 'root' group: 'root' /tmp/molecule_set_cluster_properties.sh: content: !Sub | #!/bin/bash LOCAL_IVP4=$(curl http://169.254.169.254/latest/meta-data/local-ipv4) echo com.boomi.container.cloudlet.initialHosts=${!LOCAL_IVP4}[7800] >> ${MoleculeSharedDir}/Molecule_${MoleculeClusterName}/conf/container.properties echo com.boomi.container.cloudlet.clusterConfig=UNICAST >> ${MoleculeSharedDir}/Molecule_${MoleculeClusterName}/conf/container.properties echo com.boomi.deployment.quickstart=True >> ${MoleculeSharedDir}/Molecule_${MoleculeClusterName}/conf/container.properties mode: '000755' owner: 'root' group: 'root' commands: 010_create_dirs_and_perms: command: !Sub | mkdir -p ${MoleculeSharedDir}/Molecule_${MoleculeClusterName} chown ec2-user:ec2-user ${MoleculeSharedDir}/Molecule_${MoleculeClusterName} 011_install_atom: command: !If - APITokenProvided - !Sub | sudo -u ec2-user bash -c "/tmp/molecule_install.sh -q -console -VinstallToken=${BoomiInstallToken} -VatomName=${MoleculeClusterName} -VaccountId=${BoomiAccountID} -VlocalPath=${MoleculeLocalPath} -VlocalTempPath=${MoleculeLocalTemp} -dir ${MoleculeSharedDir}" - !Sub | sudo -u ec2-user bash -c "/tmp/molecule_install.sh -q -console -Vusername=${BoomiUsername} -Vpassword=\"${BoomiPassword}\" -VatomName=${MoleculeClusterName} -VaccountId=${BoomiAccountID} -VlocalPath=${MoleculeLocalPath} -VlocalTempPath=${MoleculeLocalTemp} -dir ${MoleculeSharedDir}" 020_set_cluster_properties: command: - /tmp/molecule_set_cluster_properties.sh 030_create_service: command: mv /tmp/molecule.service /lib/systemd/system/molecule.service 031_enable_service: command: systemctl enable molecule 040_cleanup_scripts: command: | rm /tmp/molecule_set_cluster_properties.sh rm /tmp/molecule_install.sh Properties: ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}' InstanceType: !Ref NodeInstanceType NetworkInterfaces: - GroupSet: - !Ref BoomiSecurityGroup - !Ref BoomiUnicastSG - !Ref MoleculeSecurityGroup - !If [ALBInPublicSubnets, !Ref BastionSecurityGroupID, !Ref AWS::NoValue] DeviceIndex: '0' DeleteOnTermination: true SubnetId: !Ref PrivateSubnet1ID BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeType: "gp2" DeleteOnTermination: true VolumeSize: !Ref MoleculeEBSVolume KeyName: !Ref KeyPairName Tags: - Value: MoleculeNode1 Key: Name UserData: Fn::Base64: !Sub | #!/bin/bash sudo yum update -y sudo /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MoleculeNode1 --region ${AWS::Region} -c head_molecule sudo /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MoleculeNode1 --region ${AWS::Region} MoleculeNode2: DependsOn: - MoleculeNode1 Type: "AWS::EC2::Instance" Properties: ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}' InstanceType: !Ref NodeInstanceType NetworkInterfaces: - GroupSet: - !Ref BoomiSecurityGroup - !Ref BoomiUnicastSG - !Ref MoleculeSecurityGroup - !If [ALBInPublicSubnets, !Ref BastionSecurityGroupID, !Ref AWS::NoValue] DeviceIndex: '0' DeleteOnTermination: true SubnetId: !Ref PrivateSubnet2ID BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeType: "gp2" DeleteOnTermination: true VolumeSize: !Ref MoleculeEBSVolume KeyName: !Ref KeyPairName UserData: Fn::Base64: !Sub | #!/bin/bash sudo yum update -y sudo /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MoleculeNode1 --region ${AWS::Region} -c molecule_workers sudo /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MoleculeNode2 --region ${AWS::Region} Tags: - Value: MoleculeNode2 Key: Name MoleculeNode3: DependsOn: MoleculeNode1 Type: "AWS::EC2::Instance" Properties: ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}' InstanceType: !Ref NodeInstanceType NetworkInterfaces: - GroupSet: - !Ref BoomiSecurityGroup - !Ref BoomiUnicastSG - !Ref MoleculeSecurityGroup - !If [ALBInPublicSubnets, !Ref BastionSecurityGroupID, !Ref AWS::NoValue] DeviceIndex: '0' DeleteOnTermination: true SubnetId: !Ref PrivateSubnet1ID BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeType: "gp2" DeleteOnTermination: true VolumeSize: !Ref MoleculeEBSVolume KeyName: !Ref KeyPairName Tags: - Value: MoleculeNode3 Key: Name UserData: Fn::Base64: !Sub | #!/bin/bash sudo yum update -y sudo /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MoleculeNode1 --region ${AWS::Region} -c molecule_workers sudo /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MoleculeNode3 --region ${AWS::Region} MoleculeNode4: DependsOn: MoleculeNode1 Type: "AWS::EC2::Instance" Properties: ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}' InstanceType: !Ref NodeInstanceType NetworkInterfaces: - GroupSet: - !Ref BoomiSecurityGroup - !Ref BoomiUnicastSG - !Ref MoleculeSecurityGroup - !If [ALBInPublicSubnets, !Ref BastionSecurityGroupID, !Ref AWS::NoValue] DeviceIndex: '0' DeleteOnTermination: true SubnetId: !Ref PrivateSubnet2ID BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeType: "gp2" DeleteOnTermination: true VolumeSize: !Ref MoleculeEBSVolume KeyName: !Ref KeyPairName UserData: Fn::Base64: !Sub | #!/bin/bash sudo yum update -y sudo /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource MoleculeNode1 --region ${AWS::Region} -c last_molecule sudo /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MoleculeNode4 --region ${AWS::Region} Tags: - Value: MoleculeNode4 Key: Name # ALB Target Group ELBTargetGroup: Condition: UsingALB Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckPort: '9093' HealthCheckProtocol: HTTPS Port: 9093 Protocol: HTTPS TargetType: instance Targets: - Id: !Ref MoleculeNode1 - Id: !Ref MoleculeNode2 - Id: !Ref MoleculeNode3 - Id: !Ref MoleculeNode4 VpcId: !Ref VPCID # ALB Listener ELBListener: Condition: UsingALB Type: AWS::ElasticLoadBalancingV2::Listener Properties: Certificates: - CertificateArn: !Ref SSLCertificateArn DefaultActions: - Type: forward TargetGroupArn: !Ref ELBTargetGroup LoadBalancerArn: !Ref ElasticLoadBalancer Port: !Ref LBListenerPort Protocol: HTTPS # ALB ElasticLoadBalancer: Condition: UsingALB Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Type: application Subnets: !If - ALBInPrivateSubnets - - !Ref PrivateSubnet1ID - !Ref PrivateSubnet2ID - - !Ref PublicSubnet1ID - !Ref PublicSubnet2ID SecurityGroups: - !Ref LoadBalancerSecurityGroup Scheme: !If - ALBInPrivateSubnets - internal - internet-facing EFSFilesystemProvisioned: Type: AWS::EFS::FileSystem Condition: EFSProvisionedThroughput Metadata: cfn-lint: config: ignore_checks: [EFSFilesystemEncryptionEnabled] ignore_reasons: EFSFilesystemEncryptionEnabled: Optional encryption is required. Properties: Encrypted: !Ref EFSEncryption PerformanceMode: !Ref EFSPerformanceMode ProvisionedThroughputInMibps: !Ref EFSProvisionedThroughput ThroughputMode: !Ref EFSThroughputMode KmsKeyId: !GetAtt - KMSKey - Arn EFSFilesystemBursting: Type: AWS::EFS::FileSystem Condition: EFSBurstingThroughput Metadata: cfn-lint: config: ignore_checks: [EFSFilesystemEncryptionEnabled] ignore_reasons: EFSFilesystemEncryptionEnabled: Optional encryption is required. Properties: Encrypted: !Ref EFSEncryption PerformanceMode: !Ref EFSPerformanceMode ThroughputMode: !Ref EFSThroughputMode KmsKeyId: !GetAtt - KMSKey - Arn Node4WaitHandle: Type: AWS::CloudFormation::WaitConditionHandle Node4WaitCondition: Type: AWS::CloudFormation::WaitCondition Properties: Handle: !Ref 'Node4WaitHandle' Timeout: "1800" Count: 1 BoomiVerifyLicense: Condition: PasswordProvided Type: Custom::BoomiVerifyLicense Properties: ServiceToken: !GetAtt 'BoomiVerifyLicenseFunction.Arn' BoomiUsername: !If - APITokenProvided - !Sub "BOOMI_TOKEN.${BoomiUsername}" - !Ref "BoomiUsername" BoomiPassword: !If - APITokenProvided - !Ref "BoomiInstallToken" - !Ref "BoomiPassword" BoomiAccountID: !Ref "BoomiAccountID" TokenType: "Molecule" TokenTimeout: 60 BoomiVerifyLicenseFunction: Condition: PasswordProvided Type: AWS::Lambda::Function Properties: Description: Verifies account has available molecule licenses. Handler: lambda_function.lambda_handler Runtime: python3.7 Role: !GetAtt 'BoomiAPIRole.Arn' Timeout: 240 Code: S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Key: !Sub "${QSS3KeyPrefix}functions/packages/LicenseVerificationAndTokenGenerator/lambda.zip" BoomiAPI: Condition: UsingALBAndPassword DependsOn: - MoleculeNode4 Type: Custom::BoomiAPI Properties: ServiceToken: !GetAtt 'BoomiAPIFunction.Arn' BoomiUsername: !If - APITokenProvided - !Sub "BOOMI_TOKEN.${BoomiUsername}" - !Ref "BoomiUsername" BoomiPassword: !If - APITokenProvided - !Ref "BoomiInstallToken" - !Ref "BoomiPassword" BoomiAccountID: !Ref "BoomiAccountID" WaitHandleData: !GetAtt 'Node4WaitCondition.Data' ELB_FQDN: !GetAtt 'ElasticLoadBalancer.DNSName' HttpPort: '9093' BoomiAPIFunction: Type: AWS::Lambda::Function Condition: UsingALBAndPassword Properties: Description: Sends ELB FQDN to Boomi. Handler: index.handler Runtime: python3.7 Role: !GetAtt 'BoomiAPIRole.Arn' Timeout: 240 Code: ZipFile: | import json import logging import threading import boto3 import cfnresponse import urllib3 import copy def timeout(event, context): logging.error('Execution is about to time out, sending failure response to CloudFormation') cfnresponse.send(event, context, cfnresponse.FAILED, {}, None) def pull_container_id(whdata): whraw = json.loads(whdata) for k,v in whraw.items(): if 'container_id' in v: cidraw = json.loads(v) container_id = cidraw['container_id'] return container_id def register_elb_with_atom(username, password, account, elb_url, http_port, atom_id): API_URL = f"https://api.boomi.com/api/rest/v1/{account}/SharedServerInformation/{atom_id}/update" payload = { "@type":"SharedServerInformation", "atomId": atom_id, "url": elb_url, "overrideUrl": "true", "httpPort": http_port } payload = json.dumps(payload) headers = {'Content-Type':'application/json', 'Accept':'application/json'} headers.update(urllib3.util.make_headers(basic_auth = f"{username}:{password}")) http = urllib3.PoolManager() resp = http.request('POST', API_URL, headers=headers, body=payload) if resp.status != 200: raise def delete_atom_from_boomi_platform(username, password, account, atom_id): API_URL = f"https://api.boomi.com/api/rest/v1/{account}/Atom/{atom_id}" headers = {'Content-Type':'application/json', 'Accept':'application/json'} headers.update(urllib3.util.make_headers(basic_auth = f"{username}:{password}")) http = urllib3.PoolManager() resp = http.request('DELETE', API_URL, headers=headers) def handler(event, context): # make sure we send a failure to CloudFormation if the function # is going to timeout timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) timer.start() sanitized_event = copy.deepcopy(event) sanitized_event['ResourceProperties']['BoomiPassword'] = "" print('Received event: %s' % json.dumps(sanitized_event)) status = cfnresponse.SUCCESS try: username = event['ResourceProperties']['BoomiUsername'] password = event['ResourceProperties']['BoomiPassword'] account_id = event['ResourceProperties']['BoomiAccountID'] elb_fqdn = event['ResourceProperties']['ELB_FQDN'] container_id = pull_container_id(event['ResourceProperties']['WaitHandleData']) http_port = event['ResourceProperties']['HttpPort'] if event['RequestType'] == 'Create': register_elb_with_atom(username, password, account_id, f"{elb_fqdn}:{http_port}", http_port, container_id) elif event['RequestType'] == 'Delete': delete_atom_from_boomi_platform(username, password, account_id, container_id) except Exception as e: logging.error('Exception: %s' % e, exc_info=True) status = cfnresponse.FAILED finally: timer.cancel() cfnresponse.send(event, context, status, {}, None) BoomiAPIRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Outputs: VPC: Description: The VPC Value: !Ref VPCID