{"id":13602610,"url":"https://github.com/aws-samples/aws-cdk-project-template-for-devops","last_synced_at":"2025-04-11T09:30:38.933Z","repository":{"id":42439712,"uuid":"409226614","full_name":"aws-samples/aws-cdk-project-template-for-devops","owner":"aws-samples","description":"This repository provides best practices and template framework for developing AWS Cloud Development Kit(CDK)-based applications effectively, quickly and collaboratively.","archived":false,"fork":false,"pushed_at":"2024-08-14T06:02:18.000Z","size":2863,"stargazers_count":155,"open_issues_count":2,"forks_count":32,"subscribers_count":16,"default_branch":"main","last_synced_at":"2024-11-07T05:39:44.645Z","etag":null,"topics":["aws","cdk","cloudformation","devops","modern-applications"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit-0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aws-samples.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-22T14:00:22.000Z","updated_at":"2024-10-31T00:32:33.000Z","dependencies_parsed_at":"2024-03-13T05:26:24.432Z","dependency_job_id":"9ba5ee38-a2e6-4315-b074-b4443aebebe6","html_url":"https://github.com/aws-samples/aws-cdk-project-template-for-devops","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-samples%2Faws-cdk-project-template-for-devops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-samples%2Faws-cdk-project-template-for-devops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-samples%2Faws-cdk-project-template-for-devops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-samples%2Faws-cdk-project-template-for-devops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aws-samples","download_url":"https://codeload.github.com/aws-samples/aws-cdk-project-template-for-devops/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248368166,"owners_count":21092312,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","cdk","cloudformation","devops","modern-applications"],"created_at":"2024-08-01T18:01:31.649Z","updated_at":"2025-04-11T09:30:38.587Z","avatar_url":"https://github.com/aws-samples.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","aws"],"sub_categories":[],"readme":"# AWS CDK Project Template for DevOps\n\nThis repository provides best practices and template framework for developing AWS Cloud Development Kit(CDK)-based applications effectively, quickly and collaboratively. In detail, practical approaches such as how to deploy to multi-environment, how to organize directories and how to manage dependencies between stacks will be introduced, and template codes are provided to support them. Gradually, these template codes will be further expanded to support various DevOps scenario.\n\nThis template framework suports both CDK Ver2 and CDK Ver1.\n\n- AWS CDK Version2 branch: [main, default branch](https://github.com/aws-samples/aws-cdk-project-template-for-devops/tree/main)\n- AWS CDK Version1 branch: [release_cdk_v1, now in maintenance mode](https://github.com/aws-samples/aws-cdk-project-template-for-devops/tree/release_cdk_v1)\n\n## Agenda\n\n1. [AWS CDK Introduction](#1-aws-cdk-introduction)\n\n2. [Prerequisites](#2-prerequisites)\n\n3. [Basic Principles](#3-basic-principles)\n\n    3-a. [DevOps Collaboration: How to organize directory for collaboration](#3-a-devops-collaboration-how-to-organize-directory-for-collaboration)\n\n    3-b. [Multi-Target Deployment: How to separate configuration from codes](#3-b-multi-target-deployment-how-to-separate-configuration-from-codes)\n\n    3-c. [Stack Independence: How to manage dependency between stacks](#3-c-stack-independence-how-to-manage-dependency-between-stacks)\n\n    3-d. [Code Reuse: How to make it a framework](#3-d-code-reuse-how-to-make-it-a-framework)\n\n4. [Sample Stacks](#4-sample-stacks)\n\n5. [Projects based on this framework](#5-projects-based-on-this-framework)\n\n6. [Security](#6-security)\n\n7. [License](#7-license)\n\n## 1. AWS CDK Introduction\n\n [AWS Cloud Development Kit(CDK)](https://aws.amazon.com/cdk) is an open source software development framework to define your cloud application resources using familiar programming languages. After coding using CDK Construct and Stack, if you run it through CDK CLI, it is finally compiled and deployed through AWS CloudFormation.\n\n![1. AWSCDKIntro](docs/asset/aws_cdk_intro.png)\n\n AWS CDK supports TypeScript, JavaScript, Python, Java, C#/.Net, and (in developer preview) Go. The template codes of this repository are implemented in **TypeScript**, because it clearly defines restrictions on types. Restrictions on types provide automated/powerful guide within IDE.\n\n Because AWS CDK is provided in a language that supports OOP(Object-Oriented Programming), it is possible to configure and deploy cloud resources in the most abstract and modern way. This repository provides a template framework by maximizing these characteristics.\n\n### CDK Useful commands\n\n- `npm install`     install dependencies only for Typescript\n- `cdk list`        list up all stacks\n- `cdk deploy`      deploy this stack to your default or specific AWS account/region\n- `cdk diff`        compare deployed stack with current state\n- `cdk synth`       emits the synthesized CloudFormation template\n- `cdk destroy`     destroy this stack to your default or specific AWS account/region\n  \n### CDK Project Entry-point\n\n `cdk.json` in the root directory describes a entry-point file, in this repository we use **infra/app-main.ts** as the entry-point.\n\n### CDK Useful Links\n\n- CDK Intro: [https://docs.aws.amazon.com/cdk/latest/guide/home.html](https://docs.aws.amazon.com/cdk/latest/guide/home.html)\n- CDK Getting Started: [https://docs.aws.amazon.com/cdk/latest/guide/hello_world.html](https://docs.aws.amazon.com/cdk/latest/guide/hello_world.html)\n- API Reference: [https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html)\n- CDK Workshop: [https://cdkworkshop.com/](https://cdkworkshop.com/)\n- CDK Examples: [https://github.com/aws-samples/aws-cdk-examples](https://github.com/aws-samples/aws-cdk-examples)\n\n## 2. Prerequisites\n\n### AWS Account \u0026 IAM User\n\nFirst of all, AWS Account and IAM User is required. IAM user's credential keys also are requried.\n\n### Dependencies\n\nTo execute this template codes, the following modules must be installed.\n\n- AWS CLI: aws --version\n- Node.js: node --version\n- AWS CDK: cdk --version\n- [jq](https://stedolan.github.io/jq/): jq --version\n\nPlease refer to the kind guide in [CDK Workshop](https://cdkworkshop.com/15-prerequisites.html).\n\n### AWS Credential\n\nConfigure your AWS credential keys using AWS CLI.\n\n```bash\naws configure --profile [your-profile] \nAWS Access Key ID [None]: xxxxxx\nAWS Secret Access Key [None]:yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\nDefault region name [None]: us-east-2 \nDefault output format [None]: json\n```\n\nIf you don't know your account number, execute the following command:\n\n```bash\naws sts get-caller-identity --profile [optional: your-profile]\n...\n...\n{\n    \"UserId\": \".............\",\n    \"Account\": \"75157*******\",\n    \"Arn\": \"arn:aws:iam::75157*******:user/[your IAM User ID]\"\n}\n```\n\n## 3. Basic Principles\n\nSeveral principles were selected to improve DevOps efficiency through AWS CDK. Conversely, if you are considering using AWS CDK as an IaC template for a one-time deployment, there is no need to apply these principles.\n\n### 3-a. **DevOps Collaboration**: How to organize directory for collaboration\n\n- **Purpose**: As an IaC tool for DevOps, it is very important to organize the directory of the project so that you can collaborate by role.\n- **Approach**: I recommend having a separate directory for each role within a project so that each member interacts within a fence. The following figure shows the directory structure intuitively.\n\n \u003cimg src = \"docs/asset/refactoring-directories.png\" width=\"70%\"\u003e\n\n  Although it is not an mandatory guide, it is necessary to configure this way so that development without boundaries between each other is possible. In particular, as the development paradigm shifts to serverless, the boundary between infrastructure(infra, config, lib) and business codes(app, codes, models) is disappearing.\n\n### 3-b. **Multi-Target Deployment**: How to separate configuration from codes\n\n- **Purpose**: Code and configuration should be separated so that they can be freely deployed to various AWS account/region without modifying the code.\n- **Approach**: Prepare a json file for each distribution in `config` directory in order to isolate the configuration from the code as much as possible. The following figure shows the configuration files in `config` directory.\n\n\u003cimg src = \"docs/asset/app-config-demo.png\" width=\"70%\"\u003e\n\nBecause we need to ensure that a single source code is maintained, all configurations are managed in `config/app-config-[your-suffix].json`. And several files are made according to the environment you want to deploy to, and you have to choose one of them when deploying.\n\nEach `config/app-config-[your-suffix].json file` consists of two main parts in json format.\n\n```json\n{\n    \"Project\": {\n        \n    },\n\n    \"Stack\": {\n        \n    }\n}\n```\n\n#### Project Part\n\n**Project** part describes project name and stage, and where to deploy.\n\nThe project name and stage are combined to create a unique project prefix, which is used as a prefix of all stacks.\n\nSpecifying AWS account number and region name in CDK source code causes us to modify the code per release. As a result, such information must be managed outside of the source code.\n\nThe final project part consists of:\n\n```json\n{\n    \"Project\": {\n        \"Name\": \"HelloWorld\", \u003c----- Essential: your project name, all stacks will be prefixed with [Project.Name+Project.Stage]\n        \"Stage\": \"Demo\",      \u003c----- Essential: your project stage, all stacks will be prefixed with [Project.Name+Project.Stage]\n        \"Account\": \"75157*******\", \u003c----- Essential: update according to your AWS Account\n        \"Region\": \"eu-central-1\",     \u003c----- Essential: update according to your target region\n        \"Profile\": \"cdk-demo\"      \u003c----- Essential: AWS Profile, keep empty string if no profile configured\n    },\n\n    \"Stack\": {\n    }\n}\n```\n\nThe above 5 items are mandatory, and if there is no profile name, you can leave it empty string.\n\nIn this example configuration, all stack names start with `HelloWorldDemo`. By setting this prefix, it is possible to deploy multiple stages to the same AWS account/region.\n\n#### **Stack Part**\n\nUsually a CDK project is implemented in several stacks, which have some degree of dependency on each other. **Stack** part describes detailed configuration of each stack. There is no need to define a standardized format because each stack requires different resource configurations, but the `Name` item must be declared because it is common.\n\nA sample stack configuration consists of:\n\n```json\n{\n    \"Project\": {\n    },\n\n    \"Stack\": {\n        \"RealtimeProcessing\": {\n            \"Name\": \"DataProcessingStack\",\n\n            \"BucketName\": \"my-data\",\n\n            \"LambdaName\": \"my-function1\",\n            \"LambdaMemory\": 256,\n            \"LambdaPath\": \"codes/lambda/function-a/src\",\n        }\n        \"BatchJob\": {\n            \"Name\": \"BatchJobStack\",\n\n            \"VpcId\": \"vpc-yyyyyyyy\",\n\n            \"ECSClusterName\": \"main-cluster\",\n            \"ECSServiceName\": \"main-service\",\n        }\n    }\n}\n```\n\n#### How to select a target deployment\n\n Set the path of this json configuration file through an environment variable. The key name of environment variable is `APP_CONFIG`, which can be modified in `infra/app-main.ts` file.\n\n```bash\nexport APP_CONFIG=config/app-config-demo.json\n```\n\n Or you can select this configuration file in command line like this:\n\n ```bash\n cdk deploy *DataProcessingStack --context APP_CONFIG=config/app-config-demo.json\n ```\n\n Through this external configuration injection, multiple deployments(multiple account, multiple region, multiple stage) are possible without code modification.\n\n### 3-c. **Stack Independence**: How to manage dependency between stacks\n\n- **Purpose**: It should be possible to independently deploy each stack by removing the strong coupling between each stack.\n- **Approach**: If `Output` of CloudFormation is directly referenced between stacks, a strong dependency occurs and deployment becomes difficult when there are many stacks. To solve this problem, I recommend placing a key-value registry between them and referencing each other. Of course, this method does not change that the deployment order of each stack must be respected, but once stored in the parameter store, independent deployment is possible afterwards. Luckily, AWS provides **Parameter Store** in **System Manager**, which is the best solution for this.\n\n![stack-dependency](docs/asset/stack-dependency.png)\n\n For frequently used parameter store access, we provide methods to help with this in our base class.\n\nFor parameter provider: putParameter()\n\n ```typescript\nimport * as base from '../../../lib/template/stack/base/base-stack';\nimport { AppContext } from '../../../lib/template/app-context';\n\nexport class DataStoreStack extends base.BaseStack {\n\n    constructor(appContext: AppContext, stackConfig: any) {\n        super(appContext, stackConfig);\n\n        const ddbTable = this.createDdbTable();\n        this.putParameter('TableName', ddbTable.tableName)\n    }\n\n    ...\n}\n ```\n\nFor parameter user: getParameter()\n\n ```typescript\nimport * as base from '../../../lib/template/stack/base/base-stack';\nimport { AppContext } from '../../../lib/template/app-context';\n\nexport class DataProcessStack extends base.BaseStack {\n\n    constructor(appContext: AppContext, stackConfig: any) {\n        super(appContext, stackConfig);\n\n        const tableName = this.getParameter('TableName')\n        \n    }\n}\n ```\n\n### 3-d. **Code Reuse**: How to make it a framework\n\n- **Purpose**: Frequently reused workloads should be abstracted and easily reused without duplication of code.\n- **Approach**: Frequently used patterns and resources are provided using OOP's [template method pattern](https://en.wikipedia.org/wiki/Template_method_pattern). That is, frequently used things will be provided through the parent class, and the child class will inherit and reuse it. This is an essential approach used in the process of creating a framework.\n\n![custom-framework](docs/asset/custom-framework.png)\n\nAs shown in the figure above, we can now use the framework to focus on more core business logic and reliably speed up development.\n\nThe stack and construct corresponding to the parent class are planned to be gradually expanded based on the workload or pattern that is essential. All contributors are welcome on this, so please contact me.\n\n![classdiagram-core](docs/asset/classdiagram-core.png)\n\n## 4. Sample Stacks\n\nThis section explains how to use each base class with example codes. This sample implements a typical backend service, which has a private ALB, ECS Cluster/Service/Task(python container), Aurora RDS and Cloud9(RDS bastion host) in a VPC. Based on CDK best practices, all of this has been implemented in four stacks.\n\n![sample-backend-service-architecture1](docs/asset/sample-backend-service-architecture1.png)\n\nYou can see what parent class each stack inherits from through the following full diagram.\n\n![classdiagram-overall](docs/asset/classdiagram-overall.png)\n\n### SampleCfnVpcStack\n\nThis stack creates a VPC using CloudFormation yaml file. For that reason, it inherits from CfnIncludeStack which can automatically load yaml file instead of us. Write the information about CloudFormation template in the config. If you pass yaml path and parameters to `onLoadTemplateProps` method, Cfn object is passed to `onPostConstructor`.\n\n- Stack Configuration\n\n```json\n{\n    \"Project\": {\n        ...\n    },\n\n    \"Stack\": {\n        \"SampleCfnVpc\": {\n            \"Name\": \"SampleCfnVpcStack\",\n\n            \"TemplatePath\": \"infra/stack/template/sample-cfn-vpc.yaml\",\n            \"Parameters\": [\n                {\n                    \"Key\": \"VpcName\",\n                    \"Value\": \"HelloWorldDemo-Vpc\"\n                }\n            ]\n        },\n        \"SampleVpcRds\": {\n            ...\n        },      \n        \"SampleVpcCloud9\": {\n            ...\n        },      \n        \"SampleVpcEcs\": {\n            ...\n        }   \n    }\n}\n```\n\n- Stack Implementation\n\n  - [sample-cfn-vpc-stack.ts](infra/stack/sample-cfn-vpc-stack.ts)\n\nVPC name is stored in memory via `putVariable` method and will be used to retrieve VPC object from other stacks.\n\n### SampleVpcRdsStack\n\nThis stack creates Aurora serverless database in VPC which was created in `SampleCfnVpcStack`. Since it inherits from VpcBastStack, if you pass VPC name to `onLookupLegacyVpc` method, VPC object is passed to `onPostConstructor`.\n\nAnd database parameters are saved through `putParateter` method, which will save those into `Parameter store` in `Secrets Manager` instead of us.\n\n- Stack Configuration\n\n```json\n{\n    \"Project\": {\n        ...\n    },\n\n    \"Stack\": {\n        \"SampleCfnVpc\": {\n            ...\n        },\n        \"SampleVpcRds\": {\n            \"Name\": \"SampleVpcRdsStack\",\n\n            \"ClusterIdentifier\": \"SampeDatabase\",\n            \"DatabaseName\": \"helloworld\"\n        },\n        \"SampleVpcCloud9\": {\n            ...\n        },\n        \"SampleVpcEcs\": {\n            ...\n        },\n    }\n}\n```\n\n- Stack Implementation\n\n  - [sample-vpc-rds-stack.ts](infra/stack/sample-vpc-rds-stack.ts)\n\n### SampleVpcCloud9Stack\n\nThis stack just creates a Cloud9 EC2 instance in the first publict subent of VPC, so there is no special configuration in the config file. Since it inherits from VpcBastStack, if you pass VPC name to `onLookupLegacyVpc` method, VPC object is passed to `onPostConstructor`.\n\n- Stack Configuration\n\n```json\n{\n    \"Project\": {\n        ...\n    },\n\n    \"Stack\": {\n        \"SampleCfnVpc\": {\n            ...\n        },\n        \"SampleVpcRds\": {\n            ...\n        },\n        \"SampleVpcCloud9\": {\n            \"Name\": \"SampleVpcCloud9Stack\",\n\n            \"InstanceType\": \"t3.large\",\n            \"IamUser\": \"your-iam-user-id\"\n        },  \n        \"SampleVpcEcs\": {\n            ...\n        },\n    }\n}\n```\n\nPlease change `IamUser` above configuration before deployment.\n\n- Stack Implementation\n\n  - [sample-vpc-cloud9-stack.ts](infra/stack/sample-vpc-cloud9-stack.ts)\n\n### SampleVpcEcsStack\n\nThis stack creates ECS Cluster/Serice/Task. Since it inherits from VpcBastStack, if you pass VPC name to `onLookupLegacyVpc` method, VPC object is passed to `onPostConstructor`.\n\n- Stack Configuration\n\n```json\n{\n    \"Project\": {\n        ...\n    },\n\n    \"Stack\": {\n        \"SampleCfnVpc\": {\n            ...\n        },\n        \"SampleVpcRds\": {\n            ...\n        },     \n        \"SampleVpcEcs\": {\n            \"Name\": \"SampleVpcEcsStack\",\n\n            \"ClusterName\": \"SampleCluster\",\n            \"FilePath\": \"codes/sample-backend-fastapi\",\n            \"Memory\": 1024,\n            \"Cpu\": 512,\n            \"DesiredCount\": 1\n        },\n    }\n}\n```\n\n- Stack Implementation\n\n  - [sample-vpc-ecs-stack.ts](infra/stack/sample-vpc-ecs-stack.ts)\n\n### Install dependecies \u0026 Bootstrap\n\nExecute the following command:\n\n```bash\nsh script/setup_initial.sh config/app-config-demo.json\n```\n\nFor more details, open `script/setup_initial.sh` file.\n\n### Deploy stacks\n\n***Caution***: This solution contains not-free tier AWS services. So be careful about the possible costs.\n\nSince each stack refers to each other through `Parameter Store`, it must be deployed sequentially during the only first deployment. After that, independent deployment is possible.\n\nYou can deploy the entire stacks by running:\n\n```bash\nsh script/deploy_stacks.sh config/app-config-demo.json\n```\n\n#### Deployment Results\n\nYou can find the deployment results in AWS CloudFormation.\n\nAfter `Cloud9` is deployed, connect and run the following sql script.  completing deployment of Cloud9. Database access information(host_name, username, password) can be checked in `Secrets Manager`.\n\nDatabase Connection\n\n```bash\nmysql -h host_name -u admin -p\n```\n\nSQL Commands\n\n```\nCREATE DATABASE IF NOT EXISTS helloworld;\nUSE helloworld;\n\nCREATE TABLE IF NOT EXISTS Items (\n\t            ID int NOT NULL AUTO_INCREMENT,\n\t\t        NAME varchar(255) NOT NULL UNIQUE,\n\t\t\t    PRIMARY KEY (ID)\n\t\t\t);\n\n\nINSERT INTO Items (NAME) VALUES (\"name-001\");\nSELECT * FROM Items;\n```\n\nFinally we can call internal REST APIs in `Cloud9`. Execute the following commands in `Cloud9`:\n\n```bash\nexport ALB_DNS_NAME=xxxxxxxxxxxxxxxx.region.elb.amazonaws.com\n\ncurl $ALB_DNS_NAME\n...\n...\n{\"Health\": \"Good\"}\n```\n\nOr\n\n```bash\ncurl $ALB_DNS_NAME/items\n...\n...\n{\"items\": [[1,\"name-001\"]]}\n```\n\nWhere `ALB_DNS_NAME` is found in `LoadBalancers` DNS name in `EC2` web console.\n\n#### How to clean up\n\nExecute the following command, which will destroy all resources except RDS Database. So destroy these resources in AWS web console manually(Go RDS -\u003e Select RDS Name -\u003e Modify -\u003e disable deletion protection -\u003e Select again -\u003e Delete).\n\n```bash\nsh ./script/destroy_stacks.sh config/app-config-demo.json\n```\n\n## 5. Projects based on this framework\n\n- [AWS CDK Deploy Pipeline using AWS CodePipeline](https://github.com/aws-samples/aws-cdk-deploy-pipeline-using-aws-codepipeline)\n- [AWS ECS DevOps using AWS CDK](https://github.com/aws-samples/aws-ecs-devops-using-aws-cdk)\n- [AWS IoT Greengrass Ver2 using AWS CDK](https://github.com/aws-samples/aws-iot-greengrass-v2-using-aws-cdk)\n- [Amazon SageMaker Built-in Algorithm MLOps Pipeline using AWS CDK](https://github.com/aws-samples/amazon-sagemaker-built-in-algorithms-mlops-pipeline-using-aws-cdk)\n- [Amazon Cognito and API Gateway based machine to machine authorization using AWS CDK](https://github.com/aws-samples/amazon-cognito-and-api-gateway-based-machine-to-machine-authorization-using-aws-cdk)\n\n## 6. Security\n\nSee [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.\n\n## 7. License\n\nThis library is licensed under the MIT-0 License. See the LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faws-samples%2Faws-cdk-project-template-for-devops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faws-samples%2Faws-cdk-project-template-for-devops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faws-samples%2Faws-cdk-project-template-for-devops/lists"}