AWSTemplateFormatVersion: '2010-09-09' Description: This deploys an Automation Document that builds a .Net Framework Container that includes msbuild (qs-1qh1429dt) Resources: GenerateDotNetContainer: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: schemaVersion: "0.3" description: "Create a .NET Framework Container for CodeBuild" assumeRole: "{{AutomationAssumeRole}}" parameters: StackName: default: "" description: "Stack Name Input for cfn resource signal" type: "String" ECRRepoName: default: "" description: "ECR Repo Name" type: "String" QSS3BucketName: 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: default: "quickstart-dotnet-serverless-cicd/" 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" AutomationAssumeRole: default: "" description: "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf." type: "String" mainSteps: - name: createStack action: aws:createStack onFailure: "step:signalfailure" inputs: StackName: !Sub "DotNetContainer-${AWS::StackName}" Capabilities: [ "CAPABILITY_IAM" ] TemplateBody: | Description: "Deploy Instance to Create a Container" Parameters: LatestAmiId: Type: 'AWS::SSM::Parameter::Value' Default: "/aws/service/ami-windows-latest/Windows_Server-2019-English-Core-ContainersLatest" QSS3BucketName: Type: "String" Default: "{{QSS3BucketName}}" Description: "Name of Target S3 Bucket" QSS3BucketRegion: Default: "{{QSS3BucketRegion}}" 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: Type: "String" Default: "{{QSS3KeyPrefix}}" Description: "Name of Target S3 Prefix" Resources: DockerCreateRole: Type : AWS::IAM::Role Properties: 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: s3-instance-bucket-policy Path: / ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore' - !Sub 'arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy' - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess" - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonS3FullAccess" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "ec2.amazonaws.com" - "ssm.amazonaws.com" Action: "sts:AssumeRole" IamInstanceProfile: Type: "AWS::IAM::InstanceProfile" Properties: Roles: - !Ref DockerCreateRole EC2Instance: Type: "AWS::EC2::Instance" Properties: ImageId: !Ref LatestAmiId InstanceType: "t3.2xlarge" BlockDeviceMappings: - DeviceName: "/dev/sda1" Ebs: VolumeSize: "50" IamInstanceProfile: !Ref IamInstanceProfile Tags: - Key: "Name" Value: "DotNetFrameworkContainer" - name: "getInstanceId" action: aws:executeAwsApi onFailure: "step:signalfailure" inputs: Service: ec2 Api: DescribeInstances Filters: - Name: "tag:Name" Values: [ "DotNetFrameworkContainer" ] - Name: "instance-state-name" Values: [ "running" ] outputs: - Name: InstanceId Selector: "$.Reservations..Instances..InstanceId" Type: "StringList" - name: "CreateDockerImage" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{getInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.amazonaws.com/{{QSS3KeyPrefix}}scripts/Dockerfile"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "docker build -t {{ECRRepoName}}:latest -m 2GB ." - name: "PushDockerImagetoECR" action: aws:runCommand onFailure: "step:signalfailure" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - "{{getInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" Parameters: commands: - | $Region = (Invoke-RestMethod -Method Get -Uri http://169.254.169.254/latest/dynamic/instance-identity/document).region $AccountID = (Invoke-RestMethod -Method Get -Uri http://169.254.169.254/latest/dynamic/instance-identity/document).accountId $ecrurl = $AccountID + '.dkr.ecr.' + $Region + '.amazonaws.com/{{ECRRepoName}}:latest' Invoke-Expression -Command (Get-ECRLoginCommand -Region $Region).Command docker tag {{ECRRepoName}}:latest $ecrurl docker push $ecrurl # Determines if CFN Needs to be Signaled or if Work flow should just end - name: CFNSignalEnd action: aws:branch inputs: Choices: - NextStep: signalsuccess Not: Variable: "{{StackName}}" StringEquals: "" - NextStep: sleepend Variable: "{{StackName}}" StringEquals: "" # If all steps complete successfully signals CFN of Success - name: "signalsuccess" action: "aws:executeAwsApi" nextStep: "deleteStack" inputs: Service: cloudformation Api: SignalResource LogicalResourceId: "SSMWaitCondition" StackName: "{{StackName}}" Status: SUCCESS UniqueId: "SSMWaitCondition" # If CFN Signl Not Needed this sleep ends work flow - name: "sleepend" action: "aws:sleep" nextStep: "deleteStack" inputs: Duration: PT1S # If any steps fails signals CFN of Failure - name: "signalfailure" action: "aws:executeAwsApi" nextStep: "deleteStack" inputs: Service: cloudformation Api: SignalResource LogicalResourceId: "SSMWaitCondition" StackName: "{{StackName}}" Status: FAILURE UniqueId: "SSMWaitCondition" - name: deleteStack action: aws:deleteStack isEnd: true onFailure: Continue inputs: StackName: !Sub "DotNetContainer-${AWS::StackName}"