AWSTemplateFormatVersion: 2010-09-09 Description: This template deploys Autodesk Forge in an ASG behind an ALB load balancer in two private subnets. **WARNING** This template creates EC2 instances and related resources. You will be billed for the AWS resources used if you create a stack from this template. (qs-1q4sbh1q9) Metadata: cfn-lint: config: ignore_checks: - W9006 # temporary to get rid of warnings AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network configuration Parameters: - VPCID - PrivateSubnet1ID - PrivateSubnet2ID - PublicSubnet1ID - PublicSubnet2ID - RemoteAccessCIDR - Label: default: Security configuration Parameters: - KeyPairName - BastionSecurityGroupID - Label: default: BIM 360 integration nodes configuration Parameters: - NodeInstanceType - NodesMinSize - NodesMaxSize - NodesDesiredCapacity - OperatorEmail - Label: default: BIM 360 integration application runtime configuration Parameters: - ApplicationRuntime - Label: default: Autodesk Forge credentials Parameters: - ForgeClientId - ForgeClientSecret - ForgeCallbackUrl - Label: default: "[Optional] BIM 360 integration site domain configuration" Parameters: - SiteDomain - ALBSSLCertificateARN - Route53HostedZoneId - Label: default: AWS Quick Start configuration Parameters: - QSS3BucketName - QSS3BucketRegion - QSS3KeyPrefix ParameterLabels: BastionSecurityGroupID: default: Bastion security group ID KeyPairName: default: Key pair name OperatorEmail: default: Operator email ApplicationRuntime: default: BIM 360 integration application runtime ForgeClientId: default: Forge client ID ForgeClientSecret: default: Forge client secret PrivateSubnet1ID: default: Private subnet 1 ID PrivateSubnet2ID: default: Private subnet 2 ID PublicSubnet1ID: default: Public subnet 1 ID PublicSubnet2ID: default: Public subnet 2 ID QSS3BucketName: default: Quick Start S3 Bucket Name QSS3BucketRegion: default: Quick Start S3 bucket region QSS3KeyPrefix: default: Quick Start S3 Key Prefix RemoteAccessCIDR: default: Allowed external access CIDR VPCID: default: VPC ID NodeInstanceType: default: BIM 360 integration nodes instance type NodesDesiredCapacity: default: BIM 360 integration nodes desired capacity NodesMaxSize: default: BIM 360 integration nodes max size NodesMinSize: default: BIM 360 integration nodes min size SiteDomain: default: BIM 360 integration site domain ForgeCallbackUrl: default: Forge callback URL ALBSSLCertificateARN: default: ALB SSL certificate ARN Route53HostedZoneId: default: Route 53 hosted zone ID Parameters: ALBSSLCertificateARN: Default: "" Description: "[Optional] The ARN of the SSL certificate to be used for the Application Load Balancer." Type: String BastionSecurityGroupID: Description: ID of the bastion host security group to enable SSH connections (e.g., sg-7f16e910). Type: AWS::EC2::SecurityGroup::Id KeyPairName: Description: The name of an existing public/private key pair, which allows you to securely connect to your instance after it launches. Type: AWS::EC2::KeyPair::KeyName OperatorEmail: AllowedPattern: ([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?) ConstraintDescription: Must be a valid email address. Description: Email address that notifications of any scaling operations will be sent to. Type: String ApplicationRuntime: AllowedValues: - Node.js - .NET Core Default: Node.js Description: Defines what kind of server-side BIM 360 integration application you will be deploying Type: String ForgeClientId: ConstraintDescription: Input your Forge Client ID Description: The client ID of your Forge application. You can obtain it on the Forge Developer Platform at https://developer.autodesk.com/myapps. NoEcho: "True" Type: String ForgeClientSecret: ConstraintDescription: Input your Forge Client Secret Description: The client secret of your Forge application. You can obtain it on the Forge Developer Platform at https://developer.autodesk.com/myapps. NoEcho: "True" Type: String PrivateSubnet1ID: Description: The ID of the private subnet in Availability Zone 1 in your existing VPC (e.g., subnet-a0246dcd). Type: AWS::EC2::Subnet::Id PrivateSubnet2ID: Description: The ID of the private subnet in Availability Zone 2 in your existing VPC (e.g., subnet-b58c3d67). Type: AWS::EC2::Subnet::Id PublicSubnet1ID: Description: The ID of the public subnet in Availability Zone 1 in your existing VPC (e.g., subnet-9bc642ac) Type: AWS::EC2::Subnet::Id PublicSubnet2ID: Description: The ID of the public subnet in Availability Zone 2 in your existing VPC (e.g., subnet-e3246d8e) Type: AWS::EC2::Subnet::Id 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. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String QSS3BucketRegion: Default: 'us-east-1' Description: 'The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value.' 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-bim360-integration/ 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 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: The CIDR IP range that is permitted to access the bastions and Forge web application. We recommend that you set this value to a trusted IP range. Type: String Route53HostedZoneId: Description: "[Optional] Route53 Hosted Zone ID where DNS record for Forge Site Domain will be added." Type: String Default: "" VPCID: Description: The ID of your existing VPC (e.g., vpc-0343606e). Type: AWS::EC2::VPC::Id NodeInstanceType: 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: Must contain valid instance type Default: t3.large Description: Amazon EC2 instance type for the BIM 360 integration instances. Type: String NodesDesiredCapacity: Default: "2" Description: The desired capacity for BIM 360 integration nodes in the Auto Scaling group. Type: String NodesMaxSize: Default: "4" Description: The maximum number of BIM 360 integration nodes in the Auto Scaling group. Type: String NodesMinSize: Default: "2" Description: The minimum number of BIM 360 integration nodes in the Auto Scaling group. Type: String SiteDomain: Description: "[Optional] Domain name of the BIM 360 integration site. e.g. example.com. Valid FQDN required when using SSL." AllowedPattern: (?!-)[a-zA-Z0-9-.]*(?/api/forge/callback/oauth). You can obtain it on the Forge Developer Platform at https://developer.autodesk.com/myapps. If you don't have one, you must modify the value in the Forge portal with the ForgeCallbackURL output after. ConstraintDescription: Must be a valid fully-qualified callback url. Type: String Default: "" Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] UseALBSSL: Fn::Not: - Fn::Equals: - Ref: ALBSSLCertificateARN - "" ForgeSiteDomainRoute53Condition: Fn::And: - Fn::Not: - Fn::Equals: - Ref: SiteDomain - "" - Fn::Not: - Fn::Equals: - Ref: Route53HostedZoneId - "" ForgeCallbackUrlCondition: Fn::Not: - Fn::Equals: - Ref: ForgeCallbackUrl - "" UseNodeJSConfig: Fn::Equals: - Ref: ApplicationRuntime - Node.js Rules: KeyPairsNotEmpty: Assertions: - Assert: Fn::Not: - Fn::EachMemberEquals: - Fn::RefAll: AWS::EC2::KeyPair::KeyName - "" AssertDescription: All key pair parameters must not be empty SubnetsInVPC: Assertions: - Assert: Fn::EachMemberIn: - Fn::ValueOfAll: - AWS::EC2::Subnet::Id - VpcId - Fn::RefAll: AWS::EC2::VPC::Id AssertDescription: All subnets must in the VPC SslAndRoute53Rule: RuleCondition: Fn::Or: - Fn::Not: - Fn::Equals: - Ref: ALBSSLCertificateARN - "" - Fn::Not: - Fn::Equals: - Ref: Route53HostedZoneId - "" Assertions: - Assert: Fn::Not: - Fn::Equals: - Ref: SiteDomain - "" AssertDescription: Parameter SiteDomain cannot be empty and must provide FQDN e.g. example.com, when ALBSSLCertificateARN or Route53HostedZoneId values are provided. T3InstanceSupportedRegionRule: Assertions: - Assert: Fn::Not: - Fn::And: - Fn::Contains: - - ap-northeast-2 - ap-northeast-3 - ap-south-1 - eu-west-3 - Ref: AWS::Region - Fn::Contains: - - t3.nano - t3.micro - t3.small - t3.medium - t3.large - t3.xlarge - t3.2xlarge - Ref: NodeInstanceType AssertDescription: T3 instances are not supported in Seoul (ap-northeast-2), Osaka-Local (ap-northeast-3), Mumbai (ap-south-1) and Paris (eu-west-3) regions. Please launch the stack with another instance type. TwoAZsRequiredRegionRule: Assertions: - Assert: Fn::Not: - Fn::Contains: - - ap-northeast-3 - Ref: AWS::Region AssertDescription: This Quick Start requires two Availability Zones and not supported in Osaka-Local (ap-northeast-3) region. Please launch the stack in another region to continue. Resources: ForgeClientIdSSMParameter: Type: AWS::SSM::Parameter Properties: Type: String Value: Ref: ForgeClientId Description: Forge Client ID from SSM ForgeClientSecretSSMParameter: Type: AWS::SSM::Parameter Properties: Type: String Value: Ref: ForgeClientSecret Description: Forge Client Secret from SSM NotificationTopic: Type: AWS::SNS::Topic Properties: Subscription: - Endpoint: Ref: OperatorEmail Protocol: email ELBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow access to the ELB VpcId: Ref: VPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: Fn::If: - UseALBSSL - 443 - 80 ToPort: Fn::If: - UseALBSSL - 443 - 80 CidrIp: Ref: RemoteAccessCIDR ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Subnets: - Ref: PublicSubnet1ID - Ref: PublicSubnet2ID SecurityGroups: - Ref: ELBSecurityGroup ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: Ref: ALBTargetGroup LoadBalancerArn: Ref: ApplicationLoadBalancer Port: Fn::If: - UseALBSSL - 443 - 80 Protocol: Fn::If: - UseALBSSL - HTTPS - HTTP Certificates: - Fn::If: - UseALBSSL - CertificateArn: Ref: ALBSSLCertificateARN - Ref: AWS::NoValue ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 30 HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 Port: 3000 Protocol: HTTP UnhealthyThresholdCount: 5 VpcId: Ref: VPCID TargetGroupAttributes: - Key: stickiness.enabled Value: "true" - Key: stickiness.type Value: lb_cookie - Key: stickiness.lb_cookie.duration_seconds Value: "30" ForgeSiteDomainRoute53Record: Type: AWS::Route53::RecordSet Condition: ForgeSiteDomainRoute53Condition Properties: Name: Ref: SiteDomain Type: A HostedZoneId: Ref: Route53HostedZoneId AliasTarget: DNSName: Fn::GetAtt: - ApplicationLoadBalancer - DNSName EvaluateTargetHealth: true HostedZoneId: Fn::GetAtt: - ApplicationLoadBalancer - CanonicalHostedZoneID ForgeCallbackUrlSSMParameter: Type: AWS::SSM::Parameter Properties: Type: String Value: Fn::If: - ForgeCallbackUrlCondition - Ref: ForgeCallbackUrl - REPLACE-ME-with-ForgeCallbackURL Description: Forge Callback Url SetupRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyDocument: Version: 2012-10-17 Statement: - Action: - s3:GetObject Resource: !Sub - arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}* - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Effect: Allow PolicyName: aws-quick-start-s3-policy - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: [ "ssm:DescribePatchProperties", "ssm:DescribeMaintenanceWindowSchedule", "ssm:DescribeDocumentParameters", "ssm:DescribePatchBaselines", "ssm:DescribeInstanceProperties", "ssm:DescribeParameters", "ssm:DescribeMaintenanceWindowExecutions", "ssm:DescribeMaintenanceWindowsForTarget", "ssm:DescribeMaintenanceWindows", "ssm:DescribeEffectiveInstanceAssociations", "ssm:DescribeInstancePatches", "ssm:DescribeMaintenanceWindowExecutionTaskInvocations", "ssm:DescribeDocumentPermission", "ssm:DescribeInstanceInformation", "ssm:DescribeAvailablePatches", "ssm:DescribePatchGroupState", "ssm:DescribeMaintenanceWindowTargets", "ssm:DescribeSessions", "ssm:DescribeAssociationExecutions", "ssm:DescribeInstancePatchStates", "ssm:DescribeAutomationStepExecutions", "ssm:DescribeAssociation", "ssm:DescribeInstancePatchStatesForPatchGroup", "ssm:DescribeMaintenanceWindowExecutionTasks", "ssm:DescribeAssociationExecutionTargets", "ssm:DescribeDocument", "ssm:DescribePatchGroups", "ssm:DescribeOpsItems", "ssm:DescribeActivations", "ssm:DescribeInventoryDeletions", "ssm:DescribeInstanceAssociationsStatus", "ssm:DescribeAutomationExecutions", "ssm:DescribeEffectivePatchesForPatchBaseline", "ssm:DescribeMaintenanceWindowTasks", "ssm:GetDocument", "ssm:GetOpsMetadata", "ssm:GetMaintenanceWindowExecutionTask", "ssm:GetConnectionStatus", "ssm:GetDeployablePatchSnapshotForInstance", "ssm:GetParameterHistory", "ssm:GetOpsItem", "ssm:GetPatchBaseline", "ssm:GetInventory", "ssm:GetManifest", "ssm:GetCalendarState", "ssm:GetParameter", "ssm:GetOpsSummary", "ssm:GetCommandInvocation", "ssm:GetMaintenanceWindow", "ssm:GetParametersByPath", "ssm:GetInventorySchema", "ssm:GetParameters", "ssm:GetAutomationExecution", "ssm:GetServiceSetting", "ssm:GetMaintenanceWindowTask", "ssm:GetDefaultPatchBaseline", "ssm:GetMaintenanceWindowExecution", "ssm:GetMaintenanceWindowExecutionTaskInvocation", "ssm:GetPatchBaselineForPatchGroup", "ssm:ListOpsItemRelatedItems", "ssm:ListTagsForResource", "ssm:ListCommands", "ssm:ListResourceDataSync", "ssm:ListOpsMetadata", "ssm:ListInstanceAssociations", "ssm:ListAssociations", "ssm:ListAssociationVersions", "ssm:ListDocumentMetadataHistory", "ssm:ListCommandInvocations", "ssm:ListInventoryEntries", "ssm:ListComplianceItems", "ssm:ListComplianceSummaries", "ssm:ListResourceComplianceSummaries", "ssm:ListDocuments", "ssm:ListDocumentVersions", "ssm:ListOpsItemEvents" ] Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/* PolicyName: aws-quick-start-forge-ssm-policy SetupRoleProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: - Ref: SetupRole WorkloadSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow access to the Workload instances VpcId: Ref: VPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: 3000 ToPort: 3000 SourceSecurityGroupId: Ref: ELBSecurityGroup - IpProtocol: tcp FromPort: 22 ToPort: 22 SourceSecurityGroupId: Ref: BastionSecurityGroupID WorkloadASLaunchConfigStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/${ForgeLaunchConfigTemplate}' - ForgeLaunchConfigTemplate: !If [UseNodeJSConfig,'autodesk-forge-bim360-nodejs.template.yaml', 'autodesk-forge-bim360-netcore.template.yaml'] S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Parameters: ForgeNodeInstanceType: Ref: NodeInstanceType KeyPairName: Ref: KeyPairName ForgeClientIdSSMParameter: Ref: ForgeClientIdSSMParameter ForgeClientSecretSSMParameter: Ref: ForgeClientSecretSSMParameter ForgeCallbackUrlSSMParameter: Ref: ForgeCallbackUrlSSMParameter WorkloadSecurityGroup: Ref: WorkloadSecurityGroup SetupRoleProfile: Ref: SetupRoleProfile ParentStack: Ref: AWS::StackName QSS3BucketName: Ref: QSS3BucketName QSS3KeyPrefix: Ref: QSS3KeyPrefix WebServerTargetTrackingScalingPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AutoScalingGroupName: Ref: WorkloadAutoScalingGroup Cooldown: "60" PolicyType: TargetTrackingScaling TargetTrackingConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ASGAverageCPUUtilization TargetValue: 75 WorkloadAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: - Ref: PrivateSubnet1ID - Ref: PrivateSubnet2ID Cooldown: "600" DesiredCapacity: Ref: NodesDesiredCapacity HealthCheckGracePeriod: 600 HealthCheckType: EC2 LaunchConfigurationName: Fn::GetAtt: - WorkloadASLaunchConfigStack - Outputs.WorkloadASLaunchConfig TargetGroupARNs: - Ref: ALBTargetGroup MaxSize: Ref: NodesMaxSize MinSize: Ref: NodesMinSize NotificationConfigurations: - TopicARN: Ref: NotificationTopic NotificationTypes: - autoscaling:EC2_INSTANCE_LAUNCH - autoscaling:EC2_INSTANCE_LAUNCH_ERROR - autoscaling:EC2_INSTANCE_TERMINATE - autoscaling:EC2_INSTANCE_TERMINATE_ERROR - autoscaling:TEST_NOTIFICATION Tags: - Key: Name Value: Autodesk Forge Instance PropagateAtLaunch: true CreationPolicy: ResourceSignal: Count: Ref: NodesDesiredCapacity Timeout: PT2H Outputs: ALBDNSName: Description: ALB DNS Name Value: Fn::GetAtt: - ApplicationLoadBalancer - DNSName BIM360IntegrationAppURL: Description: BIM 360 integration application URL Value: Fn::Sub: - ${AppScheme}://${AppDomain} - AppScheme: Fn::If: - UseALBSSL - https - http AppDomain: Fn::If: - ForgeSiteDomainRoute53Condition - Ref: SiteDomain - Fn::GetAtt: - ApplicationLoadBalancer - DNSName ForgeCallbackURL: Description: Forge Callback URL Value: Fn::If: - ForgeCallbackUrlCondition - Ref: ForgeCallbackUrl - Fn::Sub: - ${AppScheme}://${AppDomain}/api/forge/callback/oauth - AppScheme: Fn::If: - UseALBSSL - https - http AppDomain: Fn::If: - ForgeSiteDomainRoute53Condition - Ref: SiteDomain - Fn::GetAtt: - ApplicationLoadBalancer - DNSName ForgeCallbackURLParameter: Description: Forge Callback URL SSM Parameter Value: Ref: ForgeCallbackUrlSSMParameter