├── 1-Basics.yaml
├── 2-IntrinsicFunctions.yaml
├── 3-VpsWithPublicAndPrivateSubnets.yaml
├── CICD-for-CFN
├── 1-source-code
│ └── cfn-vpc-app
│ │ ├── buildspec.yml
│ │ ├── vpc-config.json
│ │ └── vpc.yml
├── 2-codecommit.yaml
├── 3-codebuild.yaml
└── 4-codepipeline.yaml
├── CICD
├── 1-code-commit.yaml
├── 2-source-code
│ └── cicd-dotnet-webapp
│ │ ├── .gitignore
│ │ ├── Pages
│ │ ├── Error.cshtml
│ │ ├── Error.cshtml.cs
│ │ ├── Index.cshtml
│ │ ├── Index.cshtml.cs
│ │ ├── Privacy.cshtml
│ │ ├── Privacy.cshtml.cs
│ │ ├── Shared
│ │ │ ├── _Layout.cshtml
│ │ │ └── _ValidationScriptsPartial.cshtml
│ │ ├── _ViewImports.cshtml
│ │ └── _ViewStart.cshtml
│ │ ├── Program.cs
│ │ ├── Properties
│ │ └── launchSettings.json
│ │ ├── README.md
│ │ ├── Startup.cs
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── appspec.yml
│ │ ├── buildspec.yml
│ │ ├── cicd-dotnet-webapp.csproj
│ │ ├── cicd-dotnet-webapp
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── cicd-dotnet-webapp.Views.dll
│ │ ├── cicd-dotnet-webapp.Views.pdb
│ │ ├── cicd-dotnet-webapp.deps.json
│ │ ├── cicd-dotnet-webapp.dll
│ │ ├── cicd-dotnet-webapp.exe
│ │ ├── cicd-dotnet-webapp.pdb
│ │ ├── cicd-dotnet-webapp.runtimeconfig.json
│ │ ├── web.config
│ │ └── wwwroot
│ │ │ ├── css
│ │ │ └── site.css
│ │ │ ├── favicon.ico
│ │ │ ├── js
│ │ │ └── site.js
│ │ │ └── lib
│ │ │ ├── bootstrap
│ │ │ ├── LICENSE
│ │ │ └── dist
│ │ │ │ ├── css
│ │ │ │ ├── bootstrap-grid.css
│ │ │ │ ├── bootstrap-grid.css.map
│ │ │ │ ├── bootstrap-grid.min.css
│ │ │ │ ├── bootstrap-grid.min.css.map
│ │ │ │ ├── bootstrap-reboot.css
│ │ │ │ ├── bootstrap-reboot.css.map
│ │ │ │ ├── bootstrap-reboot.min.css
│ │ │ │ ├── bootstrap-reboot.min.css.map
│ │ │ │ ├── bootstrap.css
│ │ │ │ ├── bootstrap.css.map
│ │ │ │ ├── bootstrap.min.css
│ │ │ │ └── bootstrap.min.css.map
│ │ │ │ └── js
│ │ │ │ ├── bootstrap.bundle.js
│ │ │ │ ├── bootstrap.bundle.js.map
│ │ │ │ ├── bootstrap.bundle.min.js
│ │ │ │ ├── bootstrap.bundle.min.js.map
│ │ │ │ ├── bootstrap.js
│ │ │ │ ├── bootstrap.js.map
│ │ │ │ ├── bootstrap.min.js
│ │ │ │ └── bootstrap.min.js.map
│ │ │ ├── jquery-validation-unobtrusive
│ │ │ ├── LICENSE.txt
│ │ │ ├── jquery.validate.unobtrusive.js
│ │ │ └── jquery.validate.unobtrusive.min.js
│ │ │ ├── jquery-validation
│ │ │ ├── LICENSE.md
│ │ │ └── dist
│ │ │ │ ├── additional-methods.js
│ │ │ │ ├── additional-methods.min.js
│ │ │ │ ├── jquery.validate.js
│ │ │ │ └── jquery.validate.min.js
│ │ │ └── jquery
│ │ │ ├── LICENSE.txt
│ │ │ └── dist
│ │ │ ├── jquery.js
│ │ │ ├── jquery.min.js
│ │ │ └── jquery.min.map
│ │ ├── codedeploy-scripts
│ │ ├── after-install.sh
│ │ ├── application-start.sh
│ │ ├── application-stop.sh
│ │ └── before-install.sh
│ │ └── wwwroot
│ │ ├── css
│ │ └── site.css
│ │ ├── favicon.ico
│ │ ├── js
│ │ └── site.js
│ │ └── lib
│ │ ├── bootstrap
│ │ ├── LICENSE
│ │ └── dist
│ │ │ ├── css
│ │ │ ├── bootstrap-grid.css
│ │ │ ├── bootstrap-grid.css.map
│ │ │ ├── bootstrap-grid.min.css
│ │ │ ├── bootstrap-grid.min.css.map
│ │ │ ├── bootstrap-reboot.css
│ │ │ ├── bootstrap-reboot.css.map
│ │ │ ├── bootstrap-reboot.min.css
│ │ │ ├── bootstrap-reboot.min.css.map
│ │ │ ├── bootstrap.css
│ │ │ ├── bootstrap.css.map
│ │ │ ├── bootstrap.min.css
│ │ │ └── bootstrap.min.css.map
│ │ │ └── js
│ │ │ ├── bootstrap.bundle.js
│ │ │ ├── bootstrap.bundle.js.map
│ │ │ ├── bootstrap.bundle.min.js
│ │ │ ├── bootstrap.bundle.min.js.map
│ │ │ ├── bootstrap.js
│ │ │ ├── bootstrap.js.map
│ │ │ ├── bootstrap.min.js
│ │ │ └── bootstrap.min.js.map
│ │ ├── jquery-validation-unobtrusive
│ │ ├── LICENSE.txt
│ │ ├── jquery.validate.unobtrusive.js
│ │ └── jquery.validate.unobtrusive.min.js
│ │ ├── jquery-validation
│ │ ├── LICENSE.md
│ │ └── dist
│ │ │ ├── additional-methods.js
│ │ │ ├── additional-methods.min.js
│ │ │ ├── jquery.validate.js
│ │ │ └── jquery.validate.min.js
│ │ └── jquery
│ │ ├── LICENSE.txt
│ │ └── dist
│ │ ├── jquery.js
│ │ ├── jquery.min.js
│ │ └── jquery.min.map
├── 3-s3-artifact.yaml
├── 4-code-build.yaml
├── 5-ec2-for-dev-and-prod.yaml
├── 6-code-deploy.yaml
└── 7-code-pipeline.yaml
├── Conditions
├── conditionInsideCondition.yaml
├── noValue-ignoreSGAttachmentToEc2IfDev.yaml
└── or-eitherRegionAorRegionB.yaml
├── EC2
├── 1-EC2-SG.yaml
├── 2.ec2-sg-eip.yaml
├── 3-ec2-sg-html.yaml
├── 4-ec2-sg-lamp.yaml
├── 5-ec2-ebs-vs-ephemeral-drive.yaml
└── links.md
├── ECS
├── 1-ecs-empty-cluster.yaml
├── 2-vpc-with-2-public-subnets.yaml
└── cluster-types.png
├── IAM
├── Groups-AttachUsersToGroup.yaml
├── Groups-Group.yaml
├── Policies-CustomerManagedPolicy.yaml
├── Policies-InlinePolicy.yaml
├── Roles-InstanceProfile.yaml
├── Roles-MoreExamples.yaml
├── Roles-Role.yaml
├── Roles-RoleWithPolicies.yaml
├── Users-User.yaml
└── Users-UserWithPolicies.yaml
├── Metadata
├── img-interface.png
└── interface.yaml
├── NestedStacks
├── 1-vpc-as-nested-stack.yaml
├── 2-sg-as-nested-stack.yaml
├── 3-save-nested-stacks-in-s3
│ ├── 1-upload-files.png
│ ├── 2-make-file-public.png
│ ├── 3-test-file-access.png
│ ├── README.md
│ └── s3-bucket.yaml
├── 4-ec2-as-root-stack.yaml
└── final-results.png
├── Outputs
├── export-condition.yaml
├── export.yaml
├── img-export-import.png
└── import.yaml
├── README.md
├── StackPolicy
├── 1-deny-resource-update.json
├── 2-deny-resource-type-update.json
├── 3-deny-replacement-updates.json
├── 4-not-action.json
└── README.md
└── UserDataAndMetadata
├── 0-source-code
├── README.md
├── S3-bucket.yaml
├── WAR-Files
│ ├── demo1.zip
│ └── demo2.zip
└── screenshots
│ ├── 1-upload-files.png
│ ├── 2-make-file-public.png
│ └── 3-test-file-access.png
├── 1-base.yaml
├── 2-metadata-schema.yaml
├── 3-metadata.yaml
├── 4-userdata.yaml
├── 5-outputs.yaml
├── 6-creationPolicy.png
├── 6-creationPolicy.yaml
├── 7-configSet-single.yaml
└── 8-configSet-multiple.yaml
/1-Basics.yaml:
--------------------------------------------------------------------------------
1 | # create a new S3 bucket
2 | Resources:
3 | MyS3Bucket: # logical ID
4 | Type: 'AWS::S3::Bucket'
5 | Properties:
6 | BucketName: jon-snow-bucket
7 | Tags: # list of tags
8 | - Key: CloudFormationLab
9 | Value: JonSnow
--------------------------------------------------------------------------------
/2-IntrinsicFunctions.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION ===================
2 | Description: >-
3 | AWS CloudFormation sample template.
4 | Create a new EC2 instance and if environment is 'prod' then attach a new EBS volume to it
5 |
6 | ## =================== PARAMETERS ===================
7 | Parameters:
8 | paramEnvironmentType: # ask a user to define whether it is 'dev', 'qa' or 'prod' environment
9 | Description: Environment type
10 | Default: dev # by default it is 'dev' environment
11 | Type: String
12 | AllowedValues: [dev, qa, prod]
13 | ConstraintDescription: Must specify 'dev', 'qa' or 'prod'
14 | paramTagValues: #ask a user to specify some values for tags
15 | Description: 'Comma-delimited list of tag values'
16 | Type: CommaDelimitedList
17 | Default: 'JonSnow, DaenerysTargaryen, AryaStark'
18 |
19 | ## =================== MAPPINGS ===================
20 | Mappings: # map image ids with regions
21 | mapRegion:
22 | us-east-1:
23 | AMI: ami-1853ac65
24 | us-west-1:
25 | AMI: ami-bf5540df
26 | eu-west-1:
27 | AMI: ami-3bfab942
28 | ap-southeast-1:
29 | AMI: ami-e2adf99e
30 | ap-southeast-2:
31 | AMI: ami-43874721
32 |
33 | ## =================== CONDITIONS ===================
34 | Conditions:
35 | isProd: !Equals [!Ref paramEnvironmentType, prod] # if 'prod' then TRUE, otherwise FALSE
36 | isDev: !Equals [!Ref paramEnvironmentType, dev] # if 'dev' then TRUE, otherwise FALSE
37 |
38 | ## =================== RESOURCES ===================
39 | Resources:
40 | myEC2Instance: # create a new EC2 instance
41 | Type: 'AWS::EC2::Instance'
42 | Properties:
43 | ImageId: !FindInMap # define imageId based on region
44 | - mapRegion # map's name
45 | - !Ref 'AWS::Region' # top level key which is a region where a new instance is being created
46 | - AMI # second level key - e.g. for 'us-east-1' the value for ImageId is 'ami-0ff8a91507f77f867'
47 | InstanceType: !If [isProd, t2.micro, !If [isDev, t2.nano, t1.micro] ] # if 'prod', then t2.micro, (else) if 'dev' then t2.nano otherwise (if 'qa') then t1.micro
48 | Tags:
49 | - Key: CloudFormationLab
50 | Value: !Join [' ', ['EC2 Instance for', !Ref AWS::Region] ]
51 |
52 | myVolume: # create a new EBS volume only if environment is 'prod'
53 | Type: 'AWS::EC2::Volume'
54 | Condition: isProd # conditionally create EBS volume (only if environment is 'prod')
55 | Properties:
56 | Size: 100 # 100 GiB
57 | AvailabilityZone: !GetAtt myEC2Instance.AvailabilityZone # get AZ of a new EC2 instance
58 | Tags:
59 | - Key: CloudFormationLab
60 | Value: !Select [ 0, !Ref paramTagValues ] # output is 'JonSnow'
61 |
62 | myMountPoint: # attach an Amazon EBS volume to an EC2 instance only i environment is 'prod'
63 | Type: 'AWS::EC2::VolumeAttachment'
64 | Condition: isProd # conditionally attach EBS volume (only if environment is 'prod')
65 | Properties:
66 | InstanceId: !Ref myEC2Instance # ref to a new EC2 instance
67 | VolumeId: !Ref myVolume # ref to a new EBS volume
68 | Device: /dev/sdh
--------------------------------------------------------------------------------
/CICD-for-CFN/1-source-code/cfn-vpc-app/buildspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | environment_variables:
4 | plaintext:
5 | TEMPLATE_FILES: |
6 | vpc.yml
7 | CONFIG_FILES: |
8 | vpc-config.json
9 | #https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#runtime-versions-buildspec-file
10 | phases:
11 | install:
12 | runtime-versions:
13 | nodejs: 12
14 | commands:
15 | npm install jsonlint -g
16 | pre_build:
17 | commands:
18 | - echo "Validating CFN templates"
19 | - |
20 | for cfn_template in $TEMPLATE_FILES; do
21 | echo "Validating CloudFormation template file $cfn_template"
22 | aws cloudformation validate-template --template-body file://$cfn_template
23 | done
24 | - |
25 | for conf in $CONFIG_FILES; do
26 | echo "Validating CFN parameters config file $conf"
27 | jsonlint -q $conf
28 | done
29 | build:
30 | commands:
31 | - echo "do nothing"
32 | artifacts:
33 | files:
34 | - vpc.yml
35 | - vpc-config.json
--------------------------------------------------------------------------------
/CICD-for-CFN/1-source-code/cfn-vpc-app/vpc-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "Parameters" : {
3 | "paramVpcCIDR" : "10.192.0.0/16",
4 | "paramPublicSubnet1CIDR" : "10.192.10.0/24"
5 | }
6 | }
--------------------------------------------------------------------------------
/CICD-for-CFN/1-source-code/cfn-vpc-app/vpc.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation sample template.
6 | Create a custom VPC with a public subnet
7 |
8 | ## =================== PARAMETERS =================== ##
9 | Parameters:
10 | paramVpcCIDR:
11 | Description: Enter the IP range (CIDR notation) for VPC
12 | Type: String
13 | paramPublicSubnet1CIDR:
14 | Description: Enter the IP range (CIDR notation) for the public subnet in AZ 1
15 | Type: String
16 | # paramPublicSubnet2CIDR:
17 | # Description: Enter the IP range (CIDR notation) for the public subnet in AZ 2
18 | # Type: String
19 |
20 | ## =================== RESOURCES ===================
21 | Resources:
22 |
23 | myVPC: # Create a VPC
24 | Type: AWS::EC2::VPC
25 | Properties:
26 | CidrBlock: !Ref paramVpcCIDR
27 | EnableDnsSupport: true
28 | EnableDnsHostnames: true
29 | Tags:
30 | - Key: Name
31 | Value: !Sub '${AWS::StackName}-myVPC'
32 |
33 | myInternetGateway: # Create a Internet Gateway
34 | Type: AWS::EC2::InternetGateway
35 |
36 | myVPCGatewayAttachment: # Attach the Internet Gateway to the VPC
37 | Type: AWS::EC2::VPCGatewayAttachment
38 | Properties:
39 | VpcId: !Ref myVPC
40 | InternetGatewayId: !Ref myInternetGateway
41 |
42 | myPublicRouteTable: # Create a public route table for the VPC (will be public once it is associated with the Internet Gateway)
43 | Type: AWS::EC2::RouteTable
44 | Properties:
45 | VpcId: !Ref myVPC
46 |
47 | myPublicRoute: # Associate the public route table with the Internet Gateway
48 | Type: AWS::EC2::Route
49 | DependsOn: myVPCGatewayAttachment
50 | Properties:
51 | RouteTableId: !Ref myPublicRouteTable
52 | DestinationCidrBlock: 0.0.0.0/0
53 | GatewayId: !Ref myInternetGateway
54 |
55 | myPublicSubnet1: # Create a public subnet in AZ 1 (will be public once it is associated with public route table)
56 | Type: AWS::EC2::Subnet
57 | Properties:
58 | VpcId: !Ref myVPC
59 | AvailabilityZone: !Select [ 0, !GetAZs '' ] # AZ 1
60 | CidrBlock: !Ref paramPublicSubnet1CIDR
61 | MapPublicIpOnLaunch: true
62 | Tags:
63 | - Key: Name
64 | Value: !Sub '${AWS::StackName}-myPublicSubnet1'
65 |
66 | # myPublicSubnet2: # Create a public subnet in AZ 2 (will be public once it is associated with public route table)
67 | # Type: AWS::EC2::Subnet
68 | # Properties:
69 | # VpcId: !Ref myVPC
70 | # AvailabilityZone: !Select [ 1, !GetAZs '' ] # AZ 2
71 | # CidrBlock: !Ref paramPublicSubnet2CIDR
72 | # MapPublicIpOnLaunch: true
73 | # Tags:
74 | # - Key: Name
75 | # Value: !Sub '${AWS::StackName}-myPublicSubnet2'
76 |
77 | myPublicSubnet1RouteTableAssociation: # Associate the public route table with the public subnet in AZ 1
78 | Type: AWS::EC2::SubnetRouteTableAssociation
79 | Properties:
80 | RouteTableId: !Ref myPublicRouteTable
81 | SubnetId: !Ref myPublicSubnet1
82 |
83 | # myPublicSubnet2RouteTableAssociation: # Associate the public route table with the public subnet in AZ 1
84 | # Type: AWS::EC2::SubnetRouteTableAssociation
85 | # Properties:
86 | # RouteTableId: !Ref myPublicRouteTable
87 | # SubnetId: !Ref myPublicSubnet2
88 |
89 | ## =================== OUTPUTS =================== ##
90 | Outputs:
91 | outputVpcId:
92 | Description: VPC ID
93 | Value: !Ref myVPC
94 | outputPublicSubnet1Id:
95 | Description: Public subnet1 ID
96 | Value: !Ref myPublicSubnet1
97 | # outputPublicSubnet2Id:
98 | # Description: Public subnet2 ID
99 | # Value: !Ref myPublicSubnet2
--------------------------------------------------------------------------------
/CICD-for-CFN/2-codecommit.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION =================== ##
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an empty repository in AWS CodeCommit
8 |
9 | ## =================== PARAMETERS =================== ##
10 | Parameters:
11 | paramRepoName:
12 | Description: Repository name (must be unique across the calling AWS account)
13 | Type: String
14 | MinLength: 1
15 | MaxLength: 100
16 | AllowedPattern: '^[\w\.-]+$'
17 | ConstraintDescription: Repository name is limited to 100 alphanumeric, underscore, dash, and dot
18 | Default: cfn-repo
19 | paramRepoDescription:
20 | Description: Repository description
21 | Type: String
22 | MaxLength: 1000
23 | Default: This repository is for cfn-vpc-app (to store Cloudformation templates and apply in CI/CD)
24 | ConstraintDescription: Repository desciption is limited to 1000 alphanumeric, underscore, dash, and dot
25 |
26 | ## =================== RESOURCES =================== ##
27 | Resources:
28 | myRepo: # a new repository
29 | Type: 'AWS::CodeCommit::Repository'
30 | Properties:
31 | RepositoryName: !Ref paramRepoName # (required)
32 | RepositoryDescription: !Ref paramRepoDescription
33 |
34 | ## =================== OUTPUT =================== ##
35 | Outputs:
36 | outputName:
37 | Description: Repository's name
38 | Value: !GetAtt myRepo.Name
39 | outputArn:
40 | Description: Repository's ARN
41 | Value: !GetAtt myRepo.Arn
42 | outputCloneUrlHttp:
43 | Description: Repository's URL to use for cloning the repository over HTTPS
44 | Value: !GetAtt myRepo.CloneUrlHttp
45 | outputCloneUrlSsh:
46 | Description: Repository's URL to use for cloning the repository over SSH
47 | Value: !GetAtt myRepo.CloneUrlSsh
--------------------------------------------------------------------------------
/CICD-for-CFN/3-codebuild.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION =================== ##
5 | Description: >-
6 | AWS CloudFormation sample template
7 | 1. Create an S3 bucket for storing CodeBuild artifacts
8 | 2. Create CodeBuild project that gets source code from CodeCommit repo and stores the built artifacts in S3 bucket
9 | 3. Create a new role for CodeBuild to access CloudFormation, CodeCommit, S3, CloudWatch logs, etc
10 |
11 | ## =================== PARAMETERS =================== ##
12 | Parameters:
13 | paramCodeCommitRepoName:
14 | Type: String
15 | Description: Repository name that contains initial source code
16 | Default: cfn-repo
17 |
18 | ## =================== RESOURCES =================== ##
19 | Resources:
20 |
21 | # Create an S3 bucket for storing CodeBuild artifacts
22 | myS3BucketForCodeBuildArtifacts:
23 | Type: AWS::S3::Bucket
24 | Properties:
25 | AccessControl: PublicRead
26 | BucketName: !Sub artifacts-s3bucket-for-${paramCodeCommitRepoName}
27 | VersioningConfiguration:
28 | Status: Enabled
29 |
30 | # Create CodeBuild project that gets source code from CodeCommit repo and stores the built artifacts in S3 bucket
31 | myCodeBuildProject:
32 | Type: AWS::CodeBuild::Project
33 | Properties:
34 | Name: !Sub my-codebuild-project-${AWS::StackName}
35 | Description: CodeBuild for CFN-WPC-APP project
36 | ServiceRole: !GetAtt myCodeBuildRole.Arn
37 | Source: # get source code from CodeCommit repo
38 | Location: !Sub 'https://git-codecommit.${AWS::AccountId}.amazonaws.com/v1/repos/${paramCodeCommitRepoName}'
39 | Type: CODECOMMIT
40 | Artifacts:
41 | Type: S3
42 | Name: !Sub codebuild-artifacts-${AWS::StackName}
43 | Location: !Ref myS3BucketForCodeBuildArtifacts
44 | Environment:
45 | Type: LINUX_CONTAINER
46 | ComputeType: BUILD_GENERAL1_SMALL
47 | Image: aws/codebuild/standard:4.0 # original is 2.0
48 | EnvironmentVariables:
49 | - Name: TEMPLATE_BUCKET
50 | Value: !Ref myS3BucketForCodeBuildArtifacts
51 | - Name: TEMPLATE_PREFIX
52 | Value: codebuild
53 | TimeoutInMinutes: 15
54 | Tags:
55 | - Key: Name
56 | Value: !Sub my-codebuild-project-${AWS::StackName}
57 |
58 | # Create a new role for CodeBuild to access CloudFormation, CodeCommit, S3, CloudWatch logs, etc
59 | myCodeBuildRole:
60 | Type: AWS::IAM::Role
61 | Properties:
62 | RoleName: !Sub my-codebuild-role-${AWS::StackName}
63 | AssumeRolePolicyDocument:
64 | Version: '2012-10-17'
65 | Statement:
66 | - Action:
67 | - 'sts:AssumeRole'
68 | Effect: Allow
69 | Principal:
70 | Service:
71 | - codebuild.amazonaws.com
72 | Path: /
73 | Policies:
74 | - PolicyName: CodeBuildAccessPolicy
75 | PolicyDocument:
76 | Version: '2012-10-17'
77 | Statement:
78 | - Effect: 'Allow'
79 | Action:
80 | - 'cloudformation:Get*'
81 | - 'cloudformation:Describe*'
82 | - 'cloudformation:List*'
83 | Resource: '*'
84 | - Effect: 'Allow'
85 | Action:
86 | - 'codecommit:ListBranches'
87 | - 'codecommit:ListRepositories'
88 | - 'codecommit:BatchGetRepositories'
89 | - 'codecommit:Get*'
90 | - 'codecommit:GitPull'
91 | Resource:
92 | - Fn::Sub: arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${paramCodeCommitRepoName}
93 | - Effect: 'Allow'
94 | Action:
95 | - 'ec2:Describe*'
96 | - 'cloudformation:ValidateTemplate'
97 | - 'elasticloadbalancing:Describe*'
98 | - 'autoscaling:Describe*'
99 | - 'iam:Get*'
100 | - 'iam:List*'
101 | - 'logs:Describe*'
102 | - 'logs:Get*'
103 | - 'tag:Get*'
104 | Resource:
105 | - '*'
106 | - Effect: 'Allow'
107 | Action:
108 | - 'logs:CreateLogGroup'
109 | - 'logs:CreateLogStream'
110 | - 'logs:PutLogEvents'
111 | Resource:
112 | - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*
113 | - Effect: 'Allow'
114 | Action:
115 | - 's3:PutObject'
116 | - 's3:GetObject'
117 | - 's3:GetObjectVersion'
118 | - 's3:ListBucket'
119 | Resource:
120 | - Fn::Sub: arn:aws:s3:::codepipeline-${AWS::Region}-*
121 | - Fn::Sub: arn:aws:s3:::${myS3BucketForCodeBuildArtifacts}/*
122 | - Fn::Sub: arn:aws:s3:::${myS3BucketForCodeBuildArtifacts}
123 |
124 | ## =================== OUTPUT =================== ##
125 | Outputs:
126 | outputCodeBuildProjectName:
127 | Description: CodeBuild project name
128 | Value: !Ref myCodeBuildProject
129 | outputCodeBuildProjectArn:
130 | Description: CodeBuild project ARN
131 | Value: !GetAtt myCodeBuildProject.Arn
--------------------------------------------------------------------------------
/CICD/1-code-commit.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION =================== ##
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an empty repository in AWS CodeCommit
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codecommit-repository.html
9 |
10 | ## =================== PARAMETERS =================== ##
11 | Parameters:
12 | paramRepoName:
13 | Description: A new repository name which must be unique across the calling AWS account (required)
14 | Type: String
15 | MinLength: 1
16 | MaxLength: 100
17 | AllowedPattern: '^[\w\.-]+$'
18 | ConstraintDescription: Repository name is limited to 100 alphanumeric, underscore, dash, and dot
19 | Default: CICDRepo
20 | paramRepoDescription:
21 | Description: Describe a new repository
22 | Type: String
23 | MaxLength: 1000
24 | AllowedPattern: '^[\w \.-]+$'
25 | Default: This repository is for CICD project
26 | ConstraintDescription: Repository desciption is limited to 1000 alphanumeric, underscore, dash, and dot
27 |
28 | ## =================== RESOURCES =================== ##
29 | Resources:
30 | myRepo: # a new repository
31 | Type: 'AWS::CodeCommit::Repository'
32 | Properties:
33 | RepositoryName: !Ref paramRepoName # (required)
34 | RepositoryDescription: !Ref paramRepoDescription
35 |
36 | ## =================== OUTPUT =================== ##
37 | Outputs:
38 | outputName:
39 | Description: Repository's name
40 | Value: !GetAtt myRepo.Name
41 | outputArn:
42 | Description: Repository's ARN
43 | Value: !GetAtt myRepo.Arn
44 | outputCloneUrlHttp:
45 | Description: Repository's URL to use for cloning the repository over HTTPS
46 | Value: !GetAtt myRepo.CloneUrlHttp
47 | outputCloneUrlSsh:
48 | Description: Repository's URL to use for cloning the repository over SSH
49 | Value: !GetAtt myRepo.CloneUrlSsh
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.*~
3 | project.lock.json
4 | .DS_Store
5 | *.pyc
6 | nupkg/
7 |
8 | # Visual Studio Code
9 | .vscode
10 |
11 | # Rider
12 | .idea
13 |
14 | # User-specific files
15 | *.suo
16 | *.user
17 | *.userosscache
18 | *.sln.docstates
19 |
20 | # Build results
21 | [Dd]ebug/
22 | [Dd]ebugPublic/
23 | [Rr]elease/
24 | [Rr]eleases/
25 | x64/
26 | x86/
27 | build/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Oo]ut/
32 | msbuild.log
33 | msbuild.err
34 | msbuild.wrn
35 |
36 | # Visual Studio 2015
37 | .vs/
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Error.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ErrorModel
3 | @{
4 | ViewData["Title"] = "Error";
5 | }
6 |
7 |
Error.
8 | An error occurred while processing your request.
9 |
10 | @if (Model.ShowRequestId)
11 | {
12 |
13 | Request ID: @Model.RequestId
14 |
15 | }
16 |
17 | Development Mode
18 |
19 | Swapping to the Development environment displays detailed information about the error that occurred.
20 |
21 |
22 | The Development environment shouldn't be enabled for deployed applications.
23 | It can result in displaying sensitive information from exceptions to end users.
24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
25 | and restarting the app.
26 |
27 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace cicd_dotnet_webapp.Pages
11 | {
12 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
13 | [IgnoreAntiforgeryToken]
14 | public class ErrorModel : PageModel
15 | {
16 | public string RequestId { get; set; }
17 |
18 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
19 |
20 | private readonly ILogger _logger;
21 |
22 | public ErrorModel(ILogger logger)
23 | {
24 | _logger = logger;
25 | }
26 |
27 | public void OnGet()
28 | {
29 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Index.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model IndexModel
3 | @{
4 | ViewData["Title"] = "Home page";
5 | }
6 |
7 |
8 |
Greetings, everyone!
9 |
Learn about building Web apps with ASP.NET Core .
10 |
Top fiction books
11 |
1. The Master and Margarita
12 |
2. Hard to Be a God
13 |
3. Nineteen Eighty-Four
14 |
4. Brave New World
15 |
5. Flowers for Algernon
16 |
6. Dune
17 |
7. A Song of Ice and Fire
18 |
8. Animal Farm
19 |
20 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Index.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.AspNetCore.Mvc.RazorPages;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace cicd_dotnet_webapp.Pages
10 | {
11 | public class IndexModel : PageModel
12 | {
13 | private readonly ILogger _logger;
14 |
15 | public IndexModel(ILogger logger)
16 | {
17 | _logger = logger;
18 | }
19 |
20 | public void OnGet()
21 | {
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Privacy.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model PrivacyModel
3 | @{
4 | ViewData["Title"] = "Privacy Policy";
5 | }
6 | @ViewData["Title"]
7 |
8 | Use this page to detail your site's privacy policy.
9 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Privacy.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.AspNetCore.Mvc.RazorPages;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace cicd_dotnet_webapp.Pages
10 | {
11 | public class PrivacyModel : PageModel
12 | {
13 | private readonly ILogger _logger;
14 |
15 | public PrivacyModel(ILogger logger)
16 | {
17 | _logger = logger;
18 | }
19 |
20 | public void OnGet()
21 | {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - cicd_dotnet_webapp
7 |
8 |
9 |
10 |
11 |
32 |
33 |
34 | @RenderBody()
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
47 |
48 | @await RenderSectionAsync("Scripts", required: false)
49 |
50 |
51 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using cicd_dotnet_webapp
2 | @namespace cicd_dotnet_webapp.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Pages/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 | using System.Net;
10 |
11 | namespace cicd_dotnet_webapp
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IHostBuilder CreateHostBuilder(string[] args) =>
21 | Host.CreateDefaultBuilder(args)
22 | .ConfigureWebHostDefaults(webBuilder =>
23 | {
24 | webBuilder.UseKestrel(options => { options.Listen(IPAddress.Any, 80); });
25 | webBuilder.UseStartup();
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:7038",
7 | "sslPort": 44346
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "cicd_dotnet_webapp": {
19 | "commandName": "Project",
20 | "dotnetRunMessages": "true",
21 | "launchBrowser": true,
22 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/README.md:
--------------------------------------------------------------------------------
1 | # Create a new application and push it into CodeCommit repo
2 |
3 | ## 1. Create a new .NET Core application:
4 | Run the following command to create a template:
5 | ```dotnet new webapp -o cicd-dotnet-webapp```
6 |
7 | ## 2. Run it locally
8 | ```
9 | cd cicd-dotnet-webapp
10 | dotnet run
11 | ```
12 | navigate to https://localhost:5001
13 |
14 | ## 3. Change port to 80
15 | Go to Program.cs and add the following code into CreateHostBuilder() method:
16 | ``` webBuilder.UseKestrel(options => { options.Listen(IPAddress.Any, 80); }); ```
17 | navigate to http://localhost
18 |
19 |
20 | # ----------------------------------------------------------------------------------------
21 | # Push the source code to CodeCommit repo
22 |
23 | ## 1. Add a new git local repository:
24 | ```
25 | cd cicd-dotnet-webapp
26 | git init
27 | ```
28 |
29 | ## 2. Add gitignore file
30 | a) create a '.gitignore' file inside 'cicd-dotnet-webapp' folder
31 | b) copy and add the following list from https://github.com/dotnet/core/blob/master/.gitignore
32 |
33 | ## 3. Stage and commit the source code
34 | ```
35 | git add .
36 | git commit -m"First commit"
37 | ```
38 |
39 | ## 4. Push source code to remote CodeCommit repo
40 | Use outputCloneUrlHttp after creating a stack from '1-code-commit' template
41 | ```
42 | git push {outputCloneUrlHttp} --all
43 | ```
44 |
45 | # ----------------------------------------------------------------------------------------
46 | # Added the following files:
47 | - .gitignore
48 | - buildspec.yml (for CodeBuild)
49 | - appspec.yml (for CodeDeploy)
50 | - codedeploy-scripts and 4 sh files
51 | Don't forget to stage, commit and push
52 |
53 | # Notes:
54 | 1. How can I run a dotnet application in the background using sudo on Linux?
55 | So if you run ```cd ../home/ec2-user/cicd-dotnet-webapp && sudo dotnet cicd-dotnet-webapp.dll``` in EC2 instance, then the code will run till you are SHHed to the instance. Once you close your EC2 intance connection, the app will be stoped. Use ```screen -d -m -S SERVER bash -c 'cd ../home/ec2-user/cicd-dotnet-webapp && sudo dotnet cicd-dotnet-webapp.dll'``` instead.
56 | Read:
57 | https://stackoverflow.com/questions/49479635/how-can-i-run-a-dotnet-application-in-the-background-using-sudo-on-linux
58 |
59 |
60 | 2. Issue - CodeBuild does NOT support .NET 5.0
61 | AWS Codebuild: Unknown runtime version named '5.0' of dotnet
62 | The latest supported version by AWS CodeBuild is dotnet 3.1
63 | Read:
64 | - AWS Codebuild: Unknown runtime version named '5.0' of dotnet
65 | https://stackoverflow.com/questions/65546757/aws-codebuild-unknown-runtime-version-named-5-0-of-dotnet
66 | - .NET 5 Release - runtime support
67 | https://github.com/aws/aws-codebuild-docker-images/issues/401
68 |
69 | # Useful Links
70 | - .NET docs: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.HttpsPolicy;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 | using Microsoft.Extensions.Hosting;
11 |
12 | namespace cicd_dotnet_webapp
13 | {
14 | public class Startup
15 | {
16 | public Startup(IConfiguration configuration)
17 | {
18 | Configuration = configuration;
19 | }
20 |
21 | public IConfiguration Configuration { get; }
22 |
23 | // This method gets called by the runtime. Use this method to add services to the container.
24 | public void ConfigureServices(IServiceCollection services)
25 | {
26 | services.AddRazorPages();
27 | }
28 |
29 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
30 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
31 | {
32 | if (env.IsDevelopment())
33 | {
34 | app.UseDeveloperExceptionPage();
35 | }
36 | else
37 | {
38 | app.UseExceptionHandler("/Error");
39 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
40 | app.UseHsts();
41 | }
42 |
43 | app.UseHttpsRedirection();
44 | app.UseStaticFiles();
45 |
46 | app.UseRouting();
47 |
48 | app.UseAuthorization();
49 |
50 | app.UseEndpoints(endpoints =>
51 | {
52 | endpoints.MapRazorPages();
53 | });
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "DetailedErrors": true,
3 | "Logging": {
4 | "LogLevel": {
5 | "Default": "Information",
6 | "Microsoft": "Warning",
7 | "Microsoft.Hosting.Lifetime": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/appspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.0
2 | os: linux
3 | files:
4 | - source: /cicd-dotnet-webapp
5 | destination: /home/ec2-user/cicd-dotnet-webapp # /var/www/html/DotNetWebApp
6 | hooks:
7 | BeforeInstall:
8 | # - location: codedeploy-scripts/before-install.sh
9 | # timeout: 300
10 | # runas: root
11 | AfterInstall:
12 | # - location: codedeploy-scripts/after-install.sh
13 | # timeout: 300
14 | # runas: root
15 | ApplicationStart:
16 | - location: codedeploy-scripts/application-start.sh
17 | timeout: 300
18 | runas: root
19 | ApplicationStop:
20 | # - location: codedeploy-scripts/application-stop.sh
21 | # timeout: 300
22 | # runas: root
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/buildspec.yml:
--------------------------------------------------------------------------------
1 | #Based on https://github.com/PrakashTrove/AWS-CodeBuild-NetCore/blob/master/buildspec.yml
2 | version: 0.2
3 | phases:
4 | install:
5 | commands:
6 | - echo Nothing to do in the install phase...
7 | pre_build:
8 | commands:
9 | - echo Restore started on `date`
10 | - dotnet restore cicd-dotnet-webapp.csproj
11 | build:
12 | commands:
13 | - echo Build started on `date`
14 | # - dotnet publish -c release -o ./cicd-dotnet-webapp cicd-dotnet-webapp.csproj
15 | # commented because CodeBuild doesn't support .NET 5 yet
16 | post_build:
17 | commands:
18 | - echo Build completed on `date`
19 | artifacts:
20 | files:
21 | - ./**/* # get all files and folders and build them all
22 | # - 'appspec.yml'
23 | # # - codedeploy-scripts/**/*
24 | # - codedeploy-scripts/before-install.sh
25 | # - codedeploy-scripts/after-install.sh
26 | # - codedeploy-scripts/application-start.sh
27 | # - codedeploy-scripts/application-stop.sh
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | cicd_dotnet_webapp
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "DetailedErrors": true,
3 | "Logging": {
4 | "LogLevel": {
5 | "Default": "Information",
6 | "Microsoft": "Warning",
7 | "Microsoft.Hosting.Lifetime": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.Views.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.Views.dll
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.Views.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.Views.pdb
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.dll
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.exe
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.pdb
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/cicd-dotnet-webapp.runtimeconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "runtimeOptions": {
3 | "tfm": "net5.0",
4 | "framework": {
5 | "name": "Microsoft.AspNetCore.App",
6 | "version": "5.0.0"
7 | },
8 | "configProperties": {
9 | "System.GC.Server": true,
10 | "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | /* Provide sufficient contrast against white background */
11 | a {
12 | color: #0366d6;
13 | }
14 |
15 | .btn-primary {
16 | color: #fff;
17 | background-color: #1b6ec2;
18 | border-color: #1861ac;
19 | }
20 |
21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
22 | color: #fff;
23 | background-color: #1b6ec2;
24 | border-color: #1861ac;
25 | }
26 |
27 | /* Sticky footer styles
28 | -------------------------------------------------- */
29 | html {
30 | font-size: 14px;
31 | }
32 | @media (min-width: 768px) {
33 | html {
34 | font-size: 16px;
35 | }
36 | }
37 |
38 | .border-top {
39 | border-top: 1px solid #e5e5e5;
40 | }
41 | .border-bottom {
42 | border-bottom: 1px solid #e5e5e5;
43 | }
44 |
45 | .box-shadow {
46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
47 | }
48 |
49 | button.accept-policy {
50 | font-size: 1rem;
51 | line-height: inherit;
52 | }
53 |
54 | /* Sticky footer styles
55 | -------------------------------------------------- */
56 | html {
57 | position: relative;
58 | min-height: 100%;
59 | }
60 |
61 | body {
62 | /* Margin bottom by footer height */
63 | margin-bottom: 60px;
64 | }
65 | .footer {
66 | position: absolute;
67 | bottom: 0;
68 | width: 100%;
69 | white-space: nowrap;
70 | line-height: 60px; /* Vertically center the text there */
71 | }
72 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your JavaScript code.
5 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2018 Twitter, Inc.
4 | Copyright (c) 2011-2018 The Bootstrap Authors
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | html {
15 | font-family: sans-serif;
16 | line-height: 1.15;
17 | -webkit-text-size-adjust: 100%;
18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
19 | }
20 |
21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
22 | display: block;
23 | }
24 |
25 | body {
26 | margin: 0;
27 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
28 | font-size: 1rem;
29 | font-weight: 400;
30 | line-height: 1.5;
31 | color: #212529;
32 | text-align: left;
33 | background-color: #fff;
34 | }
35 |
36 | [tabindex="-1"]:focus {
37 | outline: 0 !important;
38 | }
39 |
40 | hr {
41 | box-sizing: content-box;
42 | height: 0;
43 | overflow: visible;
44 | }
45 |
46 | h1, h2, h3, h4, h5, h6 {
47 | margin-top: 0;
48 | margin-bottom: 0.5rem;
49 | }
50 |
51 | p {
52 | margin-top: 0;
53 | margin-bottom: 1rem;
54 | }
55 |
56 | abbr[title],
57 | abbr[data-original-title] {
58 | text-decoration: underline;
59 | -webkit-text-decoration: underline dotted;
60 | text-decoration: underline dotted;
61 | cursor: help;
62 | border-bottom: 0;
63 | -webkit-text-decoration-skip-ink: none;
64 | text-decoration-skip-ink: none;
65 | }
66 |
67 | address {
68 | margin-bottom: 1rem;
69 | font-style: normal;
70 | line-height: inherit;
71 | }
72 |
73 | ol,
74 | ul,
75 | dl {
76 | margin-top: 0;
77 | margin-bottom: 1rem;
78 | }
79 |
80 | ol ol,
81 | ul ul,
82 | ol ul,
83 | ul ol {
84 | margin-bottom: 0;
85 | }
86 |
87 | dt {
88 | font-weight: 700;
89 | }
90 |
91 | dd {
92 | margin-bottom: .5rem;
93 | margin-left: 0;
94 | }
95 |
96 | blockquote {
97 | margin: 0 0 1rem;
98 | }
99 |
100 | b,
101 | strong {
102 | font-weight: bolder;
103 | }
104 |
105 | small {
106 | font-size: 80%;
107 | }
108 |
109 | sub,
110 | sup {
111 | position: relative;
112 | font-size: 75%;
113 | line-height: 0;
114 | vertical-align: baseline;
115 | }
116 |
117 | sub {
118 | bottom: -.25em;
119 | }
120 |
121 | sup {
122 | top: -.5em;
123 | }
124 |
125 | a {
126 | color: #007bff;
127 | text-decoration: none;
128 | background-color: transparent;
129 | }
130 |
131 | a:hover {
132 | color: #0056b3;
133 | text-decoration: underline;
134 | }
135 |
136 | a:not([href]):not([tabindex]) {
137 | color: inherit;
138 | text-decoration: none;
139 | }
140 |
141 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
142 | color: inherit;
143 | text-decoration: none;
144 | }
145 |
146 | a:not([href]):not([tabindex]):focus {
147 | outline: 0;
148 | }
149 |
150 | pre,
151 | code,
152 | kbd,
153 | samp {
154 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
155 | font-size: 1em;
156 | }
157 |
158 | pre {
159 | margin-top: 0;
160 | margin-bottom: 1rem;
161 | overflow: auto;
162 | }
163 |
164 | figure {
165 | margin: 0 0 1rem;
166 | }
167 |
168 | img {
169 | vertical-align: middle;
170 | border-style: none;
171 | }
172 |
173 | svg {
174 | overflow: hidden;
175 | vertical-align: middle;
176 | }
177 |
178 | table {
179 | border-collapse: collapse;
180 | }
181 |
182 | caption {
183 | padding-top: 0.75rem;
184 | padding-bottom: 0.75rem;
185 | color: #6c757d;
186 | text-align: left;
187 | caption-side: bottom;
188 | }
189 |
190 | th {
191 | text-align: inherit;
192 | }
193 |
194 | label {
195 | display: inline-block;
196 | margin-bottom: 0.5rem;
197 | }
198 |
199 | button {
200 | border-radius: 0;
201 | }
202 |
203 | button:focus {
204 | outline: 1px dotted;
205 | outline: 5px auto -webkit-focus-ring-color;
206 | }
207 |
208 | input,
209 | button,
210 | select,
211 | optgroup,
212 | textarea {
213 | margin: 0;
214 | font-family: inherit;
215 | font-size: inherit;
216 | line-height: inherit;
217 | }
218 |
219 | button,
220 | input {
221 | overflow: visible;
222 | }
223 |
224 | button,
225 | select {
226 | text-transform: none;
227 | }
228 |
229 | select {
230 | word-wrap: normal;
231 | }
232 |
233 | button,
234 | [type="button"],
235 | [type="reset"],
236 | [type="submit"] {
237 | -webkit-appearance: button;
238 | }
239 |
240 | button:not(:disabled),
241 | [type="button"]:not(:disabled),
242 | [type="reset"]:not(:disabled),
243 | [type="submit"]:not(:disabled) {
244 | cursor: pointer;
245 | }
246 |
247 | button::-moz-focus-inner,
248 | [type="button"]::-moz-focus-inner,
249 | [type="reset"]::-moz-focus-inner,
250 | [type="submit"]::-moz-focus-inner {
251 | padding: 0;
252 | border-style: none;
253 | }
254 |
255 | input[type="radio"],
256 | input[type="checkbox"] {
257 | box-sizing: border-box;
258 | padding: 0;
259 | }
260 |
261 | input[type="date"],
262 | input[type="time"],
263 | input[type="datetime-local"],
264 | input[type="month"] {
265 | -webkit-appearance: listbox;
266 | }
267 |
268 | textarea {
269 | overflow: auto;
270 | resize: vertical;
271 | }
272 |
273 | fieldset {
274 | min-width: 0;
275 | padding: 0;
276 | margin: 0;
277 | border: 0;
278 | }
279 |
280 | legend {
281 | display: block;
282 | width: 100%;
283 | max-width: 100%;
284 | padding: 0;
285 | margin-bottom: .5rem;
286 | font-size: 1.5rem;
287 | line-height: inherit;
288 | color: inherit;
289 | white-space: normal;
290 | }
291 |
292 | progress {
293 | vertical-align: baseline;
294 | }
295 |
296 | [type="number"]::-webkit-inner-spin-button,
297 | [type="number"]::-webkit-outer-spin-button {
298 | height: auto;
299 | }
300 |
301 | [type="search"] {
302 | outline-offset: -2px;
303 | -webkit-appearance: none;
304 | }
305 |
306 | [type="search"]::-webkit-search-decoration {
307 | -webkit-appearance: none;
308 | }
309 |
310 | ::-webkit-file-upload-button {
311 | font: inherit;
312 | -webkit-appearance: button;
313 | }
314 |
315 | output {
316 | display: inline-block;
317 | }
318 |
319 | summary {
320 | display: list-item;
321 | cursor: pointer;
322 | }
323 |
324 | template {
325 | display: none;
326 | }
327 |
328 | [hidden] {
329 | display: none !important;
330 | }
331 | /*# sourceMappingURL=bootstrap-reboot.css.map */
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) .NET Foundation. All rights reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | these files except in compliance with the License. You may obtain a copy of the
5 | License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software distributed
10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the
12 | specific language governing permissions and limitations under the License.
13 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | // Unobtrusive validation support library for jQuery and jQuery Validate
2 | // Copyright (c) .NET Foundation. All rights reserved.
3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
4 | // @version v3.2.11
5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a(" ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive});
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/cicd-dotnet-webapp/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors, https://js.foundation/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/codedeploy-scripts/after-install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/codedeploy-scripts/application-start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | sudo kill $(ps aux | grep 'cicd-dotnet-webapp.dll' | awk '{print $2}')
3 | screen -d -m -S SERVER bash -c 'cd ../home/ec2-user/cicd-dotnet-webapp && sudo dotnet cicd-dotnet-webapp.dll'
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/codedeploy-scripts/application-stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/codedeploy-scripts/before-install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | /* Provide sufficient contrast against white background */
11 | a {
12 | color: #0366d6;
13 | }
14 |
15 | .btn-primary {
16 | color: #fff;
17 | background-color: #1b6ec2;
18 | border-color: #1861ac;
19 | }
20 |
21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
22 | color: #fff;
23 | background-color: #1b6ec2;
24 | border-color: #1861ac;
25 | }
26 |
27 | /* Sticky footer styles
28 | -------------------------------------------------- */
29 | html {
30 | font-size: 14px;
31 | }
32 | @media (min-width: 768px) {
33 | html {
34 | font-size: 16px;
35 | }
36 | }
37 |
38 | .border-top {
39 | border-top: 1px solid #e5e5e5;
40 | }
41 | .border-bottom {
42 | border-bottom: 1px solid #e5e5e5;
43 | }
44 |
45 | .box-shadow {
46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
47 | }
48 |
49 | button.accept-policy {
50 | font-size: 1rem;
51 | line-height: inherit;
52 | }
53 |
54 | /* Sticky footer styles
55 | -------------------------------------------------- */
56 | html {
57 | position: relative;
58 | min-height: 100%;
59 | }
60 |
61 | body {
62 | /* Margin bottom by footer height */
63 | margin-bottom: 60px;
64 | }
65 | .footer {
66 | position: absolute;
67 | bottom: 0;
68 | width: 100%;
69 | white-space: nowrap;
70 | line-height: 60px; /* Vertically center the text there */
71 | }
72 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your JavaScript code.
5 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2018 Twitter, Inc.
4 | Copyright (c) 2011-2018 The Bootstrap Authors
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | html {
15 | font-family: sans-serif;
16 | line-height: 1.15;
17 | -webkit-text-size-adjust: 100%;
18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
19 | }
20 |
21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
22 | display: block;
23 | }
24 |
25 | body {
26 | margin: 0;
27 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
28 | font-size: 1rem;
29 | font-weight: 400;
30 | line-height: 1.5;
31 | color: #212529;
32 | text-align: left;
33 | background-color: #fff;
34 | }
35 |
36 | [tabindex="-1"]:focus {
37 | outline: 0 !important;
38 | }
39 |
40 | hr {
41 | box-sizing: content-box;
42 | height: 0;
43 | overflow: visible;
44 | }
45 |
46 | h1, h2, h3, h4, h5, h6 {
47 | margin-top: 0;
48 | margin-bottom: 0.5rem;
49 | }
50 |
51 | p {
52 | margin-top: 0;
53 | margin-bottom: 1rem;
54 | }
55 |
56 | abbr[title],
57 | abbr[data-original-title] {
58 | text-decoration: underline;
59 | -webkit-text-decoration: underline dotted;
60 | text-decoration: underline dotted;
61 | cursor: help;
62 | border-bottom: 0;
63 | -webkit-text-decoration-skip-ink: none;
64 | text-decoration-skip-ink: none;
65 | }
66 |
67 | address {
68 | margin-bottom: 1rem;
69 | font-style: normal;
70 | line-height: inherit;
71 | }
72 |
73 | ol,
74 | ul,
75 | dl {
76 | margin-top: 0;
77 | margin-bottom: 1rem;
78 | }
79 |
80 | ol ol,
81 | ul ul,
82 | ol ul,
83 | ul ol {
84 | margin-bottom: 0;
85 | }
86 |
87 | dt {
88 | font-weight: 700;
89 | }
90 |
91 | dd {
92 | margin-bottom: .5rem;
93 | margin-left: 0;
94 | }
95 |
96 | blockquote {
97 | margin: 0 0 1rem;
98 | }
99 |
100 | b,
101 | strong {
102 | font-weight: bolder;
103 | }
104 |
105 | small {
106 | font-size: 80%;
107 | }
108 |
109 | sub,
110 | sup {
111 | position: relative;
112 | font-size: 75%;
113 | line-height: 0;
114 | vertical-align: baseline;
115 | }
116 |
117 | sub {
118 | bottom: -.25em;
119 | }
120 |
121 | sup {
122 | top: -.5em;
123 | }
124 |
125 | a {
126 | color: #007bff;
127 | text-decoration: none;
128 | background-color: transparent;
129 | }
130 |
131 | a:hover {
132 | color: #0056b3;
133 | text-decoration: underline;
134 | }
135 |
136 | a:not([href]):not([tabindex]) {
137 | color: inherit;
138 | text-decoration: none;
139 | }
140 |
141 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
142 | color: inherit;
143 | text-decoration: none;
144 | }
145 |
146 | a:not([href]):not([tabindex]):focus {
147 | outline: 0;
148 | }
149 |
150 | pre,
151 | code,
152 | kbd,
153 | samp {
154 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
155 | font-size: 1em;
156 | }
157 |
158 | pre {
159 | margin-top: 0;
160 | margin-bottom: 1rem;
161 | overflow: auto;
162 | }
163 |
164 | figure {
165 | margin: 0 0 1rem;
166 | }
167 |
168 | img {
169 | vertical-align: middle;
170 | border-style: none;
171 | }
172 |
173 | svg {
174 | overflow: hidden;
175 | vertical-align: middle;
176 | }
177 |
178 | table {
179 | border-collapse: collapse;
180 | }
181 |
182 | caption {
183 | padding-top: 0.75rem;
184 | padding-bottom: 0.75rem;
185 | color: #6c757d;
186 | text-align: left;
187 | caption-side: bottom;
188 | }
189 |
190 | th {
191 | text-align: inherit;
192 | }
193 |
194 | label {
195 | display: inline-block;
196 | margin-bottom: 0.5rem;
197 | }
198 |
199 | button {
200 | border-radius: 0;
201 | }
202 |
203 | button:focus {
204 | outline: 1px dotted;
205 | outline: 5px auto -webkit-focus-ring-color;
206 | }
207 |
208 | input,
209 | button,
210 | select,
211 | optgroup,
212 | textarea {
213 | margin: 0;
214 | font-family: inherit;
215 | font-size: inherit;
216 | line-height: inherit;
217 | }
218 |
219 | button,
220 | input {
221 | overflow: visible;
222 | }
223 |
224 | button,
225 | select {
226 | text-transform: none;
227 | }
228 |
229 | select {
230 | word-wrap: normal;
231 | }
232 |
233 | button,
234 | [type="button"],
235 | [type="reset"],
236 | [type="submit"] {
237 | -webkit-appearance: button;
238 | }
239 |
240 | button:not(:disabled),
241 | [type="button"]:not(:disabled),
242 | [type="reset"]:not(:disabled),
243 | [type="submit"]:not(:disabled) {
244 | cursor: pointer;
245 | }
246 |
247 | button::-moz-focus-inner,
248 | [type="button"]::-moz-focus-inner,
249 | [type="reset"]::-moz-focus-inner,
250 | [type="submit"]::-moz-focus-inner {
251 | padding: 0;
252 | border-style: none;
253 | }
254 |
255 | input[type="radio"],
256 | input[type="checkbox"] {
257 | box-sizing: border-box;
258 | padding: 0;
259 | }
260 |
261 | input[type="date"],
262 | input[type="time"],
263 | input[type="datetime-local"],
264 | input[type="month"] {
265 | -webkit-appearance: listbox;
266 | }
267 |
268 | textarea {
269 | overflow: auto;
270 | resize: vertical;
271 | }
272 |
273 | fieldset {
274 | min-width: 0;
275 | padding: 0;
276 | margin: 0;
277 | border: 0;
278 | }
279 |
280 | legend {
281 | display: block;
282 | width: 100%;
283 | max-width: 100%;
284 | padding: 0;
285 | margin-bottom: .5rem;
286 | font-size: 1.5rem;
287 | line-height: inherit;
288 | color: inherit;
289 | white-space: normal;
290 | }
291 |
292 | progress {
293 | vertical-align: baseline;
294 | }
295 |
296 | [type="number"]::-webkit-inner-spin-button,
297 | [type="number"]::-webkit-outer-spin-button {
298 | height: auto;
299 | }
300 |
301 | [type="search"] {
302 | outline-offset: -2px;
303 | -webkit-appearance: none;
304 | }
305 |
306 | [type="search"]::-webkit-search-decoration {
307 | -webkit-appearance: none;
308 | }
309 |
310 | ::-webkit-file-upload-button {
311 | font: inherit;
312 | -webkit-appearance: button;
313 | }
314 |
315 | output {
316 | display: inline-block;
317 | }
318 |
319 | summary {
320 | display: list-item;
321 | cursor: pointer;
322 | }
323 |
324 | template {
325 | display: none;
326 | }
327 |
328 | [hidden] {
329 | display: none !important;
330 | }
331 | /*# sourceMappingURL=bootstrap-reboot.css.map */
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) .NET Foundation. All rights reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | these files except in compliance with the License. You may obtain a copy of the
5 | License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software distributed
10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the
12 | specific language governing permissions and limitations under the License.
13 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | // Unobtrusive validation support library for jQuery and jQuery Validate
2 | // Copyright (c) .NET Foundation. All rights reserved.
3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
4 | // @version v3.2.11
5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a(" ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive});
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/CICD/2-source-code/cicd-dotnet-webapp/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors, https://js.foundation/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/CICD/3-s3-artifact.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Creates a new S3 bucket to store CodeBuild artifacts
7 |
8 | ## =================== RESOURCES =================== ##
9 | Resources:
10 | myS3Bucket:
11 | Type: AWS::S3::Bucket
12 | Properties:
13 | AccessControl: PublicRead
14 | BucketName: bucket-for-code-build-artifacts
15 | VersioningConfiguration:
16 | Status: Enabled
17 |
18 | ## =================== OUTPUTS =================== ##
19 | Outputs:
20 | outputsS3Bucket:
21 | Value: !Join ['', ['https://', !GetAtt myS3Bucket.DomainName]]
22 | Description: Domain Name of the Amazon S3 bucket
--------------------------------------------------------------------------------
/CICD/4-code-build.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION =================== ##
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create CodeBuild stack that builds the source code and stores built artifacts in S3 bucket
8 |
9 | ## =================== PARAMETERS =================== ##
10 | Parameters:
11 | paramRepoName:
12 | Type: String
13 | Description: Name of the repo which contains Rest Application.
14 | Default: CICDRepo
15 | paramRepoHTTPUrl:
16 | Type: String
17 | Description: CodeCommit repo HTTP URL. Copy and past CodeCommit's outputCloneUrlHttp here
18 | paramArtifactStoreS3Location:
19 | Type: String
20 | Description: S3 bucket name to store CodeBuild artifacts
21 | Default: bucket-for-code-build-artifacts
22 | paramAppName:
23 | Type: String
24 | Description: Specify an application Name
25 | Default: cicd-dotnet-webapp
26 |
27 | ## =================== RESOURCES =================== ##
28 | Resources:
29 |
30 | myCodeBuildProject: #
31 | Type: 'AWS::CodeBuild::Project'
32 | Properties:
33 | Name: myCodeBuildProjectName
34 | Description: CodeBuild for .NET Core WebApi project
35 | ServiceRole: !GetAtt myCodeBuildRole.Arn
36 | Artifacts:
37 | Type: S3
38 | Name: !Ref paramAppName
39 | Location: !Ref paramArtifactStoreS3Location
40 | Packaging: ZIP # need to ZIP for CodeDeploy
41 | Environment:
42 | Type: LINUX_CONTAINER
43 | ComputeType: BUILD_GENERAL1_SMALL
44 | Image: aws/codebuild/standard:4.0
45 | Source: # get source code from CodeCommit repo
46 | Location: !Ref paramRepoHTTPUrl
47 | Type: CODECOMMIT
48 | TimeoutInMinutes: 15
49 |
50 | myCodeBuildRole: # role for CodeBuild
51 | Type: 'AWS::IAM::Role'
52 | Properties:
53 | RoleName: myCodeBuildRoleName
54 | AssumeRolePolicyDocument:
55 | Version: '2012-10-17'
56 | Statement:
57 | - Action:
58 | - 'sts:AssumeRole'
59 | Effect: Allow
60 | Principal:
61 | Service:
62 | - codebuild.amazonaws.com
63 | Path: /
64 | Policies:
65 | - PolicyName: CodeBuildAccessPolicy
66 | PolicyDocument:
67 | Version: '2012-10-17'
68 | Statement:
69 | - Action:
70 | - 'codecommit:GitPull'
71 | Effect: Allow
72 | Resource:
73 | - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${paramRepoName}
74 | - Action:
75 | - 'logs:CreateLogGroup'
76 | - 'logs:CreateLogStream'
77 | - 'logs:PutLogEvents'
78 | Effect: Allow
79 | Resource:
80 | - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*
81 | - Action:
82 | - 's3:PutObject'
83 | - 's3:GetObject'
84 | - 's3:GetObjectVersion'
85 | - 's3:ListBucket'
86 | Effect: Allow
87 | Resource:
88 | - !Sub arn:aws:s3:::codepipeline-${AWS::Region}-*
89 | - !Sub arn:aws:s3:::${paramArtifactStoreS3Location}/*
90 | - !Sub arn:aws:s3:::${paramArtifactStoreS3Location}
91 |
92 | ## =================== OUTPUT =================== ##
93 | Outputs:
94 | outputArn:
95 | Description: CodeBuilds ARN
96 | Value: !GetAtt myCodeBuildProject.Arn
--------------------------------------------------------------------------------
/CICD/5-ec2-for-dev-and-prod.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation sample template
6 | Create two EC2 instances:
7 | - dev instance
8 | - prod instance
9 | Install codedeploy-agent to both instances
10 |
11 | # Useful AWS docs for codedeploy-agent installation:
12 | # - Verify the CodeDeploy agent for Amazon Linux or RHEL is running https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-verify.html
13 | # - Install the CodeDeploy agent for Amazon Linux or RHEL https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html
14 | # - How can I use launch configurations to automatically install the CodeDeploy agent on an Amazon EC2 instance running Amazon Linux or Ubuntu? https://aws.amazon.com/premiumsupport/knowledge-center/codedeploy-agent-launch-configuration/
15 |
16 | ## =================== PARAMETERS =================== ##
17 | Parameters:
18 | paramEC2KeyPair:
19 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
20 | Type: AWS::EC2::KeyPair::KeyName
21 |
22 | ## =================== RESOURCES =================== ##
23 | Resources:
24 |
25 | myDevInstance: # instance for DEV
26 | Type: 'AWS::EC2::Instance'
27 | Properties:
28 | ImageId: ami-05880939912ddc43d # Amazon Linux 2 with .Net Core, PowerShell, Mono, and MATE Desktop Environment - Free tier eligible
29 | InstanceType: t2.micro # Free tier eligible
30 | KeyName: !Ref paramEC2KeyPair
31 | SecurityGroups:
32 | - !Ref mySecurityGroup
33 | IamInstanceProfile: !Ref myInstanceProfile
34 | UserData:
35 | # After stack is built, SSH and test instance by running the following cmd:
36 | # curl http://169.254.169.254/latest/user-data
37 | # sudo service codedeploy-agent status
38 | # if not working, use this: https://aws.amazon.com/premiumsupport/knowledge-center/codedeploy-agent-launch-configuration/
39 | Fn::Base64: |
40 | #!/bin/bash
41 | sudo yum -y update
42 | sudo yum install -y ruby
43 | sudo yum install -y wget
44 | cd /home/ec2-user
45 | wget https://aws-codedeploy-us-east-1.s3.amazonaws.com/latest/install
46 | chmod +x ./install
47 | sudo ./install auto
48 | sudo service codedeploy-agent start
49 | Tags:
50 | - Key: Name
51 | Value: CICD-dev
52 |
53 | myProdInstance: # instance for Prod
54 | Type: 'AWS::EC2::Instance'
55 | Properties:
56 | ImageId: ami-05880939912ddc43d # Amazon Linux 2 with .Net Core, PowerShell, Mono, and MATE Desktop Environment - Free tier eligible
57 | InstanceType: t2.micro # Free tier eligible
58 | KeyName: !Ref paramEC2KeyPair
59 | SecurityGroups:
60 | - !Ref mySecurityGroup
61 | IamInstanceProfile: !Ref myInstanceProfile
62 | UserData:
63 | # After stack is built, SSH and test instance by running the following cmd:
64 | # curl http://169.254.169.254/latest/user-data
65 | # sudo service codedeploy-agent status
66 | # if not working, use this: https://aws.amazon.com/premiumsupport/knowledge-center/codedeploy-agent-launch-configuration/
67 | Fn::Base64: |
68 | #!/bin/bash
69 | sudo yum -y update
70 | sudo yum install -y ruby
71 | sudo yum install -y wget
72 | cd /home/ec2-user
73 | wget https://aws-codedeploy-us-east-1.s3.amazonaws.com/latest/install
74 | chmod +x ./install
75 | sudo ./install auto
76 | sudo service codedeploy-agent start
77 | Tags:
78 | - Key: Name
79 | Value: CICD-prod
80 |
81 | mySecurityGroup: # SG for SSH and HTTP
82 | Type: 'AWS::EC2::SecurityGroup'
83 | Properties:
84 | GroupDescription: My SG with port 22 and 80 inbound
85 | SecurityGroupIngress:
86 | - IpProtocol: tcp
87 | FromPort: '22'
88 | ToPort: '22'
89 | CidrIp: 0.0.0.0/0
90 | - IpProtocol: tcp
91 | FromPort: '80'
92 | ToPort: '80'
93 | CidrIp: 0.0.0.0/0
94 |
95 | myCICDInstanceProfileRole: # role for InstanceProfile
96 | Type: 'AWS::IAM::Role'
97 | Properties:
98 | AssumeRolePolicyDocument:
99 | Version: '2012-10-17'
100 | Statement:
101 | - Effect: Allow
102 | Principal:
103 | Service:
104 | - ec2.amazonaws.com
105 | Action: 'sts:AssumeRole'
106 | Path: /
107 | Policies: # allow read-only access to all S3 buckets and objects
108 | - PolicyName: myCICDInstanceProfilePolicy
109 | PolicyDocument:
110 | Version: '2012-10-17'
111 | Statement:
112 | - Action:
113 | - 's3:Get*'
114 | - 's3:List*'
115 | - 'codedeploy:*'
116 | Effect: Allow
117 | Resource: '*'
118 |
119 | myInstanceProfile: # assing role to InstanceProfile
120 | Type: 'AWS::IAM::InstanceProfile'
121 | Properties:
122 | Path: /
123 | Roles:
124 | - !Ref myCICDInstanceProfileRole
125 |
126 |
127 | ## =================== OUTPUTS =================== ##
128 | Outputs:
129 | outputDevAppURL:
130 | Description: Staging Application Access URL
131 | Value: !Sub 'http://${myDevInstance.PublicDnsName}'
132 | outputProdAppURL:
133 | Description: Prod Application Access URL
134 | Value: !Sub 'http://${myProdInstance.PublicDnsName}'
--------------------------------------------------------------------------------
/CICD/6-code-deploy.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION =================== ##
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create CodeDeploy stack that gets build code from S3 bucket and deploys it to EC2 instances
8 |
9 | ## =================== PARAMETERS =================== ##
10 | Parameters:
11 | paramArtifactStoreS3Location:
12 | Type: String
13 | Description: S3 bucket name to store CodeBuild artifacts
14 | Default: bucket-for-code-build-artifacts
15 | paramAppName:
16 | Type: String
17 | Description: Specify an application Name
18 | Default: cicd-dotnet-webapp
19 | paramInstanceTagValue:
20 | Type: String
21 | Description: Specify the value of instance tag that you want to deploy
22 | Default: CICD-dev
23 |
24 | ## =================== RESOURCES =================== ##
25 | Resources:
26 |
27 | myCodeDeployApplication:
28 | Type: 'AWS::CodeDeploy::Application'
29 | Properties:
30 | ApplicationName: myCodeDeployApplicationName
31 | ComputePlatform: Server # Allowed values: ECS | Lambda | Server
32 |
33 | myCodeDeployDeploymentGroup:
34 | Type: 'AWS::CodeDeploy::DeploymentGroup'
35 | Properties:
36 | DeploymentGroupName: myCodeDeployDeploymentGroupName
37 | ApplicationName: !Ref myCodeDeployApplication
38 | Ec2TagFilters:
39 | - Key: Name
40 | Value: !Ref paramInstanceTagValue # get all EC2 instances with {Name: my-tag-value} tag
41 | Type: 'KEY_AND_VALUE'
42 | ServiceRoleArn: !GetAtt myCodeDeployRole.Arn
43 | Deployment:
44 | Description: !Sub My CodeDeploy deployment for ${AWS::StackName}
45 | IgnoreApplicationStopFailures: true
46 | Revision: # info about the location of stored app artifacts
47 | RevisionType: S3
48 | S3Location:
49 | Bucket: !Ref paramArtifactStoreS3Location
50 | Key: !Ref paramAppName
51 | BundleType: Zip
52 |
53 | myCodeDeployRole:
54 | Type: 'AWS::IAM::Role'
55 | Properties:
56 | RoleName: myCodeDeployRole
57 | AssumeRolePolicyDocument:
58 | Version: '2012-10-17'
59 | Statement:
60 | - Action:
61 | - 'sts:AssumeRole'
62 | Effect: Allow
63 | Principal:
64 | Service:
65 | - codedeploy.amazonaws.com
66 | Path: /
67 | Policies:
68 | - PolicyName: myCodeDeployPolicy
69 | PolicyDocument:
70 | Version: '2012-10-17'
71 | Statement:
72 | - Action:
73 | - 'ec2:DescribeInstances'
74 | - 'ec2:DescribeInstanceStatus'
75 | - 'ec2:TerminateInstances'
76 | - 'tag:GetTags'
77 | - 'tag:GetResources'
78 | - 'sns:Publish'
79 | - 'cloudwatch:DescribeAlarms'
80 | - 'cloudwatch:PutMetricAlarm'
81 | Effect: Allow
82 | Resource: '*'
83 |
84 | ## =================== OUTPUT =================== ##
85 | Outputs:
86 | outputApplicationName:
87 | Description: CodeDeploy Application Name
88 | Value: !Ref myCodeDeployApplication
89 | outputDeploymentGroupName:
90 | Description: CodeDeploy DeploymentGroup Name
91 | Value: !Ref myCodeDeployDeploymentGroup
--------------------------------------------------------------------------------
/Conditions/conditionInsideCondition.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION ===================
2 | Description: >-
3 | AWS CloudFormation sample template
4 | Playground for 'Conditions' section - using condition inside condition
5 | - if PROD then attach SecurityGroups for PROD to EC2 instance
6 | - otherwise (if DEV, QA or UAT) then attach SecurityGroups for non-PROD to EC2 instance
7 |
8 | ## =================== PARAMETERS ===================
9 | Parameters:
10 | paramEnvironment:
11 | Description: Select the environment
12 | Type: String
13 | Default: dev # by default it is 'dev' environment
14 | AllowedValues:
15 | - dev
16 | - prod
17 | - qa
18 | - uat
19 | ConstraintDescription: Must be development, production, QA or UAT
20 |
21 | ## =================== CONDITIONS ===================
22 | Conditions:
23 | isProd: !Equals [!Ref paramEnvironment, prod] # if prod then TRUE, otherwise FALSE
24 | isNonProd: !Not [{Condition: isProd}] # if non-prod then TRUE, otherwise FALSE
25 |
26 | ## =================== RESOURCES ===================
27 | Resources:
28 |
29 | myEC2Instance: # create a new EC2 instance
30 | Type: 'AWS::EC2::Instance'
31 | Properties:
32 | ImageId: 'ami-0ff8a91507f77f867'
33 | InstanceType: !If [isProd, t2.micro, t2.nano ] # if 'prod' then t2.micro, otherwise t2.nano
34 | SecurityGroups: !If [isProd, [!Ref myHTTPSSecurityGroupForProd], [!Ref myHTTPSSecurityGroupForNonProd] ]
35 |
36 | myHTTPSSecurityGroupForProd: # create a new Security Group for HTTPS only if PROD
37 | Type: 'AWS::EC2::SecurityGroup'
38 | Condition: isProd # If PROD
39 | Properties:
40 | GroupDescription: Enable HTTPS access via port 443
41 | SecurityGroupIngress:
42 | - IpProtocol: tcp
43 | FromPort: '443'
44 | ToPort: '443'
45 | CidrIp: 0.0.0.0/0
46 |
47 | myHTTPSSecurityGroupForNonProd: # create a new Security Group for HTTPS only if non-PROD
48 | Type: 'AWS::EC2::SecurityGroup'
49 | Condition: isNonProd # if non-PROD
50 | Properties:
51 | GroupDescription: Enable HTTPS access via port 443
52 | SecurityGroupIngress:
53 | - IpProtocol: tcp
54 | FromPort: '443'
55 | ToPort: '443'
56 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/Conditions/noValue-ignoreSGAttachmentToEc2IfDev.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION ===================
2 | Description: >-
3 | AWS CloudFormation sample template
4 | Playground for 'Conditions' section - using 'AWS::NoValue'
5 | Attach SecurityGroups to EC2 instance conditionally:
6 | - if PROD then attach
7 | - otherwise (if DEV) then ingnore
8 |
9 | ## =================== PARAMETERS ===================
10 | Parameters:
11 | paramEnvironment: # ask a user to define whether it is 'dev' or 'prod' environment
12 | Description: Select the environment
13 | Type: String
14 | Default: dev # by default it is 'dev' environment
15 | AllowedValues:
16 | - dev
17 | - prod
18 | ConstraintDescription: Must be development or production
19 |
20 | ## =================== CONDITIONS ===================
21 | Conditions:
22 | isProd: !Equals [!Ref paramEnvironment, prod] # if 'prod' then TRUE, otherwise FALSE
23 |
24 | ## =================== RESOURCES ===================
25 | Resources:
26 |
27 | myEC2Instance: # create a new EC2 instance
28 | Type: 'AWS::EC2::Instance'
29 | Properties:
30 | ImageId: 'ami-0ff8a91507f77f867'
31 | InstanceType: !If [isProd, t2.micro, t1.nano ] # if 'prod' then t2.micro, otherwise t2.nano
32 | SecurityGroups: !If [isProd, [!Ref myHTTPSSecurityGroup], !Ref 'AWS::NoValue'] # if PROD then attach SecurityGroups, otherwise ignore
33 |
34 | myHTTPSSecurityGroup: # create a new Security Group for HTTPS only if PROD
35 | Type: 'AWS::EC2::SecurityGroup'
36 | Condition: isProd
37 | Properties:
38 | GroupDescription: Enable HTTPS access via port 443
39 | SecurityGroupIngress:
40 | - IpProtocol: tcp
41 | FromPort: '443'
42 | ToPort: '443'
43 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/Conditions/or-eitherRegionAorRegionB.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION ===================
2 | Description: >-
3 | AWS CloudFormation sample template
4 | Playground for 'Conditions' section - using 'AWS::NoValue'
5 | Attach key pair to EC2 instance instance conditionally:
6 | - if region is either 'us-east-1' or 'us-east-2' then attach 'myPpkKeyPairA' key pair
7 | - otherwise (for other regions) attach 'myPpkKeyPairB' key pair
8 | Note, you need to create 'myPpkKeyPairA' and 'myPpkKeyPairB' key pairs prior to run CF stack
9 |
10 | ## =================== CONDITIONS ===================
11 | Conditions:
12 | isRegionForKeyA: !Or [!Equals [!Ref 'AWS::Region', us-east-1], !Equals [!Ref 'AWS::Region', us-east-2]]
13 |
14 | ## =================== RESOURCES ===================
15 | Resources:
16 |
17 | myEC2Instance: # create a new EC2 instance
18 | Type: 'AWS::EC2::Instance'
19 | Properties:
20 | ImageId: 'ami-0ff8a91507f77f867'
21 | InstanceType: t2.micro
22 | KeyName: !If [isRegionForKeyA, myPpkKeyPairA, myPpkKeyPairB]
--------------------------------------------------------------------------------
/EC2/links.md:
--------------------------------------------------------------------------------
1 | # Top links
2 |
3 | ## Application frameworks
4 | - Creates a LAMP stack on a single Amazon EC2 instance with a local MySQL database for storage.
5 | - Creates a LAMP stack on Amazon EC2 instances in an Auto Scaling group with a multi-AZ Amazon RDS database instance for storage.
6 | - Creates a Ruby on Rails stack on a single Amazon EC2 instance with a local MySQL database for storage.
7 | - Creates a Ruby on Rails stack on Amazon EC2 instances in an Auto Scaling group with a multi-AZ Amazon RDS database instance for storage.
8 | Link: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/sample-templates-appframeworks-us-east-1.html
9 |
10 | ## Amazon EC2 template snippets
11 | - EC2 block device mapping examples
12 | - Assigning an Amazon EC2 elastic IP using AWS::EC2::EIP snippet
13 | - Assigning an existing elastic IP to an amazon EC2 instance using AWS::EC2::EIPAssociation snippet
14 | - Assigning an existing VPC elastic IP to an Amazon EC2 instance using AWS::EC2::EIPAssociation snippet
15 | - Elastic network interface (ENI) template snippets
16 | - Amazon EC2 instance resource
17 | - Amazon EC2 instance with Volume, Tag, and UserData properties
18 | - Amazon EC2 instance resource with an Amazon SimpleDB Domain
19 | - Amazon EC2 security group resource with two CIDR range ingress rules
20 | - Amazon EC2 security group resource with two security group ingress rules
21 | - Amazon EC2 security group resource with LoadBalancer ingress rule
22 | - Using AWS::EC2::SecurityGroupIngress to create mutually referencing Amazon EC2 security group resources
23 | - Amazon EC2 volume resource
24 | - Amazon EC2 VolumeAttachment resource
25 | - Amazon EC2 instance in a default VPC security group
26 | - Amazon EC2 route with egress-only Internet gateway
27 | link: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-ec2.html
--------------------------------------------------------------------------------
/ECS/1-ecs-empty-cluster.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== #
4 | Description: >-
5 | AWS CloudFormation sample template.
6 | Create an empty ECS cluster with enabled CloudWatch Container Insights
7 | Cluster description: Networking only (cluster only) - Powered by AWS Fargate
8 |
9 | ## =================== PARAMETERS =================== #
10 | Parameters:
11 | paramClusterName:
12 | Description: Specify an empty cluster name
13 | Type: String
14 | Default: my-empty-cluster-demo
15 | paramUniqueName:
16 | Description: Specify a unique name
17 | Type: String
18 | Default: OberynMartell
19 |
20 | ## =================== RESOURCES =================== #
21 | Resources:
22 |
23 | # create an empty cluster
24 | myCluster:
25 | Type: AWS::ECS::Cluster
26 | Properties:
27 | ClusterName: !Ref paramClusterName
28 | ClusterSettings: # enable CloudWatch Container Insights that is tagged with the key 'MasteringECS' and the value
29 | - Name: containerInsights
30 | Value: enabled
31 | Tags:
32 | - Key: MasteringECS
33 | Value: !Ref paramUniqueName
34 |
35 | ## =================== OUTPUTS =================== #
36 | Outputs:
37 | outputClusterName:
38 | Description: The name of the ECS cluster
39 | Value: !Ref myCluster
--------------------------------------------------------------------------------
/ECS/2-vpc-with-2-public-subnets.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== #
4 | Description: >-
5 | AWS CloudFormation sample template.
6 | Create a custom VPC with a pair of public subnets spread across two AZs
7 |
8 | ## =================== PARAMETERS =================== #
9 | Parameters:
10 | paramVpcCIDR:
11 | Description: Enter the IP range (CIDR notation) for VPC
12 | Type: String
13 | Default: 10.192.0.0/16
14 | paramPublicSubnet1CIDR:
15 | Description: Enter the IP range (CIDR notation) for the public subnet in AZ A
16 | Type: String
17 | Default: 10.192.10.0/24
18 | paramPublicSubnet2CIDR:
19 | Description: Enter the IP range (CIDR notation) for the public subnet in AZ B
20 | Type: String
21 | Default: 10.192.11.0/24
22 | paramUniqueName:
23 | Description: Specify a unique name
24 | Type: String
25 | Default: OberynMartell
26 |
27 | ## =================== RESOURCES =================== #
28 | Resources:
29 |
30 | # create a VPC
31 | myVPC:
32 | Type: AWS::EC2::VPC
33 | Properties:
34 | CidrBlock: !Ref paramVpcCIDR
35 | EnableDnsSupport: true # let instances in the VPC get DNS hostnames
36 | EnableDnsHostnames: true # allow DNS resolution
37 | Tags:
38 | - Key: MasteringECS
39 | Value: !Ref paramUniqueName
40 |
41 | # create an Internet Gateway
42 | myInternetGateway:
43 | Type: AWS::EC2::InternetGateway
44 | Properties:
45 | Tags:
46 | - Key: MasteringECS
47 | Value: !Ref paramUniqueName
48 |
49 | # attach the Internet Gateway to the VPC
50 | myVPCGatewayAttachment:
51 | Type: AWS::EC2::VPCGatewayAttachment
52 | Properties:
53 | VpcId: !Ref myVPC
54 | InternetGatewayId: !Ref myInternetGateway
55 |
56 | # create a public route table for the VPC (will be public once it is associated with the Internet Gateway)
57 | myPublicRouteTable:
58 | Type: AWS::EC2::RouteTable
59 | Properties:
60 | VpcId: !Ref myVPC
61 | Tags:
62 | - Key: MasteringECS
63 | Value: !Ref paramUniqueName
64 |
65 | # associate the public route table with the Internet Gateway
66 | myPublicRoute:
67 | Type: AWS::EC2::Route
68 | DependsOn: myVPCGatewayAttachment # myPublicRoute should be created only AFTER myVPCGatewayAttachment
69 | Properties:
70 | RouteTableId: !Ref myPublicRouteTable
71 | DestinationCidrBlock: 0.0.0.0/0
72 | GatewayId: !Ref myInternetGateway
73 |
74 | # create a public subnet in AZ 1 (will be public once it is associated with public route table)
75 | myPublicSubnetInAZ1:
76 | Type: AWS::EC2::Subnet
77 | Properties:
78 | VpcId: !Ref myVPC
79 | AvailabilityZone: !Select [ 0, !GetAZs '' ] # AZ 1
80 | CidrBlock: !Ref paramPublicSubnet1CIDR
81 | MapPublicIpOnLaunch: true # allow instances launched in this subnet receive a public IPv4 address
82 | Tags:
83 | - Key: MasteringECS
84 | Value: !Ref paramUniqueName
85 |
86 | # create a public subnet in AZ 2 (will be public once it is associated with public route table)
87 | myPublicSubnetInAZ2:
88 | Type: AWS::EC2::Subnet
89 | Properties:
90 | VpcId: !Ref myVPC
91 | AvailabilityZone: !Select [ 1, !GetAZs '' ] # AZ 2
92 | CidrBlock: !Ref paramPublicSubnet2CIDR
93 | MapPublicIpOnLaunch: true # allow instances launched in this subnet receive a public IPv4 address
94 | Tags:
95 | - Key: MasteringECS
96 | Value: !Ref paramUniqueName
97 |
98 | # associate the public route table with the public subnet in AZ 1
99 | myPublicSubnetInAZ1RouteTableAssociation:
100 | Type: AWS::EC2::SubnetRouteTableAssociation
101 | Properties:
102 | RouteTableId: !Ref myPublicRouteTable
103 | SubnetId: !Ref myPublicSubnetInAZ1
104 |
105 | # associate the public route table with the public subnet in AZ 2
106 | myPublicSubnetInAZ2RouteTableAssociation:
107 | Type: AWS::EC2::SubnetRouteTableAssociation
108 | Properties:
109 | RouteTableId: !Ref myPublicRouteTable
110 | SubnetId: !Ref myPublicSubnetInAZ2
111 |
112 | ## =================== OUTPUTS =================== #
113 | Outputs:
114 | outputVPC:
115 | Description: A reference to the created VPC
116 | Value: !Ref myVPC
117 | outputPublicSubnets:
118 | Description: A list of the public subnets
119 | Value: !Join [ ",", [ !Ref myPublicSubnetInAZ1, !Ref myPublicSubnetInAZ2 ]]
--------------------------------------------------------------------------------
/ECS/cluster-types.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/ECS/cluster-types.png
--------------------------------------------------------------------------------
/IAM/Groups-AttachUsersToGroup.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template.
7 | Adds single or multiple users to the group.
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-addusertogroup.html
9 |
10 | ## =================== PARAMETERS ===================
11 | Parameters:
12 | paramGroupName:
13 | Description: Name of existing group
14 | Type: String
15 | MinLength: 1
16 | paramUserNames:
17 | Description: Comma-delimited list of user names to attach to the group
18 | Type: CommaDelimitedList
19 |
20 |
21 | ## =================== RESOURCES ===================
22 | Resources:
23 | myUserToGroupAddition:
24 | Type: 'AWS::IAM::UserToGroupAddition'
25 | Properties:
26 | GroupName: !Ref paramGroupName # existing group name
27 | Users: !Ref paramUserNames # list of existing user names
28 |
29 | ## =================== OUTPUT ===================
30 | Outputs:
31 | outputName:
32 | Description: Name of users to a group addition
33 | Value: !Ref myUserToGroupAddition
--------------------------------------------------------------------------------
/IAM/Groups-Group.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template.
7 | Create an IAM Group.
8 | Optionally embed AWS managed policies, customer managed policies and inline policies in the group.
9 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-group.html
10 |
11 | ## =================== PARAMETERS ===================
12 | Parameters:
13 | paramPath:
14 | Description: IAM Path that you want to associate with the group
15 | Type: String
16 | AllowedPattern: (^\/$)|(^\/.*\/$)
17 | Default: '/'
18 |
19 | ## =================== RESOURCES ===================
20 | Resources:
21 | myGroup:
22 | Type: 'AWS::IAM::Group'
23 | Properties:
24 | GroupName: ApiDevelopers # give a name to this group
25 | Path: !Ref paramPath
26 | ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the group
27 | - arn:aws:iam::aws:policy/AWSCloud9Administrator # provide administrator access to AWS Cloud9
28 | - arn:aws:iam::aws:policy/AmazonAPIGatewayAdministrator # provide full access to create/edit/delete APIs in Amazon API Gateway
29 | # - arn:aws:iam::111111111111:policy/customerManagedBlahBlahPolicy # use your own customer managed policy specifying its ARN
30 | Policies: # list of inline policy documents that are embedded in the group
31 | - PolicyName: inlineCloudWatchLogsPolicy # give a unique name to this policy
32 | PolicyDocument: # JSON policy document
33 | Version: '2012-10-17'
34 | Statement: # provide write permissions to CloudWatch Logs
35 | - Effect: Allow
36 | Action:
37 | - 'logs:CreateLogGroup'
38 | - 'logs:CreateLogStream*'
39 | - 'logs:PutLogEvents'
40 | Resource: '*'
41 |
42 | ## =================== OUTPUT ===================
43 | Outputs:
44 | outputName:
45 | Description: Group name
46 | Value: !Ref myGroup
47 | outputARN:
48 | Description: Group ARN
49 | Value: !GetAtt myGroup.Arn
--------------------------------------------------------------------------------
/IAM/Policies-CustomerManagedPolicy.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create a Customer Managed IAM Policy and optionally attach it to IAM user(s), group(s), or(and) role(s)
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-managedpolicy.html
9 |
10 | ## =================== PARAMETERS ===================
11 | Parameters:
12 | paramPath:
13 | Description: IAM Path that you want to associate with the policy
14 | Type: String
15 | AllowedPattern: (^\/$)|(^\/.*\/$)
16 | Default: '/'
17 | paramUsers:
18 | Description: 'Comma-delimited list of user names to attach the policy to (optional)'
19 | Type: CommaDelimitedList
20 | Default: ''
21 | paramGroups:
22 | Description: 'Comma-delimited list of group names to attach the policy to (optional)'
23 | Type: CommaDelimitedList
24 | Default: ''
25 | paramRoles:
26 | Description: 'Comma-delimited list of role names to attach the policy to (optional)'
27 | Type: CommaDelimitedList
28 | Default: ''
29 |
30 | ## =================== CONDITIONS ===================
31 | Conditions:
32 | hasUsers: # check if any user was specified as an input parameter
33 | !Not [!Equals [ !Join ['', !Ref paramUsers], '' ] ]
34 | hasGroups: # check if any group was specified as an input parameter
35 | !Not [!Equals [ !Join ['', !Ref paramGroups], '' ] ]
36 | hasRoles: # check if any role was specified as an input parameter
37 | !Not [!Equals [ !Join ['', !Ref paramRoles], '' ] ]
38 |
39 | ## =================== RESOURCES ===================
40 | Resources:
41 | # Note, PolicyDocument is the only required field in Properties
42 | myCustomerManagedPolicyForEC2:
43 | Type: 'AWS::IAM::ManagedPolicy'
44 | Properties:
45 | ManagedPolicyName: customerManagedEC2ReadOnlyPolicy # give a name to this policy
46 | Description: Customer managed policy for read only access to EC2 instance
47 | Path: !Ref paramPath
48 | PolicyDocument: # (required) JSON policy document
49 | Version: '2012-10-17'
50 | Statement: # allow read only access to EC2 instance
51 | - Effect: Allow
52 | Action:
53 | - 'ec2:Describe'
54 | Resource: '*'
55 | # IAM entities (Groups, Roles, and Users) are optional properties
56 | Users: !If [ hasUsers, !Ref paramUsers, !Ref "AWS::NoValue"] # attach this policy to the list of specified users if any
57 | Groups: !If [ hasGroups, !Ref paramGroups, !Ref "AWS::NoValue"] # attach this policy to the list of specified groups if any
58 | Roles: !If [ hasRoles, !Ref paramRoles, !Ref "AWS::NoValue"] # attach this policy to the list of specified roles if any
59 |
60 | ## =================== OUTPUT ===================
61 | Outputs:
62 | outputName:
63 | Description: Customer managed policy name
64 | Value: !Ref myCustomerManagedPolicyForEC2
--------------------------------------------------------------------------------
/IAM/Policies-InlinePolicy.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an Inline IAM Policy that is embedded in the specified IAM user(s), group(s), or(and) role(s)
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-policy.html
9 |
10 | ## =================== PARAMETERS ===================
11 | Parameters:
12 | paramUsers:
13 | Description: 'Comma-delimited list of user names to associate the inline policy with. Users are optional but you must specify at least one of Users, Groups, and Roles'
14 | Type: CommaDelimitedList
15 | Default: ''
16 | paramGroups:
17 | Description: 'Comma-delimited list of group names to associate the inline policy with. Groups are optional but you must specify at least one of Users, Groups, and Roles'
18 | Type: CommaDelimitedList
19 | Default: ''
20 | paramRoles:
21 | Description: 'Comma-delimited list of role names to associate the inline policy with. Roles are optional but you must specify at least one of Users, Groups, and Roles'
22 | Type: CommaDelimitedList
23 | Default: ''
24 |
25 | ## =================== CONDITIONS ===================
26 | Conditions:
27 | hasUsers: # check if any user was specified as an input parameter
28 | !Not [!Equals [ !Join ['', !Ref paramUsers], '' ] ]
29 | hasGroups: # check if any group was specified as an input parameter
30 | !Not [!Equals [ !Join ['', !Ref paramGroups], '' ] ]
31 | hasRoles: # check if any role was specified as an input parameter
32 | !Not [!Equals [ !Join ['', !Ref paramRoles], '' ] ]
33 |
34 | ## =================== RESOURCES ===================
35 | Resources:
36 | myInlinePolicyForS3ReadOnly:
37 | Type: 'AWS::IAM::Policy'
38 | Properties:
39 | PolicyName: inlineS3ReadOnlyPolicy # (required) give a name to this policy
40 | PolicyDocument: # (required) JSON policy document
41 | Version: '2012-10-17'
42 | Statement: # allow read only access to all S3 buckets
43 | - Effect: Allow
44 | Action:
45 | - 's3:Get*'
46 | - 's3:List*'
47 | Resource: '*'
48 | # Note, Groups, Roles, and Users fields are optional. However, you must specify at least one of these fields
49 | Users: !If [ hasUsers, !Ref paramUsers, !Ref "AWS::NoValue"] # attach this policy to the list of specified users if any
50 | Groups: !If [ hasGroups, !Ref paramGroups, !Ref "AWS::NoValue"] # attach this policy to the list of specified groups if any
51 | Roles: !If [ hasRoles, !Ref paramRoles, !Ref "AWS::NoValue"] # attach this policy to the list of specified roles if any
52 |
53 | ## =================== OUTPUT ===================
54 | Outputs:
55 | outputName:
56 | Description: Inline policy name
57 | Value: !Ref myInlinePolicyForS3ReadOnly
--------------------------------------------------------------------------------
/IAM/Roles-InstanceProfile.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Use an instance profile to pass an IAM role to an EC2 instance
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-instanceprofile.html
9 |
10 | ## =================== PARAMETERS ===================
11 | Parameters:
12 | paramInstanceProfileName:
13 | Description: Unique name for a new instance profile
14 | Type: String
15 | MinLength: 3
16 | AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]{1,64}$"
17 | ConstraintDescription: Instance profile name must be between 1 and 64 alphanumeric characters in length, starting with an uppercase or lowercase character of the alphabet
18 | paramRoleName:
19 | Description: Existing role name you want to associate the instance profile with
20 | Type: String
21 | MinLength: 2
22 | ConstraintDescription: Make sure that this role exist
23 | paramPath:
24 | Description: IAM Path that you want to associate with the instance profile
25 | Type: String
26 | AllowedPattern: (^\/$)|(^\/.*\/$)
27 | Default: '/'
28 |
29 | ## =================== RESOURCES ===================
30 | Resources:
31 | myInstanceProfile:
32 | Type: 'AWS::IAM::InstanceProfile'
33 | Properties:
34 | InstanceProfileName: !Ref paramInstanceProfileName
35 | Roles: # (required) existing role name to associate with the instance profile
36 | # Note: only one role can be assigned to an EC2 instance at a time, but type is 'List of String'
37 | - !Ref paramRoleName
38 | Path: !Ref paramPath
39 |
40 | ## =================== OUTPUT ===================
41 | Outputs:
42 | outputName:
43 | Description: Instance profile name
44 | Value: !Ref myInstanceProfile
45 | outputArn:
46 | Description: Instance profile ARN
47 | Value: !GetAtt myInstanceProfile.Arn
--------------------------------------------------------------------------------
/IAM/Roles-MoreExamples.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template.
7 | Create a custom IAM policy and some custom IAM roles with inline and managed policies.
8 |
9 | ## =================== PARAMETERS ===================
10 | Parameters:
11 | paramUniqueKey:
12 | Description: Specify a unique key that identifies resources as a target for deployments
13 | Type: String
14 | Default: DoloresAbernathy
15 | AllowedPattern: "[\\x20-\\x7E]*"
16 | ConstraintDescription: Must contain only ASCII characters
17 |
18 | ## =================== RESOURCES ===================
19 | Resources:
20 |
21 | # ---------------- Create custom role and attach a custom policy to it ----------------
22 | # a) Create a custom role without any policy
23 | myCustomRole:
24 | Type: 'AWS::IAM::Role'
25 | Properties:
26 | AssumeRolePolicyDocument:
27 | Version: '2012-10-17'
28 | Statement:
29 | -
30 | Effect: Allow
31 | Principal:
32 | Service:
33 | - lambda.amazonaws.com
34 | Action:
35 | - 'sts:AssumeRole'
36 | Description: Custom IAM role for Lambda
37 | Path: '/'
38 | RoleName: CustomRole
39 | Tags:
40 | - Key: Name
41 | Value: !Ref paramUniqueKey
42 |
43 | # b) Create a custom policy and attach it to 'myCustomRole'
44 | myCustomPolicy:
45 | Type: 'AWS::IAM::Policy'
46 | Properties:
47 | PolicyName: !Join ['', [ !Ref paramUniqueKey, 'CustomPolicy' ]]
48 | PolicyDocument:
49 | Version: '2012-10-17'
50 | Statement:
51 | - Effect: Allow
52 | Action:
53 | - 's3:Get*'
54 | - 's3:List*'
55 | Resource: '*'
56 | Roles:
57 | - !Ref myCustomRole # attach 'myCustomRole' to 'myCustomPolicy'
58 |
59 | # ------- Create a custom role with two AWS managed policies ---------
60 | myCustomRoleWithAWSManagedPolicies:
61 | Type: 'AWS::IAM::Role'
62 | Properties:
63 | AssumeRolePolicyDocument:
64 | Version: '2012-10-17'
65 | Statement:
66 | -
67 | Effect: Allow
68 | Principal:
69 | Service:
70 | - ec2.amazonaws.com
71 | Action:
72 | - 'sts:AssumeRole'
73 | Description: Custom IAM role for EC2 instance to grand a) read only access to all Kinesis streams and b) full access to CloudWatch
74 | ManagedPolicyArns: # use AWS managed policies
75 | - arn:aws:iam::aws:policy/AmazonKinesisReadOnlyAccess
76 | - arn:aws:iam::aws:policy/CloudWatchFullAccess
77 | Path: '/'
78 | RoleName: !Join ['', [ !Ref paramUniqueKey, 'CustomRoleWithAWSManagedPolicies' ]]
79 | Tags:
80 | - Key: Name
81 | Value: !Ref paramUniqueKey
82 |
83 | # ------- Create a custom role with two inline policies ---------
84 | myCustomRoleWithInlinePolicies:
85 | Type: 'AWS::IAM::Role'
86 | Properties:
87 | AssumeRolePolicyDocument:
88 | Version: '2012-10-17'
89 | Statement:
90 | -
91 | Effect: Allow
92 | Principal:
93 | Service:
94 | - ec2.amazonaws.com
95 | Action:
96 | - 'sts:AssumeRole'
97 | Description: Custom IAM role for EC2 instance to grand a) read only access to all S3 buckets, and b) read only access to Amazon SNS
98 | Path: '/'
99 | Policies: # create inline policies
100 | # inline policy to read only access to all S3 buckets
101 | - PolicyName: !Join ['', [ !Ref paramUniqueKey, 'InlinePolicy1' ]]
102 | PolicyDocument:
103 | Version: '2012-10-17'
104 | Statement:
105 | - Effect: Allow
106 | Action:
107 | - 's3:Get*'
108 | - 's3:List*'
109 | Resource: '*'
110 | # inline policy to read only access to Amazon SNS
111 | - PolicyName: !Join ['', [ !Ref paramUniqueKey, 'InlinePolicy2' ]]
112 | PolicyDocument:
113 | Version: '2012-10-17'
114 | Statement:
115 | - Effect: Allow
116 | Action:
117 | - 'sns:GetTopicAttributes'
118 | - 'sns:List*'
119 | Resource: '*'
120 | RoleName: !Join ['', [ !Ref paramUniqueKey, 'CustomRoleWithInlinePolicies' ]]
121 | Tags:
122 | - Key: Name
123 | Value: !Ref paramUniqueKey
--------------------------------------------------------------------------------
/IAM/Roles-Role.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an IAM Role
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html
9 |
10 | ## =================== PARAMETERS ===================
11 | Parameters:
12 | paramRoleName:
13 | Description: Unique name for a new role within the account
14 | Type: String
15 | MinLength: 3
16 | AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]{1,64}$"
17 | ConstraintDescription: Role name must be between 1 and 64 alphanumeric characters in length, starting with an uppercase or lowercase character of the alphabet
18 | paramMaxSessionDuration:
19 | Description: The maximum session duration (in seconds) that you want to set for the specified role
20 | Type: Number
21 | MinValue: 3600 # 1 hour
22 | MaxValue: 43200 # 12 hours
23 | Default: 7200 # 2 hours
24 | paramPath:
25 | Description: IAM Path that you want to associate with the role
26 | Type: String
27 | AllowedPattern: (^\/$)|(^\/.*\/$)
28 | Default: '/'
29 | paramTagValue:
30 | Description: Tag value that identifies resources as a target for deployments
31 | Type: String
32 | Default: DoloresAbernathy
33 | AllowedPattern: "[\\x20-\\x7E]*"
34 | ConstraintDescription: Must contain only ASCII characters
35 |
36 | ## =================== RESOURCES ===================
37 | Resources:
38 | myRole:
39 | Type: 'AWS::IAM::Role'
40 | Properties:
41 | RoleName: !Ref paramRoleName # give a name to this role
42 | Description: IAM role for EC2 instance
43 | AssumeRolePolicyDocument: # (required) only one trust policy with a role
44 | Version: '2012-10-17'
45 | Statement:
46 | -
47 | Effect: Allow
48 | Principal:
49 | Service:
50 | - 'ec2.amazonaws.com'
51 | Action:
52 | - 'sts:AssumeRole'
53 | MaxSessionDuration: !Ref paramMaxSessionDuration
54 | Path: !Ref paramPath
55 | Tags:
56 | - Key: Name
57 | Value: !Ref paramTagValue
58 |
59 | ## =================== OUTPUT ===================
60 | Outputs:
61 | outputName:
62 | Description: Role name
63 | Value: !Ref myRole
64 | outputArn:
65 | Description: Role ARN
66 | Value: !GetAtt myRole.Arn
67 | outputId:
68 | Description: Role ID
69 | Value: !GetAtt myRole.RoleId
--------------------------------------------------------------------------------
/IAM/Roles-RoleWithPolicies.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an IAM Role
8 | Optionally embed AWS managed policies, customer managed policies and inline policies in the role
9 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html
10 |
11 | ## =================== PARAMETERS ===================
12 | Parameters:
13 | paramRoleName:
14 | Description: Unique name for a new role within the account
15 | Type: String
16 | MinLength: 3
17 | AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]{1,64}$"
18 | ConstraintDescription: Role name must be between 1 and 64 alphanumeric characters in length, starting with an uppercase or lowercase character of the alphabet
19 | paramMaxSessionDuration:
20 | Description: The maximum session duration (in seconds) that you want to set for the specified role
21 | Type: Number
22 | MinValue: 3600 # 1 hour
23 | MaxValue: 43200 # 12 hours
24 | Default: 7200 # 2 hours
25 | paramPath:
26 | Description: IAM Path that you want to associate with the role
27 | Type: String
28 | AllowedPattern: (^\/$)|(^\/.*\/$)
29 | Default: '/'
30 | paramManagedPolicy:
31 | Type: String
32 | Description: Select predefined Managed Policy that you want to associate with the role
33 | AllowedValues:
34 | - DatabaseAdministrator
35 | - SystemAdministrator
36 | # - MyCustomerManaged Policy
37 | - View-Only
38 | - None
39 | Default: None
40 | paramTagValue:
41 | Description: Tag value that identifies resources as a target for deployments
42 | Type: String
43 | Default: DoloresAbernathy
44 | AllowedPattern: "[\\x20-\\x7E]*"
45 | ConstraintDescription: Must contain only ASCII characters
46 |
47 | ## =================== MAPPINGS ===================
48 | Mappings:
49 | # listing managed IAM policies
50 | # AWS CLI command to get the full list of policies: 'aws iam list-policies'
51 | mapManagedPolicies: # AWS and customer managed
52 | DatabaseAdministrator:
53 | ARN: arn:aws:iam::aws:policy/job-function/DatabaseAdministrator
54 | SystemAdministrator:
55 | ARN: arn:aws:iam::aws:policy/job-function/SystemAdministrator
56 | # example with custom managed IAM policy
57 | # CustomS3Admin: # this is Customer Managed Policy - replace arn with your own
58 | # ARN: arn:aws:iam::111111111111:policy/customerManagedEC2ReadOnlyPolicy
59 | # Important! line below will NOT work because Mapping section does NOT support parameters, pseudo parameters, or intrinsic functions
60 | # ARN: !Sub 'arn:aws:iam::${AWS::AccountId}:policy/customerManagedEC2ReadOnlyPolicy'
61 | View-Only:
62 | ARN: arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
63 | None:
64 | ARN: arn:aws:iam::aws:policy/NoAccess
65 |
66 | ## =================== CONDITIONS ===================
67 | Conditions:
68 | hasManagedPolicy: # check if any group was specified as an input parameter
69 | !Not [!Equals [ !Ref paramManagedPolicy, 'None'] ]
70 |
71 | ## =================== RESOURCES ===================
72 | Resources:
73 | myRole:
74 | Type: 'AWS::IAM::Role'
75 | Properties:
76 | RoleName: !Ref paramRoleName # give a name to this role
77 | Description: IAM role for EC2 instance
78 | AssumeRolePolicyDocument: # (required) only one trust policy with a role
79 | Version: '2012-10-17'
80 | Statement:
81 | -
82 | Effect: Allow
83 | Principal:
84 | Service:
85 | - 'ec2.amazonaws.com'
86 | Action:
87 | - 'sts:AssumeRole'
88 | MaxSessionDuration: !Ref paramMaxSessionDuration
89 | Path: !Ref paramPath
90 | ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the role
91 | - !If [ hasManagedPolicy, !FindInMap [ mapManagedPolicies, !Ref paramManagedPolicy, ARN], !Ref "AWS::NoValue" ] # find an ARN of specified paramManagedPolicy
92 | - arn:aws:iam::aws:policy/AWSCloud9Administrator # provides administrator access to AWS Cloud9
93 | # - arn:aws:iam::111111111111:policy/customerManagedEC2ReadOnlyPolicy # use your own customer managed policy
94 | Policies: # list of inline policy documents that are embedded in the role
95 | - PolicyName: inlineS3ReadOnlyPolicy # give a unique name to this policy
96 | PolicyDocument: # JSON policy document
97 | Version: '2012-10-17'
98 | Statement: # allow read only access to all S3 buckets
99 | - Effect: Allow
100 | Action:
101 | - 's3:Get*'
102 | - 's3:List*'
103 | Resource: '*'
104 | - PolicyName: inlineS3CreateBucketOnlyPolicy # give a unique name to this policy
105 | PolicyDocument: # JSON policy document
106 | Version: '2012-10-17'
107 | Statement: # allow create S3 bucket only access
108 | - Effect: Allow
109 | Action:
110 | - 's3:CreateBucket*'
111 | Resource: '*'
112 | Tags:
113 | - Key: Name
114 | Value: !Ref paramTagValue
115 |
116 | ## =================== OUTPUT ===================
117 | Outputs:
118 | outputName:
119 | Description: Role name
120 | Value: !Ref myRole
121 | outputArn:
122 | Description: Role ARN
123 | Value: !GetAtt myRole.Arn
124 | outputId:
125 | Description: Role ID
126 | Value: !GetAtt myRole.RoleId
--------------------------------------------------------------------------------
/IAM/Users-User.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an IAM User and optionally attach it to IAM group(s)
8 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-user.html
9 |
10 | ## =================== PARAMETERS ===================
11 | Parameters:
12 | paramUserName:
13 | Description: Unique name for a new user
14 | Type: String
15 | AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]{1,64}$"
16 | ConstraintDescription: User name must be between 1 and 64 alphanumeric characters in length, starting with an uppercase or lowercase character of the alphabet.
17 | paramUserPassword:
18 | Description: Account password for a new user
19 | Type: String
20 | NoEcho: 'true' # mask the parameter value as asterisks (*****) to prevent it from being displayed in the console, CLI, or API
21 | AllowedPattern: ^[a-zA-Z][a-zA-Z0-9!@#$%&]{8,32}$
22 | ConstraintDescription: Password must be between 8 and 32 characters, start with lowercase or uppercase letter, and can be alphanumeric with the following special characters !@#$%&
23 | paramGroups:
24 | Description: 'Comma-delimited list of group names to which you want to add the user (optional)'
25 | Type: CommaDelimitedList
26 | Default: ''
27 | paramPath:
28 | Description: IAM Path that you want to associate with the user
29 | Type: String
30 | AllowedPattern: (^\/$)|(^\/.*\/$)
31 | Default: '/'
32 | paramTagValue:
33 | Description: Tag value that identifies resources as a target for deployments
34 | Type: String
35 | Default: DoloresAbernathy
36 | AllowedPattern: "[\\x20-\\x7E]*"
37 | ConstraintDescription: Must contain only ASCII characters
38 |
39 | ## =================== CONDITIONS ===================
40 | Conditions:
41 | hasGroups: # check if at list one group was specified as an input parameter
42 | !Not [!Equals [ !Join ['', !Ref paramGroups], '' ] ]
43 |
44 | ## =================== RESOURCES ===================
45 | Resources:
46 | myUser:
47 | Type: 'AWS::IAM::User'
48 | Properties:
49 | UserName: !Ref paramUserName # give a name to this user
50 | LoginProfile: # specify a password for this user
51 | Password: !Ref paramUserPassword
52 | PasswordResetRequired: true # make this user to set a new password on next sign-in
53 | Path: !Ref paramPath
54 | Groups: !If [ hasGroups, !Ref paramGroups, !Ref "AWS::NoValue"] # attach this user to the list of specified groups if any
55 | Tags:
56 | - Key: Name
57 | Value: !Ref paramTagValue
58 |
59 | ## =================== OUTPUT ===================
60 | Outputs:
61 | outputName:
62 | Description: User name
63 | Value: !Ref myUser
64 | outputArn:
65 | Description: User ARN
66 | Value: !GetAtt myUser.Arn
--------------------------------------------------------------------------------
/IAM/Users-UserWithPolicies.yaml:
--------------------------------------------------------------------------------
1 | ## =================== VERSION ===================
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | ## =================== DESCRIPTION ===================
5 | Description: >-
6 | AWS CloudFormation sample template
7 | Create an IAM User and optionally attach it to IAM group(s)
8 | Optionally embed AWS managed policies, customer managed policies and inline policies in the user
9 | AWS doc: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iam-user.html
10 |
11 | ## =================== PARAMETERS ===================
12 | Parameters:
13 | paramUserName:
14 | Description: Unique name for a new user
15 | Type: String
16 | AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]{1,64}$"
17 | ConstraintDescription: User name must be between 1 and 64 alphanumeric characters in length, starting with an uppercase or lowercase character of the alphabet.
18 | paramUserPassword:
19 | Description: Account password for a new user
20 | Type: String
21 | NoEcho: 'true' # mask the parameter value as asterisks (*****) to prevent it from being displayed in the console, CLI, or API
22 | AllowedPattern: ^[a-zA-Z][a-zA-Z0-9!@#$%&]{8,32}$
23 | ConstraintDescription: Password must be between 8 and 32 characters, start with lowercase or uppercase letter, and can be alphanumeric with the following special characters !@#$%&
24 | paramGroups:
25 | Description: 'Comma-delimited list of group names to which you want to add the user (optional)'
26 | Type: CommaDelimitedList
27 | Default: ''
28 | paramPath:
29 | Description: IAM Path that you want to associate with the user
30 | Type: String
31 | AllowedPattern: (^\/$)|(^\/.*\/$)
32 | Default: '/'
33 | paramManagedPolicy:
34 | Type: String
35 | Description: Select predefined Managed Policy that you want to associate with the user
36 | AllowedValues:
37 | - DatabaseAdministrator
38 | - SystemAdministrator
39 | - DeveloperPowerUser
40 | # - CustomS3Admin
41 | - View-Only
42 | - None
43 | Default: None
44 | paramTagValue:
45 | Description: Tag value that identifies resources as a target for deployments
46 | Type: String
47 | Default: DoloresAbernathy
48 | AllowedPattern: "[\\x20-\\x7E]*"
49 | ConstraintDescription: Must contain only ASCII characters
50 |
51 | ## =================== MAPPINGS ===================
52 | Mappings:
53 | # listing managed IAM policies
54 | # AWS CLI command to get the full list of policies: 'aws iam list-policies'
55 | mapManagedPolicies: # AWS and customer managed
56 | DatabaseAdministrator:
57 | ARN: arn:aws:iam::aws:policy/job-function/DatabaseAdministrator
58 | SystemAdministrator:
59 | ARN: arn:aws:iam::aws:policy/job-function/SystemAdministrator
60 | DeveloperPowerUser:
61 | ARN: arn:aws:iam::aws:policy/PowerUserAccess
62 | # example with custom managed IAM policy -
63 | # CustomS3Admin: # this is Customer Managed Policy - replace arn with your own
64 | # ARN: arn:aws:iam::111111111111:policy/customerManagedEC2ReadOnlyPolicy
65 | # Important! line below will NOT work because Mapping section does NOT support parameters, pseudo parameters, or intrinsic functions
66 | # ARN: !Sub 'arn:aws:iam::${AWS::AccountId}:policy/customerManagedEC2ReadOnlyPolicy'
67 | View-Only:
68 | ARN: arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
69 | None:
70 | ARN: arn:aws:iam::aws:policy/NoAccess
71 |
72 | ## =================== CONDITIONS ===================
73 | Conditions:
74 | hasGroups: # check if at list one group was specified as an input parameter
75 | !Not [!Equals [ !Join ['', !Ref paramGroups], '' ] ]
76 | hasManagedPolicy: # check if any group was specified as an input parameter
77 | !Not [!Equals [ !Ref paramManagedPolicy, 'None'] ]
78 |
79 | ## =================== RESOURCES ===================
80 | Resources:
81 | myUser:
82 | Type: 'AWS::IAM::User'
83 | Properties:
84 | UserName: !Ref paramUserName # give a name to this user
85 | LoginProfile: # specify a password for this user
86 | Password: !Ref paramUserPassword
87 | PasswordResetRequired: true # make this user to set a new password on next sign-in
88 | Path: !Ref paramPath
89 | Groups: !If [ hasGroups, !Ref paramGroups, !Ref "AWS::NoValue"] # attach this user to the list of specified groups if any
90 | ManagedPolicyArns: # list of ARNs of IAM managed policies that you want to attach to the user
91 | - !If [ hasManagedPolicy, !FindInMap [ mapManagedPolicies, !Ref paramManagedPolicy, ARN], !Ref "AWS::NoValue" ] # find an ARN of specified paramManagedPolicy
92 | - arn:aws:iam::aws:policy/AWSCloud9Administrator # provides administrator access to AWS Cloud9
93 | # - arn:aws:iam::111111111111:policy/customerManagedEC2ReadOnlyPolicy # use your own customer managed policy
94 | Policies: # list of inline policy documents that are embedded in the user
95 | - PolicyName: inlineS3ReadOnlyPolicy # give a unique name to this policy
96 | PolicyDocument: # JSON policy document
97 | Version: '2012-10-17'
98 | Statement: # allow read only access to all S3 buckets
99 | - Effect: Allow
100 | Action:
101 | - 's3:Get*'
102 | - 's3:List*'
103 | Resource: '*'
104 | - PolicyName: inlineS3CreateBucketOnlyPolicy # give a unique name to this policy
105 | PolicyDocument: # JSON policy document
106 | Version: '2012-10-17'
107 | Statement: # allow create S3 bucket only access
108 | - Effect: Allow
109 | Action:
110 | - 's3:CreateBucket*'
111 | Resource: '*'
112 | Tags:
113 | - Key: Name
114 | Value: !Ref paramTagValue
115 |
116 | ## =================== OUTPUT ===================
117 | Outputs:
118 | outputName:
119 | Description: User name
120 | Value: !Ref myUser
121 | outputArn:
122 | Description: User ARN
123 | Value: !GetAtt myUser.Arn
--------------------------------------------------------------------------------
/Metadata/img-interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/Metadata/img-interface.png
--------------------------------------------------------------------------------
/Metadata/interface.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation sample template
6 | Playground for 'Metadata' section
7 | Group, sort and label parameters using ParameterGroups and ParameterLabels
8 |
9 | ## =================== METADATA =================== ##
10 | Metadata:
11 | AWS::CloudFormation::Interface:
12 | ParameterGroups: # specify group names, the parameters in each group, and the order in which the parameters are shown
13 | - Label:
14 | default: "EC2 Instance Configuration"
15 | Parameters: # order of parameters
16 | - paramAZ
17 | - paramInstanceType
18 | - paramImageId
19 | - paramEC2KeyPair
20 | - Label:
21 | default: "Environment Configuration"
22 | Parameters: # order of parameters
23 | - paramEnvironment
24 | ParameterLabels: # map parameters and their friendly names that CF console shows when a stack is created or updated
25 | paramEnvironment:
26 | default: "Which environment you want to create this instance in?"
27 | paramAZ:
28 | default: "Which AZ you want to create this instance in?"
29 | paramEC2KeyPair:
30 | default: "Be aware that once keyname is selected you can NOT change it unless instance replaced"
31 |
32 | ## =================== PARAMETERS =================== ##
33 | Parameters:
34 | paramEnvironment:
35 | Description: Select the environment
36 | Type: String
37 | Default: dev
38 | AllowedValues:
39 | - dev
40 | - prod
41 | ConstraintDescription: Must be development or production
42 | paramInstanceType:
43 | Description: Specify EC2 instance type
44 | Type: String
45 | AllowedValues:
46 | - t1.micro
47 | - t2.nano
48 | - t2.micro
49 | - t2.small
50 | - t2.medium
51 | Default: t2.micro # free tier eligible
52 | paramImageId:
53 | Description: Specify AMI Id for EC2 instance
54 | Type: String
55 | Default: ami-0be2609ba883822ec # for us-east-1, Amazon Linux, free tier eligible
56 | ConstraintDescription: Must be a valid AMI and based on Amazon Linux
57 | paramEC2KeyPair:
58 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
59 | Type: AWS::EC2::KeyPair::KeyName
60 | paramAZ:
61 | Description: Select AZ
62 | Type: String
63 | AllowedValues:
64 | - us-east-1a
65 | - us-east-1b
66 | - us-east-1c
67 | Default: us-east-1a
68 |
69 | ## =================== CONDITIONS =================== ##
70 | Conditions:
71 | isProd: !Equals [!Ref paramEnvironment, prod] # if 'prod' then TRUE, otherwise FALSE
72 |
73 | ## =================== RESOURCES =================== ##
74 | Resources:
75 | myEC2Instance: # create a new EC2 instance
76 | Type: 'AWS::EC2::Instance'
77 | Properties:
78 | ImageId: !Ref paramImageId
79 | InstanceType: !Ref paramInstanceType
80 | KeyName: !Ref paramEC2KeyPair
81 | AvailabilityZone: !Ref paramAZ
82 | SecurityGroups: !If [isProd, [!Ref mySSHSecurityGroup], !Ref 'AWS::NoValue'] # if PROD then attach SecurityGroups, otherwise ignore
83 | mySSHSecurityGroup: # create a new Security Group for SSH
84 | Type: 'AWS::EC2::SecurityGroup'
85 | Condition: isProd
86 | Properties:
87 | GroupDescription: Enable SSH access via port 22
88 | SecurityGroupIngress:
89 | - IpProtocol: tcp
90 | FromPort: '22'
91 | ToPort: '22'
92 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/NestedStacks/1-vpc-as-nested-stack.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation sample template.
6 | Create a custom VPC with a public subnet
7 |
8 | ## =================== PARAMETERS =================== ##
9 | Parameters:
10 | paramVpcCIDR:
11 | Description: Enter the IP range (CIDR notation) for VPC
12 | Type: String
13 | Default: 10.192.0.0/16
14 | paramPublicSubnetCIDR:
15 | Description: Enter the IP range (CIDR notation) for the public subnet in AZ A
16 | Type: String
17 | Default: 10.192.10.0/24
18 |
19 | ## =================== RESOURCES ===================
20 | Resources:
21 |
22 | myVPC: # Create a VPC
23 | Type: AWS::EC2::VPC
24 | Properties:
25 | CidrBlock: !Ref paramVpcCIDR
26 | EnableDnsSupport: true
27 | EnableDnsHostnames: true
28 |
29 | myInternetGateway: # Create a Internet Gateway
30 | Type: AWS::EC2::InternetGateway
31 |
32 | myVPCGatewayAttachment: # Attach the Internet Gateway to the VPC
33 | Type: AWS::EC2::VPCGatewayAttachment
34 | Properties:
35 | VpcId: !Ref myVPC
36 | InternetGatewayId: !Ref myInternetGateway
37 |
38 | myPublicRouteTable: # Create a public route table for the VPC (will be public once it is associated with the Internet Gateway)
39 | Type: AWS::EC2::RouteTable
40 | Properties:
41 | VpcId: !Ref myVPC
42 |
43 | myPublicRoute: # Associate the public route table with the Internet Gateway
44 | Type: AWS::EC2::Route
45 | DependsOn: myVPCGatewayAttachment
46 | Properties:
47 | RouteTableId: !Ref myPublicRouteTable
48 | DestinationCidrBlock: 0.0.0.0/0
49 | GatewayId: !Ref myInternetGateway
50 |
51 | myPublicSubnet: # Create a public subnet in AZ 1 (will be public once it is associated with public route table)
52 | Type: AWS::EC2::Subnet
53 | Properties:
54 | VpcId: !Ref myVPC
55 | AvailabilityZone: !Select [ 0, !GetAZs '' ] # AZ 1
56 | CidrBlock: !Ref paramPublicSubnetCIDR
57 | MapPublicIpOnLaunch: true
58 |
59 | myPublicSubnetRouteTableAssociation: # Associate the public route table with the public subnet in AZ 1
60 | Type: AWS::EC2::SubnetRouteTableAssociation
61 | Properties:
62 | RouteTableId: !Ref myPublicRouteTable
63 | SubnetId: !Ref myPublicSubnet
64 |
65 | ## =================== OUTPUTS =================== ##
66 | Outputs:
67 | outputVpcId:
68 | Description: VPC ID
69 | Value: !Ref myVPC
70 | outputPublicSubnetId:
71 | Description: Public subnet ID
72 | Value: !Ref myPublicSubnet
--------------------------------------------------------------------------------
/NestedStacks/2-sg-as-nested-stack.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation sample template.
6 | Create a custom VPC with a public subnet
7 |
8 | ## =================== PARAMETERS =================== ##
9 | Parameters:
10 | paramVpcId:
11 | Description: Select VPC ID for a new security group
12 | Type: AWS::EC2::VPC::Id
13 |
14 | ## =================== RESOURCES =================== ##
15 | Resources:
16 | mySecurityGroup:
17 | Type: AWS::EC2::SecurityGroup
18 | Properties:
19 | GroupDescription: Apps Security Group
20 | SecurityGroupIngress:
21 | - IpProtocol: tcp
22 | FromPort: '22'
23 | ToPort: '22'
24 | CidrIp: 0.0.0.0/0
25 | - IpProtocol: tcp
26 | FromPort: '8080'
27 | ToPort: '8080'
28 | CidrIp: 0.0.0.0/0
29 | VpcId: !Ref paramVpcId
30 |
31 | ## =================== OUTPUTS =================== ##
32 | Outputs:
33 | outputSecurityGroup:
34 | Description: Security Group ID
35 | Value: !Ref mySecurityGroup
--------------------------------------------------------------------------------
/NestedStacks/3-save-nested-stacks-in-s3/1-upload-files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/NestedStacks/3-save-nested-stacks-in-s3/1-upload-files.png
--------------------------------------------------------------------------------
/NestedStacks/3-save-nested-stacks-in-s3/2-make-file-public.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/NestedStacks/3-save-nested-stacks-in-s3/2-make-file-public.png
--------------------------------------------------------------------------------
/NestedStacks/3-save-nested-stacks-in-s3/3-test-file-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/NestedStacks/3-save-nested-stacks-in-s3/3-test-file-access.png
--------------------------------------------------------------------------------
/NestedStacks/3-save-nested-stacks-in-s3/README.md:
--------------------------------------------------------------------------------
1 | # Step 1
2 | Create a new S3 bucket by running a new CloudFormation stack from 'S3-bucket.yaml' template
3 |
4 | # Step 2
5 | From S3 Console, upload 2 nested stack templates to a newly created S3 bucket:
6 | - 1-vpc-as-nested-stack.yaml
7 | - 2-sg-as-nested-stack.yaml
8 | :eyes: Screenshot: 1-upload-files.png
9 |
10 | # Step 3
11 | From S3 Console, make both files publically accessable
12 | :eyes: Screenshot: 2-make-file-public.png
13 | Test if you can upload each file to your local machine
14 | :eyes: Screenshot: 3-test-file-access.png
--------------------------------------------------------------------------------
/NestedStacks/3-save-nested-stacks-in-s3/s3-bucket.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Creates a new S3 bucket with public acceess
7 |
8 | ## =================== RESOURCES =================== ##
9 | Resources:
10 | myS3Bucket:
11 | Type: AWS::S3::Bucket
12 | Properties:
13 | AccessControl: PublicRead
14 | BucketName: bucket-for-nested-stacks
15 | VersioningConfiguration:
16 | Status: Enabled
17 |
18 | ## =================== OUTPUTS =================== ##
19 | Outputs:
20 | outputsS3Bucket:
21 | Value: !Join ['', ['https://', !GetAtt [myS3Bucket, DomainName]]]
22 | Description: Domain Name of the Amazon S3 bucket
--------------------------------------------------------------------------------
/NestedStacks/4-ec2-as-root-stack.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation sample template.
6 | Create a custom VPC with a public subnet
7 |
8 | ## =================== PARAMETERS =================== ##
9 | Parameters:
10 | paramEC2KeyPair:
11 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
12 | Type: AWS::EC2::KeyPair::KeyName
13 | # the following paramaters are copied from '1-vpc-as-nested-stack' template
14 | paramVpcCIDR:
15 | Description: Enter the IP range (CIDR notation) for VPC
16 | Type: String
17 | Default: 10.192.0.0/16
18 | paramPublicSubnetCIDR:
19 | Description: Enter the IP range (CIDR notation) for the public subnet in AZ A
20 | Type: String
21 | Default: 10.192.10.0/24
22 |
23 | ## =================== RESOURCES =================== ##
24 | Resources:
25 |
26 | myVcpNestedStack: # refer to '1-vpc-as-nested-stack' template
27 | Type: AWS::CloudFormation::Stack
28 | Properties:
29 | TemplateURL: 'https://bucket-for-nested-stacks.s3.amazonaws.com/1-vpc-as-nested-stack.yaml'
30 | Parameters:
31 | paramVpcCIDR: !Ref paramVpcCIDR
32 | paramPublicSubnetCIDR: !Ref paramPublicSubnetCIDR
33 | TimeoutInMinutes: 5 # in minutes
34 | mySGNestedStack: # refer to '2-sg-as-nested-stack' template
35 | Type: AWS::CloudFormation::Stack
36 | Properties:
37 | TemplateURL: 'https://bucket-for-nested-stacks.s3.amazonaws.com/2-sg-as-nested-stack.yaml'
38 | Parameters:
39 | paramVpcId: !GetAtt myVcpNestedStack.Outputs.outputVpcId
40 | TimeoutInMinutes: 5 # in minutes
41 |
42 |
43 | myEC2Instance: # create a new EC2 instance
44 | Type: 'AWS::EC2::Instance'
45 | Properties:
46 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
47 | # ImageId: ami-047a51fa27710816e # Amazon Linux 2 64-bit x86, Free tier eligible
48 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
49 | InstanceType: t2.micro # Free tier eligible
50 | KeyName: !Ref paramEC2KeyPair
51 | NetworkInterfaces:
52 | - AssociatePublicIpAddress: "true"
53 | DeviceIndex: "0"
54 | SubnetId: !GetAtt myVcpNestedStack.Outputs.outputPublicSubnetId
55 | GroupSet:
56 | - !GetAtt mySGNestedStack.Outputs.outputSecurityGroup
57 | UserData:
58 | Fn::Base64: |
59 | #!/bin/bash
60 | sudo yum update
61 | sudo yum -y erase java-1.7.0-openjdk.x86_64
62 | sudo yum -y install java-1.8.0-openjdk.x86_64
63 | sudo yum -y install java-1.8.0-openjdk-devel
64 | sudo yum -y install tomcat8
65 | service tomcat8 start
66 | mkdir /usr/share/tomcat8/webapps/ROOT
67 | touch /usr/share/tomcat8/webapps/ROOT/index.html
68 | echo "Cloud Formation Tomcat8" > /usr/share/tomcat8/webapps/ROOT/index.html
69 |
70 | ## =================== OUTPUTS =================== ##
71 | Outputs:
72 | AppURL:
73 | Description: Application URL to access
74 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/index.html'
--------------------------------------------------------------------------------
/NestedStacks/final-results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/NestedStacks/final-results.png
--------------------------------------------------------------------------------
/Outputs/export-condition.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION ===================
2 | Description: >-
3 | AWS CloudFormation sample template
4 | Playground for 'Outputs' section - using Condition
5 | Attach SecurityGroups to EC2 instance and export it conditionally:
6 | - if PROD then attach and export
7 | - otherwise (if DEV) ingnore
8 |
9 | ## =================== PARAMETERS ===================
10 | Parameters:
11 | paramEnvironment: # ask a user to define whether it is 'dev' or 'prod' environment
12 | Description: Select the environment
13 | Type: String
14 | Default: dev # by default it is 'dev' environment
15 | AllowedValues:
16 | - dev
17 | - prod
18 | ConstraintDescription: Must be development or production
19 |
20 | ## =================== CONDITIONS ===================
21 | Conditions:
22 | isProd: !Equals [!Ref paramEnvironment, prod] # if 'prod' then TRUE, otherwise FALSE
23 |
24 | ## =================== RESOURCES ===================
25 | Resources:
26 |
27 | myEC2Instance: # create a new EC2 instance
28 | Type: 'AWS::EC2::Instance'
29 | Properties:
30 | ImageId: 'ami-0ff8a91507f77f867'
31 | InstanceType: t2.micro
32 | SecurityGroups: !If [isProd, [!Ref myHTTPSSecurityGroup], !Ref 'AWS::NoValue'] # if PROD then attach SecurityGroups, otherwise ignore
33 |
34 | myHTTPSSecurityGroup: # create a new Security Group for HTTPS only if PROD
35 | Type: 'AWS::EC2::SecurityGroup'
36 | Condition: isProd
37 | Properties:
38 | GroupDescription: Enable HTTPS access via port 443
39 | SecurityGroupIngress:
40 | - IpProtocol: tcp
41 | FromPort: '443'
42 | ToPort: '443'
43 | CidrIp: 0.0.0.0/0
44 |
45 | ## =================== OUTPUTS =================== ##
46 | Outputs:
47 | outputAZ:
48 | Description: Instance AZ
49 | Value: !GetAtt myEC2Instance.AvailabilityZone
50 | Export: #export
51 | Name: !Sub "${AWS::StackName}-InstanceAz-Exported"
52 | outputHTTPSSecurityGroup: # if PROD then export
53 | Description: My HTTPS SG
54 | Value: !Ref myHTTPSSecurityGroup
55 | Condition: isProd # only if PROD
56 | Export: #export
57 | Name: myHTTPSSecurityGroup-Exported
--------------------------------------------------------------------------------
/Outputs/export.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | Description: >-
5 | AWS CloudFormation Ec2InstanceWithSecurityGroup template
6 | Playground for 'Outputs' section - using Export
7 | Export EC2 instanceA's AZ and SecurityGroup from here
8 | First, create a stack from export.yaml template, then create a stack from import.yaml template
9 |
10 | ## =================== RESOURCES =================== ##
11 | Resources:
12 | myEC2InstanceA: # create a new EC2 instance
13 | Type: 'AWS::EC2::Instance'
14 | Properties:
15 | ImageId: 'ami-0be2609ba883822ec'
16 | InstanceType: t2.nano
17 | SecurityGroups:
18 | - !Ref mySSHSecurityGroup
19 | mySSHSecurityGroup: # create a new Security Group for SSH
20 | Type: 'AWS::EC2::SecurityGroup'
21 | Properties:
22 | GroupDescription: Enable SSH access via port 22
23 | SecurityGroupIngress:
24 | - IpProtocol: tcp
25 | FromPort: '22'
26 | ToPort: '22'
27 | CidrIp: 0.0.0.0/0
28 |
29 | ## =================== OUTPUTS =================== ##
30 | Outputs:
31 | outputAZ:
32 | Description: AZ of the newly created EC2 instance
33 | Value: !GetAtt myEC2InstanceA.AvailabilityZone
34 | Export: #export
35 | Name: myInstanceAZ-Exported
36 | outputSSHSecurityGroup:
37 | Description: My SSH SG
38 | Value: !Ref mySSHSecurityGroup
39 | Export: #export
40 | Name: mySSHSecurityGroup-Exported
--------------------------------------------------------------------------------
/Outputs/img-export-import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/Outputs/img-export-import.png
--------------------------------------------------------------------------------
/Outputs/import.yaml:
--------------------------------------------------------------------------------
1 | ## =================== DESCRIPTION =================== ##
2 | AWSTemplateFormatVersion: '2010-09-09'
3 |
4 | Description: >-
5 | AWS CloudFormation Ec2InstanceWithSecurityGroup template
6 | Playground for 'Outputs' section - using Ref::ImportValue
7 | Import EC2 instanceA's AZ and SecurityGroup here
8 | First, create a stack from export.yaml template, then create a stack from import.yaml template
9 |
10 | ## =================== RESOURCES =================== ##
11 | Resources:
12 | myEC2InstanceB: # create a new EC2 instance
13 | Type: 'AWS::EC2::Instance'
14 | Properties:
15 | ImageId: 'ami-0be2609ba883822ec'
16 | InstanceType: t2.nano
17 | SecurityGroups:
18 | - !ImportValue mySSHSecurityGroup-Exported # import SecurityGroup
19 | AvailabilityZone: !ImportValue myInstanceAZ-Exported # import AZ of instance A
20 |
21 | ## =================== OUTPUTS =================== ##
22 | Outputs:
23 | outputImportedAZ:
24 | Description: Imported AZ
25 | Value: !ImportValue myInstanceAZ-Exported
26 | outputImportedSSHSecurityGroup:
27 | Description: Imported SSH SG
28 | Value: !ImportValue mySSHSecurityGroup-Exported
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mastering-AWS-CloudFormation
2 |
--------------------------------------------------------------------------------
/StackPolicy/1-deny-resource-update.json:
--------------------------------------------------------------------------------
1 | {
2 | "Statement" : [
3 | {
4 | "Effect" : "Allow",
5 | "Action" : "Update:*",
6 | "Principal": "*",
7 | "Resource" : "*"
8 | },
9 | {
10 | "Effect" : "Deny",
11 | "Action" : "Update:*",
12 | "Principal": "*",
13 | "Resource" : "LogicalResourceId/MySecurityGroup"
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/StackPolicy/2-deny-resource-type-update.json:
--------------------------------------------------------------------------------
1 | {
2 | "Statement" : [
3 | {
4 | "Effect" : "Allow",
5 | "Action" : "Update:*",
6 | "Principal": "*",
7 | "Resource" : "*"
8 | },
9 | {
10 | "Effect" : "Deny",
11 | "Action" : "Update:*",
12 | "Principal": "*",
13 | "Resource" : "*",
14 | "Condition": {
15 | "StringEquals" : {
16 | "ResourceType": ["AWS::EC2::SecurityGroup"]
17 | }
18 | }
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/StackPolicy/3-deny-replacement-updates.json:
--------------------------------------------------------------------------------
1 | {
2 | "Statement" : [
3 | {
4 | "Effect" : "Allow",
5 | "Action" : "Update:*",
6 | "Principal": "*",
7 | "Resource" : "*"
8 | },
9 | {
10 | "Effect" : "Deny",
11 | "Action" : "Update:Replace",
12 | "Principal": "*",
13 | "Resource" : "LogicalResourceId/MyEc2Instance"
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/StackPolicy/4-not-action.json:
--------------------------------------------------------------------------------
1 | {
2 | "Statement" : [
3 | {
4 | "Effect" : "Allow",
5 | "NotAction" : "Update:Delete",
6 | "Principal": "*",
7 | "Resource" : "*"
8 | }
9 | ]
10 | }
--------------------------------------------------------------------------------
/StackPolicy/README.md:
--------------------------------------------------------------------------------
1 | # Deny resource updation
2 | File: 1-deny-resource-update.json
3 | Description: Deny stack update if MySecurityGroup resource should be updated. In other words, if ACTION in CloudFormation 'Change set preview' for MySecurityGroup resource is MODIFY, then deny stack updation.
4 |
5 | # Deny resource type updation
6 | File: 1-deny-resource-update.json
7 | Description: Deny stack update if at least one 'SecurityGroup' resource type should be updated. In other words, if ACTION in CloudFormation 'Change set preview' for at least one 'SecurityGroup' resource type is MODIFY, then deny stack updation.
8 |
9 | # Deny updation if resource should be replaced
10 | File: 3-deny-replacement-updates.json
11 | Description: Deny stack update if MyEc2Instance resource should be replaced by CloudFormation (e.g. when you add a new SecurityGroup to an existing EC2 instance, CloudFormation terminated this instance and create a new one). In other words, if REPLACEMENT in CloudFormation 'Change set preview' for MyEc2Instance resource is TRUE, then deny stack updation.
12 |
13 | # Deny updation if resource should be removed
14 | File: 4-not-action.json
15 | Description: Allow modify and replace but don't allow to delete resource. In other words, if ACTION in CloudFormation 'Change set preview' for any resource is REMOVE, then deny stack updation.
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/README.md:
--------------------------------------------------------------------------------
1 | # Step 1
2 | Create a new S3 bucket by running a new CloudFormation stack from 'S3-bucket.yaml' template
3 |
4 | # Step 2
5 | From S3 Console, upload two files to a newly created S3 bucket from 'WAR-Files' folder:
6 | - demo1.zip
7 | - demo2.zip
8 | :eyes: Screenshot: 1-upload-files.png
9 |
10 | # Step 3
11 | From S3 Console, make each file publically accessable
12 | :eyes: Screenshot: 2-make-file-public.png
13 | Test if you can upload both files to your local machine
14 | :eyes: Screenshot: 3-test-file-access.png
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/S3-bucket.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Creates a new S3 bucket with public acceess
7 |
8 | ## =================== RESOURCES =================== ##
9 | Resources:
10 | myS3Bucket:
11 | Type: AWS::S3::Bucket
12 | Properties:
13 | AccessControl: PublicRead
14 | BucketName: bucket-for-user-data-and-metadata-app
15 | VersioningConfiguration:
16 | Status: Enabled
17 |
18 | Outputs:
19 | outputsS3Bucket:
20 | Value: !Join ['', ['https://', !GetAtt [myS3Bucket, DomainName]]]
21 | Description: Domain Name of the Amazon S3 bucket
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/WAR-Files/demo1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/UserDataAndMetadata/0-source-code/WAR-Files/demo1.zip
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/WAR-Files/demo2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/UserDataAndMetadata/0-source-code/WAR-Files/demo2.zip
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/screenshots/1-upload-files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/UserDataAndMetadata/0-source-code/screenshots/1-upload-files.png
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/screenshots/2-make-file-public.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/UserDataAndMetadata/0-source-code/screenshots/2-make-file-public.png
--------------------------------------------------------------------------------
/UserDataAndMetadata/0-source-code/screenshots/3-test-file-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/UserDataAndMetadata/0-source-code/screenshots/3-test-file-access.png
--------------------------------------------------------------------------------
/UserDataAndMetadata/1-base.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 0. Follow README in '0-source-code' folder to create S3 bucket and upload source code there
8 | Step 1. Create EC2 intance with attached SG (with SSH and HTTP ports)
9 |
10 | ## =================== PARAMETERS =================== ##
11 | Parameters:
12 | paramEC2KeyPair:
13 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
14 | Type: AWS::EC2::KeyPair::KeyName
15 |
16 | ## =================== RESOURCES =================== ##
17 | Resources:
18 |
19 | myEC2Instance:
20 | Type: 'AWS::EC2::Instance'
21 | Properties:
22 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
23 | #ImageId: ami-047a51fa27710816e # amzn2-ami-hvm-2.0.20210126.0-x86_64-gp2 - ami-047a51fa27710816e - Amazon Linux 2 AMI 2.0.20210126.0 x86_64 HVM gp2, free tier eligible
24 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
25 | InstanceType: t2.micro # free tier eligible
26 | KeyName: !Ref paramEC2KeyPair
27 | SecurityGroups:
28 | - !Ref mySecurityGroup
29 |
30 | mySecurityGroup:
31 | Type: 'AWS::EC2::SecurityGroup'
32 | Properties:
33 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
34 | SecurityGroupIngress:
35 | - IpProtocol: tcp
36 | FromPort: '22'
37 | ToPort: '22'
38 | CidrIp: 0.0.0.0/0
39 | - IpProtocol: tcp
40 | FromPort: '8080'
41 | ToPort: '8080'
42 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/UserDataAndMetadata/2-metadata-schema.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 0. Follow README in '0-source-code' folder to create S3 bucket and upload source code there
8 | Step 1. Create EC2 intance with attached SG (with SSH and HTTP ports)
9 | Step 2. Include 'Metadata' section on EC2 instance for the cfn-init helper script
10 | - add AWS::CloudFormation::Init
11 | - add configuration sections: packages, groups, users, sources, files, commands, services
12 |
13 | ## =================== PARAMETERS =================== ##
14 | Parameters:
15 | paramEC2KeyPair:
16 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
17 | Type: AWS::EC2::KeyPair::KeyName
18 |
19 | ## =================== RESOURCES =================== ##
20 | Resources:
21 |
22 | myEC2Instance:
23 | Type: 'AWS::EC2::Instance'
24 | Metadata:
25 | Comment: Step 2. Include 'Metadata' section on EC2 instance
26 | AWS::CloudFormation::Init: # need it for cfn-init helper script
27 | config:
28 | # order matters: packages, groups, users, sources, files, commands, and then services
29 | # for different order need to use configSets and different config keys
30 | packages: # coming soon...
31 | groups: # coming soon...
32 | users: # coming soon...
33 | sources: # coming soon...
34 | files: # coming soon...
35 | commands: # coming soon...
36 | services: # coming soon...
37 | Properties:
38 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
39 | #ImageId: ami-047a51fa27710816e # amzn2-ami-hvm-2.0.20210126.0-x86_64-gp2 - ami-047a51fa27710816e - Amazon Linux 2 AMI 2.0.20210126.0 x86_64 HVM gp2, free tier eligible
40 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
41 | InstanceType: t2.micro # free tier eligible
42 | KeyName: !Ref paramEC2KeyPair
43 | SecurityGroups:
44 | - !Ref mySecurityGroup
45 |
46 | mySecurityGroup:
47 | Type: 'AWS::EC2::SecurityGroup'
48 | Properties:
49 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
50 | SecurityGroupIngress:
51 | - IpProtocol: tcp
52 | FromPort: '22'
53 | ToPort: '22'
54 | CidrIp: 0.0.0.0/0
55 | - IpProtocol: tcp
56 | FromPort: '8080'
57 | ToPort: '8080'
58 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/UserDataAndMetadata/3-metadata.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 0. Follow README in '0-source-code' folder to create S3 bucket and upload source code there
8 | Step 1. Create EC2 intance with attached SG (with SSH and HTTP ports)
9 | Step 2. Include 'Metadata' section on EC2 instance for the cfn-init helper script
10 | - add AWS::CloudFormation::Init
11 | - add configuration sections: packages, groups, users, sources, files, commands, services
12 | Step 3. Add logic for packages, groups, users, sources, files, commands, services
13 |
14 | AWS docs:
15 | - Metadata - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html
16 | - AWS::CloudFormation::Init - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html
17 |
18 |
19 | ## =================== PARAMETERS =================== ##
20 | Parameters:
21 | paramEC2KeyPair:
22 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
23 | Type: AWS::EC2::KeyPair::KeyName
24 |
25 | ## =================== RESOURCES =================== ##
26 | Resources:
27 |
28 | myEC2Instance:
29 | Type: 'AWS::EC2::Instance'
30 | Metadata:
31 | Comment: Step 3. Add logic for packages, groups, users, sources, files, commands, ser
32 | AWS::CloudFormation::Init: # need it for cfn-init helper script
33 | config:
34 | # order matters: packages, groups, users, sources, files, commands, and then services
35 | # for different order you need to use configSets and different config keys
36 | packages: # use to download and install pre-packaged apps and components
37 | # supports: yum, apt, msi, python, rpm, rubygems
38 | yum:
39 | # install 3 packages
40 | java-1.8.0-openjdk.x86_64: []
41 | java-1.8.0-openjdk-devel: []
42 | tomcat8: []
43 | groups: # for Linux/Unix groups (not for Windows)
44 | groupone: {}
45 | grouptwo:
46 | gid: "501"
47 | users: # use the users key to create Linux/UNIX users on the EC2 instance (not for Windows)
48 | user1:
49 | groups:
50 | - groupone
51 | - grouptwo
52 | uid: "501"
53 | homeDir: "/home"
54 | sources: # use to download and unpack file in a target directory on the EC2 instance (for both Linux and Windows))
55 | # use S3 bucket url which output of '0-source-code/S3-bucket.yaml' template
56 | /tmp: "https://bucket-for-user-data-and-metadata-app.s3.amazonaws.com/demo1.zip"
57 | files: # use to create files on the EC2 instance
58 | "/etc/cfn/cfn-hup.conf": # cfn-hup
59 | content: !Sub |
60 | [main]
61 | stack=${AWS::StackId}
62 | region=${AWS::Region}
63 | interval=7
64 | mode: "000400"
65 | owner: "root"
66 | group: "root"
67 | "/etc/cfn/hooks.d/cfn-auto-reloader.conf": # cfn-auto-reloader
68 | content: !Sub |
69 | [cfn-auto-reloader-hook]
70 | triggers=post.update
71 | path=Resources.myEC2Instance.Metadata.AWS::CloudFormation::Init
72 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource myEC2Instance --region ${AWS::Region}
73 | mode: "000400"
74 | owner: "root"
75 | group: "root"
76 | commands: # use to execute commands on the EC2 instance
77 | test1:
78 | command: "chmod 755 demo.war"
79 | cwd: "/tmp"
80 | test2:
81 | command: "sudo yum -y erase java-1.7.0-openjdk.x86_64"
82 | cwd: "~"
83 | test3:
84 | command: "rm -rf demo*"
85 | cwd: "/var/lib/tomcat8/webapps"
86 | test4:
87 | command: "cp demo.war /var/lib/tomcat8/webapps"
88 | cwd: "/tmp"
89 | services: # use to define which services should be enabled or disabled when the instance is launched
90 | sysvinit:
91 | tomcat8:
92 | enabled: "true"
93 | ensureRunning: "true"
94 | Properties:
95 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
96 | #ImageId: ami-047a51fa27710816e # amzn2-ami-hvm-2.0.20210126.0-x86_64-gp2 - ami-047a51fa27710816e - Amazon Linux 2 AMI 2.0.20210126.0 x86_64 HVM gp2, free tier eligible
97 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
98 | InstanceType: t2.micro # free tier eligible
99 | KeyName: !Ref paramEC2KeyPair
100 | SecurityGroups:
101 | - !Ref mySecurityGroup
102 |
103 | mySecurityGroup:
104 | Type: 'AWS::EC2::SecurityGroup'
105 | Properties:
106 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
107 | SecurityGroupIngress:
108 | - IpProtocol: tcp
109 | FromPort: '22'
110 | ToPort: '22'
111 | CidrIp: 0.0.0.0/0
112 | - IpProtocol: tcp
113 | FromPort: '8080'
114 | ToPort: '8080'
115 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/UserDataAndMetadata/4-userdata.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 0. Follow README in '0-source-code' folder to create S3 bucket and upload source code there
8 | Step 1. Create EC2 intance with attached SG (with SSH and HTTP ports)
9 | Step 2. Include 'Metadata' section on EC2 instance for the cfn-init helper script
10 | - add AWS::CloudFormation::Init
11 | - add configuration sections: packages, groups, users, sources, files, commands, services
12 | Step 3. Add logic for packages, groups, users, sources, files, commands, services
13 | Step 4. Create UserData for EC2 instance that uses Metadata config data from AWS::CloudFormation::Init section
14 |
15 | AWS docs:
16 | - Metadata - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html
17 | - AWS::CloudFormation::Init - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html
18 |
19 | ## =================== PARAMETERS =================== ##
20 | Parameters:
21 | paramEC2KeyPair:
22 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
23 | Type: AWS::EC2::KeyPair::KeyName
24 |
25 | ## =================== RESOURCES =================== ##
26 | Resources:
27 |
28 | myEC2Instance:
29 | Type: 'AWS::EC2::Instance'
30 | Metadata:
31 | Comment: Step 3. Add logic for packages, groups, users, sources, files, commands, ser
32 | AWS::CloudFormation::Init: # need it for cfn-init helper script
33 | config:
34 | # order matters: packages, groups, users, sources, files, commands, and then services
35 | # for different order you need to use configSets and different config keys
36 | packages: # use to download and install pre-packaged apps and components
37 | # supports: yum, apt, msi, python, rpm, rubygems
38 | yum:
39 | # install 3 packages
40 | java-1.8.0-openjdk.x86_64: []
41 | java-1.8.0-openjdk-devel: []
42 | tomcat8: []
43 | groups: # for Linux/Unix groups (not for Windows)
44 | groupone: {}
45 | grouptwo:
46 | gid: "501"
47 | users: # use the users key to create Linux/UNIX users on the EC2 instance (not for Windows)
48 | user1:
49 | groups:
50 | - groupone
51 | - grouptwo
52 | uid: "501"
53 | homeDir: "/home"
54 | sources: # use to download and unpack file in a target directory on the EC2 instance (for both Linux and Windows))
55 | # use S3 bucket url which output of '0-source-code/S3-bucket.yaml' template
56 | /tmp: "https://bucket-for-user-data-and-metadata-app.s3.amazonaws.com/demo1.zip"
57 | files: # use to create files on the EC2 instance
58 | "/etc/cfn/cfn-hup.conf": # cfn-hup
59 | content: !Sub |
60 | [main]
61 | stack=${AWS::StackId}
62 | region=${AWS::Region}
63 | interval=7
64 | mode: "000400"
65 | owner: "root"
66 | group: "root"
67 | "/etc/cfn/hooks.d/cfn-auto-reloader.conf": # cfn-auto-reloader
68 | content: !Sub |
69 | [cfn-auto-reloader-hook]
70 | triggers=post.update
71 | path=Resources.myEC2Instance.Metadata.AWS::CloudFormation::Init
72 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource myEC2Instance --region ${AWS::Region}
73 | mode: "000400"
74 | owner: "root"
75 | group: "root"
76 | commands: # use to execute commands on the EC2 instance
77 | test1:
78 | command: "chmod 755 demo.war"
79 | cwd: "/tmp"
80 | test2:
81 | command: "sudo yum -y erase java-1.7.0-openjdk.x86_64"
82 | cwd: "~"
83 | test3:
84 | command: "rm -rf demo*"
85 | cwd: "/var/lib/tomcat8/webapps"
86 | test4:
87 | command: "cp demo.war /var/lib/tomcat8/webapps"
88 | cwd: "/tmp"
89 | services: # use to define which services should be enabled or disabled when the instance is launched
90 | sysvinit:
91 | tomcat8:
92 | enabled: "true"
93 | ensureRunning: "true"
94 | Properties:
95 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
96 | #ImageId: ami-047a51fa27710816e # amzn2-ami-hvm-2.0.20210126.0-x86_64-gp2 - ami-047a51fa27710816e - Amazon Linux 2 AMI 2.0.20210126.0 x86_64 HVM gp2, free tier eligible
97 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
98 | InstanceType: t2.micro # free tier eligible
99 | KeyName: !Ref paramEC2KeyPair
100 | SecurityGroups:
101 | - !Ref mySecurityGroup
102 | UserData: # add userdata that uses AWS::CloudFormation::Init config data
103 | "Fn::Base64":
104 | !Sub |
105 | #!/bin/bash -xe
106 | # Get latest CloudFormation package - these packages change frequently
107 | yum update -y aws-cfn-bootstrap
108 | # Start cfn-init to install all Metadata content (packages, sources, files, commands and services)
109 | /opt/aws/bin/cfn-init -s ${AWS::StackId} -r myEC2Instance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'
110 | # Signal the status from cfn-init
111 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource myEC2Instance --region ${AWS::Region}
112 | # Start cfn-hup daemon so that it will keep listening to any changes to EC2 Instance Metadata.
113 | /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
114 |
115 | mySecurityGroup:
116 | Type: 'AWS::EC2::SecurityGroup'
117 | Properties:
118 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
119 | SecurityGroupIngress:
120 | - IpProtocol: tcp
121 | FromPort: '22'
122 | ToPort: '22'
123 | CidrIp: 0.0.0.0/0
124 | - IpProtocol: tcp
125 | FromPort: '8080'
126 | ToPort: '8080'
127 | CidrIp: 0.0.0.0/0
--------------------------------------------------------------------------------
/UserDataAndMetadata/5-outputs.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 0. Follow README in '0-source-code' folder to create S3 bucket and upload source code there
8 | Step 1. Create EC2 intance with attached SG (with SSH and HTTP ports)
9 | Step 2. Include 'Metadata' section on EC2 instance for the cfn-init helper script
10 | - add AWS::CloudFormation::Init
11 | - add configuration sections: packages, groups, users, sources, files, commands, services
12 | Step 3. Add logic for packages, groups, users, sources, files, commands, services
13 | Step 4. Create UserData for EC2 instance that uses Metadata config data from AWS::CloudFormation::Init section
14 | Step 5. Add 'Outputs' section with app url
15 |
16 | AWS docs:
17 | - Metadata - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html
18 | - AWS::CloudFormation::Init - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html
19 |
20 | ## =================== PARAMETERS =================== ##
21 | Parameters:
22 | paramEC2KeyPair:
23 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
24 | Type: AWS::EC2::KeyPair::KeyName
25 |
26 | ## =================== RESOURCES =================== ##
27 | Resources:
28 |
29 | myEC2Instance:
30 | Type: 'AWS::EC2::Instance'
31 | Metadata:
32 | Comment: Step 3. Add logic for packages, groups, users, sources, files, commands, ser
33 | AWS::CloudFormation::Init: # need it for cfn-init helper script
34 | config:
35 | # order matters: packages, groups, users, sources, files, commands, and then services
36 | # for different order you need to use configSets and different config keys
37 | packages: # use to download and install pre-packaged apps and components
38 | # supports: yum, apt, msi, python, rpm, rubygems
39 | yum:
40 | # install 3 packages
41 | java-1.8.0-openjdk.x86_64: []
42 | java-1.8.0-openjdk-devel: []
43 | tomcat8: []
44 | groups: # for Linux/Unix groups (not for Windows)
45 | groupone: {}
46 | grouptwo:
47 | gid: "501"
48 | users: # use the users key to create Linux/UNIX users on the EC2 instance (not for Windows)
49 | user1:
50 | groups:
51 | - groupone
52 | - grouptwo
53 | uid: "501"
54 | homeDir: "/home"
55 | sources: # use to download and unpack file in a target directory on the EC2 instance (for both Linux and Windows))
56 | # use S3 bucket url which output of '0-source-code/S3-bucket.yaml' template
57 | /tmp: "https://bucket-for-user-data-and-metadata-app.s3.amazonaws.com/demo1.zip"
58 | files: # use to create files on the EC2 instance
59 | "/etc/cfn/cfn-hup.conf": # cfn-hup
60 | content: !Sub |
61 | [main]
62 | stack=${AWS::StackId}
63 | region=${AWS::Region}
64 | interval=7
65 | mode: "000400"
66 | owner: "root"
67 | group: "root"
68 | "/etc/cfn/hooks.d/cfn-auto-reloader.conf": # cfn-auto-reloader
69 | content: !Sub |
70 | [cfn-auto-reloader-hook]
71 | triggers=post.update
72 | path=Resources.myEC2Instance.Metadata.AWS::CloudFormation::Init
73 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource myEC2Instance --region ${AWS::Region}
74 | mode: "000400"
75 | owner: "root"
76 | group: "root"
77 | commands: # use to execute commands on the EC2 instance
78 | test1:
79 | command: "chmod 755 demo.war"
80 | cwd: "/tmp"
81 | test2:
82 | command: "sudo yum -y erase java-1.7.0-openjdk.x86_64"
83 | cwd: "~"
84 | test3:
85 | command: "rm -rf demo*"
86 | cwd: "/var/lib/tomcat8/webapps"
87 | test4:
88 | command: "cp demo.war /var/lib/tomcat8/webapps"
89 | cwd: "/tmp"
90 | services: # use to define which services should be enabled or disabled when the instance is launched
91 | sysvinit:
92 | tomcat8:
93 | enabled: "true"
94 | ensureRunning: "true"
95 | Properties:
96 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
97 | #ImageId: ami-047a51fa27710816e # amzn2-ami-hvm-2.0.20210126.0-x86_64-gp2 - ami-047a51fa27710816e - Amazon Linux 2 AMI 2.0.20210126.0 x86_64 HVM gp2, free tier eligible
98 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
99 | InstanceType: t2.micro # free tier eligible
100 | KeyName: !Ref paramEC2KeyPair
101 | SecurityGroups:
102 | - !Ref mySecurityGroup
103 | UserData: # add userdata that uses AWS::CloudFormation::Init config data
104 | "Fn::Base64":
105 | !Sub |
106 | #!/bin/bash -xe
107 | # Get latest CloudFormation package - these packages change frequently
108 | yum update -y aws-cfn-bootstrap
109 | # Start cfn-init to install all Metadata content (packages, sources, files, commands and services)
110 | /opt/aws/bin/cfn-init -s ${AWS::StackId} -r myEC2Instance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'
111 | # Signal the status from cfn-init
112 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource myEC2Instance --region ${AWS::Region}
113 | # Start cfn-hup daemon so that it will keep listening to any changes to EC2 Instance Metadata.
114 | /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
115 |
116 | mySecurityGroup:
117 | Type: 'AWS::EC2::SecurityGroup'
118 | Properties:
119 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
120 | SecurityGroupIngress:
121 | - IpProtocol: tcp
122 | FromPort: '22'
123 | ToPort: '22'
124 | CidrIp: 0.0.0.0/0
125 | - IpProtocol: tcp
126 | FromPort: '8080'
127 | ToPort: '8080'
128 | CidrIp: 0.0.0.0/0
129 |
130 | ## =================== OUTPUTS =================== ##
131 | Outputs:
132 | outputAppURL:
133 | Description: Application URL to access
134 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/demo/hello'
--------------------------------------------------------------------------------
/UserDataAndMetadata/6-creationPolicy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tiamatt/Mastering-AWS-CloudFormation/4d11a23db5b2d2210b47ff0f32647196bc16bcb2/UserDataAndMetadata/6-creationPolicy.png
--------------------------------------------------------------------------------
/UserDataAndMetadata/6-creationPolicy.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 0. Follow README in '0-source-code' folder to create S3 bucket and upload source code there
8 | Step 1. Create EC2 intance with attached SG (with SSH and HTTP ports)
9 | Step 2. Include 'Metadata' section on EC2 instance for the cfn-init helper script
10 | - add AWS::CloudFormation::Init
11 | - add configuration sections: packages, groups, users, sources, files, commands, services
12 | Step 3. Add logic for packages, groups, users, sources, files, commands, services
13 | Step 4. Create UserData for EC2 instance that uses Metadata config data from AWS::CloudFormation::Init section
14 | Step 5. Add 'Outputs' section with app url
15 | Step 6. Add CreationPolicy attribute that helps to prevent instance status from reaching create complete until AWS CloudFormation receives a specified number of success signals or the timeout period is exceeded
16 |
17 |
18 | # AWS docs:
19 | # - Metadata - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html
20 | # - AWS::CloudFormation::Init - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html
21 | # - CreationPolicy attribute - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html
22 |
23 | ## =================== PARAMETERS =================== ##
24 | Parameters:
25 | paramEC2KeyPair:
26 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
27 | Type: AWS::EC2::KeyPair::KeyName
28 |
29 | ## =================== RESOURCES =================== ##
30 | Resources:
31 |
32 | myEC2Instance:
33 | Type: 'AWS::EC2::Instance'
34 | CreationPolicy: # prevent instance status from reaching create complete until AWS CloudFormation receives a specified number of success signals or the timeout period is exceeded
35 | ResourceSignal:
36 | Timeout: PT5M # wait 5 mins
37 | Metadata:
38 | Comment: Step 3. Add logic for packages, groups, users, sources, files, commands, ser
39 | AWS::CloudFormation::Init: # need it for cfn-init helper script
40 | config:
41 | # order matters: packages, groups, users, sources, files, commands, and then services
42 | # for different order you need to use configSets and different config keys
43 | packages: # use to download and install pre-packaged apps and components
44 | # supports: yum, apt, msi, python, rpm, rubygems
45 | yum:
46 | # install 3 packages
47 | java-1.8.0-openjdk.x86_64: []
48 | java-1.8.0-openjdk-devel: []
49 | tomcat8: []
50 | groups: # for Linux/Unix groups (not for Windows)
51 | groupone: {}
52 | grouptwo:
53 | gid: "501"
54 | users: # use the users key to create Linux/UNIX users on the EC2 instance (not for Windows)
55 | user1:
56 | groups:
57 | - groupone
58 | - grouptwo
59 | uid: "501"
60 | homeDir: "/home"
61 | sources: # use to download and unpack file in a target directory on the EC2 instance (for both Linux and Windows))
62 | # use S3 bucket url which output of '0-source-code/S3-bucket.yaml' template
63 | /tmp: "https://bucket-for-user-data-and-metadata-app.s3.amazonaws.com/demo1.zip"
64 | files: # use to create files on the EC2 instance
65 | "/etc/cfn/cfn-hup.conf": # cfn-hup
66 | content: !Sub |
67 | [main]
68 | stack=${AWS::StackId}
69 | region=${AWS::Region}
70 | interval=7
71 | mode: "000400"
72 | owner: "root"
73 | group: "root"
74 | "/etc/cfn/hooks.d/cfn-auto-reloader.conf": # cfn-auto-reloader
75 | content: !Sub |
76 | [cfn-auto-reloader-hook]
77 | triggers=post.update
78 | path=Resources.myEC2Instance.Metadata.AWS::CloudFormation::Init
79 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource myEC2Instance --region ${AWS::Region}
80 | mode: "000400"
81 | owner: "root"
82 | group: "root"
83 | commands: # use to execute commands on the EC2 instance
84 | test1:
85 | command: "chmod 755 demo.war"
86 | cwd: "/tmp"
87 | test2:
88 | command: "sudo yum -y erase java-1.7.0-openjdk.x86_64"
89 | cwd: "~"
90 | test3:
91 | command: "rm -rf demo*"
92 | cwd: "/var/lib/tomcat8/webapps"
93 | test4:
94 | command: "cp demo.war /var/lib/tomcat8/webapps"
95 | cwd: "/tmp"
96 | services: # use to define which services should be enabled or disabled when the instance is launched
97 | sysvinit:
98 | tomcat8:
99 | enabled: "true"
100 | ensureRunning: "true"
101 | Properties:
102 | # Kalyan Reddy: If you are using Linux AMI 2-series, mostly it might not work because AWS has done lot and lot of changes from AMI-1 to AMI-2 series VMs
103 | #ImageId: ami-047a51fa27710816e # amzn2-ami-hvm-2.0.20210126.0-x86_64-gp2 - ami-047a51fa27710816e - Amazon Linux 2 AMI 2.0.20210126.0 x86_64 HVM gp2, free tier eligible
104 | ImageId: ami-0080e4c5bc078760e # amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2 - Amazon Linux AMI 2018.03.0.20181129 x86_64 HVM gp2
105 | InstanceType: t2.micro # free tier eligible
106 | KeyName: !Ref paramEC2KeyPair
107 | SecurityGroups:
108 | - !Ref mySecurityGroup
109 | UserData: # add userdata that uses AWS::CloudFormation::Init config data
110 | "Fn::Base64":
111 | !Sub |
112 | #!/bin/bash -xe
113 | # Get latest CloudFormation package - these packages change frequently
114 | yum update -y aws-cfn-bootstrap
115 | # Start cfn-init to install all Metadata content (packages, sources, files, commands and services)
116 | /opt/aws/bin/cfn-init -s ${AWS::StackId} -r myEC2Instance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'
117 | # Signal the status from cfn-init
118 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource myEC2Instance --region ${AWS::Region}
119 | # Start cfn-hup daemon so that it will keep listening to any changes to EC2 Instance Metadata.
120 | /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
121 |
122 | mySecurityGroup:
123 | Type: 'AWS::EC2::SecurityGroup'
124 | Properties:
125 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
126 | SecurityGroupIngress:
127 | - IpProtocol: tcp
128 | FromPort: '22'
129 | ToPort: '22'
130 | CidrIp: 0.0.0.0/0
131 | - IpProtocol: tcp
132 | FromPort: '8080'
133 | ToPort: '8080'
134 | CidrIp: 0.0.0.0/0
135 |
136 | ## =================== OUTPUTS =================== ##
137 | Outputs:
138 | outputAppURL:
139 | Description: Application URL to access
140 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/demo/hello'
--------------------------------------------------------------------------------
/UserDataAndMetadata/7-configSet-single.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 7. Group metadata config keys into configsets. Add config for App1 and App2
8 |
9 | ## =================== PARAMETERS =================== ##
10 | Parameters:
11 | paramEC2KeyPair:
12 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
13 | Type: AWS::EC2::KeyPair::KeyName
14 |
15 | ## =================== RESOURCES =================== ##
16 | Resources:
17 |
18 | myEC2Instance:
19 | Type: 'AWS::EC2::Instance'
20 | CreationPolicy:
21 | ResourceSignal:
22 | Timeout: PT5M
23 | Metadata:
24 | Comment: Step 3. Add logic for packages, groups, users, sources, files, commands, ser
25 | AWS::CloudFormation::Init:
26 | configSets:
27 | App1AndApp2:
28 | - App1
29 | - App2
30 | App1: # config settings for App1
31 | packages:
32 | yum:
33 | java-1.8.0-openjdk.x86_64: []
34 | java-1.8.0-openjdk-devel: []
35 | tomcat8: []
36 | groups:
37 | groupone: {}
38 | grouptwo:
39 | gid: "501"
40 | users:
41 | user1:
42 | groups:
43 | - groupone
44 | - grouptwo
45 | uid: "501"
46 | homeDir: "/home"
47 | sources:
48 | /tmp: "https://bucket-for-user-data-and-metadata-app.s3.amazonaws.com/demo1.zip"
49 | files:
50 | "/etc/cfn/cfn-hup.conf":
51 | content: !Sub |
52 | [main]
53 | stack=${AWS::StackId}
54 | region=${AWS::Region}
55 | interval=7
56 | mode: "000400"
57 | owner: "root"
58 | group: "root"
59 | "/etc/cfn/hooks.d/cfn-auto-reloader.conf":
60 | content: !Sub |
61 | [cfn-auto-reloader-hook]
62 | triggers=post.update
63 | path=Resources.myEC2Instance.Metadata.AWS::CloudFormation::Init
64 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource myEC2Instance --region ${AWS::Region}
65 | mode: "000400"
66 | owner: "root"
67 | group: "root"
68 | commands:
69 | test1:
70 | command: "chmod 755 demo.war"
71 | cwd: "/tmp"
72 | test2:
73 | command: "sudo yum -y erase java-1.7.0-openjdk.x86_64"
74 | cwd: "~"
75 | test3:
76 | command: "rm -rf demo*"
77 | cwd: "/var/lib/tomcat8/webapps"
78 | test4:
79 | command: "cp demo.war /var/lib/tomcat8/webapps"
80 | cwd: "/tmp"
81 | services:
82 | sysvinit:
83 | tomcat8:
84 | enabled: "true"
85 | ensureRunning: "true"
86 | App2: # config settings for App2 (create a simple html page)
87 | commands:
88 | test1:
89 | command: "mkdir ROOT"
90 | cwd: "/var/lib/tomcat8/webapps"
91 | test2:
92 | command: "echo \"$INDEXCONTENT\" > index.html"
93 | env:
94 | INDEXCONTENT: "Root Page of tomcat from App2"
95 | cwd: "/var/lib/tomcat8/webapps/ROOT"
96 | Properties:
97 | ImageId: ami-0080e4c5bc078760e
98 | InstanceType: t2.micro
99 | KeyName: !Ref paramEC2KeyPair
100 | SecurityGroups:
101 | - !Ref mySecurityGroup
102 | UserData: # in '/opt/aws/bin/cfn-init' section add '--configsets App1AndApp2' right after instance's logical ID
103 | "Fn::Base64":
104 | !Sub |
105 | #!/bin/bash -xe
106 | # Get latest CloudFormation package - these packages change frequently
107 | yum update -y aws-cfn-bootstrap
108 | # Start cfn-init to install all Metadata content (packages, sources, files, commands and services)
109 | /opt/aws/bin/cfn-init -s ${AWS::StackId} -r myEC2Instance --configsets App1AndApp2 --region ${AWS::Region} || error_exit 'Failed to run cfn-init'
110 | # Signal the status from cfn-init
111 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource myEC2Instance --region ${AWS::Region}
112 | # Start cfn-hup daemon so that it will keep listening to any changes to EC2 Instance Metadata.
113 | /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
114 |
115 | mySecurityGroup:
116 | Type: 'AWS::EC2::SecurityGroup'
117 | Properties:
118 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
119 | SecurityGroupIngress:
120 | - IpProtocol: tcp
121 | FromPort: '22'
122 | ToPort: '22'
123 | CidrIp: 0.0.0.0/0
124 | - IpProtocol: tcp
125 | FromPort: '8080'
126 | ToPort: '8080'
127 | CidrIp: 0.0.0.0/0
128 |
129 | ## =================== OUTPUTS =================== ##
130 | Outputs:
131 | outputApp1URL: # for App1
132 | Description: App1 URL to access
133 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/demo/hello'
134 | outputApp2URL: # for App2
135 | Description: App2 URL to access
136 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/index.html'
--------------------------------------------------------------------------------
/UserDataAndMetadata/8-configSet-multiple.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 |
3 | ## =================== DESCRIPTION =================== ##
4 | Description: >-
5 | AWS CloudFormation template
6 | Playground for 'userDataAndMetadata'
7 | Step 8. Add multiple config sets:
8 | - SingleAppConfigSet: # for App1 only
9 | - DualAppsConfigSet: # for both App1 and App2
10 | - defaut: # for App2 only
11 | Now, go to UserData section, find '/opt/aws/bin/cfn-init' line:
12 | - for SingleAppConfigSet use '--configsets SingleAppConfigSet'
13 | - for DualAppsConfigSet use '--configsets DualAppsConfigSet'
14 | - for defaut remove '--configsets BlahBlah'
15 | save and run the template!
16 |
17 | ## =================== PARAMETERS =================== ##
18 | Parameters:
19 | paramEC2KeyPair:
20 | Description: Specify an EC2 KeyPair to enable SSH access to the instance
21 | Type: AWS::EC2::KeyPair::KeyName
22 |
23 | ## =================== RESOURCES =================== ##
24 | Resources:
25 |
26 | myEC2Instance:
27 | Type: 'AWS::EC2::Instance'
28 | CreationPolicy:
29 | ResourceSignal:
30 | Timeout: PT5M
31 | Metadata:
32 | Comment: Step 3. Add logic for packages, groups, users, sources, files, commands, ser
33 | AWS::CloudFormation::Init:
34 | configSets: # add 3 config sets - SingleAppConfigSet, DualAppsConfigSet, and defaut
35 | SingleAppConfigSet: # App1 only
36 | - App1
37 | DualAppsConfigSet: # both App1 and App2
38 | - ConfigSet: "SingleAppConfigSet"
39 | - App2
40 | defaut: # App2 only
41 | - ConfigSet: "DualAppsConfigSet"
42 | App1: # config settings for App1
43 | packages:
44 | yum:
45 | java-1.8.0-openjdk.x86_64: []
46 | java-1.8.0-openjdk-devel: []
47 | tomcat8: []
48 | groups:
49 | groupone: {}
50 | grouptwo:
51 | gid: "501"
52 | users:
53 | user1:
54 | groups:
55 | - groupone
56 | - grouptwo
57 | uid: "501"
58 | homeDir: "/home"
59 | sources:
60 | /tmp: "https://bucket-for-user-data-and-metadata-app.s3.amazonaws.com/demo1.zip"
61 | files:
62 | "/etc/cfn/cfn-hup.conf":
63 | content: !Sub |
64 | [main]
65 | stack=${AWS::StackId}
66 | region=${AWS::Region}
67 | interval=7
68 | mode: "000400"
69 | owner: "root"
70 | group: "root"
71 | "/etc/cfn/hooks.d/cfn-auto-reloader.conf":
72 | content: !Sub |
73 | [cfn-auto-reloader-hook]
74 | triggers=post.update
75 | path=Resources.myEC2Instance.Metadata.AWS::CloudFormation::Init
76 | action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource myEC2Instance --region ${AWS::Region}
77 | mode: "000400"
78 | owner: "root"
79 | group: "root"
80 | commands:
81 | test1:
82 | command: "chmod 755 demo.war"
83 | cwd: "/tmp"
84 | test2:
85 | command: "sudo yum -y erase java-1.7.0-openjdk.x86_64"
86 | cwd: "~"
87 | test3:
88 | command: "rm -rf demo*"
89 | cwd: "/var/lib/tomcat8/webapps"
90 | test4:
91 | command: "cp demo.war /var/lib/tomcat8/webapps"
92 | cwd: "/tmp"
93 | services:
94 | sysvinit:
95 | tomcat8:
96 | enabled: "true"
97 | ensureRunning: "true"
98 | App2: # config settings for App2 (create a simple html page)
99 | commands:
100 | test1:
101 | command: "mkdir ROOT"
102 | cwd: "/var/lib/tomcat8/webapps"
103 | test2:
104 | command: "echo \"$INDEXCONTENT\" > index.html"
105 | env:
106 | INDEXCONTENT: "Root Page of tomcat from App2"
107 | cwd: "/var/lib/tomcat8/webapps/ROOT"
108 | Properties:
109 | ImageId: ami-0080e4c5bc078760e
110 | InstanceType: t2.micro
111 | KeyName: !Ref paramEC2KeyPair
112 | SecurityGroups:
113 | - !Ref mySecurityGroup
114 | UserData: # in '/opt/aws/bin/cfn-init' section add '--configsets SingleAppConfigSet' right after instance's logical ID
115 | "Fn::Base64":
116 | !Sub |
117 | #!/bin/bash -xe
118 | # Get latest CloudFormation package - these packages change frequently
119 | yum update -y aws-cfn-bootstrap
120 | # Start cfn-init to install all Metadata content (packages, sources, files, commands and services)
121 | /opt/aws/bin/cfn-init -s ${AWS::StackId} -r myEC2Instance --configsets DualAppsConfigSet --region ${AWS::Region} || error_exit 'Failed to run cfn-init'
122 | # Signal the status from cfn-init
123 | /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource myEC2Instance --region ${AWS::Region}
124 | # Start cfn-hup daemon so that it will keep listening to any changes to EC2 Instance Metadata.
125 | /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'
126 |
127 | mySecurityGroup:
128 | Type: 'AWS::EC2::SecurityGroup'
129 | Properties:
130 | GroupDescription: Enable SSH and HTTP access via port 22 and 8080
131 | SecurityGroupIngress:
132 | - IpProtocol: tcp
133 | FromPort: '22'
134 | ToPort: '22'
135 | CidrIp: 0.0.0.0/0
136 | - IpProtocol: tcp
137 | FromPort: '8080'
138 | ToPort: '8080'
139 | CidrIp: 0.0.0.0/0
140 |
141 | ## =================== OUTPUTS =================== ##
142 | Outputs:
143 | outputApp1URL: # for App1
144 | Description: App1 URL to access
145 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/demo/hello'
146 | outputApp2URL: # for App2
147 | Description: App2 URL to access
148 | Value: !Sub 'http://${myEC2Instance.PublicDnsName}:8080/index.html'
--------------------------------------------------------------------------------