├── .gitignore ├── .gitmodules ├── .taskcat.yml ├── CODEOWNERS ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── blog-assets ├── automate-ami-builds-aws-codepipeline-D35708869 │ ├── linux-ami-codepipeline.yaml │ ├── linux-ami-imagebuilder.yaml │ └── stack-configuration.json ├── change-cfn-stack-name │ ├── 01-vpc-basic.yaml │ └── 02-vpc-retain.yaml ├── clwtch-cstm-matrix-wth-Tagging-V457384788 │ └── template.yaml ├── eks-cluster-prework │ ├── scripts │ │ └── pw-script.sh │ └── templates │ │ ├── eks-cluster-prework.template.yaml │ │ └── prework.template.yaml ├── svcvirt-apigateway-cfn │ ├── AWS Blog Post.SVwithAPIGateway.postman_collection.json │ └── template.yaml └── upd-lmbda-wthout-zipping-V448302319 │ └── template.yaml ├── ci └── taskcat.yml ├── doc ├── eks-architecture-examples │ └── discngine-3decision-architecture-diagram.pptx ├── serverless-architecture-examples │ └── snowflake-sagemaker-autopilot-architecture-diagram.pptx └── three-tier-architecture-examples │ ├── crest-infosolutions-cloudmeet-architecture-diagram.pptx │ └── nvidia-cheminformatics-architecture-diagram.pptx ├── patterns ├── LambdaZips │ ├── README.md │ └── example.yaml └── blog │ └── CircularDependency │ ├── LessSimpleNonWorking.yaml │ ├── LessSimpleWorking.yaml │ ├── SimpleNonWorking.yaml │ └── SimpleWorking.yaml ├── samples ├── ami-factory-step-function │ └── ami-factory.yaml ├── cloudformation-codebuild-container │ ├── Dockerfile │ ├── Dockerfile.zip │ ├── README.md │ ├── codebuild.yaml │ ├── lambda_codebuild.py │ ├── lambda_codebuild.zip │ └── overview.png ├── cloudformation-cross-account │ ├── README.md │ ├── examples │ │ ├── bucket.yaml │ │ ├── central-iam.yaml │ │ ├── cross-account.yaml │ │ └── dev-iam.yaml │ └── functions │ │ ├── packages │ │ └── CfnStackAssumeRole │ │ │ └── lambda.zip │ │ └── source │ │ └── CfnStackAssumeRole │ │ └── lambda_function.py ├── cloudformation-stack-ttl │ ├── README.md │ ├── scripts │ │ ├── deploy-admin-stack.sh │ │ └── deploy-demo-stack.sh │ └── templates │ │ ├── cloudformation-admin-iam.yaml │ │ ├── cloudformation-stack-ttl.yaml │ │ └── demo-stack-ttl.yaml ├── ec2-instance-connect │ └── ec2-instance-connection-example.yaml ├── ec2-instance-userdata │ └── ec2InstanceUserData.yaml ├── eks-app-helm-deploy │ ├── helm-wordpress-deploy-RDS.yml │ ├── helm-wordpress-deploy.yml │ ├── helm3-wordpress-deploy-RDS.yml │ └── helm3-wordpress-deploy.yml ├── hugo-pipeline │ ├── .taskcat.yml │ └── templates │ │ ├── iam.template.yaml │ │ ├── master.template.yaml │ │ └── pipeline.template.yaml ├── ia4ct.ps1 ├── ia4ct.py ├── iot-button-deploy-cloudformation │ ├── demo-params.json │ ├── demo-stack.yaml │ └── iot-button-deploy-cloudformation.yaml └── session-manager-ssh │ ├── session-manager-example.yaml │ └── session-manager-ssh-example.yaml └── templates ├── workload-yaml-entrypoint-new-vpc.template.yaml └── workload-yaml.template.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | ci/taskcat_project_override.json 2 | ci/taskcat-dev* 3 | .DS_Store 4 | venv/ 5 | .idea/ 6 | doc/~$rtner Quick Start Template and Style Guide.docx 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/quickstart-aws-vpc"] 2 | path = submodules/quickstart-aws-vpc 3 | url = https://github.com/aws-quickstart/quickstart-aws-vpc.git 4 | branch = main 5 | [submodule "submodules/quickstart-linux-bastion"] 6 | path = submodules/quickstart-linux-bastion 7 | url = https://github.com/aws-quickstart/quickstart-linux-bastion.git 8 | branch = main 9 | [submodule "submodules/quickstart-microsoft-rdgateway"] 10 | path = submodules/quickstart-microsoft-rdgateway 11 | url = https://github.com/aws-quickstart/quickstart-microsoft-rdgateway.git 12 | branch = main 13 | -------------------------------------------------------------------------------- /.taskcat.yml: -------------------------------------------------------------------------------- 1 | project: 2 | name: quickstart-examples 3 | owner: quickstart-eng@amazon.com 4 | package_lambda: false 5 | shorten_stack_name: true 6 | s3_regional_buckets: true 7 | regions: 8 | - ap-northeast-1 9 | - ap-northeast-2 10 | - ap-south-1 11 | - ap-southeast-1 12 | - ap-southeast-2 13 | - ca-central-1 14 | - eu-central-1 15 | - eu-west-1 16 | - eu-west-2 17 | - sa-east-1 18 | - us-east-1 19 | - us-east-2 20 | - us-west-1 21 | - us-west-2 22 | s3_bucket: '' 23 | tests: 24 | examples-main: 25 | parameters: 26 | AvailabilityZones: $[alfred_getaz_2] 27 | BastionAMIOS: Amazon-Linux2-HVM 28 | BastionInstanceType: t2.micro 29 | KeyPairName: $[alfred_getkeypair] 30 | OperatorEmail: operator@example.com 31 | PrivateSubnet1CIDR: 10.0.0.0/19 32 | PrivateSubnet2CIDR: 10.0.32.0/19 33 | PublicSubnet1CIDR: 10.0.128.0/20 34 | PublicSubnet2CIDR: 10.0.144.0/20 35 | QSS3BucketName: $[taskcat_autobucket] 36 | QSS3BucketRegion: $[taskcat_current_region] 37 | RemoteAccessCIDR: 10.0.0.0/16 38 | S3BucketName: alfred-develop-examples-$[alfred_genuuid] 39 | VPCCIDR: 10.0.0.0/16 40 | WorkloadInstanceType: m4.xlarge 41 | WorkloadNodesDesiredCapacity: '2' 42 | WorkloadNodesMaxSize: '4' 43 | WorkloadNodesMinSize: '2' 44 | regions: 45 | - eu-west-1 46 | - eu-central-1 47 | s3_bucket: '' 48 | template: templates/workload-yaml-entrypoint-new-vpc.template.yaml 49 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @aws-quickstart/aws_quickstart_team 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at 4 | 5 | http://aws.amazon.com/apache2.0/ 6 | 7 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Deprecation Notice 2 | 3 | :x: This repository is subject to deprecation in Q4 2024. For more details, [please review this announcement](https://github.com/aws-ia/.announcements/issues/1). 4 | 5 | 6 | ## AWS Partner Solution examples 7 | 8 | This GitHub repository contains example files for [AWS Partner Solutions](https://aws.amazon.com/solutions/browse-all/?solutions-all.sort-by=item.additionalFields.sortDate&solutions-all.sort-order=desc&awsf.Content-Type=*all&awsf.AWS-Product%20Category=*all), including AWS CloudFormation templates, deployment guides, and architecture diagrams. It also includes examples that are discussed in posts on the [Integration & Automation Blog](https://aws.amazon.com/blogs/infrastructure-and-automation/). 9 | -------------------------------------------------------------------------------- /blog-assets/automate-ami-builds-aws-codepipeline-D35708869/linux-ami-codepipeline.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: | 4 | AWS CloudFormation Template for Continuous Delivery: This template builds an AWS CodePipeline pipeline that implements a continuous delivery release process using an AWS CloudFormation stack that builds custom EC2 AMIs using EC2 ImageBuilder. Submit the CloudFormation template to CodeCommit and the pipeline will take the artifacts to automatically create the stack, run the pipeline, put an approval step, and clean up the stack. (qs-1tkj0sj93) 5 | Parameters: 6 | Email: 7 | Default: my@email 8 | Description: The email address where CodePipeline sends pipeline notifications 9 | Type: String 10 | S3BucketName: 11 | Type: String 12 | Default: test-ami-builder-blog-pipeline 13 | Description: The S3 bucket for the temporary artifacts used in CodePipeline 14 | CodeCommitRepositoryName: 15 | Type: String 16 | Default: test-ami-builder-blog-linux-pipeline 17 | Description: name of the codecommit repository that must hold the files "linux-ami-imagebuilder.yaml" and "stack-configuration.json" 18 | PipelineName: 19 | Default: test-ami-builder-blog-linux-pipeline 20 | Description: A name for pipeline 21 | Type: String 22 | TemplateFileName: 23 | Default: linux-ami-imagebuilder.yaml 24 | Description: The file name of the template 25 | Type: String 26 | StackName: 27 | Default: test-amazon-linux2-arm64-ami 28 | Description: A name for the stack which will also be the AMI name to be used in EC2 29 | Type: String 30 | StackConfig: 31 | Default: stack-configuration.json 32 | Description: The configuration file name for the stack 33 | Type: String 34 | Metadata: 35 | AWS::CloudFormation::Interface: 36 | ParameterGroups: 37 | - Label: 38 | default: CodePipeline Settings 39 | Parameters: 40 | - PipelineName 41 | - S3BucketName 42 | - Email 43 | - Label: 44 | default: Stack Settings 45 | Parameters: 46 | - TemplateFileName 47 | - StackName 48 | - StackConfig 49 | Resources: 50 | S3Bucket: 51 | Type: AWS::S3::Bucket 52 | Properties: 53 | BucketName: 54 | Fn::Join: 55 | - '-' 56 | - - !Ref 'S3BucketName' 57 | - Fn::Select: 58 | - 4 59 | - Fn::Split: 60 | - '-' 61 | - Fn::Select: 62 | - 2 63 | - Fn::Split: 64 | - / 65 | - Ref: AWS::StackId 66 | VersioningConfiguration: 67 | Status: Enabled 68 | BucketEncryption: 69 | ServerSideEncryptionConfiguration: 70 | - ServerSideEncryptionByDefault: 71 | SSEAlgorithm: AES256 72 | DeletionPolicy: Delete 73 | CodeCommitRepo: 74 | Type: AWS::CodeCommit::Repository 75 | Properties: 76 | RepositoryName: !Ref 'CodeCommitRepositoryName' 77 | CodePipelineSNSTopic: 78 | Type: AWS::SNS::Topic 79 | Properties: 80 | KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns 81 | Subscription: 82 | - Endpoint: !Ref 'Email' 83 | Protocol: email 84 | Pipeline: 85 | Type: AWS::CodePipeline::Pipeline 86 | Properties: 87 | ArtifactStore: 88 | Location: !Ref 'S3Bucket' 89 | Type: S3 90 | DisableInboundStageTransitions: [] 91 | Name: !Ref 'PipelineName' 92 | RoleArn: !GetAtt 'PipelineRole.Arn' 93 | Stages: 94 | - Name: Source 95 | Actions: 96 | - Name: Source 97 | ActionTypeId: 98 | Category: Source 99 | Owner: AWS 100 | Provider: CodeCommit 101 | Version: '1' 102 | Configuration: 103 | BranchName: main 104 | OutputArtifactFormat: CODE_ZIP 105 | RepositoryName: !Ref 'CodeCommitRepositoryName' 106 | RunOrder: 1 107 | OutputArtifacts: 108 | - Name: TemplateSource 109 | - Name: Build 110 | Actions: 111 | - Name: CreateStack 112 | ActionTypeId: 113 | Category: Deploy 114 | Owner: AWS 115 | Provider: CloudFormation 116 | Version: '1' 117 | InputArtifacts: 118 | - Name: TemplateSource 119 | Configuration: 120 | ActionMode: REPLACE_ON_FAILURE 121 | RoleArn: !GetAtt 'CFNRole.Arn' 122 | StackName: !Ref 'StackName' 123 | Capabilities: CAPABILITY_NAMED_IAM 124 | TemplateConfiguration: !Sub 'TemplateSource::${StackConfig}' 125 | TemplatePath: !Sub 'TemplateSource::${TemplateFileName}' 126 | RunOrder: 1 127 | - Name: ApproveStack 128 | ActionTypeId: 129 | Category: Approval 130 | Owner: AWS 131 | Provider: Manual 132 | Version: '1' 133 | Configuration: 134 | NotificationArn: !Ref 'CodePipelineSNSTopic' 135 | CustomData: !Sub 'Perform checks on the AMI built and after approval the stack ${StackName} will be deleted' 136 | RunOrder: 2 137 | - Name: DeleteStack 138 | ActionTypeId: 139 | Category: Deploy 140 | Owner: AWS 141 | Provider: CloudFormation 142 | Version: '1' 143 | Configuration: 144 | ActionMode: DELETE_ONLY 145 | RoleArn: !GetAtt 'CFNRole.Arn' 146 | StackName: !Ref 'StackName' 147 | RunOrder: 3 148 | CFNRole: 149 | Type: AWS::IAM::Role 150 | Properties: 151 | AssumeRolePolicyDocument: 152 | Version: '2012-10-17' 153 | Statement: 154 | - Effect: Allow 155 | Principal: 156 | Service: 157 | - cloudformation.amazonaws.com 158 | Action: 159 | - sts:AssumeRole 160 | Path: / 161 | Policies: 162 | - PolicyName: CloudFormationRole 163 | PolicyDocument: 164 | Version: '2012-10-17' 165 | Statement: 166 | - Effect: Allow 167 | Action: 168 | - ec2:ImportKeyPair 169 | - ec2:ImportVolume 170 | - ec2:ImportImage 171 | - ec2:RegisterImage 172 | - ec2:CreateImage 173 | - ec2:ExportImage 174 | - ec2:DescribeImages 175 | - ec2:DescribeVpcs 176 | - ec2:DescribeVolumeAttribute 177 | - ec2:DescribeInstances 178 | - ec2:DescribeKeyPairs 179 | - ec2:DescribeSecurityGroups 180 | - ec2:DescribeSecurityGroupRules 181 | - ec2:DescribeSecurityGroupReferences 182 | - ec2:DescribeIamInstanceProfileAssociations 183 | - ec2:GetResourcePolicy 184 | - ec2:GetConsoleOutput 185 | - ec2:ModifyInstanceAttribute 186 | - ec2:ModifyVolumeAttribute 187 | - ec2:ModifySecurityGroupRules 188 | - ec2:ModifyVolume 189 | - ec2:ReportInstanceStatus 190 | - ec2:ReplaceIamInstanceProfileAssociation 191 | - ec2:AssociateIamInstanceProfile 192 | - ec2:DisassociateIamInstanceProfile 193 | - ec2:DeleteSecurityGroup 194 | - ec2:ModifySecurityGroupRules 195 | - ec2:CreateSecurityGroup 196 | - ec2:AuthorizeSecurityGroupIngress 197 | - ec2:AuthorizeSecurityGroupEgress 198 | - ec2:UpdateSecurityGroupRuleDescriptionsEgress 199 | - ec2:RevokeSecurityGroupIngress 200 | - ec2:RevokeSecurityGroupEgress 201 | - ec2:UpdateSecurityGroupRuleDescriptionsIngress 202 | Resource: "*" 203 | - PolicyName: AdditionalPerms 204 | PolicyDocument: 205 | Version: '2012-10-17' 206 | Statement: 207 | - Effect: Allow 208 | Action: 209 | - iam:GetRole 210 | - iam:CreateRole 211 | - iam:DetachRolePolicy 212 | - iam:AttachRolePolicy 213 | - iam:DeleteRole 214 | - iam:PassRole 215 | - iam:GetPolicy 216 | - iam:ListPolicyVersions 217 | - iam:CreatePolicy 218 | - iam:DeletePolicy 219 | - iam:CreateInstanceProfile 220 | - iam:DeleteInstanceProfile 221 | - iam:GetInstanceProfile 222 | - iam:AddRoleToInstanceProfile 223 | - iam:RemoveRoleFromInstanceProfile 224 | - imagebuilder:GetDistributionConfiguration 225 | - imagebuilder:GetComponent 226 | - imagebuilder:GetComponentPolicy 227 | - imagebuilder:GetInfrastructureConfiguration 228 | - imagebuilder:GetImage 229 | - imagebuilder:GetImageRecipe 230 | - imagebuilder:ListDistributionConfigurations 231 | - imagebuilder:ListInfrastructureConfigurations 232 | - imagebuilder:ListImagePipelines 233 | - imagebuilder:ListComponents 234 | - imagebuilder:ListImageRecipes 235 | - imagebuilder:ListImages 236 | - imagebuilder:ListComponentBuildVersions 237 | - imagebuilder:ListTagsForResource 238 | - imagebuilder:CreateDistributionConfiguration 239 | - imagebuilder:CreateComponent 240 | - imagebuilder:CreateImageRecipe 241 | - imagebuilder:CreateImage 242 | - imagebuilder:CreateInfrastructureConfiguration 243 | - imagebuilder:DeleteDistributionConfiguration 244 | - imagebuilder:DeleteComponent 245 | - imagebuilder:DeleteImage 246 | - imagebuilder:DeleteImageRecipe 247 | - imagebuilder:DeleteInfrastructureConfiguration 248 | - imagebuilder:UntagResource 249 | - imagebuilder:ImportComponent 250 | - imagebuilder:PutComponentPolicy 251 | - imagebuilder:TagResource 252 | - imagebuilder:UpdateDistributionConfiguration 253 | Resource: 254 | - !Sub 'arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:*' 255 | - !Sub 'arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:instance/*' 256 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/*' 257 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*' 258 | - !Sub 'arn:${AWS::Partition}:imagebuilder:${AWS::Region}:${AWS::AccountId}:component/*' 259 | - !Sub 'arn:${AWS::Partition}:imagebuilder:${AWS::Region}:${AWS::Partition}:component/*/*/*' 260 | - !Sub 'arn:${AWS::Partition}:imagebuilder:${AWS::Region}:${AWS::AccountId}:image/*' 261 | - !Sub 'arn:${AWS::Partition}:imagebuilder:${AWS::Region}:${AWS::AccountId}:image-recipe/*/*' 262 | - !Sub 'arn:${AWS::Partition}:imagebuilder:${AWS::Region}:${AWS::AccountId}:infrastructure-configuration/*' 263 | PipelineRole: 264 | Type: AWS::IAM::Role 265 | Properties: 266 | AssumeRolePolicyDocument: 267 | Statement: 268 | - Action: sts:AssumeRole 269 | Effect: Allow 270 | Principal: 271 | Service: codepipeline.amazonaws.com 272 | Version: '2012-10-17' 273 | Path: / 274 | Policies: 275 | - PolicyName: CodePipelineAccess 276 | PolicyDocument: 277 | Version: '2012-10-17' 278 | Statement: 279 | - Action: 280 | - cloudformation:CreateStack 281 | - cloudformation:DescribeStacks 282 | - cloudformation:DeleteStack 283 | - cloudformation:UpdateStack 284 | - cloudformation:CreateChangeSet 285 | - cloudformation:ExecuteChangeSet 286 | - cloudformation:DeleteChangeSet 287 | - cloudformation:DescribeChangeSet 288 | - cloudformation:SetStackPolicy 289 | - iam:PassRole 290 | - sns:Publish 291 | Effect: Allow 292 | Resource: 293 | - !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/*/*' 294 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:*' 295 | - !Sub 'arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:*' 296 | - PolicyName: codecommit 297 | PolicyDocument: 298 | Version: '2012-10-17' 299 | Statement: 300 | - Effect: Allow 301 | Action: 302 | - codecommit:Get* 303 | - codecommit:UploadArchive 304 | Resource: 305 | - !GetAtt 'CodeCommitRepo.Arn' 306 | - PolicyName: s3-artifacts 307 | PolicyDocument: 308 | Version: '2012-10-17' 309 | Statement: 310 | - Effect: Allow 311 | Action: 312 | - s3:GetObject 313 | - s3:ListBucket 314 | - s3:PutObject 315 | Resource: 316 | - !GetAtt 'S3Bucket.Arn' 317 | - !Sub '${S3Bucket.Arn}/*' 318 | -------------------------------------------------------------------------------- /blog-assets/automate-ami-builds-aws-codepipeline-D35708869/linux-ami-imagebuilder.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: | 4 | This template builds an EC2 AMI based on Amazon Linux2 ARM64 and installs software to demonstrate an AWS CodePipeline driven AMI builing use-case using EC2 ImageBuilder. The automatically installed software includes the following packages: amazon-cloudwatch-agent-linux, aws-cli-version-2-linux, the stig-build-linux-high (https://docs.aws.amazon.com/imagebuilder/latest/userguide/toe-stig.html), and two custom components executing bash code. (qs-1tkj0sj93) 5 | Parameters: 6 | AWSRegion: 7 | Type: String 8 | Description: Define in which region you want to build and deploy the pipeline 9 | VpcId: 10 | Type: AWS::EC2::VPC::Id 11 | Description: VpcId of your existing Virtual Private Cloud (VPC) to be used to build the AMI 12 | ConstraintDescription: must be the VPC Id of an existing VPC 13 | SubnetId: 14 | Type: String 15 | Description: SubnetId of an existing subnet in your VPC 16 | ConstraintDescription: must be an existing subnet in the selected VPC 17 | SSHKeyPairName: 18 | Type: AWS::EC2::KeyPair::KeyName 19 | Description: Name of an existing EC2 KeyPair to enable SSH access to the instances 20 | ConstraintDescription: must be the name of an existing EC2 KeyPair 21 | SSHLocation: 22 | Type: String 23 | Description: The IP address range that can be used to SSH to the EC2 instances 24 | MinLength: '9' 25 | MaxLength: '18' 26 | AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) 27 | ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. 28 | Default: 0.0.0.0/0 29 | Version: 30 | Type: String 31 | Description: Version number for the ImageBuilder Component, that the service needs, but the components will be removed after pipeline completion. 32 | Default: 0.0.1 33 | Architecture: 34 | Type: String 35 | Description: Select between x86 and ARM instances 36 | Default: arm64 37 | AllowedValues: 38 | - x86 39 | - arm64 40 | InstanceType: 41 | Type: String 42 | Description: Instance Type for building the instances 43 | Default: t4g.micro 44 | AllowedValues: 45 | - t2.micro 46 | - t3.nano 47 | - t3a.nano 48 | - t3.large 49 | - t3.2xlarge 50 | - t4g.nano 51 | - t4g.micro 52 | - t4g.small 53 | - t4g.medium 54 | - t4g.large 55 | - t4g.xlarge 56 | - t4g.2xlarge 57 | BaseImageId: 58 | Type: String 59 | Description: define the base AMI ID to build upon 60 | Resources: 61 | LinuxImage: 62 | Type: AWS::ImageBuilder::Image 63 | Properties: 64 | ImageRecipeArn: !GetAtt 'LinuxImageRecipe.Arn' 65 | InfrastructureConfigurationArn: !GetAtt 'InfrastructureConfiguration.Arn' 66 | EnhancedImageMetadataEnabled: true 67 | LinuxImageRecipe: 68 | Type: AWS::ImageBuilder::ImageRecipe 69 | Properties: 70 | Name: !Sub 71 | - ${AWS::StackName}-Image-${Uniqueval} 72 | - Uniqueval: !Select 73 | - 2 74 | - !Split 75 | - / 76 | - !Ref 'AWS::StackId' 77 | Description: !Sub 78 | - ${ShortName} Image (${Architecture}) version ${Version} 79 | - ShortName: !Select 80 | - 0 81 | - !Split 82 | - '-' 83 | - !Ref 'AWS::StackName' 84 | Components: 85 | - ComponentArn: !GetAtt 'YumUpdateComponent.Arn' 86 | - ComponentArn: !GetAtt 'SetLocaleComponent.Arn' 87 | - ComponentArn: !Sub 'arn:${AWS::Partition}:imagebuilder:${AWSRegion}:aws:component/aws-cli-version-2-linux/x.x.x' 88 | - ComponentArn: !Sub 'arn:${AWS::Partition}:imagebuilder:${AWSRegion}:aws:component/amazon-cloudwatch-agent-linux/x.x.x' 89 | - ComponentArn: !Sub 'arn:${AWS::Partition}:imagebuilder:${AWSRegion}:aws:component/stig-build-linux-low/x.x.x' 90 | ParentImage: !Ref 'BaseImageId' 91 | Version: !Sub '${Version}' 92 | WorkingDirectory: /opt/aws/amibuilder/ 93 | BlockDeviceMappings: 94 | - DeviceName: /dev/sda1 95 | VirtualName: vol2 96 | Ebs: 97 | DeleteOnTermination: true 98 | VolumeSize: 20 99 | VolumeType: gp2 100 | InfrastructureConfiguration: 101 | Type: AWS::ImageBuilder::InfrastructureConfiguration 102 | Properties: 103 | InstanceProfileName: !Ref 'InstanceProfile' 104 | InstanceTypes: 105 | - !Sub '${InstanceType}' 106 | Name: !Sub 107 | - ${AWS::StackName}-InfraConfig-${Uniqueval} 108 | - Uniqueval: !Select 109 | - 2 110 | - !Split 111 | - / 112 | - !Ref 'AWS::StackId' 113 | KeyPair: !Ref 'SSHKeyPairName' 114 | TerminateInstanceOnFailure: false 115 | SecurityGroupIds: 116 | - !GetAtt 'InstanceSecurityGroup.GroupId' 117 | SubnetId: !Ref 'SubnetId' 118 | SetLocaleComponent: 119 | Type: AWS::ImageBuilder::Component 120 | Properties: 121 | ChangeDescription: !Sub 122 | - Update ${ShortName} Image (${Architecture}) to version ${Version} 123 | - ShortName: !Select 124 | - 0 125 | - !Split 126 | - '-' 127 | - !Ref 'AWS::StackName' 128 | Description: !Sub 129 | - ${ShortName} Component configures the LC_CTYPE locale 130 | - ShortName: !Select 131 | - 0 132 | - !Split 133 | - '-' 134 | - !Ref 'AWS::StackName' 135 | Name: !Sub 136 | - ${AWS::StackName}-Component-Locale-${Uniqueval} 137 | - Uniqueval: !Select 138 | - 2 139 | - !Split 140 | - / 141 | - !Ref 'AWS::StackId' 142 | Platform: Linux 143 | Version: !Sub '${Version}' 144 | Data: !Sub | 145 | name: setlocale global 146 | description: Current version - ${Version} 147 | schemaVersion: 1.0 148 | phases: 149 | - name: build 150 | steps: 151 | - name: Locale 152 | action: ExecuteBash 153 | onFailure: Continue 154 | inputs: 155 | commands: 156 | - echo "LANG=en_US.utf-8" >> /etc/environment 157 | - echo "LC_ALL=en_US.utf-8" >> /etc/environment 158 | - localectl set-locale LANG=en_US.UTF-8 159 | - name: validate 160 | steps: 161 | - name: checkLocale 162 | action: ExecuteBash 163 | inputs: 164 | commands: 165 | - localectl status 166 | YumUpdateComponent: 167 | Type: AWS::ImageBuilder::Component 168 | Properties: 169 | ChangeDescription: !Sub 170 | - Update ${ShortName} Image (${Architecture}) to version ${Version} 171 | - ShortName: !Select 172 | - 0 173 | - !Split 174 | - '-' 175 | - !Ref 'AWS::StackName' 176 | Description: !Sub 177 | - ${ShortName} Component performs a RPM package update 178 | - ShortName: !Select 179 | - 0 180 | - !Split 181 | - '-' 182 | - !Ref 'AWS::StackName' 183 | Name: !Sub 184 | - ${AWS::StackName}-Component-YumUpdate-${Uniqueval} 185 | - Uniqueval: !Select 186 | - 2 187 | - !Split 188 | - / 189 | - !Ref 'AWS::StackId' 190 | Platform: Linux 191 | Version: !Sub '${Version}' 192 | Data: !Sub | 193 | name: rpm update 194 | description: Current version - ${Version} 195 | schemaVersion: 1.0 196 | phases: 197 | - name: build 198 | steps: 199 | - name: Fail 200 | onFailure: Continue 201 | action: ExecuteBash 202 | inputs: 203 | commands: 204 | - echo 1 205 | - name: Locale 206 | action: ExecuteBash 207 | onFailure: Continue 208 | inputs: 209 | commands: 210 | - dnf update -y 211 | InstanceSecurityGroup: 212 | Type: AWS::EC2::SecurityGroup 213 | Properties: 214 | VpcId: !Ref 'VpcId' 215 | GroupName: !Sub 216 | - ${AWS::StackName}-SG-${Uniqueval} 217 | - Uniqueval: !Select 218 | - 2 219 | - !Split 220 | - / 221 | - !Ref 'AWS::StackId' 222 | GroupDescription: Enable SSH access via port 22 223 | SecurityGroupIngress: 224 | - IpProtocol: tcp 225 | FromPort: 22 226 | ToPort: 22 227 | CidrIp: !Ref 'SSHLocation' 228 | SecurityGroupEgress: 229 | - IpProtocol: -1 230 | FromPort: 0 231 | ToPort: 65535 232 | CidrIp: !Ref 'SSHLocation' 233 | InstanceProfile: 234 | Type: AWS::IAM::InstanceProfile 235 | Properties: 236 | Roles: 237 | - !Ref 'EC2Role' 238 | EC2Role: 239 | Type: AWS::IAM::Role 240 | Properties: 241 | RoleName: !Sub '${AWS::StackName}' 242 | AssumeRolePolicyDocument: 243 | Version: '2012-10-17' 244 | Statement: 245 | - Action: sts:AssumeRole 246 | Effect: Allow 247 | Principal: 248 | Service: !Sub 'ec2.${AWS::URLSuffix}' 249 | ManagedPolicyArns: 250 | - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore' 251 | - !Sub 'arn:${AWS::Partition}:iam::aws:policy/EC2InstanceProfileForImageBuilder' 252 | Outputs: 253 | ImageArn: 254 | Description: Reference to EC2 Image Builder Output Arn 255 | Value: !GetAtt 'LinuxImage.Arn' 256 | ImageId: 257 | Description: Reference to EC2 Image Builder Output ImageId 258 | Value: !GetAtt 'LinuxImage.ImageId' 259 | -------------------------------------------------------------------------------- /blog-assets/automate-ami-builds-aws-codepipeline-D35708869/stack-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters" : { 3 | "AWSRegion" : "eu-west-1", 4 | "VpcId" : "vpc-12345678", 5 | "SubnetId" : "subnet-12345678", 6 | "SSHKeyPairName" : "sshkeypairname", 7 | "SSHLocation" : "0.0.0.0/0", 8 | "Architecture" : "arm64", 9 | "InstanceType" : "t4g.large", 10 | "BaseImageId" : "ami-08182e5c2a7db8405" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /blog-assets/change-cfn-stack-name/01-vpc-basic.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Description: "Deploys a VPC (qs-1t72ibrq5)" 4 | 5 | Resources: 6 | Vpc: 7 | Type: AWS::EC2::VPC 8 | Properties: 9 | CidrBlock: 10.0.0.0/16 10 | Tags: 11 | - Key: Name 12 | Value: rename-stack-demo -------------------------------------------------------------------------------- /blog-assets/change-cfn-stack-name/02-vpc-retain.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Description: Deploys a VPC 4 | 5 | Resources: 6 | Vpc: 7 | Type: AWS::EC2::VPC 8 | DeletionPolicy: Retain 9 | Properties: 10 | CidrBlock: 10.0.0.0/16 11 | Tags: 12 | - Key: Name 13 | Value: rename-stack-demo -------------------------------------------------------------------------------- /blog-assets/clwtch-cstm-matrix-wth-Tagging-V457384788/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: "Deploys a solution to automate the CloudWatch agent configurations based on specific tags(qs-1st6kiobq)" 3 | 4 | Resources: 5 | InstanceIAMRole: 6 | Type: AWS::IAM::Role 7 | Properties: 8 | AssumeRolePolicyDocument: 9 | Version: '2012-10-17' 10 | Statement: 11 | - Sid: AssumeRole 12 | Action: 13 | - sts:AssumeRole 14 | Effect: Allow 15 | Principal: 16 | Service: "ec2.amazonaws.com" 17 | ManagedPolicyArns: 18 | - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore 19 | - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy 20 | 21 | InstanceProfile: 22 | Type: AWS::IAM::InstanceProfile 23 | Properties: 24 | Path: / 25 | Roles: 26 | - !Ref InstanceIAMRole 27 | 28 | ApplicationAJsonConfig: 29 | Type: AWS::SSM::Parameter 30 | Properties: 31 | Name: ApplicationAParameter 32 | Type: String 33 | Value: | 34 | { 35 | "metrics": { 36 | "namespace": "ApplicationA", 37 | "append_dimensions": { 38 | "InstanceId": "${aws:InstanceId}" 39 | }, 40 | "metrics_collected": { 41 | "disk": { 42 | "measurement": [ 43 | "used_percent" 44 | ], 45 | "metrics_collection_interval": 60 46 | } 47 | } 48 | } 49 | } 50 | Description: JSON config for CW Agent for Linux Application A 51 | 52 | ApplicationBJsonConfig: 53 | Type: AWS::SSM::Parameter 54 | Properties: 55 | Name: ApplicationBParameter 56 | Type: String 57 | Value: | 58 | { 59 | "metrics": { 60 | "namespace": "ApplicationB", 61 | "append_dimensions": { 62 | "InstanceId": "${aws:InstanceId}" 63 | }, 64 | "metrics_collected": { 65 | "mem": { 66 | "measurement": [ 67 | "mem_used_percent" 68 | ], 69 | "metrics_collection_interval": 60 70 | } 71 | } 72 | } 73 | } 74 | Description: JSON config for CW Agent for Linux Application B 75 | 76 | InstallAndConfigureCloudWatchAgentDocument: 77 | Type: AWS::SSM::Document 78 | Properties: 79 | Name: SSMDocumentInstallConfigureCWAgent 80 | DocumentType: Command 81 | Content: 82 | schemaVersion: '2.2' 83 | description: Configures the CloudWatch Agent on Windows and Linux instances 84 | parameters: 85 | ssmParameterStoreParameterName: 86 | type: String 87 | description: "(Required) The SSM parameter name that contains the JSON configuration" 88 | mainSteps: 89 | - action: aws:runDocument 90 | precondition: 91 | StringEquals: 92 | - platformType 93 | - Linux 94 | name: InstallCWAgent 95 | inputs: 96 | documentType: SSMDocument 97 | documentPath: AWS-ConfigureAWSPackage 98 | documentParameters: 99 | action: Install 100 | name: AmazonCloudWatchAgent 101 | - action: aws:runDocument 102 | precondition: 103 | StringEquals: 104 | - platformType 105 | - Linux 106 | name: ConfigureCWAgent 107 | inputs: 108 | documentType: SSMDocument 109 | documentPath: AmazonCloudWatch-ManageAgent 110 | documentParameters: 111 | action: configure 112 | mode: ec2 113 | optionalConfigurationSource: ssm 114 | optionalConfigurationLocation: '{{ ssmParameterStoreParameterName }}' 115 | 116 | SSMAssociationCwAgentApplicationA: 117 | Type: AWS::SSM::Association 118 | Properties: 119 | AssociationName: ApplicationAAssociation 120 | Name: !Ref InstallAndConfigureCloudWatchAgentDocument 121 | Parameters: 122 | ssmParameterStoreParameterName: 123 | - !Ref ApplicationAJsonConfig 124 | Targets: 125 | - Key: tag:Application 126 | Values: 127 | - ApplicationA 128 | WaitForSuccessTimeoutSeconds: 300 129 | 130 | SSMAssociationCwAgentApplicationB: 131 | Type: AWS::SSM::Association 132 | Properties: 133 | AssociationName: ApplicationBAssociation 134 | Name: !Ref InstallAndConfigureCloudWatchAgentDocument 135 | Parameters: 136 | ssmParameterStoreParameterName: 137 | - !Ref ApplicationBJsonConfig 138 | Targets: 139 | - Key: tag:Application 140 | Values: 141 | - ApplicationB 142 | WaitForSuccessTimeoutSeconds: 300 143 | 144 | Outputs: 145 | InstanceProfileName: 146 | Description: The name of the Instance Profile to assign to the EC2 instance 147 | Value: !Ref InstanceProfile -------------------------------------------------------------------------------- /blog-assets/eks-cluster-prework/scripts/pw-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Install kubectl 3 | 4 | # we are installing the current version if you are on an older cluster you might need to change this. 5 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" 6 | # Install kubectl 7 | install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl 8 | 9 | #============= INSERT YOUR PREWORK STEPS HERE ====================# 10 | # We will create a simple script the point of the blog is to show that you CAN run pre-work on the cluster via CloudFormation 11 | # so we are less concerned with the content of this script. 12 | 13 | # there are much better ways to manage secrets ;) 14 | kubectl create secret generic db-user-pass \ 15 | --from-literal=username=devuser \ 16 | --from-literal=password='S!B\*d$zDsb=' \ 17 | -- namespace $KUBE_NAMESPACE 18 | kubectl describe secrets/db-user-pass -------------------------------------------------------------------------------- /blog-assets/eks-cluster-prework/templates/eks-cluster-prework.template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: "Amazon EKS PreWork pattern Blog" 3 | Parameters: 4 | AccessCIDR: 5 | Default: 0.0.0.0/0 6 | Type: String 7 | KeyPairName: 8 | Description: Name of an existing key pair, which allows you to securely connect to your bastion instance after it launches. 9 | Leave empty to proceed without a key pair. You would need to use AWS Systems Manager Session Manager to connect to the provisioned EC2 instances. 10 | Type: String 11 | Default: "" 12 | JobName: 13 | Type: String 14 | Default: 'job-example' 15 | AvailabilityZones: 16 | Description: List of Availability Zones to use for the subnets in the VPC. Three 17 | Availability Zones are used for this deployment. 18 | Type: List AvailabilityZones: 19 | NumberOfAZs: 20 | Type: String 21 | AllowedValues: ["2", "3"] 22 | Default: "2" 23 | Description: Number of Availability Zones to use in the VPC. This must match the value entered for the AvailabilityZones parameter. 24 | PreworkScriptBucket: 25 | Type: String 26 | Default: 'aws-quickstart' 27 | PreworkScriptObject: 28 | Type: String 29 | Default: 'quickstart-examples/blog-assets/eks-cluster-prework/scripts/pw-script.sh' 30 | Resources: 31 | EKSStack: 32 | Type: AWS::CloudFormation::Stack 33 | Properties: 34 | TemplateURL: 'https://aws-quickstart.s3.amazonaws.com/quickstart-amazon-eks/templates/amazon-eks-entrypoint-new-vpc.template.yaml' 35 | Parameters: 36 | # Cluster properties 37 | ProvisionBastionHost: Enabled 38 | RemoteAccessCIDR: !Ref AccessCIDR 39 | AvailabilityZones: !Join [ ',', !Ref 'AvailabilityZones' ] 40 | NodeInstanceType: t3.large 41 | NumberOfNodes: 1 42 | MaxNumberOfNodes: 1 43 | GetOIDCProvider: 44 | Type: Custom::GetOIDCProvider 45 | Properties: 46 | ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" 47 | AwsCliCommand: !Sub "eks describe-cluster --name ${EKSStack.Outputs.EKSClusterName} --query 'cluster.identity.oidc.{issuer:issuer}'" 48 | IdField: 'issuer' 49 | PreworkStack: 50 | DependsOn: EKSStack 51 | Type: AWS::CloudFormation::Stack 52 | Properties: 53 | TemplateURL: 'https://aws-quickstart.s3.amazonaws.com/quickstart-examples/blog-assets/eks-cluster-prework/templates/prework.template.yaml' 54 | Parameters: 55 | ClusterName: !GetAtt "EKSStack.Outputs.EKSClusterName" 56 | PreworkScriptBucket: !Ref PreworkScriptBucket 57 | PreworkScriptObject: !Ref PreworkScriptObject 58 | JobName: !Ref JobName 59 | KubernetesNameSpace: "prework-example" 60 | Outputs: 61 | EKSClusterName: 62 | Value: !GetAtt EKSStack.Outputs.EKSClusterName 63 | BastionIP: 64 | Value: !GetAtt EKSStack.Outputs.BastionIP 65 | -------------------------------------------------------------------------------- /blog-assets/eks-cluster-prework/templates/prework.template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: "Amazon EKS cluster pre/post-work blog sample" 3 | Parameters: 4 | ClusterName: 5 | Type: String 6 | PreworkScriptBucket: 7 | Type: String 8 | Default: aws-quickstart 9 | PreworkScriptObject: 10 | Type: String 11 | Default: "quickstart-examples/blog-assets/eks-cluster-prework/scripts/pw-script.sh" 12 | JobName: 13 | Type: String 14 | Default: example-job 15 | AllowedPattern: '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*' 16 | ConstraintDescription: "a lowercase RFC 1123 subdomain must consist of lower case 17 | alphanumeric characters, '-' or '.', and must start and end with an alphanumeric 18 | character" 19 | KubernetesNameSpace: 20 | Type: String 21 | Default: "prework-example" 22 | Resources: 23 | PreWorkIAMRole: 24 | Type: AWS::IAM::Role 25 | Properties: 26 | RoleName: !Sub "pw-role-${JobName}" 27 | AssumeRolePolicyDocument: !Sub 28 | - | 29 | { 30 | "Version": "2012-10-17", 31 | "Statement": [ 32 | { 33 | "Effect": "Allow", 34 | "Principal": { 35 | "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${OIDCProvider}" 36 | }, 37 | "Action": "sts:AssumeRoleWithWebIdentity", 38 | "Condition": { 39 | "StringEquals": { 40 | "${OIDCProvider}:sub": "system:serviceaccount:${NameSpace}:${ResourceName}" 41 | } 42 | } 43 | } 44 | ] 45 | } 46 | - NameSpace: !Ref KubernetesNameSpace 47 | ResourceName: !Sub "pw-service-account-${JobName}" 48 | OIDCProvider: !Join [ '', !Split [ 'https://', !Ref 'GetOIDCProvider' ] ] 49 | Path: "/" 50 | Policies: 51 | - PolicyName: root 52 | PolicyDocument: 53 | Version: '2012-10-17' 54 | Statement: 55 | - Effect: Allow 56 | Action: 57 | - s3:GetObject 58 | - s3:HeadObject 59 | Resource: 60 | - !Sub "arn:${AWS::Partition}:s3:::${PreworkScriptBucket}/${PreworkScriptObject}" 61 | GetOIDCProvider: 62 | Type: Custom::GetOIDCProvider 63 | Properties: 64 | ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:eks-quickstart-ResourceReader" 65 | AwsCliCommand: !Sub "eks describe-cluster --name ${ClusterName} --query 'cluster.identity.oidc.{issuer:issuer}'" 66 | IdField: 'issuer' 67 | KubePreWorkNamespace: 68 | Type: "AWSQS::Kubernetes::Resource" 69 | Properties: 70 | ClusterName: !Ref ClusterName 71 | Namespace: default 72 | Manifest: !Sub | 73 | kind: Namespace 74 | apiVersion: v1 75 | metadata: 76 | name: ${KubernetesNameSpace} 77 | KubePreWorkRole: 78 | Type: AWSQS::Kubernetes::Resource 79 | DependsOn: [ KubePreWorkNamespace ] 80 | Properties: 81 | ClusterName: !Ref ClusterName 82 | Namespace: !Ref KubernetesNameSpace 83 | Manifest: !Sub 84 | - | 85 | apiVersion: rbac.authorization.k8s.io/v1 86 | kind: Role 87 | metadata: 88 | labels: 89 | app.kubernetes.io/name: "${ResourceName}" 90 | name: "${ResourceName}" 91 | # Modify for your scripts here 92 | rules: 93 | - apiGroups: 94 | - "" 95 | resources: 96 | - secrets 97 | verbs: 98 | - create 99 | - delete 100 | - get 101 | - ResourceName: !Sub "pw-role-${JobName}" 102 | NameSpace: !Ref "KubernetesNameSpace" 103 | KubePreWorkServiceAccount: 104 | Type: AWSQS::Kubernetes::Resource 105 | DependsOn: [ KubePreWorkNamespace ] 106 | Properties: 107 | ClusterName: !Ref ClusterName 108 | Namespace: !Ref KubernetesNameSpace 109 | Manifest: !Sub 110 | - | 111 | apiVersion: v1 112 | kind: ServiceAccount 113 | metadata: 114 | labels: 115 | app.kubernetes.io/name: "${ResourceName}" 116 | annotations: 117 | eks.amazonaws.com/role-arn: arn:aws:iam::${AWS::AccountId}:role/${RoleName} 118 | name: "${ResourceName}" 119 | namespace: ${NameSpace} 120 | - ResourceName: !Sub "pw-service-account-${JobName}" 121 | NameSpace: !Ref KubernetesNameSpace 122 | RoleName: !Ref PreWorkIAMRole 123 | KubePreWorkRoleBinding: 124 | Type: AWSQS::Kubernetes::Resource 125 | DependsOn: [ KubePreWorkNamespace, KubePreWorkRole, KubePreWorkServiceAccount ] 126 | Properties: 127 | ClusterName: !Ref ClusterName 128 | Namespace: !Ref KubernetesNameSpace 129 | Manifest: !Sub 130 | - | 131 | apiVersion: rbac.authorization.k8s.io/v1 132 | kind: RoleBinding 133 | metadata: 134 | labels: 135 | app.kubernetes.io/name: "${ResourceName}" 136 | name: "${ResourceName}" 137 | roleRef: 138 | apiGroup: rbac.authorization.k8s.io 139 | kind: Role 140 | name: "pw-role-${JobName}" 141 | subjects: 142 | - kind: ServiceAccount 143 | name: "pw-service-account-${JobName}" 144 | namespace: ${NameSpace} 145 | - ResourceName: !Sub "pw-role-binding-${JobName}" 146 | NameSpace: !Ref KubernetesNameSpace 147 | KubePreWorkJob: 148 | DependsOn: [ PreWorkIAMRole, KubePreWorkRole, KubePreWorkServiceAccount, KubePreWorkRoleBinding ] 149 | Type: AWSQS::Kubernetes::Resource 150 | Properties: 151 | ClusterName: !Ref ClusterName 152 | Namespace: !Ref KubernetesNameSpace 153 | Manifest: !Sub 154 | - | 155 | apiVersion: batch/v1 156 | kind: Job 157 | metadata: 158 | name: "${ResourceName}" 159 | namespace: ${NameSpace} 160 | spec: 161 | template: 162 | spec: 163 | containers: 164 | - name: ${ResourceName} 165 | image: amazonlinux:2 166 | command: ["/bin/bash","-c"] 167 | args: 168 | - > 169 | sleep 15; 170 | export AWS_REGION=${AWS::Region}; 171 | export NS=${NameSpace}; 172 | yum install -y aws-cli; 173 | aws sts get-caller-identity; 174 | aws s3 cp ${!S3_SCRIPT_URL} ./prework-script.sh && 175 | chmod +x ./prework-script.sh && 176 | ./prework-script.sh 177 | env: 178 | - name: S3_SCRIPT_URL 179 | value: ${S3ScriptURL} 180 | - name: AWS_REGION 181 | value: ${AWS::Region} 182 | - name: KUBE_NAMESPACE 183 | value: ${KubernetesNameSpace} 184 | serviceAccountName: "pw-service-account-${JobName}" 185 | restartPolicy: Never 186 | backoffLimit: 4 187 | - ResourceName: !Sub "pw-job-${JobName}" 188 | NameSpace: !Ref "KubernetesNameSpace" 189 | S3ScriptURL: !Sub "s3://${PreworkScriptBucket}/${PreworkScriptObject}" 190 | -------------------------------------------------------------------------------- /blog-assets/svcvirt-apigateway-cfn/AWS Blog Post.SVwithAPIGateway.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "233e8d84-5068-4909-84f0-c0340b451606", 4 | "name": "AWS Blog Post", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "GET Method", 10 | "request": { 11 | "method": "GET", 12 | "header": [], 13 | "url": { 14 | "raw": "https://put-your-api-gateway-stage-address-here/v0/mock?method=created", 15 | "protocol": "https", 16 | "host": [ 17 | "put-your-api-gateway-stage-address-here" 18 | ], 19 | "path": [ 20 | "v0", 21 | "mock" 22 | ], 23 | "query": [ 24 | { 25 | "key": "method", 26 | "value": "created" 27 | } 28 | ] 29 | } 30 | }, 31 | "response": [] 32 | }, 33 | { 34 | "name": "POST Method", 35 | "request": { 36 | "method": "POST", 37 | "header": [ 38 | { 39 | "key": "Content-Type", 40 | "value": "application/json", 41 | "type": "text" 42 | } 43 | ], 44 | "body": { 45 | "mode": "raw", 46 | "raw": "{\r\n \"statusCode\": 226\r\n}" 47 | }, 48 | "url": { 49 | "raw": "https://put-your-api-gateway-stage-address-here/v0/mock", 50 | "protocol": "https", 51 | "host": [ 52 | "put-your-api-gateway-stage-address-here" 53 | ], 54 | "path": [ 55 | "v0", 56 | "mock" 57 | ], 58 | "query": [ 59 | { 60 | "key": "scope", 61 | "value": "internal", 62 | "disabled": true 63 | } 64 | ] 65 | } 66 | }, 67 | "response": [] 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /blog-assets/svcvirt-apigateway-cfn/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Description: "AWS API Gateway working as a Service Virtualization (qs-1sq3s942d)" 4 | 5 | Resources: 6 | 7 | RestApi: 8 | Type: AWS::ApiGateway::RestApi 9 | Properties: 10 | ApiKeySourceType: HEADER 11 | Description: An API Gateway as Service Virtualization 12 | EndpointConfiguration: 13 | Types: 14 | - EDGE 15 | Name: mock-api 16 | 17 | Resource: 18 | Type: AWS::ApiGateway::Resource 19 | Properties: 20 | ParentId: !GetAtt RestApi.RootResourceId 21 | PathPart: 'mock' 22 | RestApiId: !Ref RestApi 23 | 24 | GetMethod: 25 | Type: AWS::ApiGateway::Method 26 | Properties: 27 | ApiKeyRequired: false 28 | AuthorizationType: NONE 29 | HttpMethod: GET 30 | RequestParameters: 31 | method.request.querystring.method: true 32 | MethodResponses: 33 | - ResponseModels: 34 | application/json: !Ref ApiGatewayModel 35 | StatusCode: 200 36 | - ResponseModels: 37 | application/json: !Ref ApiGatewayModel 38 | StatusCode: 201 39 | - ResponseModels: 40 | application/json: !Ref ApiGatewayModel 41 | StatusCode: 500 42 | - ResponseModels: 43 | application/json: !Ref ApiGatewayModel 44 | StatusCode: 503 45 | Integration: 46 | ConnectionType: INTERNET 47 | IntegrationResponses: 48 | - ResponseTemplates: 49 | application/json: | 50 | { 51 | "statusCode": 200, 52 | "message": "OK. No problem here." 53 | } 54 | StatusCode: 200 55 | - ResponseTemplates: 56 | application/json: | 57 | { 58 | "statusCode": 201, 59 | "message": "Created. It appears to be good." 60 | } 61 | SelectionPattern: '201' 62 | StatusCode: 201 63 | - ResponseTemplates: 64 | application/json: | 65 | { 66 | "statusCode": 500, 67 | "message": "Internal Server Error. Houston, we have a problem." 68 | } 69 | SelectionPattern: '500' 70 | StatusCode: 500 71 | - ResponseTemplates: 72 | application/json: | 73 | { 74 | "statusCode": 503, 75 | "message": "Service Unavailable. I am not ready yet." 76 | } 77 | SelectionPattern: '503' 78 | StatusCode: 503 79 | PassthroughBehavior: WHEN_NO_TEMPLATES 80 | RequestTemplates: 81 | application/json: | 82 | { 83 | #if ( $input.params('method') == "ok" ) 84 | "statusCode": 200 85 | #elseif ( $input.params('method') == "created" ) 86 | "statusCode": 201 87 | #elseif ( $input.params('method') == "internalerror" ) 88 | "statusCode": 500 89 | #else 90 | "statusCode": 503 91 | #end 92 | } 93 | Type: MOCK 94 | TimeoutInMillis: 29000 95 | OperationName: 'mock' 96 | ResourceId: !Ref Resource 97 | RestApiId: !Ref RestApi 98 | 99 | PostMethod: 100 | Type: AWS::ApiGateway::Method 101 | Properties: 102 | ApiKeyRequired: false 103 | AuthorizationType: NONE 104 | HttpMethod: POST 105 | MethodResponses: 106 | - ResponseModels: 107 | application/json: !Ref ApiGatewayModel 108 | StatusCode: 200 109 | - ResponseModels: 110 | application/json: !Ref ApiGatewayModel 111 | StatusCode: 500 112 | Integration: 113 | ConnectionType: INTERNET 114 | IntegrationResponses: 115 | - ResponseTemplates: 116 | application/json: "{\"message\": \"OK. No problem here.\"}" 117 | # SelectionPattern: '2\d{2}' 118 | StatusCode: 200 119 | - ResponseTemplates: 120 | application/json: "{\"message\": \"Internal Server Error. Houston, we have a problem.\"}" 121 | SelectionPattern: '5\d{2}' 122 | StatusCode: 500 123 | PassthroughBehavior: WHEN_NO_TEMPLATES 124 | RequestTemplates: 125 | application/json: | 126 | { 127 | "statusCode": $input.json('$.statusCode'), 128 | "message": $input.json('$.message') 129 | } 130 | Type: MOCK 131 | TimeoutInMillis: 29000 132 | OperationName: 'mock' 133 | ResourceId: !Ref Resource 134 | RestApiId: !Ref RestApi 135 | 136 | ApiGatewayModel: 137 | Type: AWS::ApiGateway::Model 138 | Properties: 139 | ContentType: 'application/json' 140 | RestApiId: !Ref RestApi 141 | Schema: {} 142 | 143 | ApiGatewayStage: 144 | Type: AWS::ApiGateway::Stage 145 | Properties: 146 | DeploymentId: !Ref ApiGatewayDeployment 147 | Description: Mock API Stage v0 148 | RestApiId: !Ref RestApi 149 | StageName: 'v0' 150 | 151 | ApiGatewayDeployment: 152 | Type: AWS::ApiGateway::Deployment 153 | DependsOn: 154 | - GetMethod 155 | - PostMethod 156 | Properties: 157 | Description: Mock API Deployment 158 | RestApiId: !Ref RestApi 159 | -------------------------------------------------------------------------------- /blog-assets/upd-lmbda-wthout-zipping-V448302319/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: "Update your Lambda functions without zipping and uploading files to S3 (qs-1t29l4g74)" 3 | Parameters: 4 | CodeCommitRepoName: 5 | Description: The name of the CodeCommit Repository which stores the Lambda code 6 | Type: String 7 | CodeCommitBranchName: 8 | Description: The name of the CodeCommit branch in the repo which stores the lambda code 9 | Type: String 10 | PipelineBucket: 11 | Description: Enter the name of the pre-existing pipeline bucket 12 | Type: String 13 | Region: 14 | Description: Region to deploy resources in 15 | Type: String 16 | Default: us-east-1 17 | 18 | 19 | Resources: 20 | BuildProjectRole: 21 | Type: AWS::IAM::Role 22 | Properties: 23 | RoleName: CodeBuildUpdateLambdaRole 24 | AssumeRolePolicyDocument: 25 | Version: 2012-10-17 26 | Statement: 27 | - Effect: Allow 28 | Principal: 29 | Service: 30 | - codebuild.amazonaws.com 31 | Action: 32 | - sts:AssumeRole 33 | ManagedPolicyArns: 34 | - "arn:aws:iam::aws:policy/AWSCodeCommitPowerUser" 35 | - "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" 36 | Path: "/service-role/" 37 | 38 | 39 | BuildProjectPolicy: 40 | Type: AWS::IAM::Policy 41 | Properties: 42 | PolicyName: CodeBuildUpdateLambdaRolePolicy 43 | PolicyDocument: 44 | Version: 2012-10-17 45 | Statement: 46 | - Effect: Allow 47 | Action: 48 | - s3:Put* 49 | - s3:Get* 50 | - s3:List* 51 | Resource: 52 | - !Join [ 53 | "", 54 | [ 55 | "arn:aws:s3:::", 56 | !Ref "PipelineBucket", 57 | "/*", 58 | ], 59 | ] 60 | - !Join [ 61 | "", 62 | [ 63 | "arn:aws:s3:::", 64 | !Ref "PipelineBucket", 65 | ], 66 | ] 67 | - Effect: Allow 68 | Action: 69 | - logs:CreateLogGroup 70 | - logs:CreateLogStream 71 | - logs:PutLogEvents 72 | Resource: arn:aws:logs:*:*:* 73 | - Effect: Allow 74 | Action: 75 | - lambda:Update* 76 | Resource: !GetAtt Lambda.Arn 77 | Roles: 78 | - !Ref BuildProjectRole 79 | 80 | BuildProject: 81 | Type: AWS::CodeBuild::Project 82 | Properties: 83 | Description: This stage runs the updating of the Lambda code 84 | ServiceRole: !GetAtt BuildProjectRole.Arn 85 | Artifacts: 86 | Type: NO_ARTIFACTS 87 | Environment: 88 | ComputeType: BUILD_GENERAL1_SMALL 89 | Image: aws/codebuild/amazonlinux2-x86_64-standard:2.0 90 | Type: LINUX_CONTAINER 91 | PrivilegedMode: false 92 | EncryptionKey: 93 | alias/aws/s3 94 | LogsConfig: 95 | CloudWatchLogs: 96 | Status: ENABLED 97 | Source: 98 | Type: CODECOMMIT 99 | Location: !Join 100 | - "" 101 | - - "https://git-codecommit." 102 | - !Ref "AWS::Region" 103 | - ".amazonaws.com/v1/repos/" 104 | - !Ref "CodeCommitRepoName" 105 | BuildSpec: !Sub 106 | - | 107 | version: 0.2 108 | env: 109 | git-credential-helper: yes 110 | phases: 111 | install: 112 | runtime-versions: 113 | python: 3.9 114 | commands: 115 | - pwd 116 | - ls 117 | pre_build: 118 | commands: 119 | - ACCOUNT_ID=$(echo $CODEBUILD_BUILD_ARN | cut -f5 -d ':') 120 | build: 121 | commands: 122 | - zip index.zip index.py 123 | - aws s3api put-object --bucket ${artifactbucket} --key index.zip --body index.zip --expected-bucket-owner $ACCOUNT_ID 124 | - wait 125 | - aws lambda update-function-code --function-name ${Lambda} --s3-bucket ${artifactbucket} --s3-key index.zip 126 | - artifactbucket: 127 | !Ref PipelineBucket 128 | 129 | 130 | CodePipelineRole: 131 | Type: AWS::IAM::Role 132 | Properties: 133 | AssumeRolePolicyDocument: 134 | Statement: 135 | - Action: ["sts:AssumeRole"] 136 | Effect: Allow 137 | Principal: 138 | Service: 139 | - codepipeline.amazonaws.com 140 | Version: "2012-10-17" 141 | Path: / 142 | ManagedPolicyArns: 143 | - arn:aws:iam::aws:policy/AWSCodeCommitPowerUser 144 | Policies: 145 | - PolicyName: IAM-PassRole 146 | PolicyDocument: 147 | Version: "2012-10-17" 148 | Statement: 149 | - Action: 150 | - "iam:PassRole" 151 | Effect: Allow 152 | Resource: 153 | !Join [ 154 | "", 155 | ["arn:aws:iam:", ":", !Ref "AWS::AccountId", ":role/*"], 156 | ] 157 | - PolicyName: AllowS3Access 158 | PolicyDocument: 159 | Version: "2012-10-17" 160 | Statement: 161 | - Action: 162 | - "s3:PutObject" 163 | - "s3:GetObject" 164 | - "s3:GetObjectVersion" 165 | - "s3:List*" 166 | Effect: Allow 167 | Resource: 168 | - !Join [ 169 | "", 170 | [ 171 | "arn:aws:s3:::", 172 | !Ref PipelineBucket, 173 | ], 174 | ] 175 | - !Join [ 176 | "", 177 | [ 178 | "arn:aws:s3:::", 179 | !Ref "PipelineBucket", 180 | "/*" 181 | ], 182 | ] 183 | - PolicyName: AllowCodeBuildAccess 184 | PolicyDocument: 185 | Version: "2012-10-17" 186 | Statement: 187 | - Action: 188 | - "codebuild:Start*" 189 | - "codebuild:Batch*" 190 | Effect: Allow 191 | Resource: !GetAtt BuildProject.Arn 192 | - PolicyName: AllowCodeCommitUploadArchive 193 | PolicyDocument: 194 | Version: "2012-10-17" 195 | Statement: 196 | - Action: 197 | - "codecommit:UploadArchive" 198 | Effect: Allow 199 | Resource: !Sub arn:aws:codecommit:${Region}:${AWS::AccountId}:${CodeCommitRepoName} 200 | 201 | CodePipeline: 202 | Type: AWS::CodePipeline::Pipeline 203 | Properties: 204 | Name: UpdateLambdaCodePipeline 205 | RestartExecutionOnUpdate: true 206 | RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/${CodePipelineRole} 207 | Stages: 208 | - Name: Source 209 | Actions: 210 | - Name: Source 211 | ActionTypeId: 212 | Category: Source 213 | Owner: AWS 214 | Version: "1" 215 | Provider: CodeCommit 216 | OutputArtifacts: 217 | - Name: SourceArtifact 218 | Configuration: 219 | RepositoryName: !Ref CodeCommitRepoName 220 | BranchName: !Ref CodeCommitBranchName 221 | PollForSourceChanges: "false" 222 | RunOrder: 1 223 | Region: !Ref Region 224 | - Name: Deploy 225 | Actions: 226 | - Name: UpdateQueryCreationLambdaCode 227 | RunOrder: 1 228 | ActionTypeId: 229 | Category: Build 230 | Owner: AWS 231 | Version: "1" 232 | Provider: CodeBuild 233 | InputArtifacts: 234 | - Name: SourceArtifact 235 | Configuration: 236 | ProjectName: !Ref BuildProject 237 | ArtifactStore: 238 | Type: S3 239 | Location: !Ref PipelineBucket 240 | 241 | LambdaRole: 242 | Type: AWS::IAM::Role 243 | Properties: 244 | AssumeRolePolicyDocument: 245 | Version: 2012-10-17 246 | Statement: 247 | - Effect: Allow 248 | Principal: 249 | Service: 250 | - lambda.amazonaws.com 251 | Action: 252 | - "sts:AssumeRole" 253 | ManagedPolicyArns: 254 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 255 | Path: /service-role/ 256 | Policies: 257 | - PolicyName: S3PutObject 258 | PolicyDocument: 259 | Version: 2012-10-17 260 | Statement: 261 | - Effect: Allow 262 | Action: 263 | - "s3:PutObject" 264 | Resource: 265 | - !Join [ 266 | "", 267 | [ 268 | "arn:aws:s3:::", 269 | !Ref "PipelineBucket", 270 | "/*", 271 | ], 272 | ] 273 | - !Join [ 274 | "", 275 | [ 276 | "arn:aws:s3:::", 277 | !Ref "PipelineBucket", 278 | ], 279 | ] 280 | 281 | Lambda: 282 | Type: AWS::Lambda::Function 283 | Properties: 284 | Handler: index.lambda_handler 285 | Role: !GetAtt LambdaRole.Arn 286 | Runtime: python3.9 287 | Timeout: 120 288 | FunctionName: SampleLambda 289 | Code: 290 | S3Bucket: !Ref PipelineBucket 291 | S3Key: index.zip 292 | -------------------------------------------------------------------------------- /ci/taskcat.yml: -------------------------------------------------------------------------------- 1 | global: 2 | marketplace-ami: false 3 | owner: quickstart-eng@amazon.com 4 | qsname: quickstart-examples 5 | regions: 6 | - ap-northeast-1 7 | - ap-northeast-2 8 | - ap-south-1 9 | - ap-southeast-1 10 | - ap-southeast-2 11 | - ca-central-1 12 | - eu-central-1 13 | - eu-west-1 14 | - eu-west-2 15 | - sa-east-1 16 | - us-east-1 17 | - us-east-2 18 | - us-west-1 19 | - us-west-2 20 | reporting: true 21 | tests: 22 | json-master: 23 | parameter_input: workload-master.json 24 | regions: 25 | # - ap-northeast-1 26 | # - ap-northeast-2 27 | # - ap-south-1 28 | # - ap-southeast-1 29 | # - ap-southeast-2 30 | # - ca-central-1 31 | - eu-central-1 32 | template_file: workload-yaml-entrypoint-new-vpc.template.yaml 33 | yaml-master: 34 | parameter_input: workload-master.json 35 | regions: 36 | - eu-west-1 37 | # - eu-west-2 38 | # - us-east-1 39 | # - us-east-2 40 | # - us-west-1 41 | # - us-west-2 42 | template_file: workload-yaml-entrypoint-new-vpc.template.yaml 43 | -------------------------------------------------------------------------------- /doc/eks-architecture-examples/discngine-3decision-architecture-diagram.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/doc/eks-architecture-examples/discngine-3decision-architecture-diagram.pptx -------------------------------------------------------------------------------- /doc/serverless-architecture-examples/snowflake-sagemaker-autopilot-architecture-diagram.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/doc/serverless-architecture-examples/snowflake-sagemaker-autopilot-architecture-diagram.pptx -------------------------------------------------------------------------------- /doc/three-tier-architecture-examples/crest-infosolutions-cloudmeet-architecture-diagram.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/doc/three-tier-architecture-examples/crest-infosolutions-cloudmeet-architecture-diagram.pptx -------------------------------------------------------------------------------- /doc/three-tier-architecture-examples/nvidia-cheminformatics-architecture-diagram.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/doc/three-tier-architecture-examples/nvidia-cheminformatics-architecture-diagram.pptx -------------------------------------------------------------------------------- /patterns/LambdaZips/README.md: -------------------------------------------------------------------------------- 1 | # Lambda Zips 2 | 3 | This pattern enables templates that include Lambda functions to be deployed in any region without needing to manually 4 | create and populate additional regional buckets containing function zips. 5 | 6 | ## Example implementation 7 | 8 | [Full example template including custom resource source code.](/patterns/LambdaZips/example.yaml) 9 | 10 | ## Usage: 11 | ```yaml 12 | Resources: 13 | # Create a bucket in the local region 14 | LambdaZipsBucket: 15 | Type: AWS::S3::Bucket 16 | Properties: 17 | BucketEncryption: 18 | ServerSideEncryptionConfiguration: 19 | - ServerSideEncryptionByDefault: 20 | SSEAlgorithm: AES256 21 | PublicAccessBlockConfiguration: 22 | BlockPublicAcls: true 23 | BlockPublicPolicy: true 24 | IgnorePublicAcls: true 25 | RestrictPublicBuckets: true 26 | # Copy zip files from source bucket 27 | CopyZips: 28 | Type: Custom::CopyZips 29 | Properties: 30 | ServiceToken: !GetAtt 'CopyZipsFunction.Arn' 31 | DestBucket: !Ref 'LambdaZipsBucket' 32 | SourceBucket: !Ref 'QSS3BucketName' 33 | Prefix: !Ref 'QSS3KeyPrefix' 34 | Objects: 35 | - functions/packages/MyFunction/lambda.zip 36 | # Your lambda function 37 | MyFunction: 38 | # DependsOn is required to ensure copy is complete before creating the function 39 | DependsOn: CopyZips 40 | Type: AWS::Lambda::Function 41 | Properties: 42 | Code: 43 | # points to regional bucket 44 | S3Bucket: !Ref 'LambdaZipsBucket' 45 | S3Key: !Sub '${QSS3KeyPrefix}functions/packages/MyFunction/lambda.zip' 46 | ... 47 | ``` -------------------------------------------------------------------------------- /patterns/LambdaZips/example.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: 'Example Lambda zip copy' 3 | Parameters: 4 | QSS3BucketName: 5 | AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ 6 | Default: aws-quickstart 7 | Type: String 8 | QSS3KeyPrefix: 9 | AllowedPattern: ^[0-9a-zA-Z-/]*$ 10 | Default: quickstart-redhat-openshift/ 11 | Type: String 12 | Resources: 13 | LambdaZipsBucket: 14 | Type: AWS::S3::Bucket 15 | Properties: 16 | VersioningConfiguration: 17 | Status: Enabled 18 | BucketEncryption: 19 | ServerSideEncryptionConfiguration: 20 | - ServerSideEncryptionByDefault: 21 | SSEAlgorithm: AES256 22 | PublicAccessBlockConfiguration: 23 | BlockPublicAcls: true 24 | BlockPublicPolicy: true 25 | IgnorePublicAcls: true 26 | RestrictPublicBuckets: true 27 | CopyZips: 28 | Type: Custom::CopyZips 29 | Properties: 30 | ServiceToken: !GetAtt 'CopyZipsFunction.Arn' 31 | DestBucket: !Ref 'LambdaZipsBucket' 32 | SourceBucket: !Ref 'QSS3BucketName' 33 | Prefix: !Ref 'QSS3KeyPrefix' 34 | Objects: 35 | - functions/packages/CleanupPV/lambda.zip 36 | CopyZipsRole: 37 | Type: AWS::IAM::Role 38 | Properties: 39 | AssumeRolePolicyDocument: 40 | Version: '2012-10-17' 41 | Statement: 42 | - Effect: Allow 43 | Principal: 44 | Service: lambda.amazonaws.com 45 | Action: sts:AssumeRole 46 | ManagedPolicyArns: 47 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 48 | Path: / 49 | Policies: 50 | - PolicyName: lambda-copier 51 | PolicyDocument: 52 | Version: '2012-10-17' 53 | Statement: 54 | - Effect: Allow 55 | Action: 56 | - s3:GetObject 57 | Resource: 58 | - !Sub 'arn:aws:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*' 59 | - Effect: Allow 60 | Action: 61 | - s3:PutObject 62 | - s3:DeleteObject 63 | Resource: 64 | - !Sub 'arn:aws:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*' 65 | CopyZipsFunction: 66 | Type: AWS::Lambda::Function 67 | Properties: 68 | Description: Copies objects from a source S3 bucket to a destination 69 | Handler: index.handler 70 | Runtime: python3.7 71 | Role: !GetAtt 'CopyZipsRole.Arn' 72 | Timeout: 240 73 | Code: 74 | ZipFile: | 75 | import json 76 | import logging 77 | import threading 78 | import boto3 79 | import cfnresponse 80 | 81 | 82 | def copy_objects(source_bucket, dest_bucket, prefix, objects): 83 | s3 = boto3.client('s3') 84 | for o in objects: 85 | key = prefix + o 86 | copy_source = { 87 | 'Bucket': source_bucket, 88 | 'Key': key 89 | } 90 | print(('copy_source: %s' % copy_source)) 91 | print(('dest_bucket = %s'%dest_bucket)) 92 | print(('key = %s' %key)) 93 | s3.copy_object(CopySource=copy_source, Bucket=dest_bucket, 94 | Key=key) 95 | 96 | 97 | def delete_objects(bucket, prefix, objects): 98 | s3 = boto3.client('s3') 99 | objects = {'Objects': [{'Key': prefix + o} for o in objects]} 100 | s3.delete_objects(Bucket=bucket, Delete=objects) 101 | 102 | 103 | def timeout(event, context): 104 | logging.error('Execution is about to time out, sending failure response to CloudFormation') 105 | cfnresponse.send(event, context, cfnresponse.FAILED, {}, None) 106 | 107 | 108 | def handler(event, context): 109 | # make sure we send a failure to CloudFormation if the function 110 | # is going to timeout 111 | timer = threading.Timer((context.get_remaining_time_in_millis() 112 | / 1000.00) - 0.5, timeout, args=[event, context]) 113 | timer.start() 114 | 115 | print(('Received event: %s' % json.dumps(event))) 116 | status = cfnresponse.SUCCESS 117 | try: 118 | source_bucket = event['ResourceProperties']['SourceBucket'] 119 | dest_bucket = event['ResourceProperties']['DestBucket'] 120 | prefix = event['ResourceProperties']['Prefix'] 121 | objects = event['ResourceProperties']['Objects'] 122 | if event['RequestType'] == 'Delete': 123 | delete_objects(dest_bucket, prefix, objects) 124 | else: 125 | copy_objects(source_bucket, dest_bucket, prefix, objects) 126 | except Exception as e: 127 | logging.error('Exception: %s' % e, exc_info=True) 128 | status = cfnresponse.FAILED 129 | finally: 130 | timer.cancel() 131 | cfnresponse.send(event, context, status, {}, None) 132 | 133 | MyFunctionRole: 134 | Type: AWS::IAM::Role 135 | Properties: 136 | AssumeRolePolicyDocument: 137 | Version: '2012-10-17' 138 | Statement: 139 | - Effect: Allow 140 | Principal: 141 | Service: lambda.amazonaws.com 142 | Action: sts:AssumeRole 143 | ManagedPolicyArns: 144 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 145 | MyFunction: 146 | DependsOn: CopyZips 147 | Type: AWS::Lambda::Function 148 | Properties: 149 | Description: Example 150 | Handler: lambda_function.handler 151 | Runtime: python3.7 152 | Role: !GetAtt 'MyFunctionRole.Arn' 153 | Timeout: 300 154 | Code: 155 | S3Bucket: !Ref 'LambdaZipsBucket' 156 | S3Key: !Sub '${QSS3KeyPrefix}functions/packages/CleanupPV/lambda.zip' 157 | -------------------------------------------------------------------------------- /patterns/blog/CircularDependency/LessSimpleNonWorking.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | Properties: 7 | VersioningConfiguration: 8 | Status: Enabled 9 | BucketEncryption: 10 | ServerSideEncryptionConfiguration: 11 | - ServerSideEncryptionByDefault: 12 | SSEAlgorithm: AES256 13 | PublicAccessBlockConfiguration: 14 | BlockPublicAcls: true 15 | BlockPublicPolicy: true 16 | IgnorePublicAcls: true 17 | RestrictPublicBuckets: true 18 | Function: 19 | Type: AWS::Serverless::Function 20 | Properties: 21 | CodeUri: s3://bucketname/object.zip # Add in an S3 URI where you have code Lambda Code 22 | Runtime: python3.7 23 | Handler: index.handler 24 | Policies: 25 | - Version: 2012-10-17 26 | Statement: 27 | - Effect: Allow 28 | Action: s3:GetObject* 29 | Resource: !Sub "arn:aws:s3:::${Bucket}*" 30 | Events: 31 | Upload: 32 | Properties: 33 | Bucket: 34 | Ref: Bucket 35 | Events: s3:ObjectCreated:* 36 | Type: S3 -------------------------------------------------------------------------------- /patterns/blog/CircularDependency/LessSimpleWorking.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | Properties: 7 | VersioningConfiguration: 8 | Status: Enabled 9 | BucketName: !Sub "cderror-${AWS::AccountId}" 10 | BucketEncryption: 11 | ServerSideEncryptionConfiguration: 12 | - ServerSideEncryptionByDefault: 13 | SSEAlgorithm: AES256 14 | PublicAccessBlockConfiguration: 15 | BlockPublicAcls: true 16 | BlockPublicPolicy: true 17 | IgnorePublicAcls: true 18 | RestrictPublicBuckets: true 19 | Function: 20 | Type: AWS::Serverless::Function 21 | Properties: 22 | CodeUri: s3://bucketname/object.zip # Add in an S3 URI where you have code Lambda Code 23 | Runtime: python3.7 24 | Handler: index.handler 25 | Policies: 26 | - Version: 2012-10-17 27 | Statement: 28 | - Effect: Allow 29 | Action: s3:GetObject* 30 | Resource: !Sub "arn:aws:s3:::cderror-${AWS::AccountId}/*" 31 | Events: 32 | Upload: 33 | Properties: 34 | Bucket: 35 | Ref: Bucket 36 | Events: s3:ObjectCreated:* 37 | Type: S3 -------------------------------------------------------------------------------- /patterns/blog/CircularDependency/SimpleNonWorking.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Parameters: 3 | VPCID: 4 | Description: ID of the VPC (e.g., vpc-0343606e) 5 | Type: AWS::EC2::VPC::Id 6 | SubnetID: 7 | Description: ID of the private subnet 1 in Availability Zone 1 (e.g., subnet-a0246dcd) 8 | Type: AWS::EC2::Subnet::Id 9 | KeyPairName: 10 | Description: Public/private key pairs allow you to securely connect to your instance 11 | after it launches 12 | Type: AWS::EC2::KeyPair::KeyName 13 | WS2016FULLBASE: 14 | Type: 'AWS::SSM::Parameter::Value' 15 | Default: '/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base' 16 | Resources: 17 | MyEC2Instance: 18 | Type: AWS::EC2::Instance 19 | Properties: 20 | ImageId: !Ref 'WS2016FULLBASE' 21 | InstanceType: m4.large 22 | SubnetId: !Ref 'SubnetID' 23 | Tags: 24 | - Key: Name 25 | Value: TestBox 26 | BlockDeviceMappings: 27 | - DeviceName: /dev/sda1 28 | Ebs: 29 | VolumeSize: '80' 30 | VolumeType: gp2 31 | SecurityGroupIds: 32 | - !Ref 'InstanceSG' 33 | KeyName: !Ref 'KeyPairName' 34 | InstanceSG: 35 | Type: AWS::EC2::SecurityGroup 36 | Properties: 37 | GroupDescription: Domain Controllers Security Group 38 | VpcId: 39 | Ref: VPCID 40 | SecurityGroupIngress: 41 | - IpProtocol: tcp 42 | FromPort: 80 43 | ToPort: 80 44 | SourceSecurityGroupId: !Ref InstanceSG 45 | -------------------------------------------------------------------------------- /patterns/blog/CircularDependency/SimpleWorking.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Parameters: 3 | VPCID: 4 | Description: ID of the VPC (e.g., vpc-0343606e) 5 | Type: AWS::EC2::VPC::Id 6 | SubnetID: 7 | Description: ID of the private subnet 1 in Availability Zone 1 (e.g., subnet-a0246dcd) 8 | Type: AWS::EC2::Subnet::Id 9 | KeyPairName: 10 | Description: Public/private key pairs allow you to securely connect to your instance 11 | after it launches 12 | Type: AWS::EC2::KeyPair::KeyName 13 | WS2016FULLBASE: 14 | Type: 'AWS::SSM::Parameter::Value' 15 | Default: '/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base' 16 | Resources: 17 | MyEC2Instance: 18 | Type: AWS::EC2::Instance 19 | Properties: 20 | ImageId: !Ref 'WS2016FULLBASE' 21 | InstanceType: m4.large 22 | SubnetId: !Ref 'SubnetID' 23 | Tags: 24 | - Key: Name 25 | Value: TestBox 26 | BlockDeviceMappings: 27 | - DeviceName: /dev/sda1 28 | Ebs: 29 | VolumeSize: '80' 30 | VolumeType: gp2 31 | SecurityGroupIds: 32 | - !Ref 'InstanceSG' 33 | KeyName: !Ref 'KeyPairName' 34 | InstanceSG: 35 | Type: AWS::EC2::SecurityGroup 36 | Properties: 37 | GroupDescription: Domain Controllers Security Group 38 | VpcId: 39 | Ref: VPCID 40 | InstanceSecurityGroupIngress: 41 | Type: AWS::EC2::SecurityGroupIngress 42 | Properties: 43 | Description: Security Group Rule between Domain Controllers 44 | GroupId: !Ref InstanceSG 45 | IpProtocol: tcp 46 | FromPort: 80 47 | ToPort: 80 48 | SourceSecurityGroupId: !Ref InstanceSG -------------------------------------------------------------------------------- /samples/cloudformation-codebuild-container/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.9 as builder 2 | RUN go get -d -v golang.org/x/net/html 3 | RUN go get -d -v github.com/alexellis/href-counter/ 4 | WORKDIR /go/src/github.com/alexellis/href-counter/. 5 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . 6 | 7 | FROM alpine:latest 8 | RUN apk --no-cache add ca-certificates 9 | WORKDIR /root/ 10 | COPY --from=builder /go/src/github.com/alexellis/href-counter/app . 11 | CMD ["./app"] -------------------------------------------------------------------------------- /samples/cloudformation-codebuild-container/Dockerfile.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/samples/cloudformation-codebuild-container/Dockerfile.zip -------------------------------------------------------------------------------- /samples/cloudformation-codebuild-container/README.md: -------------------------------------------------------------------------------- 1 | ## Build container images using AWS CloudFormation 2 | 3 | In this example I demonstrate using Custom Lambda-backed resource to run a CodeBuild project, creating a Docker container image and uploading it to Amazon Elastic Container Regsitry, using Cloudformation. 4 | 5 | ![Overview](./overview.png) 6 | 7 | -------------------------------------------------------------------------------- /samples/cloudformation-codebuild-container/lambda_codebuild.py: -------------------------------------------------------------------------------- 1 | """This AWS Lambda Function kicks off a code build job.""" 2 | import http.client 3 | import urllib.parse 4 | import json 5 | import boto3 6 | import traceback 7 | 8 | 9 | def lambda_handler(event, context): 10 | """Main Lambda Handling function.""" 11 | account_id = context.invoked_function_arn.split(":")[4] 12 | 13 | try: 14 | # Log the received event 15 | print(("Received event: " + json.dumps(event, indent=2))) 16 | 17 | # Setup base response 18 | response = get_response_dict(event) 19 | 20 | # CREATE UPDATE (want to avoid rebuilds unless something changed) 21 | if event['RequestType'] in ("Create", "Update"): 22 | try: 23 | print("Kicking off Build") 24 | execute_build(event) 25 | except Exception as build_exce: 26 | print("ERROR: Build threw exception") 27 | print((repr(build_exce))) 28 | # Signal back that we failed 29 | return send_response(event, get_response_dict(event), 30 | "FAILED", repr(build_exce)) 31 | else: 32 | # CodeBuild will send the signal 33 | print("Build Kicked off ok CodeBuild should signal back") 34 | return 35 | elif event['RequestType'] == "Delete": 36 | # TODO: Remove the created images in the Repositories 37 | print("Delete event remove container images") 38 | response['PhysicalResourceId'] = "1233244324" 39 | try: 40 | resources = event['ResourceProperties'] 41 | repository = resources['ECRRepository'] 42 | cleanup_images_repo(repository, account_id) 43 | except Exception as cleanup_exception: 44 | # signal failure to CFN 45 | print((json.dumps(event, indent=2))) 46 | traceback.print_stack() 47 | print("---------") 48 | traceback.print_exc() 49 | print((repr(cleanup_exception))) 50 | return send_response(event, response, "FAILED", 51 | "Cleanup of Container image failed." + repr(cleanup_exception)) 52 | # signal success to CFN 53 | return send_response(event, response) 54 | else: 55 | # Invalid RequestType 56 | print("ERROR: Invalid request type send error signal to cfn") 57 | print("ERROR: Expected - Create, Update, Delete") 58 | except Exception as unhandled: 59 | response = get_response_dict(event) 60 | return send_response(event, response, "FAILED", 61 | "Unhandled exception, failing gracefully: " + str(unhandled)) 62 | 63 | 64 | def cleanup_images_repo(repository, account_id): 65 | """ 66 | Delete Container images 67 | """ 68 | ecr_client = boto3.client('ecr') 69 | 70 | print(("Repo:" + repository + " AccountID:" + account_id)) 71 | response = ecr_client.describe_images( 72 | registryId=account_id, 73 | repositoryName=repository 74 | ) 75 | image_ids = [] 76 | for imageDetail in response['imageDetails']: 77 | image_ids.append( 78 | { 79 | 'imageDigest': imageDetail['imageDigest'], 80 | } 81 | ) 82 | 83 | if len(image_ids): 84 | # delete images 85 | response = ecr_client.batch_delete_image( 86 | registryId=account_id, 87 | repositoryName=repository, 88 | imageIds=image_ids 89 | ) 90 | 91 | 92 | def execute_build(event): 93 | """Kickoff CodeBuild Project.""" 94 | build = boto3.client('codebuild') 95 | project_name = event["ResourceProperties"]["BuildProjectName"] 96 | signal_url = event["ResponseURL"] 97 | stack_id = event["StackId"] 98 | request_id = event["RequestId"] 99 | logical_resource_id = event["LogicalResourceId"] 100 | url = urllib.parse.urlparse(event['ResponseURL']) 101 | response = build.start_build( 102 | projectName=project_name, environmentVariablesOverride=[ 103 | {'name': 'url_path', 'value': url.path}, 104 | {'name': 'url_query', 'value': url.query}, 105 | {'name': 'cfn_signal_url', 'value': signal_url}, 106 | {'name': 'cfn_stack_id', 'value': stack_id}, 107 | {'name': 'cfn_request_id', 'value': request_id}, 108 | {'name': 'cfn_logical_resource_id', 'value': logical_resource_id} 109 | ]) 110 | return response 111 | 112 | 113 | def get_response_dict(event): 114 | """Setup Response object for CFN Signal.""" 115 | response = { 116 | 'StackId': event['StackId'], 117 | 'RequestId': event['RequestId'], 118 | 'LogicalResourceId': event['LogicalResourceId'], 119 | 'Status': 'SUCCESS' 120 | } 121 | return response 122 | 123 | 124 | def send_response(event, response, status=None, reason=None): 125 | """Response sender.""" 126 | if status is not None: 127 | response['Status'] = status 128 | 129 | if reason is not None: 130 | response['Reason'] = reason 131 | 132 | if 'ResponseURL' in event and event['ResponseURL']: 133 | url = urllib.parse.urlparse(event['ResponseURL']) 134 | body = json.dumps(response) 135 | https = http.client.HTTPSConnection(url.hostname) 136 | https.request('PUT', url.path+'?'+url.query, body) 137 | print("Sent CFN Response") 138 | 139 | return response 140 | -------------------------------------------------------------------------------- /samples/cloudformation-codebuild-container/lambda_codebuild.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/samples/cloudformation-codebuild-container/lambda_codebuild.zip -------------------------------------------------------------------------------- /samples/cloudformation-codebuild-container/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/samples/cloudformation-codebuild-container/overview.png -------------------------------------------------------------------------------- /samples/cloudformation-cross-account/README.md: -------------------------------------------------------------------------------- 1 | # Cross Account (or region or IAM identity) CloudFormation Custom Resource 2 | 3 | Provides a custom resource that takes a template url, parameters, role ARN and region and launches a stack using the given role/region. 4 | 5 | For a walkthrough on it's usage see [this article](https://aws.amazon.com/blogs/infrastructure-and-automation/multiple-account-multiple-region-aws-cloudformation/) 6 | -------------------------------------------------------------------------------- /samples/cloudformation-cross-account/examples/bucket.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Parameters: 3 | Tag: 4 | Type: String 5 | Resources: 6 | S3Bucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketEncryption: 10 | ServerSideEncryptionConfiguration: 11 | - ServerSideEncryptionByDefault: 12 | SSEAlgorithm: AES256 13 | PublicAccessBlockConfiguration: 14 | BlockPublicAcls: true 15 | BlockPublicPolicy: true 16 | IgnorePublicAcls: true 17 | RestrictPublicBuckets: true 18 | Tags: 19 | - Key: cross-account 20 | Value: !Ref Tag 21 | VersioningConfiguration: 22 | Status: Enabled 23 | Outputs: 24 | AccountId: 25 | Value: !Ref AWS::AccountId 26 | BucketName: 27 | Value: !Ref S3Bucket 28 | -------------------------------------------------------------------------------- /samples/cloudformation-cross-account/examples/central-iam.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Parameters: 3 | DevAccountId: 4 | Type: String 5 | DevAccountRoleName: 6 | Type: String 7 | Default: XaccBlogDevAccountRole 8 | CentralAccountRoleName: 9 | Type: String 10 | Default: XaccBlogCentralAccountRole 11 | Resources: 12 | CentralAccountRole: 13 | Type: "AWS::IAM::Role" 14 | Properties: 15 | RoleName: !Ref CentralAccountRoleName 16 | AssumeRolePolicyDocument: 17 | Version: 2012-10-17 18 | Statement: 19 | - Effect: Allow 20 | Principal: 21 | Service: lambda.amazonaws.com 22 | Action: sts:AssumeRole 23 | Policies: 24 | - PolicyName: AssumeRole 25 | PolicyDocument: 26 | Version: '2012-10-17' 27 | Statement: 28 | - Effect: Allow 29 | Action: 30 | - logs:CreateLogGroup 31 | - logs:CreateLogStream 32 | - logs:PutLogEvents 33 | - cloudformation:DescribeStacks 34 | - lambda:AddPermission 35 | - lambda:RemovePermission 36 | - events:PutRule 37 | - events:DeleteRule 38 | - events:PutTargets 39 | - events:RemoveTargets 40 | Resource: "*" 41 | #- Effect: Allow 42 | # Action: 43 | # - iam:PassRole 44 | # Resource: !GetAtt ControlPlaneRole.Arn 45 | - Action: "sts:AssumeRole" 46 | Effect: Allow 47 | Resource: !Sub "arn:aws:iam::${DevAccountId}:role/${DevAccountRoleName}" 48 | Outputs: 49 | CentralAccountRoleArn: 50 | Value: !GetAtt CentralAccountRole.Arn 51 | -------------------------------------------------------------------------------- /samples/cloudformation-cross-account/examples/cross-account.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: Creates an S3 bucket in eu-north-1 and ap-northeast-1 in a remote account 3 | Parameters: 4 | CentralRoleArn: 5 | Type: String 6 | Description: The IAM role name for the role that is trusted by the destination role. 7 | DevRoleArn: 8 | Type: String 9 | Description: The IAM role to be assumed and used to create a CloudFormation stack containing an S3 bucket. 10 | Resources: 11 | DevStackTokyo: 12 | Type: Custom::CfnStackMaker 13 | Version: 1.0 14 | Properties: 15 | ServiceToken: !GetAtt CfnAssumeRoleLambda.Arn 16 | RoleArn: !Ref DevRoleArn 17 | TemplateURL: https://s3.amazonaws.com/aws-quickstart/quickstart-examples/samples/cloudformation-cross-account/examples/bucket.yaml 18 | ParentStackId: !Ref AWS::StackId 19 | Region: ap-northeast-1 20 | CfnParameters: 21 | Tag: Tokyo 22 | DevStackStockholm: 23 | Type: Custom::CfnStackMaker 24 | Version: 1.0 25 | Properties: 26 | ServiceToken: !GetAtt CfnAssumeRoleLambda.Arn 27 | RoleArn: !Ref DevRoleArn 28 | TemplateURL: https://s3.amazonaws.com/aws-quickstart/quickstart-examples/samples/cloudformation-cross-account/examples/bucket.yaml 29 | ParentStackId: !Ref AWS::StackId 30 | Region: eu-north-1 31 | CfnParameters: 32 | Tag: Stockholm 33 | CfnAssumeRoleLambda: 34 | Type: AWS::Lambda::Function 35 | Properties: 36 | Handler: lambda_function.lambda_handler 37 | MemorySize: 128 38 | Role: !Ref CentralRoleArn 39 | Runtime: python3.6 40 | Timeout: 900 41 | Code: 42 | S3Bucket: 'aws-quickstart' 43 | S3Key: 'quickstart-examples/samples/cloudformation-cross-account/functions/packages/CfnStackAssumeRole/lambda.zip' 44 | Outputs: 45 | DestinationAccountId: 46 | Value: !GetAtt DevStackTokyo.AccountId 47 | DevAccountTokyoBucket: 48 | Value: !GetAtt DevStackTokyo.BucketName 49 | DevAccountStockholmBucket: 50 | Value: !GetAtt DevStackStockholm.BucketName 51 | -------------------------------------------------------------------------------- /samples/cloudformation-cross-account/examples/dev-iam.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Parameters: 3 | CentralAccountId: 4 | Type: String 5 | CentralAccountRoleName: 6 | Type: String 7 | Default: XaccBlogCentralAccountRole 8 | DevAccountRoleName: 9 | Type: String 10 | Default: XaccBlogDevAccountRole 11 | Resources: 12 | DevAccountRole: 13 | Type: AWS::IAM::Role 14 | Properties: 15 | RoleName: !Ref DevAccountRoleName 16 | AssumeRolePolicyDocument: 17 | Version: '2012-10-17' 18 | Statement: 19 | - Effect: Allow 20 | Principal: 21 | AWS: !Sub 'arn:aws:iam::${CentralAccountId}:role/${CentralAccountRoleName}' 22 | Action: sts:AssumeRole 23 | Path: / 24 | Policies: 25 | - PolicyName: CfnStackAssumeRole 26 | PolicyDocument: 27 | Version: '2012-10-17' 28 | Statement: 29 | - Effect: Allow 30 | Action: 31 | - 'cloudformation:CreateStack' 32 | - 'cloudformation:UpdateStack' 33 | - 'cloudformation:DeleteStack' 34 | - 'cloudformation:DescribeStacks' 35 | Resource: "*" 36 | - Effect: Allow 37 | Action: 38 | - 's3:CreateBucket' 39 | - 's3:DeleteBucket' 40 | - 's3:DeleteBucket*' 41 | - 's3:PutBucket*' 42 | Resource: "*" 43 | Outputs: 44 | DevAccountRoleArn: 45 | Value: !GetAtt DevAccountRole.Arn 46 | -------------------------------------------------------------------------------- /samples/cloudformation-cross-account/functions/packages/CfnStackAssumeRole/lambda.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-quickstart/quickstart-examples/9e148640817b1d47203da31f8eedbde46df066f6/samples/cloudformation-cross-account/functions/packages/CfnStackAssumeRole/lambda.zip -------------------------------------------------------------------------------- /samples/cloudformation-stack-ttl/README.md: -------------------------------------------------------------------------------- 1 | Scheduling automatic deletion of CloudFormation stacks 2 | -------------------------------------------------------------------------------- /samples/cloudformation-stack-ttl/scripts/deploy-admin-stack.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aws cloudformation create-stack --stack-name --region us-east-1 cfn-admin-role-stack \ 4 | --template-url https://s3.amazonaws.com/aws-quickstart/quickstart-examples/samples/cloudformation-stack-ttl/templates/cloudformation-admin-iam.yaml \ 5 | --capabilities "CAPABILITY_IAM" "CAPABILITY_AUTO_EXPAND" \ 6 | --disable-rollback 7 | -------------------------------------------------------------------------------- /samples/cloudformation-stack-ttl/scripts/deploy-demo-stack.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aws cloudformation create-stack --stack-name --region us-east-1 demo-stack-ttl \ 4 | --template-url https://s3.amazonaws.com/aws-quickstart/quickstart-examples/samples/cloudformation-stack-ttl/templates/demo-stack-ttl.yaml \ 5 | --capabilities "CAPABILITY_IAM" "CAPABILITY_AUTO_EXPAND" \ 6 | --role-arn "" \ 7 | --disable-rollback 8 | -------------------------------------------------------------------------------- /samples/cloudformation-stack-ttl/templates/cloudformation-admin-iam.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Administrator access service role for CloudFormation 3 | Resources: 4 | CFNAdminRole: 5 | Type: "AWS::IAM::Role" 6 | Properties: 7 | AssumeRolePolicyDocument: 8 | Version: "2012-10-17" 9 | Statement: 10 | - Effect: "Allow" 11 | Principal: 12 | Service: ["cloudformation.amazonaws.com"] 13 | Action: "sts:AssumeRole" 14 | Path: "/" 15 | ManagedPolicyArns: 16 | - 'arn:aws:iam::aws:policy/AdministratorAccess' 17 | Outputs: 18 | CFNAdminRole: 19 | Description: CloudFormation admin access service role. 20 | Value: !Ref CFNAdminRole 21 | CFNAdminRoleArn: 22 | Description: CloudFormation admin access service role ARN. 23 | Value: !GetAtt CFNAdminRole.Arn 24 | -------------------------------------------------------------------------------- /samples/cloudformation-stack-ttl/templates/cloudformation-stack-ttl.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Schedule automatic deletion of CloudFormation stacks. (qs-1s7darhsn) 3 | Metadata: 4 | AWS::CloudFormation::Interface: 5 | ParameterGroups: 6 | - Label: 7 | default: Input configuration 8 | Parameters: 9 | - StackName 10 | - TTL 11 | ParameterLabels: 12 | StackName: 13 | default: Stack name 14 | TTL: 15 | default: Time-to-live 16 | Parameters: 17 | StackName: 18 | Type: String 19 | Description: Stack name that will be deleted. 20 | TTL: 21 | Type: Number 22 | Description: Time-to-live in minutes for the stack. 23 | Resources: 24 | DeleteCFNLambdaExecutionRole: 25 | Type: "AWS::IAM::Role" 26 | Properties: 27 | AssumeRolePolicyDocument: 28 | Version: "2012-10-17" 29 | Statement: 30 | - Effect: "Allow" 31 | Principal: 32 | Service: ["lambda.amazonaws.com"] 33 | Action: "sts:AssumeRole" 34 | Path: "/" 35 | Policies: 36 | - PolicyName: "lambda_policy" 37 | PolicyDocument: 38 | Version: "2012-10-17" 39 | Statement: 40 | - Effect: "Allow" 41 | Action: 42 | - "logs:CreateLogGroup" 43 | - "logs:CreateLogStream" 44 | - "logs:PutLogEvents" 45 | Resource: "arn:aws:logs:*:*:*" 46 | - Effect: "Allow" 47 | Action: 48 | - "cloudformation:DeleteStack" 49 | Resource: !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${StackName}/*" 50 | DeleteCFNLambda: 51 | Type: "AWS::Lambda::Function" 52 | DependsOn: 53 | - DeleteCFNLambdaExecutionRole 54 | Properties: 55 | FunctionName: !Sub "DeleteCFNLambda-${StackName}" 56 | Code: 57 | ZipFile: | 58 | import boto3 59 | import os 60 | import json 61 | 62 | stack_name = os.environ['stackName'] 63 | 64 | def delete_cfn(stack_name): 65 | try: 66 | cfn = boto3.resource('cloudformation') 67 | stack = cfn.Stack(stack_name) 68 | stack.delete() 69 | return "SUCCESS" 70 | except: 71 | return "ERROR" 72 | 73 | def handler(event, context): 74 | print("Received event:") 75 | print(json.dumps(event)) 76 | return delete_cfn(stack_name) 77 | Environment: 78 | Variables: 79 | stackName: !Ref 'StackName' 80 | Handler: "index.handler" 81 | Runtime: "python3.9" 82 | Timeout: "5" 83 | Role: !GetAtt DeleteCFNLambdaExecutionRole.Arn 84 | DeleteStackEventRule: 85 | DependsOn: 86 | - DeleteCFNLambda 87 | - GenerateCronExpression 88 | Type: "AWS::Events::Rule" 89 | Properties: 90 | Description: Delete stack event 91 | ScheduleExpression: !GetAtt GenerateCronExpression.cron_exp 92 | State: "ENABLED" 93 | Targets: 94 | - 95 | Arn: !GetAtt DeleteCFNLambda.Arn 96 | Id: 'DeleteCFNLambda' 97 | PermissionForDeleteCFNLambda: 98 | Type: "AWS::Lambda::Permission" 99 | Properties: 100 | FunctionName: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:DeleteCFNLambda-${StackName}" 101 | Action: "lambda:InvokeFunction" 102 | Principal: "events.amazonaws.com" 103 | SourceArn: !GetAtt DeleteStackEventRule.Arn 104 | BasicLambdaExecutionRole: 105 | Type: "AWS::IAM::Role" 106 | Properties: 107 | AssumeRolePolicyDocument: 108 | Version: "2012-10-17" 109 | Statement: 110 | - Effect: "Allow" 111 | Principal: 112 | Service: ["lambda.amazonaws.com"] 113 | Action: "sts:AssumeRole" 114 | Path: "/" 115 | Policies: 116 | - PolicyName: "lambda_policy" 117 | PolicyDocument: 118 | Version: "2012-10-17" 119 | Statement: 120 | - Effect: "Allow" 121 | Action: 122 | - "logs:CreateLogGroup" 123 | - "logs:CreateLogStream" 124 | - "logs:PutLogEvents" 125 | Resource: "arn:aws:logs:*:*:*" 126 | GenerateCronExpLambda: 127 | Type: "AWS::Lambda::Function" 128 | Properties: 129 | Code: 130 | ZipFile: | 131 | from datetime import datetime, timedelta 132 | import os 133 | import logging 134 | import json 135 | import cfnresponse 136 | 137 | def deletion_time(ttl): 138 | delete_at_time = datetime.now() + timedelta(minutes=int(ttl)) 139 | hh = delete_at_time.hour 140 | mm = delete_at_time.minute 141 | yyyy = delete_at_time.year 142 | month = delete_at_time.month 143 | dd = delete_at_time.day 144 | # minutes hours day month day-of-week year 145 | cron_exp = "cron({} {} {} {} ? {})".format(mm, hh, dd, month, yyyy) 146 | return cron_exp 147 | 148 | def handler(event, context): 149 | print('Received event: %s' % json.dumps(event)) 150 | status = cfnresponse.SUCCESS 151 | try: 152 | if event['RequestType'] == 'Delete': 153 | cfnresponse.send(event, context, status, {}) 154 | else: 155 | ttl = event['ResourceProperties']['ttl'] 156 | responseData = {} 157 | responseData['cron_exp'] = deletion_time(ttl) 158 | cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData) 159 | except Exception as e: 160 | logging.error('Exception: %s' % e, exc_info=True) 161 | status = cfnresponse.FAILED 162 | cfnresponse.send(event, context, status, {}, None) 163 | Handler: "index.handler" 164 | Runtime: "python3.9" 165 | Timeout: "5" 166 | Role: !GetAtt BasicLambdaExecutionRole.Arn 167 | 168 | GenerateCronExpression: 169 | Type: "Custom::GenerateCronExpression" 170 | Version: "1.0" 171 | Properties: 172 | ServiceToken: !GetAtt GenerateCronExpLambda.Arn 173 | ttl: !Ref 'TTL' 174 | -------------------------------------------------------------------------------- /samples/cloudformation-stack-ttl/templates/demo-stack-ttl.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Demo stack, creates one SSM parameter and gets deleted after 5 minutes. 3 | Resources: 4 | DemoParameter: 5 | Type: "AWS::SSM::Parameter" 6 | Properties: 7 | Type: "String" 8 | Value: "date" 9 | Description: "SSM Parameter for running date command." 10 | AllowedPattern: "^[a-zA-Z]{1,10}$" 11 | DeleteAfterTTLStack: 12 | Type: "AWS::CloudFormation::Stack" 13 | Properties: 14 | TemplateURL: 'https://aws-quickstart.s3.amazonaws.com/quickstart-examples/samples/cloudformation-stack-ttl/templates/cloudformation-stack-ttl.yaml' 15 | Parameters: 16 | StackName: !Ref 'AWS::StackName' 17 | TTL: '5' 18 | -------------------------------------------------------------------------------- /samples/ec2-instance-connect/ec2-instance-connection-example.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This template sets up a VPC and ec2 instance for the purposes of demonstrating connecting to bastion instance in public subnet using EC2 Instance Connect. (qs-1pri98mak) 3 | 4 | Parameters: 5 | LatestAmiId: 6 | Type: 'AWS::SSM::Parameter::Value' 7 | Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' 8 | AvailabilityZones: 9 | Description: List of Availability Zones to use for the subnets in the VPC. Only 10 | two Availability Zones are used for this deployment, and the logical order of 11 | your selections is preserved. 12 | Type: List 13 | RemoteAccessCIDR: 14 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ 15 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x 16 | Description: CIDR IP range that is permitted to access the bastions. We recommend 17 | that you set this value to a trusted IP range. 18 | Type: String 19 | 20 | Mappings: 21 | DefaultConfiguration: 22 | MachineConfiguration: 23 | EC2InstanceType: t3.micro 24 | NetworkConfiguration: 25 | VPCCIDR: 10.0.0.0/16 26 | PublicSubnet1CIDR: 10.0.128.0/20 27 | PublicSubnet2CIDR: 10.0.144.0/20 28 | 29 | Resources: 30 | EC2InstanceConnectRole: 31 | Type: "AWS::IAM::Role" 32 | Properties: 33 | AssumeRolePolicyDocument: 34 | Version: "2012-10-17" 35 | Statement: 36 | - Effect: "Allow" 37 | Principal: 38 | AWS: 39 | - Fn::Sub: arn:aws:iam::${AWS::AccountId}:root 40 | Action: "sts:AssumeRole" 41 | Path: "/" 42 | ManagedPolicyArns: 43 | - !Ref EC2InstanceConnectCLIPolicy 44 | EC2InstanceConnectSSHPolicy: 45 | Type: AWS::IAM::ManagedPolicy 46 | Properties: 47 | Description: Policy to use SSH client to connect to an instance using EC2 Instance Connect 48 | PolicyDocument: 49 | Version: "2012-10-17" 50 | Statement: 51 | - Action: 52 | - ec2-instance-connect:SendSSHPublicKey 53 | Effect: Allow 54 | Resource: 55 | Fn::Sub: arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${BastionInstance} 56 | Condition: 57 | StringEquals: 58 | ec2:osuser: "ec2-user" 59 | EC2InstanceConnectCLIPolicy: 60 | Type: AWS::IAM::ManagedPolicy 61 | Properties: 62 | Description: Policy to connect to an instance using EC2 Instance Connect CLI 63 | PolicyDocument: 64 | Version: "2012-10-17" 65 | Statement: 66 | - Action: 67 | - ec2-instance-connect:SendSSHPublicKey 68 | Effect: Allow 69 | Resource: 70 | Fn::Sub: arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${BastionInstance} 71 | Condition: 72 | StringEquals: 73 | ec2:osuser: "ec2-user" 74 | - Action: 75 | - ec2:DescribeInstances 76 | Effect: Allow 77 | Resource: "*" 78 | VPCStack: 79 | Type: AWS::CloudFormation::Stack 80 | Properties: 81 | TemplateURL: 82 | Fn::Sub: https://aws-quickstart.s3.amazonaws.com/quickstart-aws-vpc/templates/aws-vpc.template 83 | Parameters: 84 | AvailabilityZones: 85 | Fn::Join: 86 | - ',' 87 | - Ref: AvailabilityZones 88 | NumberOfAZs: '2' 89 | CreatePrivateSubnets: 'false' 90 | PublicSubnet1CIDR: !FindInMap 91 | - DefaultConfiguration 92 | - NetworkConfiguration 93 | - PublicSubnet1CIDR 94 | PublicSubnet2CIDR: !FindInMap 95 | - DefaultConfiguration 96 | - NetworkConfiguration 97 | - PublicSubnet2CIDR 98 | VPCCIDR: !FindInMap 99 | - DefaultConfiguration 100 | - NetworkConfiguration 101 | - VPCCIDR 102 | BastionSecurityGroup: 103 | Type: AWS::EC2::SecurityGroup 104 | Properties: 105 | GroupDescription: Enables SSH Access to Bastion Hosts 106 | VpcId: 107 | Fn::GetAtt: 108 | - VPCStack 109 | - Outputs.VPCID 110 | SecurityGroupIngress: 111 | - IpProtocol: tcp 112 | FromPort: '22' 113 | ToPort: '22' 114 | CidrIp: !Ref 'RemoteAccessCIDR' 115 | - IpProtocol: tcp 116 | FromPort: '22' 117 | ToPort: '22' 118 | CidrIp: !GetAtt FetchIPRange.ip_range 119 | - IpProtocol: icmp 120 | FromPort: '-1' 121 | ToPort: '-1' 122 | CidrIp: !Ref 'RemoteAccessCIDR' 123 | BastionInstance: 124 | Type: AWS::EC2::Instance 125 | Properties: 126 | ImageId: !Ref LatestAmiId 127 | InstanceType: !FindInMap 128 | - DefaultConfiguration 129 | - MachineConfiguration 130 | - EC2InstanceType 131 | SecurityGroupIds: 132 | - !Ref BastionSecurityGroup 133 | SubnetId: 134 | Fn::GetAtt: 135 | - VPCStack 136 | - Outputs.PublicSubnet1ID 137 | Tags: 138 | - 139 | Key: Name 140 | Value: EC2-Instance-Connect-Demo 141 | UserData: 142 | Fn::Base64: 143 | !Sub | 144 | #!/bin/bash 145 | sudo yum install -y ec2-instance-connect 146 | BasicLambdaExecutionRole: 147 | Type: "AWS::IAM::Role" 148 | Properties: 149 | AssumeRolePolicyDocument: 150 | Version: "2012-10-17" 151 | Statement: 152 | - Effect: "Allow" 153 | Principal: 154 | Service: ["lambda.amazonaws.com"] 155 | Action: "sts:AssumeRole" 156 | Path: "/" 157 | Policies: 158 | - PolicyName: "lambda_policy" 159 | PolicyDocument: 160 | Version: "2012-10-17" 161 | Statement: 162 | - Effect: "Allow" 163 | Action: 164 | - "logs:CreateLogGroup" 165 | - "logs:CreateLogStream" 166 | - "logs:PutLogEvents" 167 | Resource: "arn:aws:logs:*:*:*" 168 | FetchIPRangeLambda: 169 | Type: "AWS::Lambda::Function" 170 | Properties: 171 | Code: 172 | ZipFile: | 173 | import urllib 174 | import urllib.request 175 | import json 176 | import os 177 | import cfnresponse 178 | 179 | def get_url_content(url): 180 | try: 181 | template_raw_data = urllib.request.urlopen(url).read().decode('utf-8') 182 | return template_raw_data.strip() 183 | except: 184 | return "ERROR" 185 | 186 | def get_ip_range(service, region): 187 | ip_ranges_url = os.environ['ip_ranges_url'] 188 | ip_ranges_text = get_url_content(ip_ranges_url) 189 | ip_ranges_json = json.loads(ip_ranges_text) 190 | prefix_dict = ip_ranges_json["prefixes"] 191 | connect_prefix = [x for x in prefix_dict if x['service'] == service and x['region'] == region] 192 | return connect_prefix[0]['ip_prefix'] 193 | 194 | def handler(event, context): 195 | print('Received event: %s' % json.dumps(event)) 196 | status = cfnresponse.SUCCESS 197 | try: 198 | if event['RequestType'] == 'Delete': 199 | cfnresponse.send(event, context, status, {}) 200 | else: 201 | region = event['ResourceProperties']['Region'] 202 | responseData = {} 203 | responseData['ip_range'] = get_ip_range('EC2_INSTANCE_CONNECT', region) 204 | cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData) 205 | except Exception as e: 206 | logging.error('Exception: %s' % e, exc_info=True) 207 | status = cfnresponse.FAILED 208 | cfnresponse.send(event, context, status, {}, None) 209 | Environment: 210 | Variables: 211 | ip_ranges_url: 'https://ip-ranges.amazonaws.com/ip-ranges.json' 212 | Handler: "index.handler" 213 | Runtime: "python3.6" 214 | Timeout: "30" 215 | Role: !GetAtt BasicLambdaExecutionRole.Arn 216 | FetchIPRange: 217 | Type: "Custom::GenerateCronExpression" 218 | Version: "1.0" 219 | Properties: 220 | ServiceToken: !GetAtt FetchIPRangeLambda.Arn 221 | Region: !Ref AWS::Region 222 | 223 | Outputs: 224 | BastionInstance: 225 | Description: The instance ID of the demo bastion instance. 226 | Value: !Ref BastionInstance 227 | BastionDNSName: 228 | Description: The DNS name of the bastion instance. 229 | Value: !GetAtt BastionInstance.PublicDnsName 230 | DeployAZ: 231 | Description: The Availability Zone where the bastion instance is launched. 232 | Value: !GetAtt BastionInstance.AvailabilityZone 233 | BastionSecurityGroup: 234 | Description: Bastion Security Group ID 235 | Value: !Ref BastionSecurityGroup 236 | EC2InstanceConnectRole: 237 | Description: The ARN of the EC2 Instance Connect Role 238 | Value: !Ref EC2InstanceConnectRole 239 | 240 | 241 | -------------------------------------------------------------------------------- /samples/ec2-instance-userdata/ec2InstanceUserData.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyEC2AccessRole: 3 | Type: AWS::IAM::Role 4 | Properties: 5 | AssumeRolePolicyDocument: 6 | Version: '2012-10-17' 7 | Statement: 8 | - Effect: Allow 9 | Principal: 10 | Service: 11 | - ec2.amazonaws.com 12 | Action: 13 | - sts:AssumeRole 14 | Path: "/" 15 | CWRolePolicies: 16 | Type: AWS::IAM::Policy 17 | Properties: 18 | PolicyName: CloudWatchLogsFullAccess 19 | PolicyDocument: 20 | Version: '2012-10-17' 21 | Statement: 22 | - Effect: Allow 23 | Action: "*" 24 | Resource: "*" 25 | Roles: 26 | - !Ref MyEC2AccessRole 27 | SMRolePolicies: 28 | Type: AWS::IAM::Policy 29 | Properties: 30 | PolicyName: SecretsManagerReadWrite 31 | PolicyDocument: 32 | Version: '2012-10-17' 33 | Statement: 34 | - Effect: Allow 35 | Action: "*" 36 | Resource: "*" 37 | Roles: 38 | - !Ref MyEC2AccessRole 39 | MyEC2InstanceProfile: 40 | Type: AWS::IAM::InstanceProfile 41 | Properties: 42 | Path: "/" 43 | Roles: 44 | - !Ref MyEC2AccessRole 45 | MyEC2Instance: 46 | Type: AWS::EC2::Instance 47 | Properties: 48 | ImageId: "ami-057549bd0bba43bc1" 49 | Tags: 50 | - 51 | Key: "Name" 52 | Value: "MyWindowsInstance" 53 | IamInstanceProfile: 54 | !Ref MyEC2InstanceProfile 55 | UserData: 56 | !Base64 | 57 | 58 | function Write-LogsEntry 59 | { 60 | [CmdletBinding()] 61 | Param( 62 | [Parameter(Mandatory=$true)] 63 | [string] $LogGroupName, 64 | [Parameter(Mandatory=$true)] 65 | [string] $LogStreamName, 66 | [Parameter(Mandatory=$true)] 67 | [string] $LogString 68 | ) 69 | 70 | #Determine if the LogGroup Exists 71 | If (-Not (Get-CWLLogGroup -LogGroupNamePrefix $LogGroupName)){ 72 | New-CWLLogGroup -LogGroupName $logGroupName 73 | #Since the loggroup does not exist, we know the logstream does not exist either 74 | $CWLSParam = @{ 75 | LogGroupName = $logGroupName 76 | LogStreamName = $logStreamName 77 | } 78 | New-CWLLogStream @CWLSParam 79 | } 80 | #Determine if the LogStream Exists 81 | If (-Not (Get-CWLLogStream -LogGroupName $logGroupName -LogStreamName $LogStreamName)){ 82 | $CWLSParam = @{ 83 | LogGroupName = $logGroupName 84 | LogStreamName = $logStreamName 85 | } 86 | New-CWLLogStream @CWLSParam 87 | } 88 | 89 | $logEntry = New-Object -TypeName 'Amazon.CloudWatchLogs.Model.InputLogEvent' 90 | $logEntry.Message = $LogString 91 | $logEntry.Timestamp = (Get-Date).ToUniversalTime() 92 | #Get the next sequence token 93 | $SequenceToken = (Get-CWLLogStream -LogGroupName $LogGroupName -LogStreamNamePrefix $logStreamName).UploadSequenceToken 94 | 95 | #There will be no $SequenceToken when a new Stream is created to we adjust the parameters for this 96 | if($SequenceToken){ 97 | $CWLEParam = @{ 98 | LogEvent = $logEntry 99 | LogGroupName = $logGroupName 100 | LogStreamName = $logStreamName 101 | SequenceToken = $SequenceToken 102 | } 103 | Write-CWLLogEvent @CWLEParam 104 | }else{ 105 | $CWLEParam = @{ 106 | LogEvent = $logEntry 107 | LogGroupName = $logGroupName 108 | LogStreamName = $logStreamName 109 | } 110 | Write-CWLLogEvent @CWLEParam 111 | } 112 | } 113 | 114 | $logGroupName = 'MyNewWindowsInstance' 115 | $logStreamName = "MyWindowsInstance" + (Get-Date (Get-Date).ToUniversalTime() -Format "MM-dd-yyyy" ) 116 | 117 | New-LocalUser -Name (ConvertFrom-Json -InputObject (Get-SECSecretValue -SecretId LocalBuildCredenitals).SecretString).username -Password (ConvertTo-SecureString (ConvertFrom-Json -InputObject (Get-SECSecretValue -SecretId LocalBuildCredenitals).SecretString).password -AsPlainText -Force) 118 | 119 | Write-LogsEntry -LogGroupName $LogGroupName -LogStreamName $LogStreamName -LogString 'Created local user' 120 | 121 | Add-LocalGroupMember -Group "Administrators" -Member (ConvertFrom-Json -InputObject (Get-SECSecretValue -SecretId LocalBuildCredenitals).SecretString).username 122 | Write-LogsEntry -LogGroupName $LogGroupName -LogStreamName $LogStreamName -LogString 'Added local user to Administrators Group' 123 | Add-LocalGroupMember -Group "Remote Management Users" -Member (ConvertFrom-Json -InputObject (Get-SECSecretValue -SecretId LocalBuildCredenitals).SecretString).username 124 | Write-LogsEntry -LogGroupName $LogGroupName -LogStreamName $LogStreamName -LogString 'Added local user to Remote Management Users Group' 125 | 126 | Install-WindowsFeature web-mgmt-console 127 | Write-LogsEntry -LogGroupName $LogGroupName -LogStreamName $LogStreamName -LogString 'Installed Windows Feature Web Management Console' 128 | Enable-PSRemoting -Force 129 | Write-LogsEntry -LogGroupName $LogGroupName -LogStreamName $LogStreamName -LogString 'Enabled Powersell remoting' 130 | 131 | Write-LogsEntry -LogGroupName $LogGroupName -LogStreamName $LogStreamName -LogString 'UserData processing complete' 132 | 133 | -------------------------------------------------------------------------------- /samples/eks-app-helm-deploy/helm-wordpress-deploy-RDS.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This Cloudformation template shows you how to use Cloudformation to deploy 3 | WordPress using Helm charts. You will be deploying this into the "Amazon EKS QuickStart" 4 | which is a qre-requist. "https://docs.aws.amazon.com/quickstart/latest/amazon-eks-architecture/welcome.html" **WARNING** You will be billed for the AWS resources used if you create a stack from this template. 5 | Metadata: 6 | AWS::CloudFormation::Interface: 7 | ParameterGroups: 8 | - Label: 9 | default: Wordpress 10 | Parameters: 11 | - wordpressUsername 12 | - wordpressPassword 13 | - Label: 14 | default: Kube Cluster 15 | Parameters: 16 | - KubeClusterName 17 | - KubeConfigPath 18 | - KubeGetLambdaArn 19 | - KubeConfigKmsContext 20 | - HelmLambdaArn 21 | - Namespace 22 | - Name 23 | - Label: 24 | default: MariaDB (RDS) 25 | Parameters: 26 | - DBMasterUsername 27 | - DBMasterUserPassword 28 | - DBName 29 | - Subnet1ID 30 | - Subnet2ID 31 | - VPCID 32 | - NodeGroupSecurityGroupId 33 | - BastionSecurityGroupId 34 | ParameterLabels: 35 | wordpressUsername: 36 | default: Wordpress Username 37 | wordpressPassword: 38 | default: Wordpress Password 39 | KubeClusterName: 40 | default: EKS Kube Cluster Name 41 | KubeConfigPath: 42 | default: Kube Config Path 43 | KubeGetLambdaArn: 44 | default: Kube Get Lambda ARN 45 | KubeConfigKmsContext: 46 | default: Kube KMS Context 47 | HelmLambdaArn: 48 | default: EKS Stack Helm ARN 49 | Namespace: 50 | default: Kube Namespace for this function 51 | Name: 52 | default: Kube Name for this function 53 | DBMasterUsername: 54 | default: MariaDB Master User Name 55 | DBMasterUserPassword: 56 | default: MariaDB Master User Password 57 | DBName: 58 | default: MariaDB Database Name 59 | Subnet1ID: 60 | default: Private Subnet One 61 | Subnet2ID: 62 | default: Private Subnet Two 63 | VPCID: 64 | default: EKS Stack VPC ID 65 | NodeGroupSecurityGroupId: 66 | default: Node SecurityGroup ID 67 | BastionSecurityGroupId: 68 | default: Bastion SecurityGroup ID 69 | Parameters: 70 | wordpressUsername: 71 | AllowedPattern: ^[a-z][a-z0-9_]*$ 72 | ConstraintDescription: User name parameter must be lowercase, begin with a letter, 73 | contain only alphanumeric characters or underscores, and be less than 60 characters. 74 | Default: admin 75 | Description: 'The user name that is associated with the master user account for 76 | Wordpress. The user name must contain fewer than 60 alphanumeric 77 | characters or underscores, and must be lowercase and begin with a letter. ' 78 | MaxLength: '60' 79 | MinLength: '1' 80 | Type: String 81 | wordpressPassword: 82 | Description: 'The password that is associated with the master user account for 83 | Wordpress. The password must contain 8 to 64 printable ASCII 84 | characters, excluding: /, ", \'', \ and @. It must contain one uppercase letter, 85 | one lowercase letter, and one number.' 86 | MaxLength: '64' 87 | NoEcho: 'true' 88 | Type: String 89 | HelmLambdaArn: 90 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 91 | Type: String 92 | KubeClusterName: 93 | Description: 'This is the "EKSClusterName" you get from the EKSStack outputs section in CloudFormation.' 94 | Type: String 95 | KubeConfigPath: 96 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 97 | Type: String 98 | KubeGetLambdaArn: 99 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 100 | Type: String 101 | KubeConfigKmsContext: 102 | Description: 'This is using the default from the AWS EKS Quick Start, if you modified 103 | this context when deploying. You need to use the modified KMS context here.' 104 | Type: String 105 | Default: "EKSQuickStart" 106 | Namespace: 107 | Description: 'Modify to use a custom Namespace. The Namespace up to 63 characters 108 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), 109 | and underscore(s)(cannot start or end with)' 110 | Type: String 111 | Default: "example-helm-rds" 112 | Name: 113 | Description: 'Modify to use a custom Names. The Names up to 253 characters 114 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), -, 115 | and ..' 116 | Type: String 117 | Default: "myrelease-rds" 118 | DBMasterUsername: 119 | AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' 120 | ConstraintDescription: must begin with a letter and contain only alphanumeric characters. 121 | Default: mariadb 122 | Description: "The database admin account username" 123 | MaxLength: '16' 124 | MinLength: '1' 125 | NoEcho: 'true' 126 | Type: String 127 | DBMasterUserPassword: 128 | AllowedPattern: '(?=^.{6,255}$)((?=.*\\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*' 129 | ConstraintDescription: "Min 8 chars. Must include 1 uppercase, 1 lowercase, 1 number, 1 (non / @ \" ') symbol" 130 | Description: "Password for the master ('mariadb') account. Password must meeting the following: Min 8 chars. Must include 1 uppercase, 1 lowercase, 1 number, 1 (non / @ \" ') symbol." 131 | MinLength: 8 132 | MaxLength: 128 133 | NoEcho: true 134 | Type: String 135 | DBName: 136 | AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' 137 | ConstraintDescription: must begin with a letter and contain only alphanumeric characters. Cannot be longer than 64 charcters. 138 | Default: wordpress 139 | Description: "The database name to create." 140 | MaxLength: '64' 141 | MinLength: '1' 142 | Type: String 143 | Subnet1ID: 144 | Description: 'Get Private Subnet 1 ID from the VPCStack outputs section in CloudFormation.' 145 | Type: AWS::EC2::Subnet::Id 146 | Subnet2ID: 147 | Description: 'Get Private Subnet 2 ID from the VPCStack outputs section in CloudFormation.' 148 | Type: AWS::EC2::Subnet::Id 149 | NodeGroupSecurityGroupId: 150 | Description: 'Get NodeGroupSecurityGroupId from the EKSStack outputs section in CloudFormation.' 151 | Type: String 152 | BastionSecurityGroupId: 153 | Description: 'Get BastionSecurityGroupId from the EKSStack outputs section in CloudFormation.' 154 | Type: String 155 | VPCID: 156 | Type: AWS::EC2::VPC::Id 157 | Description: 'Get VCP ID from the VPCStack outputs section in CloudFormation.' 158 | 159 | Resources: 160 | DBEC2SecurityGroup: 161 | Type: AWS::EC2::SecurityGroup 162 | Properties: 163 | GroupDescription: Open database for access 164 | VpcId: !Ref VPCID 165 | SecurityGroupIngress: 166 | - IpProtocol: tcp 167 | FromPort: '3306' 168 | ToPort: '3306' 169 | SourceSecurityGroupId: !Ref NodeGroupSecurityGroupId 170 | Description: "This rule is needed to allow RDS from the Node Instances." 171 | DBInboundRule: 172 | Type: "AWS::EC2::SecurityGroupIngress" 173 | Properties: 174 | Description: "This rule is needed to allow RDS from the Bastion Instance." 175 | GroupId: !GetAtt DBEC2SecurityGroup.GroupId 176 | IpProtocol: tcp 177 | FromPort: '3306' 178 | ToPort: '3306' 179 | SourceSecurityGroupId: !Ref BastionSecurityGroupId 180 | DBSubnetGroup: 181 | Type: "AWS::RDS::DBSubnetGroup" 182 | Properties: 183 | DBSubnetGroupDescription: "Subnets available for the MariaDB database instance" 184 | SubnetIds: 185 | - !Ref Subnet1ID 186 | - !Ref Subnet2ID 187 | WPDB: 188 | Type: AWS::RDS::DBInstance 189 | Properties: 190 | AllocatedStorage: 10 191 | AutoMinorVersionUpgrade: true 192 | BackupRetentionPeriod: 7 193 | DBInstanceClass: db.m5.large 194 | # In the next line of code the '-DB' delimeter is used to get the root stack name for database identifier 195 | # 'AWS::StackName' produces MASTER_STACK_NAME-DB (as DB is the name of the nested stack resource). 196 | DBInstanceIdentifier: !Sub ["${RootStack}-db", RootStack: !Select [0, !Split ['-DB', !Ref 'AWS::StackName']]] 197 | DBSubnetGroupName: !Ref DBSubnetGroup 198 | Engine: mariadb 199 | EngineVersion: 10.3 200 | MasterUsername: !Ref DBMasterUsername 201 | MasterUserPassword: !Ref DBMasterUserPassword 202 | MultiAZ: false 203 | StorageEncrypted: true 204 | StorageType: gp2 205 | DBName: !Ref DBName 206 | Tags: 207 | - Key: Name 208 | Value: !Sub ["${StackName} Confluence MariaDB Database", StackName: !Ref 'AWS::StackName'] 209 | VPCSecurityGroups: 210 | - !GetAtt DBEC2SecurityGroup.GroupId 211 | HelmExample: 212 | Type: "Custom::Helm" 213 | Version: '1.0' 214 | Properties: 215 | ServiceToken: !Ref HelmLambdaArn 216 | KubeConfigPath: !Ref KubeConfigPath 217 | KubeConfigKmsContext: !Ref KubeConfigKmsContext 218 | KubeClusterName: !Ref KubeClusterName 219 | Namespace: !Ref Namespace 220 | Chart: stable/wordpress 221 | Name: !Ref Name 222 | Values: 223 | wordpressUsername: !Ref wordpressUsername 224 | wordpressPassword: !Ref wordpressPassword 225 | mariadb.enabled: false 226 | externalDatabase.host: !GetAtt WPDB.Endpoint.Address 227 | externalDatabase.user: !Ref DBMasterUsername 228 | externalDatabase.password: !Ref DBMasterUserPassword 229 | externalDatabase.database: !Ref DBName 230 | externalDatabase.port: 3306 231 | WPElbHostName: 232 | DependsOn: HelmExample 233 | Type: "Custom::KubeGet" 234 | Version: '1.0' 235 | Properties: 236 | ServiceToken: !Ref KubeGetLambdaArn 237 | KubeConfigPath: !Ref KubeConfigPath 238 | KubeConfigKmsContext: !Ref KubeConfigKmsContext 239 | Namespace: !Ref Namespace 240 | Name: !Sub 'service/${Name}-wordpress' 241 | JsonPath: '{.status.loadBalancer.ingress[0].hostname}' 242 | 243 | Outputs: 244 | WPElbHostName: 245 | Value: !Ref WPElbHostName -------------------------------------------------------------------------------- /samples/eks-app-helm-deploy/helm-wordpress-deploy.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This Cloudformation template shows you how to use Cloudformation to deploy 3 | WordPress using Helm charts. You will be deploying this into the "Amazon EKS QuickStart" 4 | which is a qre-requist. "https://docs.aws.amazon.com/quickstart/latest/amazon-eks-architecture/welcome.html" **WARNING** You will be billed for the AWS resources used if you create a stack from this template. 5 | Metadata: 6 | AWS::CloudFormation::Interface: 7 | ParameterGroups: 8 | - Label: 9 | default: Wordpress 10 | Parameters: 11 | - wordpressUsername 12 | - wordpressPassword 13 | - Label: 14 | default: Kube Cluster 15 | Parameters: 16 | - KubeClusterName 17 | - KubeConfigPath 18 | - KubeGetLambdaArn 19 | - KubeConfigKmsContext 20 | - HelmLambdaArn 21 | - Namespace 22 | - Name 23 | ParameterLabels: 24 | wordpressUsername: 25 | default: Wordpress Username 26 | wordpressPassword: 27 | default: Wordpress Password 28 | KubeClusterName: 29 | default: EKS Kube Cluster Name 30 | KubeConfigPath: 31 | default: Kube Config Path 32 | KubeGetLambdaArn: 33 | default: Kube Get Lambda ARN 34 | KubeConfigKmsContext: 35 | default: Kube KMS Context 36 | HelmLambdaArn: 37 | default: EKS Stack Helm ARN 38 | Namespace: 39 | default: Kube Namespace for this function 40 | Name: 41 | default: Kube Name for this function 42 | Parameters: 43 | wordpressUsername: 44 | AllowedPattern: ^[a-z][a-z0-9_]*$ 45 | ConstraintDescription: User name parameter must be lowercase, begin with a letter, 46 | contain only alphanumeric characters or underscores, and be less than 60 characters. 47 | Default: admin 48 | Description: 'The user name that is associated with the master user account for 49 | Wordpress. The user name must contain fewer than 60 alphanumeric 50 | characters or underscores, and must be lowercase and begin with a letter. ' 51 | MaxLength: '60' 52 | MinLength: '1' 53 | Type: String 54 | wordpressPassword: 55 | Description: 'The password that is associated with the master user account for 56 | Wordpress. The password must contain 8 to 64 printable ASCII 57 | characters, excluding: /, ", \'', \ and @. It must contain one uppercase letter, 58 | one lowercase letter, and one number.' 59 | MaxLength: '64' 60 | NoEcho: 'true' 61 | Type: String 62 | HelmLambdaArn: 63 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 64 | Type: String 65 | KubeClusterName: 66 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 67 | Type: String 68 | KubeConfigPath: 69 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 70 | Type: String 71 | KubeGetLambdaArn: 72 | Description: 'Get this from the EKSStack outputs section in CloudFormation.' 73 | Type: String 74 | KubeConfigKmsContext: 75 | Description: 'This is using the default from the AWS EKS Quick Start, if you modified 76 | this context when deploying. You need to use the modified KMS context here.' 77 | Type: String 78 | Default: "EKSQuickStart" 79 | Namespace: 80 | Description: 'Modify to use a custom Namespace. The Namespace up to 63 characters 81 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), 82 | and underscore(s)(cannot start or end with)' 83 | Type: String 84 | Default: "example-helm" 85 | Name: 86 | Description: 'Modify to use a custom Names. The Names up to 253 characters 87 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), -, 88 | and ..' 89 | Type: String 90 | Default: "myrelease" 91 | Resources: 92 | HelmExample: 93 | Type: "Custom::Helm" 94 | Version: '1.0' 95 | Properties: 96 | ServiceToken: !Ref HelmLambdaArn 97 | KubeConfigPath: !Ref KubeConfigPath 98 | KubeConfigKmsContext: !Ref KubeConfigKmsContext 99 | KubeClusterName: !Ref KubeClusterName 100 | Namespace: !Ref Namespace 101 | Chart: stable/wordpress 102 | Name: !Ref Name 103 | Values: 104 | wordpressUsername: !Ref wordpressUsername 105 | wordpressPassword: !Ref wordpressPassword 106 | WPElbHostName: 107 | DependsOn: HelmExample 108 | Type: "Custom::KubeGet" 109 | Version: '1.0' 110 | Properties: 111 | ServiceToken: !Ref KubeGetLambdaArn 112 | KubeConfigPath: !Ref KubeConfigPath 113 | KubeConfigKmsContext: !Ref KubeConfigKmsContext 114 | Namespace: !Ref Namespace 115 | Name: !Sub 'service/${Name}-wordpress' 116 | JsonPath: '{.status.loadBalancer.ingress[0].hostname}' 117 | 118 | Outputs: 119 | WPElbHostName: 120 | Value: !Ref WPElbHostName 121 | -------------------------------------------------------------------------------- /samples/eks-app-helm-deploy/helm3-wordpress-deploy-RDS.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This Cloudformation template shows you how to use Cloudformation to deploy 3 | WordPress using Helm charts. You will be deploying this into the "Amazon EKS QuickStart" 4 | which is a qre-requist. "https://docs.aws.amazon.com/quickstart/latest/amazon-eks-architecture/welcome.html" **WARNING** You will be billed for the AWS resources used if you create a stack from this template. 5 | Metadata: 6 | AWS::CloudFormation::Interface: 7 | ParameterGroups: 8 | - Label: 9 | default: Wordpress 10 | Parameters: 11 | - wordpressUsername 12 | - wordpressPassword 13 | - Label: 14 | default: Kube Cluster 15 | Parameters: 16 | - EKSClusterName 17 | - Namespace 18 | - Name 19 | - Label: 20 | default: MariaDB (RDS) 21 | Parameters: 22 | - DBMasterUsername 23 | - DBMasterUserPassword 24 | - DBName 25 | - Subnet1ID 26 | - Subnet2ID 27 | - VPCID 28 | - NodeGroupSecurityGroupId 29 | - BastionSecurityGroupId 30 | ParameterLabels: 31 | wordpressUsername: 32 | default: Wordpress Username 33 | wordpressPassword: 34 | default: Wordpress Password 35 | EKSClusterName: 36 | default: EKS Kube Cluster Name 37 | Namespace: 38 | default: Kube Namespace for this function 39 | Name: 40 | default: Kube Name for this function 41 | DBMasterUsername: 42 | default: MariaDB Master User Name 43 | DBMasterUserPassword: 44 | default: MariaDB Master User Password 45 | DBName: 46 | default: MariaDB Database Name 47 | Subnet1ID: 48 | default: Private Subnet One 49 | Subnet2ID: 50 | default: Private Subnet Two 51 | VPCID: 52 | default: EKS Stack VPC ID 53 | NodeGroupSecurityGroupId: 54 | default: Node SecurityGroup ID 55 | BastionSecurityGroupId: 56 | default: Bastion SecurityGroup ID 57 | Parameters: 58 | wordpressUsername: 59 | AllowedPattern: ^[a-z][a-z0-9_]*$ 60 | ConstraintDescription: User name parameter must be lowercase, begin with a letter, 61 | contain only alphanumeric characters or underscores, and be less than 60 characters. 62 | Default: admin 63 | Description: 'The user name that is associated with the master user account for 64 | Wordpress. The user name must contain fewer than 60 alphanumeric 65 | characters or underscores, and must be lowercase and begin with a letter. ' 66 | MaxLength: '60' 67 | MinLength: '1' 68 | Type: String 69 | wordpressPassword: 70 | Description: 'The password that is associated with the master user account for 71 | Wordpress. The password must contain 8 to 64 printable ASCII 72 | characters, excluding: /, ", \'', \ and @. It must contain one uppercase letter, 73 | one lowercase letter, and one number.' 74 | MaxLength: '64' 75 | NoEcho: 'true' 76 | Type: String 77 | EKSClusterName: 78 | Description: 'Use the "EKSClusterName" from the EKSStack outputs section in CloudFormation.' 79 | Type: String 80 | Namespace: 81 | Description: 'Modify to use a custom Namespace. The Namespace up to 63 characters 82 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), 83 | and underscore(s)(cannot start or end with)' 84 | Type: String 85 | Default: "example-helm-rds" 86 | Name: 87 | Description: 'Modify to use a custom Names. The Names up to 253 characters 88 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), -, 89 | and ..' 90 | Type: String 91 | Default: "myrelease-rds" 92 | DBMasterUsername: 93 | AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' 94 | ConstraintDescription: must begin with a letter and contain only alphanumeric characters. 95 | Default: mariadb 96 | Description: "The database admin account username" 97 | MaxLength: '16' 98 | MinLength: '1' 99 | NoEcho: 'true' 100 | Type: String 101 | DBMasterUserPassword: 102 | AllowedPattern: '(?=^.{6,255}$)((?=.*\\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*' 103 | ConstraintDescription: "Min 8 chars. Must include 1 uppercase, 1 lowercase, 1 number, 1 (non / @ \" ') symbol" 104 | Description: "Password for the master ('mariadb') account. Password must meeting the following: Min 8 chars. Must include 1 uppercase, 1 lowercase, 1 number, 1 (non / @ \" ') symbol." 105 | MinLength: 8 106 | MaxLength: 128 107 | NoEcho: true 108 | Type: String 109 | DBName: 110 | AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*' 111 | ConstraintDescription: must begin with a letter and contain only alphanumeric characters. Cannot be longer than 64 charcters. 112 | Default: wordpress 113 | Description: "The database name to create." 114 | MaxLength: '64' 115 | MinLength: '1' 116 | Type: String 117 | Subnet1ID: 118 | Description: 'Get Private Subnet 1 ID from the VPCStack outputs section in CloudFormation.' 119 | Type: AWS::EC2::Subnet::Id 120 | Subnet2ID: 121 | Description: 'Get Private Subnet 2 ID from the VPCStack outputs section in CloudFormation.' 122 | Type: AWS::EC2::Subnet::Id 123 | NodeGroupSecurityGroupId: 124 | Description: 'Get NodeGroupSecurityGroupId from the EKSStack outputs section in CloudFormation.' 125 | Type: String 126 | BastionSecurityGroupId: 127 | Description: 'Get BastionSecurityGroupId from the EKSStack outputs section in CloudFormation.' 128 | Type: String 129 | VPCID: 130 | Type: AWS::EC2::VPC::Id 131 | Description: 'Get VCP ID from the VPCStack outputs section in CloudFormation.' 132 | 133 | Resources: 134 | DBEC2SecurityGroup: 135 | Type: AWS::EC2::SecurityGroup 136 | Properties: 137 | GroupDescription: Open database for access 138 | VpcId: !Ref VPCID 139 | SecurityGroupIngress: 140 | - IpProtocol: tcp 141 | FromPort: 3306 142 | ToPort: 3306 143 | SourceSecurityGroupId: !Ref NodeGroupSecurityGroupId 144 | Description: "This rule is needed to allow RDS from the Node Instances." 145 | DBInboundRule: 146 | Type: "AWS::EC2::SecurityGroupIngress" 147 | Properties: 148 | Description: "This rule is needed to allow RDS from the Bastion Instance." 149 | GroupId: !GetAtt DBEC2SecurityGroup.GroupId 150 | IpProtocol: tcp 151 | FromPort: 3306 152 | ToPort: 3306 153 | SourceSecurityGroupId: !Ref BastionSecurityGroupId 154 | DBSubnetGroup: 155 | Type: "AWS::RDS::DBSubnetGroup" 156 | Properties: 157 | DBSubnetGroupDescription: "Subnets available for the MariaDB database instance" 158 | SubnetIds: 159 | - !Ref Subnet1ID 160 | - !Ref Subnet2ID 161 | WPDB: 162 | Type: AWS::RDS::DBInstance 163 | Properties: 164 | AllocatedStorage: '10' 165 | AutoMinorVersionUpgrade: true 166 | BackupRetentionPeriod: 7 167 | DBInstanceClass: db.m5.large 168 | # In the next line of code the '-DB' delimeter is used to get the root stack name for database identifier 169 | # 'AWS::StackName' produces MASTER_STACK_NAME-DB (as DB is the name of the nested stack resource). 170 | DBInstanceIdentifier: !Sub ["${RootStack}-db", RootStack: !Select [0, !Split ['-DB', !Ref 'AWS::StackName']]] 171 | DBSubnetGroupName: !Ref DBSubnetGroup 172 | Engine: mariadb 173 | EngineVersion: '10.3' 174 | MasterUsername: !Ref DBMasterUsername 175 | MasterUserPassword: !Ref DBMasterUserPassword 176 | MultiAZ: false 177 | StorageEncrypted: true 178 | StorageType: gp2 179 | DBName: !Ref DBName 180 | Tags: 181 | - Key: Name 182 | Value: !Sub ["${StackName} Confluence MariaDB Database", StackName: !Ref 'AWS::StackName'] 183 | VPCSecurityGroups: 184 | - !GetAtt DBEC2SecurityGroup.GroupId 185 | HelmExample: 186 | Type: "AWSQS::Kubernetes::Helm" 187 | Properties: 188 | ClusterID: !Ref EKSClusterName 189 | Namespace: !Ref Namespace 190 | Chart: stable/wordpress 191 | Name: !Ref Name 192 | Values: 193 | wordpressUsername: !Ref wordpressUsername 194 | wordpressPassword: !Ref wordpressPassword 195 | mariadb.enabled: false 196 | externalDatabase.host: !GetAtt WPDB.Endpoint.Address 197 | externalDatabase.user: !Ref DBMasterUsername 198 | externalDatabase.password: !Ref DBMasterUserPassword 199 | externalDatabase.database: !Ref DBName 200 | externalDatabase.port: 3306 201 | WPElbHostName: 202 | DependsOn: HelmExample 203 | Type: "Custom::KubeGet" 204 | Version: '1.0' 205 | Properties: 206 | ServiceToken: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:EKS-QuickStart-KubeGet-${EKSClusterName}" 207 | ClusterName: !Ref EKSClusterName 208 | Namespace: !Ref Namespace 209 | Name: !Sub 'service/${Name}-wordpress' 210 | JsonPath: '{.status.loadBalancer.ingress[0].hostname}' 211 | 212 | Outputs: 213 | WPElbHostName: 214 | Value: !Ref WPElbHostName 215 | RDSDBEndpoint: 216 | Value: !GetAtt WPDB.Endpoint.Address -------------------------------------------------------------------------------- /samples/eks-app-helm-deploy/helm3-wordpress-deploy.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This Cloudformation template shows you how to use Cloudformation to deploy 3 | WordPress using Helm charts. You will be deploying this into the "Amazon EKS QuickStart" 4 | which is a qre-requist. "https://docs.aws.amazon.com/quickstart/latest/amazon-eks-architecture/welcome.html" **WARNING** You will be billed for the AWS resources used if you create a stack from this template. 5 | Metadata: 6 | AWS::CloudFormation::Interface: 7 | ParameterGroups: 8 | - Label: 9 | default: Wordpress 10 | Parameters: 11 | - wordpressUsername 12 | - wordpressPassword 13 | - Label: 14 | default: Kube Cluster 15 | Parameters: 16 | - EKSClusterName 17 | - KubeConfigKmsContext 18 | - Namespace 19 | - Name 20 | ParameterLabels: 21 | wordpressUsername: 22 | default: Wordpress Username 23 | wordpressPassword: 24 | default: Wordpress Password 25 | EKSClusterName: 26 | default: EKS Kube Cluster Name 27 | KubeConfigKmsContext: 28 | default: Kube KMS Context 29 | Namespace: 30 | default: Kube Namespace for this function 31 | Name: 32 | default: Kube Name for this function 33 | Parameters: 34 | wordpressUsername: 35 | AllowedPattern: ^[a-z][a-z0-9_]*$ 36 | ConstraintDescription: User name parameter must be lowercase, begin with a letter, 37 | contain only alphanumeric characters or underscores, and be less than 60 characters. 38 | Default: admin 39 | Description: 'The user name that is associated with the master user account for 40 | Wordpress. The user name must contain fewer than 60 alphanumeric 41 | characters or underscores, and must be lowercase and begin with a letter. ' 42 | MaxLength: '60' 43 | MinLength: '1' 44 | Type: String 45 | wordpressPassword: 46 | Description: 'The password that is associated with the master user account for 47 | Wordpress. The password must contain 8 to 64 printable ASCII 48 | characters, excluding: /, ", \'', \ and @. It must contain one uppercase letter, 49 | one lowercase letter, and one number.' 50 | MaxLength: '64' 51 | NoEcho: 'true' 52 | Type: String 53 | EKSClusterName: 54 | Description: 'Use the "EKSClusterName" from the EKSStack outputs section in CloudFormation.' 55 | Type: String 56 | KubeConfigKmsContext: 57 | Description: 'This is using the default from the AWS EKS Quick Start, if you modified 58 | this context when deploying. You need to use the modified KMS context here.' 59 | Type: String 60 | Default: "EKSQuickStart" 61 | Namespace: 62 | Description: 'Modify to use a custom Namespace. The Namespace up to 63 characters 63 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), 64 | and underscore(s)(cannot start or end with)' 65 | Type: String 66 | Default: "example-helm" 67 | Name: 68 | Description: 'Modify to use a custom Names. The Names up to 253 characters 69 | long. The characters allowed in names are: digits (0-9), lower case letters (a-z), -, 70 | and ..' 71 | Type: String 72 | Default: "myrelease" 73 | Resources: 74 | HelmExample: 75 | Type: "AWSQS::Kubernetes::Helm" 76 | Properties: 77 | ClusterID: !Ref EKSClusterName 78 | KubeConfigKmsContext: !Ref KubeConfigKmsContext 79 | Namespace: !Ref Namespace 80 | Chart: stable/wordpress 81 | Name: !Ref Name 82 | Values: 83 | wordpressUsername: !Ref wordpressUsername 84 | wordpressPassword: !Ref wordpressPassword 85 | WPElbHostName: 86 | DependsOn: HelmExample 87 | Type: "Custom::KubeGet" 88 | Version: '1.0' 89 | Properties: 90 | ServiceToken: !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:EKS-QuickStart-KubeGet-${EKSClusterName}" 91 | ClusterName: !Ref EKSClusterName 92 | KubeConfigKmsContext: !Ref KubeConfigKmsContext 93 | Namespace: !Ref Namespace 94 | Name: !Sub 'service/${Name}-wordpress' 95 | JsonPath: '{.status.loadBalancer.ingress[0].hostname}' 96 | 97 | Outputs: 98 | WPElbHostName: 99 | Value: !Ref WPElbHostName 100 | -------------------------------------------------------------------------------- /samples/hugo-pipeline/.taskcat.yml: -------------------------------------------------------------------------------- 1 | project: 2 | name: hugo-deployment-pipeline 3 | owner: sshvans@amazon.com 4 | package_lambda: false 5 | regions: 6 | - ap-northeast-1 7 | - ap-northeast-2 8 | - ap-south-1 9 | - ap-southeast-1 10 | - ap-southeast-2 11 | - ca-central-1 12 | - eu-central-1 13 | - eu-west-1 14 | - eu-west-2 15 | - sa-east-1 16 | - us-east-1 17 | - us-east-2 18 | - us-west-1 19 | - us-west-2 20 | s3_bucket: '' 21 | tests: 22 | cicd-test: 23 | parameters: 24 | RepoName: hugo-repo 25 | HostingBucketName: hugowebsitebucket 26 | S3BucketName: $[taskcat_autobucket] 27 | regions: 28 | - us-west-2 29 | s3_bucket: '' 30 | template: templates/master.template.yaml -------------------------------------------------------------------------------- /samples/hugo-pipeline/templates/iam.template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: Creates IAM roles for pipeline. 3 | Resources: 4 | CodeBuildServiceRole: 5 | Type: 'AWS::IAM::Role' 6 | Properties: 7 | AssumeRolePolicyDocument: 8 | Version: 2012-10-17 9 | Statement: 10 | - Sid: '' 11 | Effect: Allow 12 | Principal: 13 | Service: codebuild.amazonaws.com 14 | Action: 'sts:AssumeRole' 15 | Path: / 16 | Policies: 17 | - PolicyName: !Sub 'CICD-CodeBuildService-${AWS::Region}' 18 | PolicyDocument: 19 | Version: 2012-10-17 20 | Statement: 21 | - Action: 22 | - 'logs:CreateLogGroup' 23 | - 'logs:CreateLogStream' 24 | - 'logs:PutLogEvents' 25 | Resource: 26 | - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*' 27 | - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*:*' 28 | Effect: Allow 29 | - Action: 30 | - 's3:PutObject' 31 | - 's3:GetObject' 32 | - 's3:GetObjectVersion' 33 | - 's3:GetBucketAcl' 34 | - 's3:GetBucketLocation' 35 | Resource: 'arn:aws:s3:::*' 36 | Effect: Allow 37 | - Action: 38 | - 'codebuild:CreateReportGroup' 39 | - 'codebuild:CreateReport' 40 | - 'codebuild:UpdateReport' 41 | - 'codebuild:BatchPutTestCases' 42 | Resource: !Sub 'arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/*' 43 | Effect: Allow 44 | CodePipelineServiceRole: 45 | Type: 'AWS::IAM::Role' 46 | Properties: 47 | AssumeRolePolicyDocument: 48 | Version: 2012-10-17 49 | Statement: 50 | - Sid: '' 51 | Effect: Allow 52 | Principal: 53 | Service: codepipeline.amazonaws.com 54 | Action: 'sts:AssumeRole' 55 | Path: / 56 | Policies: 57 | - PolicyName: !Sub 'CICD-CodePipelineService-${AWS::Region}' 58 | PolicyDocument: 59 | Version: 2012-10-17 60 | Statement: 61 | - Action: 62 | - 's3:GetObject' 63 | - 's3:GetObjectVersion' 64 | - 's3:GetBucketVersioning' 65 | - 's3:PutObject' 66 | Resource: 67 | - !Sub 'arn:aws:s3:::${ArtifactBucket}' 68 | - !Sub 'arn:aws:s3:::${ArtifactBucket}/*' 69 | - !Sub 'arn:aws:s3:::${WebsiteBucket}' 70 | - !Sub 'arn:aws:s3:::${WebsiteBucket}/*' 71 | Effect: Allow 72 | - Action: 73 | - 'iam:PassRole' 74 | Resource: '*' 75 | Effect: Allow 76 | - Action: 77 | - 'codebuild:BatchGetBuilds' 78 | - 'codebuild:StartBuild' 79 | Resource: '*' 80 | Effect: Allow 81 | - Action: 82 | - 'codedeploy:CreateDeployment' 83 | - 'codedeploy:GetApplication' 84 | - 'codedeploy:GetApplicationRevision' 85 | - 'codedeploy:GetDeployment' 86 | - 'codedeploy:GetDeploymentConfig' 87 | - 'codedeploy:RegisterApplicationRevision' 88 | Resource: '*' 89 | Effect: Allow 90 | - Action: 91 | - 'codecommit:CancelUploadArchive' 92 | - 'codecommit:GetBranch' 93 | - 'codecommit:GetCommit' 94 | - 'codecommit:GetUploadArchiveStatus' 95 | - 'codecommit:UploadArchive' 96 | Resource: '*' 97 | Effect: Allow 98 | Parameters: 99 | ArtifactBucket: 100 | AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$' 101 | ConstraintDescription: >- 102 | Quick Start bucket name can include numbers, lowercase letters, uppercase 103 | letters, and hyphens (-). It cannot start or end with a hyphen (-). 104 | Description: S3 bucket name used to store build artifacts. 105 | Type: String 106 | WebsiteBucket: 107 | AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$' 108 | ConstraintDescription: >- 109 | Website bucket name can include numbers, lowercase letters, uppercase 110 | letters, and hyphens (-). It cannot start or end with a hyphen (-). 111 | Description: S3 bucket name used to host website content. 112 | Type: String 113 | 114 | Outputs: 115 | CodePipelineRoleArn: 116 | Description: Code Pipeline service role arn 117 | Value: !GetAtt 118 | - CodePipelineServiceRole 119 | - Arn 120 | CodeBuildRoleArn: 121 | Description: Code Build service role arn 122 | Value: !GetAtt 123 | - CodeBuildServiceRole 124 | - Arn -------------------------------------------------------------------------------- /samples/hugo-pipeline/templates/master.template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | Setup CICD pipeline to build and publish content of Hugo based website from 4 | AWS CodeCommit repo to s3 bucket. 5 | Resources: 6 | ArtifactBucket: 7 | Type: 'AWS::S3::Bucket' 8 | Properties: 9 | VersioningConfiguration: 10 | Status: Enabled 11 | BucketEncryption: 12 | ServerSideEncryptionConfiguration: 13 | - ServerSideEncryptionByDefault: 14 | SSEAlgorithm: AES256 15 | AccessControl: Private 16 | LifecycleConfiguration: 17 | Rules: 18 | - NoncurrentVersionExpirationInDays: 30 19 | Status: Enabled 20 | CodeCommitRepo: 21 | Type: AWS::CodeCommit::Repository 22 | Properties: 23 | RepositoryDescription: Repository to host content of the Hugo website 24 | RepositoryName: !Ref RepoName 25 | WebHostingBucket: 26 | Type: 'AWS::S3::Bucket' 27 | Properties: 28 | VersioningConfiguration: 29 | Status: Enabled 30 | BucketEncryption: 31 | ServerSideEncryptionConfiguration: 32 | - ServerSideEncryptionByDefault: 33 | SSEAlgorithm: AES256 34 | AccessControl: PublicRead 35 | BucketName: !Ref HostingBucketName 36 | WebsiteConfiguration: 37 | IndexDocument: index.html 38 | WebHostingBucketPolicy: 39 | Type: AWS::S3::BucketPolicy 40 | Properties: 41 | Bucket: !Ref WebHostingBucket 42 | PolicyDocument: 43 | Statement: 44 | - 45 | Action: 46 | - "s3:GetObject" 47 | Effect: "Allow" 48 | Resource: 49 | Fn::Join: 50 | - "" 51 | - 52 | - "arn:aws:s3:::" 53 | - !Ref WebHostingBucket 54 | - "/*" 55 | Principal: "*" 56 | - Action: s3:* 57 | Effect: Deny 58 | Principal: '*' 59 | Resource: 60 | - arn:aws:s3:::bucketname/* 61 | - arn:aws:s3:::bucketname 62 | Condition: 63 | Bool: 64 | aws:SecureTransport: false 65 | IAMRoleStack: 66 | Type: 'AWS::CloudFormation::Stack' 67 | DependsOn: 68 | - ArtifactBucket 69 | Properties: 70 | TemplateURL: !Sub >- 71 | https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}templates/iam.template.yaml 72 | Parameters: 73 | WebsiteBucket: !Ref WebHostingBucket 74 | ArtifactBucket: !Ref ArtifactBucket 75 | CodePipelineStack: 76 | Type: 'AWS::CloudFormation::Stack' 77 | DependsOn: 78 | - WebHostingBucket 79 | Properties: 80 | TemplateURL: !Sub >- 81 | https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}templates/pipeline.template.yaml 82 | Parameters: 83 | ArtifactBucket: !Ref ArtifactBucket 84 | CodePipelineRoleArn: !GetAtt 85 | - IAMRoleStack 86 | - Outputs.CodePipelineRoleArn 87 | CodeBuildRoleArn: !GetAtt 88 | - IAMRoleStack 89 | - Outputs.CodeBuildRoleArn 90 | CloudfrontDistId: '!Ref CloudfrontDistId' 91 | CloudfrontRole: '!Ref CloudfrontRoleArn' 92 | WebsiteBucket: !Ref WebHostingBucket 93 | RepoName: !Ref RepoName 94 | RepoBranch: 'master' 95 | 96 | Parameters: 97 | RepoName: 98 | Description: Enter the repository name to host hugo website content 99 | Type: String 100 | MinLength: 1 101 | HostingBucketName: 102 | Description: Name of the S3 bucket to hold the website content (must be globally unique) 103 | Type: String 104 | MinLength: 3 105 | S3BucketName: 106 | AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$' 107 | ConstraintDescription: >- 108 | Bucket name can include numbers, lowercase letters, uppercase 109 | letters, and hyphens (-). It cannot start or end with a hyphen (-). 110 | Default: aws-quickstart 111 | Description: >- 112 | S3 bucket name for the Quick Start assets. Quick Start bucket name can 113 | include numbers, lowercase letters, uppercase letters, and hyphens (-). It 114 | cannot start or end with a hyphen (-). 115 | Type: String 116 | S3KeyPrefix: 117 | AllowedPattern: '^[0-9a-zA-Z-/]*$' 118 | ConstraintDescription: >- 119 | Quick Start key prefix can include numbers, lowercase letters, uppercase 120 | letters, hyphens (-), and forward slash (/). 121 | Default: quickstart-examples/samples/hugo-pipeline/ 122 | Description: >- 123 | S3 key prefix for the Quick Start assets. Quick Start key prefix can 124 | include numbers, lowercase letters, uppercase letters, hyphens (-), and 125 | forward slash (/). 126 | Type: String 127 | 128 | Outputs: 129 | CodeCommitRepository: 130 | Description: AWS CodeCommit repository 131 | Value: !Ref CodeCommitRepo 132 | WebsiteURL: 133 | Value: !GetAtt [WebHostingBucket, WebsiteURL] 134 | Description: URL for website hosted on S3 135 | S3BucketSecureURL: 136 | Value: !Join ['', ['https://', !GetAtt [WebHostingBucket, DomainName]]] 137 | Description: Name of S3 bucket to hold website content 138 | CodePipelineURL: 139 | Description: The URL of the created Pipeline 140 | Value: !Sub 141 | - >- 142 | https://${AWS::Region}.console.aws.amazon.com/codepipeline/home?region=${AWS::Region}#/view/${CodePipelineName} 143 | - CodePipelineName: !GetAtt 144 | - CodePipelineStack 145 | - Outputs.CodePipelineName 146 | -------------------------------------------------------------------------------- /samples/hugo-pipeline/templates/pipeline.template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: Creates Pipeline to build and publish Hugo based static site. 3 | Resources: 4 | CodePipeline: 5 | Type: 'AWS::CodePipeline::Pipeline' 6 | Properties: 7 | ArtifactStore: 8 | Type: S3 9 | Location: !Ref ArtifactBucket 10 | RoleArn: !Ref CodePipelineRoleArn 11 | Stages: 12 | - Name: Source 13 | Actions: 14 | - Name: CodeCommit 15 | InputArtifacts: [] 16 | ActionTypeId: 17 | Category: Source 18 | Owner: AWS 19 | Version: '1' 20 | Provider: CodeCommit 21 | OutputArtifacts: 22 | - Name: SourceArtifact 23 | Configuration: 24 | BranchName: !Ref RepoBranch 25 | PollForSourceChanges: false 26 | RepositoryName: !Ref RepoName 27 | RunOrder: 1 28 | - Name: Build 29 | Actions: 30 | - Name: CodeBuild 31 | InputArtifacts: 32 | - Name: SourceArtifact 33 | ActionTypeId: 34 | Category: Build 35 | Owner: AWS 36 | Version: '1' 37 | Provider: CodeBuild 38 | OutputArtifacts: 39 | - Name: BuildArtifact 40 | Configuration: 41 | ProjectName: !Ref CodeBuildProject 42 | RunOrder: 1 43 | - Name: Deploy 44 | Actions: 45 | - Name: Deploy-to-S3 46 | InputArtifacts: 47 | - Name: BuildArtifact 48 | ActionTypeId: 49 | Category: Deploy 50 | Owner: AWS 51 | Version: '1' 52 | Provider: S3 53 | Configuration: 54 | BucketName: !Ref WebsiteBucket 55 | Extract: true 56 | RunOrder: 1 57 | CodeBuildProject: 58 | Type: 'AWS::CodeBuild::Project' 59 | Properties: 60 | Description: !Sub 'Submit build jobs for ${RepoName} as part of CI/CD pipeline' 61 | ServiceRole: !Ref CodeBuildRoleArn 62 | Artifacts: 63 | Type: CODEPIPELINE 64 | Packaging: NONE 65 | EncryptionDisabled: false 66 | Environment: 67 | Type: LINUX_CONTAINER 68 | ComputeType: BUILD_GENERAL1_SMALL 69 | Image: 'aws/codebuild/standard:3.0' 70 | EnvironmentVariables: 71 | - Name: CLOUDFRONT_DISTRIBUTION_ID 72 | Value: !Sub '${CloudfrontDistId}' 73 | - Name: CLOUDFRONT_CROSS_ACCOUNT_ROLE 74 | Value: !Sub '${CloudfrontRole}' 75 | - Name: WEBSITE_BUCKET 76 | Value: !Ref WebsiteBucket 77 | Source: 78 | Type: CODEPIPELINE 79 | BuildSpec: |- 80 | 81 | version: 0.2 82 | 83 | phases: 84 | install: 85 | runtime-versions: 86 | python: 3.8 87 | commands: 88 | - apt-get update 89 | - echo Installing hugo, jq 90 | - # Use github release to get the latest hugo binary. Ubuntu repository lags behind and contain older hugo binary version. 91 | - curl -L -o hugo.deb https://github.com/gohugoio/hugo/releases/download/v0.70.0/hugo_0.70.0_Linux-64bit.deb 92 | - dpkg -i hugo.deb 93 | - # apt-get install hugo 94 | - apt-get install jq 95 | pre_build: 96 | commands: 97 | - echo In pre_build phase.. 98 | - echo Current directory is $CODEBUILD_SRC_DIR 99 | - ls -la 100 | build: 101 | commands: 102 | - hugo -v 103 | post_build: 104 | commands: 105 | - echo Publish changes to S3 bucket.. 106 | artifacts: 107 | files: 108 | - '**/*' 109 | base-directory: public 110 | BadgeEnabled: false 111 | LogsConfig: 112 | CloudWatchLogs: 113 | Status: ENABLED 114 | AmazonCloudWatchEventRule: 115 | Type: AWS::Events::Rule 116 | Properties: 117 | EventPattern: 118 | source: 119 | - aws.codecommit 120 | detail-type: 121 | - 'CodeCommit Repository State Change' 122 | resources: 123 | - !Join [ '', [ 'arn:aws:codecommit:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref RepoName ] ] 124 | detail: 125 | event: 126 | - referenceCreated 127 | - referenceUpdated 128 | referenceType: 129 | - branch 130 | referenceName: 131 | - !Ref RepoBranch 132 | Targets: 133 | - 134 | Arn: 135 | !Join [ '', [ 'arn:aws:codepipeline:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref CodePipeline ] ] 136 | RoleArn: !GetAtt AmazonCloudWatchEventRole.Arn 137 | Id: codepipeline-CICDPipeline 138 | AmazonCloudWatchEventRole: 139 | Type: AWS::IAM::Role 140 | Properties: 141 | AssumeRolePolicyDocument: 142 | Version: 2012-10-17 143 | Statement: 144 | - 145 | Effect: Allow 146 | Principal: 147 | Service: 148 | - events.amazonaws.com 149 | Action: sts:AssumeRole 150 | Path: / 151 | Policies: 152 | - 153 | PolicyName: cwe-pipeline-execution 154 | PolicyDocument: 155 | Version: 2012-10-17 156 | Statement: 157 | - 158 | Effect: Allow 159 | Action: codepipeline:StartPipelineExecution 160 | Resource: !Join [ '', [ 'arn:aws:codepipeline:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref CodePipeline ] ] 161 | 162 | 163 | Parameters: 164 | ArtifactBucket: 165 | AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$' 166 | ConstraintDescription: >- 167 | S3 bucket name can include numbers, lowercase letters, uppercase letters, 168 | and hyphens (-). It cannot start or end with a hyphen (-). 169 | Description: S3 bucket name used to store build artifacts. 170 | Type: String 171 | CodePipelineRoleArn: 172 | Description: Code Pipeline service role ARN 173 | Type: String 174 | CodeBuildRoleArn: 175 | Description: Code Build service role ARN 176 | Type: String 177 | CloudfrontDistId: 178 | Description: AWS CloudFront distribution Id of the website 179 | Type: String 180 | CloudfrontRole: 181 | Description: >- 182 | AWS CloudFront role arn which has permissions to invalidate session of the 183 | CloudFront distribution of the website endpoint. This CloudFront role arn 184 | is used by code build job. 185 | Type: String 186 | WebsiteBucket: 187 | Description: S3 Bucket which hosts the content of the website. 188 | Type: String 189 | Default: hugo-target 190 | RepoName: 191 | Description: AWS CodeCommit repository name which contains Hugo files 192 | Type: String 193 | RepoBranch: 194 | Description: Name of the repository branch which contains the Hugo files 195 | Type: String 196 | Default: master 197 | 198 | Outputs: 199 | CodePipelineName: 200 | Description: Pipeline name 201 | Value: !Ref CodePipeline 202 | -------------------------------------------------------------------------------- /samples/ia4ct.ps1: -------------------------------------------------------------------------------- 1 | #! /usr/local/bin/pwsh 2 | [CmdletBinding()] 3 | param ( 4 | # This is the s3 path to the template file we will reference in the manifest file 5 | [Parameter()] 6 | [string] 7 | $templatePath = "templates/linux-bastion.template", 8 | [Parameter()] 9 | [string] 10 | $manifestPath = "temp/ps_manifest.yaml", 11 | [Parameter()] 12 | [string] 13 | $verboseManifest = $true 14 | ) 15 | import-module powershell-yaml 16 | 17 | # Read Yaml file 18 | $cfn = Get-Content $templatePath | ConvertFrom-Yaml 19 | 20 | class cfnParameter { 21 | [String]$pname 22 | [String]$default 23 | [String]$type 24 | [String]$description 25 | [String]$allowedValues 26 | [String]$allowedPattern 27 | [String]$constraintDescription 28 | } 29 | $parms = @() 30 | foreach ($key in $cfn.Parameters.keys) { 31 | $ctParm = New-Object cfnParameter 32 | $ctParm.pname = $key 33 | $ctParm.default = $cfn.Parameters[$key].default 34 | $ctParm.type = $cfn.Parameters[$key].type 35 | $ctParm.description = $cfn.Parameters[$key].description 36 | $ctParm.allowedValues = $cfn.Parameters[$key].allowedValues 37 | $ctParm.allowedPattern = $cfn.Parameters[$key].allowedPattern 38 | $ctParm.ConstraintDescription = $cfn.Parameters[$key].ConstraintDescription 39 | $parms += $ctParm 40 | } 41 | #$parms 42 | $manifestPath= '../temp/ps_manifest.yaml' 43 | Set-Content -Path $manifestPath -Value '---' 44 | #Add-Content -Path temp/manifest.yaml -Value '---' 45 | Add-Content -Path $manifestPath -Value 'region: [The region where Customization for Control Tower is deployed]' 46 | Add-Content -Path $manifestPath -Value 'version: 2021-03-15' 47 | Add-Content -Path $manifestPath -Value 'resources:' 48 | Add-Content -Path $manifestPath -Value ' - name: [The name for this deployment]' 49 | Add-Content -Path $manifestPath -Value " description: $($cfn.description)" 50 | Add-Content -Path $manifestPath -Value ' resource_file: [The s3 path where the template is located.]' 51 | Add-Content -Path $manifestPath -Value ' parameters:' 52 | $parms = $parms | Sort-Object -Property pname 53 | foreach ($parm in $parms) { 54 | if ($verboseManifest -eq $true) { 55 | if ($parm.description) { Add-Content -Path $manifestPath -Value " # Description: $($parm.description)" } 56 | if ($parm.allowedPattern) { Add-Content -Path $manifestPath -Value " # AllowedPattern: $($parm.allowedPattern)" } 57 | if ($parm.allowedValues) { Add-Content -Path $manifestPath -Value " # AllowedValues: $($parm.allowedValues)" } 58 | if ($parm.constraintDescription) { Add-Content -Path $manifestPath -Value " # ConstraintDescription: $($parm.constraintDescription)" } 59 | if ($parm.MaxLength) { Add-Content -Path $manifestPath -Value " # MaxLength: $($parm.MaxLength)" } 60 | if ($parm.MaxValue) { Add-Content -Path $manifestPath -Value " # MaxValue: $($parm.MaxValue)" } 61 | if ($parm.MinLength) { Add-Content -Path $manifestPath -Value " # MinLength: $($parm.MinLength)" } 62 | if ($parm.MinValue) { Add-Content -Path $manifestPath -Value " # MinValue: $($parm.MinValue)" } 63 | if ($parm.NoEcho) { Add-Content -Path $manifestPath -Value " # NoEcho: $($parm.NoEcho)" } 64 | if ($parm.type) { Add-Content -Path $manifestPath -Value " # Type: $($parm.type)" } 65 | } 66 | Add-Content -Path $manifestPath -Value " - parameter_key: $($parm.pname)" 67 | Add-Content -Path $manifestPath -Value " parameter_value: $($parm.default)" 68 | } 69 | Add-Content -Path $manifestPath -Value ' deploy_method: stack_set' 70 | Add-Content -Path $manifestPath -Value ' deployment_targets: stack_set' 71 | Add-Content -Path $manifestPath -Value ' organizational_units:' 72 | Add-Content -Path $manifestPath -Value ' - [Enter your Organizational Unit]' 73 | Add-Content -Path $manifestPath -Value ' regions:' 74 | Add-Content -Path $manifestPath -Value ' - [The region where you wish to deploy this workload]' 75 | -------------------------------------------------------------------------------- /samples/ia4ct.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import argparse 4 | from typing import DefaultDict 5 | import yaml 6 | from yaml.error import YAMLError 7 | 8 | parser = argparse.ArgumentParser() 9 | 10 | parser.add_argument("path", nargs='?', default="templates/linux-bastion.template", help="Provide a path to the template file", type=str) 11 | parser.add_argument("outPath", nargs='?', default="temp/py_manifest.yaml", help="Provide a destination path for the output file", type=str) 12 | parser.add_argument("-v", "--verboseManifest", help="Include help comments in the manifest", action="store_true") 13 | args = parser.parse_args() 14 | # print(args.path) 15 | # print(args.verboseManifest) 16 | 17 | class CtParameter(yaml.YAMLObject): 18 | yaml_tag = u'!Parameters' 19 | def __init__(self, name): 20 | self.name = name 21 | pass 22 | def method(self, arg): 23 | return True 24 | 25 | try: 26 | yaml.add_multi_constructor('!', lambda loader, suffix, node: None) 27 | # Read Yaml file 28 | cfn = yaml.full_load(open(args.path, 'r')) 29 | # Container for each parameter object 30 | parameters = [] 31 | # Get data for each parameter 32 | for n in cfn['Parameters']: 33 | ctParm = CtParameter(n) 34 | #ctParm.name = n 35 | for i in cfn['Parameters'][n]: 36 | setattr(ctParm, i, cfn['Parameters'][n][i]) 37 | # Append the parameter data to the list 38 | parameters.append(ctParm) 39 | 40 | # Create the manifest file and write the document 41 | m = open(args.outPath, "w+") 42 | m.write("---\n") 43 | m.write("region: [The region where Customization for Control Tower is deployed]\n") 44 | m.write("version: 2021-03-15\n") 45 | m.write("resources:\n") 46 | m.write(" - name: [The name for this deployment]\n") 47 | m.write(" description: " + cfn['Description'] + "\n") 48 | m.write(" resource_file: [The s3 path where the template is located.]\n") 49 | m.write(" parameters:\n") 50 | 51 | parameters.sort(key=lambda x: x.name) 52 | for p in parameters: 53 | if args.verboseManifest: 54 | if hasattr(p,"Description"): 55 | m.write(" # Description: " + p.Description + "\n") 56 | if hasattr(p,"AllowedPattern"): 57 | m.write(" # AllowedPattern: " + p.AllowedPattern + "\n") 58 | if hasattr(p,"AllowedValues"): 59 | m.write(" # AllowedValues: " + ' '.join(str(v) for v in p.AllowedValues) + "\n") 60 | if hasattr(p,"ConstraintDescription"): 61 | m.write(" # ConstraintDescription: " + p.ConstraintDescription + "\n") 62 | if hasattr(p,"MaxLength"): 63 | m.write(" # MaxLength: " + p.MaxLength + "\n") 64 | if hasattr(p,"MaxValue"): 65 | m.write(" # MaxValue: " + p.MaxValue + "\n") 66 | if hasattr(p,"MinLength"): 67 | m.write(" # MinLength: " + p.MinLength + "\n") 68 | if hasattr(p,"MinValue"): 69 | m.write(" # MinValue: " + p.MinValue + "\n") 70 | if hasattr(p,"NoEcho"): 71 | m.write(" # NoEcho: " + p.NoEcho + "\n") 72 | if hasattr(p,"Type"): 73 | m.write(" # Type: " + p.Type + "\n") 74 | m.write(" - parameter_key: " + p.name + "\n") 75 | if hasattr(p,"Default"): 76 | m.write(" parameter_value: " + str(p.Default) + "\n") 77 | else: 78 | m.write(" parameter_value: \n") 79 | m.write(" deploy_method: stack_set\n") 80 | m.write(" deployment_targets:\n") 81 | m.write(" organizational_units:\n") 82 | m.write(" - [Enter your Organizational Unit]\n") 83 | m.write(" regions:\n") 84 | m.write(" - [The region where you wish to deploy this workload]\n") 85 | 86 | 87 | except YAMLError as exc: 88 | print(exc) 89 | -------------------------------------------------------------------------------- /samples/iot-button-deploy-cloudformation/demo-params.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "ParamValue", 4 | "ParameterValue": "Demo" 5 | } 6 | ] -------------------------------------------------------------------------------- /samples/iot-button-deploy-cloudformation/demo-stack.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Demo stack, creates one SSM parameter. 3 | Parameters: 4 | ParamValue: 5 | Type: String 6 | Description: The value to store in the SSM parameter. 7 | Resources: 8 | DemoParameter: 9 | Type: "AWS::SSM::Parameter" 10 | Properties: 11 | Type: "String" 12 | Value: !Ref ParamValue 13 | Description: "SSM Parameter for storing user input." 14 | Outputs: 15 | DemoParameter: 16 | Description: The name of the demo parameter. 17 | Value: !Ref DemoParameter 18 | -------------------------------------------------------------------------------- /samples/iot-button-deploy-cloudformation/iot-button-deploy-cloudformation.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: Deploys an AWS Lambda function that will deploy an input AWS CloudFormation template with a provided parameter file. This Lambda function can be used as an action for the AWS IoT Button to deploy AWS CloudFormation templates. (qs-1s7dari0g) 3 | Metadata: 4 | AWS::CloudFormation::Interface: 5 | ParameterGroups: 6 | - Label: 7 | default: Input configuration 8 | Parameters: 9 | - TemplateURL 10 | - ParamsFile 11 | ParameterLabels: 12 | TemplateURL: 13 | default: Template URL 14 | ParamsFile: 15 | default: Parameters file S3 URI 16 | Parameters: 17 | TemplateURL: 18 | Type: String 19 | Description: URL of the CloudFormation template you want to deploy; e.g., https://s3.amazonaws.com/aws-quickstart/quickstart-examples/samples/iot-button-deploy-cloudformation/demo-stack.yaml. 20 | ParamsFile: 21 | Type: String 22 | Description: S3 URI of the parameters file stored in your S3 bucket; e.g., s3://my-bucket/demo-params.json. 23 | Resources: 24 | IoTButtonLambdaExecutionRole: 25 | Type: "AWS::IAM::Role" 26 | Properties: 27 | AssumeRolePolicyDocument: 28 | Version: "2012-10-17" 29 | Statement: 30 | - Effect: "Allow" 31 | Principal: 32 | Service: ["lambda.amazonaws.com"] 33 | Action: "sts:AssumeRole" 34 | Path: "/" 35 | ManagedPolicyArns: 36 | - 'arn:aws:iam::aws:policy/AdministratorAccess' 37 | IoTButtonDeployQSLambda: 38 | Type: "AWS::Lambda::Function" 39 | DependsOn: 40 | - IoTButtonLambdaExecutionRole 41 | Properties: 42 | FunctionName: !Sub "Lambda-${AWS::StackName}" 43 | Code: 44 | ZipFile: | 45 | import json 46 | import boto3 47 | import os 48 | from datetime import datetime 49 | from urllib.parse import urlparse 50 | 51 | params_url = os.environ['paramsFile'] 52 | template_url = os.environ['templateUrl'] 53 | 54 | def parse_params(): 55 | s3 = boto3.resource('s3') 56 | s3_parse = urlparse(params_url) 57 | bucket = s3_parse.netloc 58 | s3_key = s3_parse.path.lstrip('/') 59 | s3_obj = s3.Object(bucket, s3_key) 60 | params_raw_data = s3_obj.get()["Body"].read().decode('utf-8') 61 | template_params = json.loads(params_raw_data) 62 | return template_params 63 | 64 | def launch_stack(): 65 | cfn = boto3.client('cloudformation') 66 | current_ts = datetime.now().isoformat().split('.')[0].replace(':','-') 67 | stackname = 'IoT-QS-Deploy-' + current_ts 68 | capabilities = ['CAPABILITY_IAM', 'CAPABILITY_AUTO_EXPAND'] 69 | try: 70 | template_params = parse_params() 71 | stackdata = cfn.create_stack( 72 | StackName=stackname, 73 | DisableRollback=True, 74 | TemplateURL=template_url, 75 | Parameters=template_params, 76 | Capabilities=capabilities) 77 | except Exception as e: 78 | error_msg = str(e) 79 | print(error_msg) 80 | stackdata = {"error": error_msg} 81 | return stackdata 82 | 83 | def stack_success(stackdata): 84 | if 'error' in stackdata: 85 | return False 86 | else: 87 | return True 88 | 89 | def handler(event, context): 90 | print("Received event:") 91 | stack_result=launch_stack() 92 | print(stack_result) 93 | 94 | if stack_success(stack_result): 95 | resp_txt = "Your stack has been launched. Please visit the AWS Console to track its progress" 96 | else: 97 | resp_txt = "Your stack failed to launch. Please visit the AWS Console to investigate further" 98 | 99 | json_resp = { 100 | "version": "1.0", 101 | "response": { 102 | "outputSpeech": { 103 | "type": "PlainText", 104 | "text": resp_txt 105 | }, 106 | "shouldEndSession": "true" 107 | } 108 | } 109 | return json_resp 110 | Environment: 111 | Variables: 112 | templateUrl: !Ref 'TemplateURL' 113 | paramsFile: !Ref 'ParamsFile' 114 | Handler: "index.handler" 115 | Runtime: "python3.6" 116 | Timeout: 60 117 | Role: !GetAtt IoTButtonLambdaExecutionRole.Arn 118 | -------------------------------------------------------------------------------- /samples/session-manager-ssh/session-manager-example.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This template sets up a VPC and ec2 instance for the purposes of demonstrating connecting to instances in private subnets using Session Manager. (qs-1pqnhbcg8) 3 | Parameters: 4 | LatestAmiId: 5 | Type: 'AWS::SSM::Parameter::Value' 6 | Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' 7 | AvailabilityZones: 8 | Description: List of Availability Zones to use for the subnets in the VPC. Only 9 | two Availability Zones are used for this deployment, and the logical order of 10 | your selections is preserved. 11 | Type: List 12 | PrivateSubnet1CIDR: 13 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 14 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 15 | Default: 10.0.0.0/19 16 | Description: CIDR block for private subnet 1 located in Availability Zone 1. 17 | Type: String 18 | PrivateSubnet2CIDR: 19 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 20 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 21 | Default: 10.0.32.0/19 22 | Description: CIDR block for private subnet 2 located in Availability Zone 2. 23 | Type: String 24 | PublicSubnet1CIDR: 25 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 26 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 27 | Default: 10.0.128.0/20 28 | Description: CIDR block for the public (DMZ) subnet 1 located in Availability 29 | Zone 1. 30 | Type: String 31 | PublicSubnet2CIDR: 32 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 33 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 34 | Default: 10.0.144.0/20 35 | Description: CIDR block for the public (DMZ) subnet 2 located in Availability 36 | Zone 2. 37 | Type: String 38 | VPCCIDR: 39 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 40 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 41 | Default: 10.0.0.0/16 42 | Description: CIDR block for the VPC. 43 | Type: String 44 | Resources: 45 | EC2SSMRole: 46 | Type: "AWS::IAM::Role" 47 | Properties: 48 | AssumeRolePolicyDocument: 49 | Version: "2012-10-17" 50 | Statement: 51 | - Effect: "Allow" 52 | Principal: 53 | Service: ["ec2.amazonaws.com"] 54 | Action: "sts:AssumeRole" 55 | Path: "/" 56 | ManagedPolicyArns: 57 | - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' 58 | - 'arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy' 59 | EC2InstanceProfile: 60 | Type: AWS::IAM::InstanceProfile 61 | Properties: 62 | Path: '/' 63 | Roles: 64 | - !Ref EC2SSMRole 65 | VPCStack: 66 | Type: AWS::CloudFormation::Stack 67 | Properties: 68 | TemplateURL: 69 | Fn::Sub: https://aws-quickstart.s3.amazonaws.com/quickstart-aws-vpc/templates/aws-vpc.template.yaml 70 | Parameters: 71 | AvailabilityZones: 72 | Fn::Join: 73 | - ',' 74 | - Ref: AvailabilityZones 75 | NumberOfAZs: '2' 76 | PrivateSubnet1ACIDR: 77 | Ref: PrivateSubnet1CIDR 78 | PrivateSubnet2ACIDR: 79 | Ref: PrivateSubnet2CIDR 80 | PublicSubnet1CIDR: 81 | Ref: PublicSubnet1CIDR 82 | PublicSubnet2CIDR: 83 | Ref: PublicSubnet2CIDR 84 | VPCCIDR: 85 | Ref: VPCCIDR 86 | MyEC2Instance: 87 | Type: AWS::EC2::Instance 88 | Properties: 89 | ImageId: !Ref LatestAmiId 90 | InstanceType: "t3.micro" 91 | IamInstanceProfile: !Ref EC2InstanceProfile 92 | SubnetId: 93 | Fn::GetAtt: 94 | - VPCStack 95 | - Outputs.PrivateSubnet1AID 96 | Tags: 97 | - 98 | Key: Name 99 | Value: SSM-SSH-Demo 100 | UserData: 101 | Fn::Base64: 102 | !Sub | 103 | #!/bin/bash 104 | sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm 105 | Outputs: 106 | MyEC2Instance: 107 | Description: The instance ID of the demo instance. 108 | Value: !Ref MyEC2Instance 109 | -------------------------------------------------------------------------------- /samples/session-manager-ssh/session-manager-ssh-example.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: This template sets up a VPC and ec2 instance for the purposes of demonstrating connecting to instances in private subnets using Session Manager. (qs-1pqnhbcg8) 3 | Parameters: 4 | LatestAmiId: 5 | Type: 'AWS::SSM::Parameter::Value' 6 | Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' 7 | AvailabilityZones: 8 | Description: List of Availability Zones to use for the subnets in the VPC. Only 9 | two Availability Zones are used for this deployment, and the logical order of 10 | your selections is preserved. 11 | Type: List 12 | KeyPairName: 13 | Description: Name of an existing public/private key pair, which allows you 14 | to securely connect to your instance after it launches. 15 | Type: AWS::EC2::KeyPair::KeyName 16 | PrivateSubnet1CIDR: 17 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 18 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 19 | Default: 10.0.0.0/19 20 | Description: CIDR block for private subnet 1 located in Availability Zone 1. 21 | Type: String 22 | PrivateSubnet2CIDR: 23 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 24 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 25 | Default: 10.0.32.0/19 26 | Description: CIDR block for private subnet 2 located in Availability Zone 2. 27 | Type: String 28 | PublicSubnet1CIDR: 29 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 30 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 31 | Default: 10.0.128.0/20 32 | Description: CIDR block for the public (DMZ) subnet 1 located in Availability 33 | Zone 1. 34 | Type: String 35 | PublicSubnet2CIDR: 36 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 37 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 38 | Default: 10.0.144.0/20 39 | Description: CIDR block for the public (DMZ) subnet 2 located in Availability 40 | Zone 2. 41 | Type: String 42 | VPCCIDR: 43 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 44 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 45 | Default: 10.0.0.0/16 46 | Description: CIDR block for the VPC. 47 | Type: String 48 | Resources: 49 | EC2SSMRole: 50 | Type: "AWS::IAM::Role" 51 | Properties: 52 | AssumeRolePolicyDocument: 53 | Version: "2012-10-17" 54 | Statement: 55 | - Effect: "Allow" 56 | Principal: 57 | Service: ["ec2.amazonaws.com"] 58 | Action: "sts:AssumeRole" 59 | Path: "/" 60 | ManagedPolicyArns: 61 | - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' 62 | - 'arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy' 63 | EC2InstanceProfile: 64 | Type: AWS::IAM::InstanceProfile 65 | Properties: 66 | Path: '/' 67 | Roles: 68 | - !Ref EC2SSMRole 69 | VPCStack: 70 | Type: AWS::CloudFormation::Stack 71 | Properties: 72 | TemplateURL: 73 | Fn::Sub: https://aws-quickstart.s3.amazonaws.com/quickstart-aws-vpc/templates/aws-vpc.template.yaml 74 | Parameters: 75 | AvailabilityZones: 76 | Fn::Join: 77 | - ',' 78 | - Ref: AvailabilityZones 79 | NumberOfAZs: '2' 80 | PrivateSubnet1ACIDR: 81 | Ref: PrivateSubnet1CIDR 82 | PrivateSubnet2ACIDR: 83 | Ref: PrivateSubnet2CIDR 84 | PublicSubnet1CIDR: 85 | Ref: PublicSubnet1CIDR 86 | PublicSubnet2CIDR: 87 | Ref: PublicSubnet2CIDR 88 | VPCCIDR: 89 | Ref: VPCCIDR 90 | MyEC2Instance: 91 | Type: AWS::EC2::Instance 92 | Properties: 93 | ImageId: !Ref LatestAmiId 94 | InstanceType: "t3.micro" 95 | IamInstanceProfile: !Ref EC2InstanceProfile 96 | KeyName: !Ref KeyPairName 97 | SubnetId: 98 | Fn::GetAtt: 99 | - VPCStack 100 | - Outputs.PrivateSubnet1AID 101 | Tags: 102 | - 103 | Key: Name 104 | Value: SSM-SSH-Demo 105 | UserData: 106 | Fn::Base64: 107 | !Sub | 108 | #!/bin/bash 109 | sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm 110 | Outputs: 111 | MyEC2Instance: 112 | Description: The instance ID of the demo instance. 113 | Value: !Ref MyEC2Instance 114 | -------------------------------------------------------------------------------- /templates/workload-yaml-entrypoint-new-vpc.template.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: '2010-09-09' 3 | Description: This example template creates a VPC infrastructure for a multi-AZ, multi-tier 4 | deployment of a workload on AWS. It deploys a VPC with bastions and a workload cluster 5 | behind an ELB. The cluster is configured to use an S3 bucket for storage **WARNING** 6 | This template creates EC2 instances and related resources. You will be billed for 7 | the AWS resources used if you create a stack from this template. (qs-1s1eguahh) 8 | Metadata: 9 | cfn-lint: 10 | config: 11 | ignore_checks: 12 | - W9006 # temporary to get rid of warnings 13 | - W9002 # temporary to get rid of warnings 14 | - W9003 # temporary to get rid of warnings 15 | - W9901 # Not passing all the default parameters to reduce verbosity 16 | AWS::CloudFormation::Interface: 17 | ParameterGroups: 18 | - Label: 19 | default: Network configuration 20 | Parameters: 21 | - AvailabilityZones 22 | - VPCCIDR 23 | - PrivateSubnet1CIDR 24 | - PrivateSubnet2CIDR 25 | - PublicSubnet1CIDR 26 | - PublicSubnet2CIDR 27 | - RemoteAccessCIDR 28 | - Label: 29 | default: Amazon EC2 configuration 30 | Parameters: 31 | - KeyPairName 32 | - BastionAMIOS 33 | - BastionInstanceType 34 | - WorkloadInstanceType 35 | - Label: 36 | default: Workload nodes configuration 37 | Parameters: 38 | - WorkloadNodesMinSize 39 | - WorkloadNodesMaxSize 40 | - OperatorEmail 41 | - Label: 42 | default: Workload storage configuration 43 | Parameters: 44 | - S3BucketName 45 | - Label: 46 | default: AWS Quick Start configuration 47 | Parameters: 48 | - QSS3BucketName 49 | - QSS3BucketRegion 50 | - QSS3KeyPrefix 51 | ParameterLabels: 52 | AvailabilityZones: 53 | default: Availability Zones 54 | BastionAMIOS: 55 | default: Bastion AMI operating system 56 | BastionInstanceType: 57 | default: Bastion instance type 58 | KeyPairName: 59 | default: Key pair name 60 | OperatorEmail: 61 | default: Operator email 62 | PrivateSubnet1CIDR: 63 | default: Private subnet 1 CIDR 64 | PrivateSubnet2CIDR: 65 | default: Private subnet 2 CIDR 66 | PublicSubnet1CIDR: 67 | default: Public subnet 1 CIDR 68 | PublicSubnet2CIDR: 69 | default: Public subnet 2 CIDR 70 | QSS3BucketName: 71 | default: Quick Start S3 bucket name 72 | QSS3BucketRegion: 73 | default: Quick Start S3 bucket region 74 | QSS3KeyPrefix: 75 | default: Quick Start S3 Key Prefix 76 | S3BucketName: 77 | default: S3 bucket name 78 | RemoteAccessCIDR: 79 | default: Allowed bastion external access CIDR 80 | VPCCIDR: 81 | default: VPC CIDR 82 | WorkloadInstanceType: 83 | default: Workload servers instance type 84 | WorkloadNodesMaxSize: 85 | default: Workload nodes max size 86 | WorkloadNodesMinSize: 87 | default: Workload nodes min size 88 | Parameters: 89 | AvailabilityZones: 90 | Description: List of Availability Zones to use for the subnets in the VPC. Only 91 | two Availability Zones are used for this deployment, and the logical order of 92 | your selections is preserved. 93 | Type: List 94 | BastionAMIOS: 95 | AllowedValues: 96 | - Amazon-Linux2-HVM 97 | - CentOS-7-HVM 98 | - Ubuntu-Server-20.04-LTS-HVM 99 | - SUSE-SLES-15-HVM 100 | Default: Amazon-Linux2-HVM 101 | Description: Linux distribution for the AMI to be used for the bastion instances. 102 | Type: String 103 | BastionInstanceType: 104 | AllowedValues: 105 | - t2.nano 106 | - t2.micro 107 | - t2.small 108 | - t2.medium 109 | - t2.large 110 | - m3.large 111 | - m3.xlarge 112 | - m3.2xlarge 113 | - m4.large 114 | - m4.xlarge 115 | - m4.2xlarge 116 | - m4.4xlarge 117 | Default: t2.micro 118 | Description: Amazon EC2 instance type for the bastion instances. 119 | Type: String 120 | KeyPairName: 121 | Description: Name of an existing public/private key pair, which allows you 122 | to securely connect to your instance after it launches. 123 | Type: AWS::EC2::KeyPair::KeyName 124 | OperatorEmail: 125 | AllowedPattern: ([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?) 126 | ConstraintDescription: Must be a valid email address. 127 | Description: Email address that notifications of any scaling operations will be 128 | sent to. 129 | Type: String 130 | PrivateSubnet1CIDR: 131 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 132 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 133 | Default: 10.0.0.0/19 134 | Description: CIDR block for private subnet 1 located in Availability Zone 1. 135 | Type: String 136 | PrivateSubnet2CIDR: 137 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 138 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 139 | Default: 10.0.32.0/19 140 | Description: CIDR block for private subnet 2 located in Availability Zone 2. 141 | Type: String 142 | PublicSubnet1CIDR: 143 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 144 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 145 | Default: 10.0.128.0/20 146 | Description: CIDR block for the public (DMZ) subnet 1 located in Availability 147 | Zone 1. 148 | Type: String 149 | PublicSubnet2CIDR: 150 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 151 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 152 | Default: 10.0.144.0/20 153 | Description: CIDR block for the public (DMZ) subnet 2 located in Availability 154 | Zone 2. 155 | Type: String 156 | QSS3BucketName: 157 | AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ 158 | ConstraintDescription: Quick Start bucket name can include numbers, lowercase 159 | letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen 160 | (-). 161 | Default: aws-quickstart 162 | Description: S3 bucket name for the Quick Start assets. This string can include 163 | numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start 164 | or end with a hyphen (-). 165 | Type: String 166 | QSS3BucketRegion: 167 | Default: 'us-east-1' 168 | Description: 'The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value.' 169 | Type: String 170 | QSS3KeyPrefix: 171 | AllowedPattern: ^[0-9a-zA-Z-/]*$ 172 | ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, 173 | uppercase letters, hyphens (-), and forward slash (/). 174 | Default: quickstart-examples/ 175 | Description: S3 key prefix for the Quick Start assets. Quick Start key prefix 176 | can include numbers, lowercase letters, uppercase letters, hyphens (-), and 177 | forward slash (/). 178 | Type: String 179 | RemoteAccessCIDR: 180 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ 181 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x 182 | Description: CIDR IP range that is permitted to access the bastions. We recommend 183 | that you set this value to a trusted IP range. 184 | Type: String 185 | S3BucketName: 186 | AllowedPattern: ^[a-z0-9][a-z0-9-.]*$ 187 | Default: type-unique-value-here-in-lowercase 188 | Description: Name of the S3 bucket that will be created for your workload to store 189 | data. Enter a unique name that does not include uppercase characters. 190 | Type: String 191 | VPCCIDR: 192 | AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ 193 | ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 194 | Default: 10.0.0.0/16 195 | Description: CIDR block for the VPC. 196 | Type: String 197 | WorkloadInstanceType: 198 | AllowedValues: 199 | - t2.large 200 | - m4.large 201 | - m4.xlarge 202 | - m4.2xlarge 203 | - m4.4xlarge 204 | - m4.10xlarge 205 | - m3.medium 206 | - m3.large 207 | - m3.xlarge 208 | - m3.2xlarge 209 | - c4.large 210 | - c4.xlarge 211 | - c4.2xlarge 212 | - c4.4xlarge 213 | - c4.8xlarge 214 | - c3.large 215 | - c3.xlarge 216 | - c3.2xlarge 217 | - c3.4xlarge 218 | - c3.8xlarge 219 | - r3.large 220 | - r3.xlarge 221 | ConstraintDescription: Must contain valid instance type 222 | Default: m4.xlarge 223 | Description: EC2 instance type for the workload instances. 224 | Type: String 225 | WorkloadNodesDesiredCapacity: 226 | Default: '2' 227 | Description: Desired capacity for the workload nodes Auto Scaling group. 228 | Type: String 229 | WorkloadNodesMaxSize: 230 | Default: '4' 231 | Description: Maximum size of the Auto Scaling group. 232 | Type: String 233 | WorkloadNodesMinSize: 234 | Default: '2' 235 | Description: Minimum size of the Auto Scaling group. 236 | Type: String 237 | Conditions: 238 | UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] 239 | Resources: 240 | VPCStack: 241 | Type: AWS::CloudFormation::Stack 242 | Properties: 243 | TemplateURL: 244 | !Sub 245 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/quickstart-aws-vpc/templates/aws-vpc.template.yaml' 246 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 247 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 248 | Parameters: 249 | AvailabilityZones: 250 | Fn::Join: 251 | - ',' 252 | - Ref: AvailabilityZones 253 | NumberOfAZs: '2' 254 | PrivateSubnet1ACIDR: 255 | Ref: PrivateSubnet1CIDR 256 | PrivateSubnet2ACIDR: 257 | Ref: PrivateSubnet2CIDR 258 | PublicSubnet1CIDR: 259 | Ref: PublicSubnet1CIDR 260 | PublicSubnet2CIDR: 261 | Ref: PublicSubnet2CIDR 262 | VPCCIDR: 263 | Ref: VPCCIDR 264 | BastionStack: 265 | Type: AWS::CloudFormation::Stack 266 | Properties: 267 | TemplateURL: 268 | !Sub 269 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/quickstart-linux-bastion/templates/linux-bastion.template' 270 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 271 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 272 | Parameters: 273 | QSS3BucketName: 274 | Ref: QSS3BucketName 275 | QSS3BucketRegion: 276 | Ref: QSS3BucketRegion 277 | QSS3KeyPrefix: !Sub '${QSS3KeyPrefix}submodules/quickstart-linux-bastion/' 278 | BastionAMIOS: 279 | Ref: BastionAMIOS 280 | BastionInstanceType: 281 | Ref: BastionInstanceType 282 | KeyPairName: 283 | Ref: KeyPairName 284 | PublicSubnet1ID: 285 | Fn::GetAtt: 286 | - VPCStack 287 | - Outputs.PublicSubnet1ID 288 | PublicSubnet2ID: 289 | Fn::GetAtt: 290 | - VPCStack 291 | - Outputs.PublicSubnet2ID 292 | RemoteAccessCIDR: 293 | Ref: RemoteAccessCIDR 294 | VPCID: 295 | Fn::GetAtt: 296 | - VPCStack 297 | - Outputs.VPCID 298 | WorkloadStack: 299 | Type: AWS::CloudFormation::Stack 300 | Properties: 301 | TemplateURL: 302 | !Sub 303 | - 'https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/workload-yaml.template.yaml' 304 | - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] 305 | S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] 306 | Parameters: 307 | WorkloadInstanceType: 308 | Ref: WorkloadInstanceType 309 | WorkloadNodesDesiredCapacity: 310 | Ref: WorkloadNodesDesiredCapacity 311 | WorkloadNodesMaxSize: 312 | Ref: WorkloadNodesMaxSize 313 | WorkloadNodesMinSize: 314 | Ref: WorkloadNodesMinSize 315 | BastionSecurityGroupID: 316 | Fn::GetAtt: 317 | - BastionStack 318 | - Outputs.BastionSecurityGroupID 319 | KeyPairName: 320 | Ref: KeyPairName 321 | OperatorEmail: 322 | Ref: OperatorEmail 323 | PrivateSubnet1ID: 324 | Fn::GetAtt: 325 | - VPCStack 326 | - Outputs.PrivateSubnet1AID 327 | PrivateSubnet2ID: 328 | Fn::GetAtt: 329 | - VPCStack 330 | - Outputs.PrivateSubnet2AID 331 | PublicSubnet1ID: 332 | Fn::GetAtt: 333 | - VPCStack 334 | - Outputs.PublicSubnet1ID 335 | PublicSubnet2ID: 336 | Fn::GetAtt: 337 | - VPCStack 338 | - Outputs.PublicSubnet2ID 339 | QSS3BucketName: 340 | Ref: QSS3BucketName 341 | QSS3KeyPrefix: 342 | Ref: QSS3KeyPrefix 343 | S3BucketName: 344 | Ref: S3BucketName 345 | VPCID: 346 | Fn::GetAtt: 347 | - VPCStack 348 | - Outputs.VPCID 349 | --------------------------------------------------------------------------------