├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── code ├── UnicornStockLambda ├── Makefile ├── misc │ ├── blocked-stock-list.txt │ ├── extract │ ├── ignore.xml │ └── loadtest.yaml ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── unicorn │ └── broker │ ├── UnicornStockApplication.java │ ├── core │ ├── TransactionService.java │ └── UnicornStockBrokerHandler.java │ ├── data │ └── TransactionRepository.java │ ├── exceptions │ └── InvalidStockException.java │ └── model │ └── Transaction.java ├── cdk ├── with-snapstart │ ├── .gitignore │ ├── README.md │ ├── cdk.json │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── myorg │ │ ├── CdkApp.java │ │ └── CdkStack.java └── without-snapstart │ ├── .gitignore │ ├── README.md │ ├── cdk.json │ ├── pom.xml │ └── src │ └── main │ └── java │ └── com │ └── myorg │ ├── CdkApp.java │ └── CdkStack.java ├── cloudformation ├── template-with-snapstart.yaml └── template.yaml ├── sam ├── template-with-snapstart.yaml └── template.yaml └── terraform ├── with-snapstart └── stack-with-snapstart.tf └── without-snapstart └── stack-without-snapstart.tf /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /**/.terraform/ 3 | /**/.terraform.lock.hcl 4 | /**/terraform.tfstate 5 | /**/terraform.tfstate.backup 6 | /**/target 7 | *.iml 8 | /**/samconfig.toml 9 | /**/.aws-sam/ 10 | /**/.terraform.tfstate.lock.info 11 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to Enable Lambda Snapstart with AWS Cloudformation, AWS SAM, AWS CDK and Terraform 2 | 3 | This Sample Code repository demonstrates how to enable Lambda SnapStart with AWS Cloudformation, AWS SAM, AWS CDK and Terraform. 4 | 5 | For each IaC tooling, you will find 2 templates: one without SnapStart and one with SnapStart. 6 | Each template is configured with the same architecture: an API Gateway, a Lambda Function and a DynamoDB table, and all the examples leverage the same Lambda Function code, which you can find under `code/UnicornStockLambda/`. 7 | This allows you to compare and contrast the differences between different implementations. 8 | 9 | ## How to use this repository 10 | 11 | All the code in this repository can be deployed to your own AWS Account. Please note that you may incur cost when deploying the resources. 12 | 13 | ### Build the sample application 14 | 15 | **Before** deploying the Sample, ensure that the application successfully builds 16 | ```bash 17 | cd code/UnicornStockLambda 18 | mvn clean package 19 | ``` 20 | 21 | ### Deploy the sample 22 | #### AWS Cloudformation (without SnapStart) 23 | ```bash 24 | BUCKET_NAME=<> 25 | FUNCTION_KEY=<> 26 | aws s3 cp code/UnicornStockLambda/target/UnicornStockBroker-1.0-aws.jar s3://$BUCKET_NAME/$FUNCTION_KEY 27 | cd code/cloudformation 28 | aws cloudformation deploy --template-file ./template.yaml --stack-name UnicornBrokerWithoutSnapStart --capabilities CAPABILITY_NAMED_IAM --parameter-overrides FunctionSourceCodeBucketName=$BUCKET_NAME FunctionSourceCodeKey=$FUNCTION_KEY 29 | ``` 30 | #### AWS Cloudformation (With SnapStart) 31 | ```bash 32 | BUCKET_NAME=<> 33 | FUNCTION_KEY=<> 34 | aws s3 cp code/UnicornStockLambda/target/UnicornStockBroker-1.0-aws.jar s3://$BUCKET_NAME/$FUNCTION_KEY 35 | cd code/cloudformation 36 | aws cloudformation deploy --template-file ./template-with-snapstart.yaml --stack-name UnicornBrokerWithSnapStart --capabilities CAPABILITY_NAMED_IAM --parameter-overrides FunctionSourceCodeBucketName=$BUCKET_NAME FunctionSourceCodeKey=$FUNCTION_KEY 37 | ``` 38 | 39 | #### AWS SAM (without SnapStart) 40 | ```bash 41 | cd code/sam 42 | sam build -t template.yaml 43 | sam deploy --guided -t template.yaml 44 | ``` 45 | #### AWS SAM (with SnapStart) 46 | ```bash 47 | cd code/sam 48 | sam build -t template-with-snapstart.yaml 49 | sam deploy -t template-with-snapstart.yaml --guided 50 | ``` 51 | 52 | #### Terraform (without SnapStart) 53 | ```bash 54 | cd code/terraform/without-snapstart/ 55 | terraform apply 56 | ``` 57 | 58 | #### Terraform (with SnapStart) 59 | ```bash 60 | cd code/terraform/with-snapstart/ 61 | terraform apply 62 | ``` 63 | 64 | #### CDK (without SnapStart) 65 | ```bash 66 | cd code/cdk/without-snapstart/ 67 | mvn clean package 68 | cdk deploy 69 | ``` 70 | 71 | #### CDK (with SnapStart) 72 | ```bash 73 | cd code/cdk/with-snapstart/ 74 | mvn clean package 75 | cdk deploy 76 | ``` 77 | 78 | ### Test the application 79 | After deploying the application, you can invoke it with the following commands: 80 | ```shell 81 | export API_GW_URL="YOUR API GATEWAY URL HERE" 82 | curl -XPOST "$API_GW_URL/transactions" --data '{"stockId":"UNICORN_STOCK", "quantity":"2"}' --header 'Content-Type: application/json' 83 | ``` 84 | 85 | ## Security 86 | 87 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 88 | 89 | ## License 90 | 91 | This library is licensed under the MIT-0 License. See the LICENSE file. 92 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/Makefile: -------------------------------------------------------------------------------- 1 | build-UnicornStockBrokerFunction: 2 | @ mvn clean package 3 | @ mkdir -p $(ARTIFACTS_DIR)/lib 4 | @ cp ./target/UnicornStockBroker-1.0-aws.jar $(ARTIFACTS_DIR)/lib/ -------------------------------------------------------------------------------- /code/UnicornStockLambda/misc/blocked-stock-list.txt: -------------------------------------------------------------------------------- 1 | EVIL_STOCK 2 | MALICIOUS_STOCK 3 | FRAUD_STOCK -------------------------------------------------------------------------------- /code/UnicornStockLambda/misc/extract: -------------------------------------------------------------------------------- 1 | jq -r .message | cut -f1,2,6 -d$'\t' -------------------------------------------------------------------------------- /code/UnicornStockLambda/misc/ignore.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/misc/loadtest.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | phases: 3 | - duration: 30 4 | arrivalRate: 100 5 | name: Loadtest with 100 concurrent requests for 30 seconds 6 | http: 7 | timeout: 29 8 | scenarios: 9 | - flow: 10 | - post: 11 | url: "{{ url }}" 12 | json: 13 | stockId: "UNICORN_STOCK" 14 | quantity: "2" -------------------------------------------------------------------------------- /code/UnicornStockLambda/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.springframework.boot 6 | spring-boot-starter-parent 7 | 2.7.5 8 | 9 | 10 | com.unicorn 11 | UnicornStockBroker 12 | 1.0 13 | jar 14 | API to store unicorn transactions 15 | 16 | 11 17 | 11 18 | UTF-8 19 | UTF-8 20 | 2021.0.5 21 | 2.17.282 22 | 23 | 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-function-adapter-aws 28 | 29 | 30 | 31 | software.amazon.awssdk 32 | dynamodb 33 | 34 | 35 | software.amazon.awssdk 36 | netty-nio-client 37 | 38 | 39 | software.amazon.awssdk 40 | apache-client 41 | 42 | 43 | 44 | 45 | software.amazon.awssdk 46 | s3 47 | 48 | 49 | software.amazon.awssdk 50 | netty-nio-client 51 | 52 | 53 | software.amazon.awssdk 54 | apache-client 55 | 56 | 57 | 58 | 59 | software.amazon.awssdk 60 | aws-crt-client 61 | ${aws-sdk.version}-PREVIEW 62 | 63 | 64 | com.amazonaws 65 | aws-lambda-java-core 66 | 1.2.1 67 | 68 | 69 | io.github.crac 70 | org-crac 71 | 0.1.3 72 | 73 | 74 | com.amazonaws 75 | aws-lambda-java-events 76 | 3.11.0 77 | 78 | 79 | org.slf4j 80 | slf4j-api 81 | 2.0.2 82 | 83 | 84 | org.slf4j 85 | slf4j-simple 86 | 2.0.2 87 | 88 | 89 | junit 90 | junit 91 | 4.13.2 92 | test 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.springframework.cloud 100 | spring-cloud-dependencies 101 | ${spring-cloud.version} 102 | pom 103 | import 104 | 105 | 106 | software.amazon.awssdk 107 | bom 108 | ${aws-sdk.version} 109 | pom 110 | import 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | org.springframework.boot 119 | spring-boot-maven-plugin 120 | 121 | 122 | org.springframework.boot.experimental 123 | spring-boot-thin-layout 124 | 1.0.28.RELEASE 125 | 126 | 127 | 128 | 129 | org.apache.maven.plugins 130 | maven-shade-plugin 131 | 132 | false 133 | true 134 | aws 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/src/main/java/com/unicorn/broker/UnicornStockApplication.java: -------------------------------------------------------------------------------- 1 | package com.unicorn.broker; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UnicornStockApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UnicornStockApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/src/main/java/com/unicorn/broker/core/TransactionService.java: -------------------------------------------------------------------------------- 1 | package com.unicorn.broker.core; 2 | 3 | import com.unicorn.broker.data.TransactionRepository; 4 | import com.unicorn.broker.model.Transaction; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Optional; 10 | import java.util.UUID; 11 | 12 | @Service 13 | public class TransactionService { 14 | 15 | private UUID BROKER_ID = UUID.randomUUID(); 16 | private final TransactionRepository transactionRepository; 17 | private final Logger logger = LoggerFactory.getLogger(TransactionService.class); 18 | 19 | public TransactionService(final TransactionRepository transactionRepository) { 20 | this.transactionRepository = transactionRepository; 21 | } 22 | 23 | public Optional writeTransaction(Transaction transaction) { 24 | try { 25 | Thread.sleep(100); //Simulates some intensive calculation 26 | transaction.transactionId = UUID.randomUUID(); 27 | transaction.brokerId = BROKER_ID; 28 | 29 | return transactionRepository.writeTransaction(transaction); 30 | } catch (InterruptedException e) { 31 | logger.error("Error due to interruption while processing the transaction.", e); 32 | return Optional.empty(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/src/main/java/com/unicorn/broker/core/UnicornStockBrokerHandler.java: -------------------------------------------------------------------------------- 1 | package com.unicorn.broker.core; 2 | 3 | import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; 4 | import com.unicorn.broker.model.Transaction; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.function.Function; 8 | 9 | @Component 10 | public class UnicornStockBrokerHandler implements Function { 11 | 12 | private final TransactionService transactionService; 13 | private static final int END_OF_FIRST_UUID_GROUP = 8; 14 | 15 | public UnicornStockBrokerHandler(TransactionService transactionService) { 16 | this.transactionService = transactionService; 17 | } 18 | 19 | public APIGatewayProxyResponseEvent apply(final Transaction transaction) { 20 | if (!transaction.isValid()) { 21 | return createAPIGwResponse(400, "Invalid request body."); 22 | } 23 | 24 | var transactionResponse = transactionService.writeTransaction(transaction); 25 | return transactionResponse 26 | .map(it -> createAPIGwResponse(200, generateJSONResponse(it))) 27 | .orElseGet(() -> createAPIGwResponse(500, "Unexpected error while writing transaction.")); 28 | } 29 | 30 | private APIGatewayProxyResponseEvent createAPIGwResponse(Integer statusCode, String message){ 31 | return new APIGatewayProxyResponseEvent() 32 | .withStatusCode(statusCode) 33 | .withBody(String.format("%s%n", message)); 34 | } 35 | 36 | private String generateJSONResponse(Transaction transaction) { 37 | return String.format("Broker %s successfully created transaction %s", transaction.brokerId.toString().substring(0,END_OF_FIRST_UUID_GROUP), transaction.transactionId); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/src/main/java/com/unicorn/broker/data/TransactionRepository.java: -------------------------------------------------------------------------------- 1 | package com.unicorn.broker.data; 2 | 3 | import com.unicorn.broker.model.Transaction; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.stereotype.Component; 7 | import software.amazon.awssdk.core.SdkSystemSetting; 8 | import software.amazon.awssdk.http.crt.AwsCrtAsyncHttpClient; 9 | import software.amazon.awssdk.regions.Region; 10 | import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; 11 | import software.amazon.awssdk.services.dynamodb.model.AttributeValue; 12 | import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.Optional; 17 | import java.util.concurrent.ExecutionException; 18 | 19 | @Component 20 | public class TransactionRepository { 21 | 22 | private static final String TABLE_NAME = System.getenv("TABLE_NAME"); 23 | private final Logger logger = LoggerFactory.getLogger(TransactionRepository.class); 24 | private final DynamoDbAsyncClient dynamoDbClient = DynamoDbAsyncClient.builder() 25 | .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) 26 | .httpClientBuilder(AwsCrtAsyncHttpClient.builder()) 27 | .build(); 28 | 29 | public Optional writeTransaction(Transaction transaction) { 30 | try { 31 | dynamoDbClient.putItem(PutItemRequest.builder() 32 | .tableName(TABLE_NAME) 33 | .item(createTransactionDBItem(transaction)) 34 | .build()) 35 | .get(); 36 | 37 | return Optional.of(transaction); 38 | } catch (ExecutionException | InterruptedException e) { 39 | logger.error("Error while writing transaction to DynamoDB", e); 40 | return Optional.empty(); 41 | } 42 | } 43 | 44 | private static Map createTransactionDBItem(Transaction transaction) { 45 | Map item = new HashMap<>(); 46 | 47 | item.put("transactionId", AttributeValue.builder().s(transaction.transactionId.toString()).build()); 48 | item.put("stock", AttributeValue.builder().s(transaction.stockId).build()); 49 | item.put("quantity", AttributeValue.builder().n(transaction.quantity.toString()).build()); 50 | item.put("broker_id", AttributeValue.builder().s(transaction.brokerId.toString()).build()); 51 | 52 | return item; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/src/main/java/com/unicorn/broker/exceptions/InvalidStockException.java: -------------------------------------------------------------------------------- 1 | package com.unicorn.broker.exceptions; 2 | 3 | public class InvalidStockException extends RuntimeException{ 4 | public InvalidStockException(String errorMessage) { 5 | super(errorMessage); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /code/UnicornStockLambda/src/main/java/com/unicorn/broker/model/Transaction.java: -------------------------------------------------------------------------------- 1 | package com.unicorn.broker.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | import java.util.UUID; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class Transaction { 9 | public String stockId; 10 | public Integer quantity; 11 | public UUID brokerId; 12 | public UUID transactionId; 13 | 14 | public Boolean isValid() { 15 | return (stockId != null && !stockId.isBlank() && quantity != null && quantity > 0); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/cdk/with-snapstart/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath.txt 2 | target 3 | .classpath 4 | .project 5 | .idea 6 | .settings 7 | .vscode 8 | *.iml 9 | 10 | # CDK asset staging directory 11 | .cdk.staging 12 | cdk.out 13 | 14 | -------------------------------------------------------------------------------- /code/cdk/with-snapstart/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your CDK Java project! 2 | 3 | This is a blank project for CDK development with Java. 4 | 5 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 6 | 7 | It is a [Maven](https://maven.apache.org/) based project, so you can open this project with any Maven compatible Java IDE to build and run tests. 8 | 9 | ## Useful commands 10 | 11 | * `mvn package` compile and run tests 12 | * `cdk ls` list all stacks in the app 13 | * `cdk synth` emits the synthesized CloudFormation template 14 | * `cdk deploy` deploy this stack to your default AWS account/region 15 | * `cdk diff` compare deployed stack with current state 16 | * `cdk docs` open CDK documentation 17 | 18 | ```shell 19 | export API_GW_URL=$(aws cloudformation describe-stacks --stack-name CdkStack | jq -r '.Stacks[0].Outputs[] | select(.OutputKey | match("UnicornStockBroker")).OutputValue') 20 | curl -XPOST "$API_GW_URL/transactions" --data '{"stockId":"UNICORN_STOCK", "quantity":"2"}' --header 'Content-Type: application/json' 21 | ``` 22 | 23 | 24 | Enjoy! 25 | -------------------------------------------------------------------------------- /code/cdk/with-snapstart/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "mvn -e -q compile exec:java", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "target", 11 | "pom.xml", 12 | "src/test" 13 | ] 14 | }, 15 | "context": { 16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 17 | "@aws-cdk/core:checkSecretUsage": true, 18 | "@aws-cdk/core:target-partitions": [ 19 | "aws", 20 | "aws-cn" 21 | ], 22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 25 | "@aws-cdk/aws-iam:minimizePolicies": true, 26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 31 | "@aws-cdk/core:enablePartitionLiterals": true, 32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 33 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 34 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 35 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 36 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 37 | "@aws-cdk/aws-route53-patters:useCertificate": true, 38 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 39 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 40 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 41 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 42 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 43 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 44 | "@aws-cdk/aws-redshift:columnId": true, 45 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 46 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 47 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 48 | "@aws-cdk/aws-kms:aliasNameRef": true, 49 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 50 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 51 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 52 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 53 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 54 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /code/cdk/with-snapstart/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.myorg 7 | cdk 8 | 0.1 9 | 10 | 11 | UTF-8 12 | 2.94.0 13 | [10.0.0,11.0.0) 14 | 5.7.1 15 | 16 | 17 | 18 | 19 | 20 | org.apache.maven.plugins 21 | maven-compiler-plugin 22 | 3.8.1 23 | 24 | 11 25 | 11 26 | 27 | 28 | 29 | 30 | org.codehaus.mojo 31 | exec-maven-plugin 32 | 3.0.0 33 | 34 | com.myorg.CdkApp 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | software.amazon.awscdk 44 | aws-cdk-lib 45 | ${cdk.version} 46 | 47 | 48 | 49 | software.constructs 50 | constructs 51 | ${constructs.version} 52 | 53 | 54 | 55 | org.junit.jupiter 56 | junit-jupiter 57 | ${junit.version} 58 | test 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /code/cdk/with-snapstart/src/main/java/com/myorg/CdkApp.java: -------------------------------------------------------------------------------- 1 | package com.myorg; 2 | 3 | import software.amazon.awscdk.App; 4 | import software.amazon.awscdk.StackProps; 5 | 6 | public class CdkApp { 7 | public static void main(final String[] args) { 8 | App app = new App(); 9 | 10 | new CdkStack(app, "CdkStack", StackProps.builder() 11 | // If you don't specify 'env', this stack will be environment-agnostic. 12 | // Account/Region-dependent features and context lookups will not work, 13 | // but a single synthesized template can be deployed anywhere. 14 | 15 | // Uncomment the next block to specialize this stack for the AWS Account 16 | // and Region that are implied by the current CLI configuration. 17 | /* 18 | .env(Environment.builder() 19 | .account(System.getenv("CDK_DEFAULT_ACCOUNT")) 20 | .region(System.getenv("CDK_DEFAULT_REGION")) 21 | .build()) 22 | */ 23 | 24 | // Uncomment the next block if you know exactly what Account and Region you 25 | // want to deploy the stack to. 26 | /* 27 | .env(Environment.builder() 28 | .account("123456789012") 29 | .region("us-east-1") 30 | .build()) 31 | */ 32 | 33 | // For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html 34 | .build()); 35 | 36 | app.synth(); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /code/cdk/with-snapstart/src/main/java/com/myorg/CdkStack.java: -------------------------------------------------------------------------------- 1 | package com.myorg; 2 | 3 | import java.util.Map; 4 | import software.amazon.awscdk.Duration; 5 | import software.amazon.awscdk.RemovalPolicy; 6 | import software.amazon.awscdk.Stack; 7 | import software.amazon.awscdk.StackProps; 8 | import software.amazon.awscdk.services.apigateway.LambdaRestApi; 9 | import software.amazon.awscdk.services.dynamodb.Attribute; 10 | import software.amazon.awscdk.services.dynamodb.AttributeType; 11 | import software.amazon.awscdk.services.dynamodb.BillingMode; 12 | import software.amazon.awscdk.services.dynamodb.Table; 13 | import software.amazon.awscdk.services.lambda.Alias; 14 | import software.amazon.awscdk.services.lambda.Architecture; 15 | import software.amazon.awscdk.services.lambda.Code; 16 | import software.amazon.awscdk.services.lambda.Function; 17 | import software.amazon.awscdk.services.lambda.Runtime; 18 | import software.amazon.awscdk.services.lambda.SnapStartConf; 19 | import software.amazon.awscdk.services.lambda.Version; 20 | import software.amazon.awscdk.services.s3.Bucket; 21 | import software.amazon.awscdk.services.s3.BucketEncryption; 22 | import software.constructs.Construct; 23 | 24 | public class CdkStack extends Stack { 25 | public CdkStack(final Construct scope, final String id) { 26 | this(scope, id, null); 27 | } 28 | 29 | public CdkStack(final Construct scope, final String id, final StackProps props) { 30 | super(scope, id, props); 31 | 32 | // DDB table 33 | Table table = Table.Builder.create(this, "TransactionsTable") 34 | .partitionKey(Attribute.builder() 35 | .name("transactionId") 36 | .type(AttributeType.STRING) 37 | .build()) 38 | .billingMode(BillingMode.PAY_PER_REQUEST) 39 | .build(); 40 | 41 | // S3 bucket 42 | Bucket bucket = Bucket.Builder.create(this, "ValidationFilesS3Bucket") 43 | .encryption(BucketEncryption.S3_MANAGED) 44 | .versioned(true) 45 | .autoDeleteObjects(true) 46 | .removalPolicy(RemovalPolicy.DESTROY) 47 | .build(); 48 | 49 | // Lambda function 50 | final Function unicornStockBrokerFunction = Function.Builder.create(this, "UnicornStockBrokerFunction") 51 | .runtime(Runtime.JAVA_11) 52 | .code(Code.fromAsset("../../UnicornStockLambda/target/UnicornStockBroker-1.0-aws.jar")) 53 | .handler("org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest") 54 | .memorySize(2048) 55 | .timeout(Duration.seconds(200)) 56 | .architecture(Architecture.X86_64) 57 | .snapStart(SnapStartConf.ON_PUBLISHED_VERSIONS) 58 | .environment(Map.of( 59 | "TABLE_NAME", table.getTableName(), 60 | "BUCKET_NAME", bucket.getBucketName() 61 | )) 62 | .build(); 63 | 64 | // Lambda Version 65 | Version currentVersion = unicornStockBrokerFunction.getCurrentVersion(); 66 | 67 | // Lambda Alias 68 | Alias lambdaAlias = Alias.Builder.create(this, "UnicornStockBrokerFunctionAlias") 69 | .aliasName("prod") 70 | .description(currentVersion.getVersion()) 71 | .version(currentVersion) 72 | .build(); 73 | 74 | // Permissions 75 | table.grantReadWriteData(unicornStockBrokerFunction); 76 | bucket.grantReadWrite(unicornStockBrokerFunction); 77 | 78 | // API Gateway 79 | LambdaRestApi.Builder.create(this, "UnicornStockBrokerApi") 80 | .handler(lambdaAlias) 81 | .build(); 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /code/cdk/without-snapstart/.gitignore: -------------------------------------------------------------------------------- 1 | .classpath.txt 2 | target 3 | .classpath 4 | .project 5 | .idea 6 | .settings 7 | .vscode 8 | *.iml 9 | 10 | # CDK asset staging directory 11 | .cdk.staging 12 | cdk.out 13 | 14 | -------------------------------------------------------------------------------- /code/cdk/without-snapstart/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your CDK Java project! 2 | 3 | This is a blank project for CDK development with Java. 4 | 5 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 6 | 7 | It is a [Maven](https://maven.apache.org/) based project, so you can open this project with any Maven compatible Java IDE to build and run tests. 8 | 9 | ## Useful commands 10 | 11 | * `mvn package` compile and run tests 12 | * `cdk ls` list all stacks in the app 13 | * `cdk synth` emits the synthesized CloudFormation template 14 | * `cdk deploy` deploy this stack to your default AWS account/region 15 | * `cdk diff` compare deployed stack with current state 16 | * `cdk docs` open CDK documentation 17 | 18 | ```shell 19 | export API_GW_URL=$(aws cloudformation describe-stacks --stack-name CdkStack | jq -r '.Stacks[0].Outputs[] | select(.OutputKey | match("UnicornStockBroker")).OutputValue') 20 | curl -XPOST "$API_GW_URL/transactions" --data '{"stockId":"UNICORN_STOCK", "quantity":"2"}' --header 'Content-Type: application/json' 21 | ``` 22 | 23 | 24 | Enjoy! 25 | -------------------------------------------------------------------------------- /code/cdk/without-snapstart/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "mvn -e -q compile exec:java", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "target", 11 | "pom.xml", 12 | "src/test" 13 | ] 14 | }, 15 | "context": { 16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 17 | "@aws-cdk/core:checkSecretUsage": true, 18 | "@aws-cdk/core:target-partitions": [ 19 | "aws", 20 | "aws-cn" 21 | ], 22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 25 | "@aws-cdk/aws-iam:minimizePolicies": true, 26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 31 | "@aws-cdk/core:enablePartitionLiterals": true, 32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 33 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 34 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 35 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 36 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 37 | "@aws-cdk/aws-route53-patters:useCertificate": true, 38 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 39 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 40 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 41 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 42 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 43 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 44 | "@aws-cdk/aws-redshift:columnId": true, 45 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 46 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 47 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 48 | "@aws-cdk/aws-kms:aliasNameRef": true, 49 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 50 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 51 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 52 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 53 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 54 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /code/cdk/without-snapstart/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.myorg 7 | cdk 8 | 0.1 9 | 10 | 11 | UTF-8 12 | 2.94.0 13 | [10.0.0,11.0.0) 14 | 5.7.1 15 | 16 | 17 | 18 | 19 | 20 | org.apache.maven.plugins 21 | maven-compiler-plugin 22 | 3.8.1 23 | 24 | 11 25 | 11 26 | 27 | 28 | 29 | 30 | org.codehaus.mojo 31 | exec-maven-plugin 32 | 3.0.0 33 | 34 | com.myorg.CdkApp 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | software.amazon.awscdk 44 | aws-cdk-lib 45 | ${cdk.version} 46 | 47 | 48 | 49 | software.constructs 50 | constructs 51 | ${constructs.version} 52 | 53 | 54 | 55 | org.junit.jupiter 56 | junit-jupiter 57 | ${junit.version} 58 | test 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /code/cdk/without-snapstart/src/main/java/com/myorg/CdkApp.java: -------------------------------------------------------------------------------- 1 | package com.myorg; 2 | 3 | import software.amazon.awscdk.App; 4 | import software.amazon.awscdk.StackProps; 5 | 6 | public class CdkApp { 7 | public static void main(final String[] args) { 8 | App app = new App(); 9 | 10 | new CdkStack(app, "CdkStack", StackProps.builder() 11 | // If you don't specify 'env', this stack will be environment-agnostic. 12 | // Account/Region-dependent features and context lookups will not work, 13 | // but a single synthesized template can be deployed anywhere. 14 | 15 | // Uncomment the next block to specialize this stack for the AWS Account 16 | // and Region that are implied by the current CLI configuration. 17 | /* 18 | .env(Environment.builder() 19 | .account(System.getenv("CDK_DEFAULT_ACCOUNT")) 20 | .region(System.getenv("CDK_DEFAULT_REGION")) 21 | .build()) 22 | */ 23 | 24 | // Uncomment the next block if you know exactly what Account and Region you 25 | // want to deploy the stack to. 26 | /* 27 | .env(Environment.builder() 28 | .account("123456789012") 29 | .region("us-east-1") 30 | .build()) 31 | */ 32 | 33 | // For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html 34 | .build()); 35 | 36 | app.synth(); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /code/cdk/without-snapstart/src/main/java/com/myorg/CdkStack.java: -------------------------------------------------------------------------------- 1 | package com.myorg; 2 | 3 | import java.util.Map; 4 | import software.amazon.awscdk.Duration; 5 | import software.amazon.awscdk.RemovalPolicy; 6 | import software.amazon.awscdk.Stack; 7 | import software.amazon.awscdk.StackProps; 8 | import software.amazon.awscdk.services.apigateway.LambdaRestApi; 9 | import software.amazon.awscdk.services.dynamodb.Attribute; 10 | import software.amazon.awscdk.services.dynamodb.AttributeType; 11 | import software.amazon.awscdk.services.dynamodb.BillingMode; 12 | import software.amazon.awscdk.services.dynamodb.Table; 13 | import software.amazon.awscdk.services.lambda.Architecture; 14 | import software.amazon.awscdk.services.lambda.Code; 15 | import software.amazon.awscdk.services.lambda.Function; 16 | import software.amazon.awscdk.services.lambda.Runtime; 17 | import software.amazon.awscdk.services.s3.Bucket; 18 | import software.amazon.awscdk.services.s3.BucketEncryption; 19 | import software.constructs.Construct; 20 | 21 | public class CdkStack extends Stack { 22 | public CdkStack(final Construct scope, final String id) { 23 | this(scope, id, null); 24 | } 25 | 26 | public CdkStack(final Construct scope, final String id, final StackProps props) { 27 | super(scope, id, props); 28 | 29 | // DDB table 30 | Table table = Table.Builder.create(this, "TransactionsTable") 31 | .partitionKey(Attribute.builder() 32 | .name("transactionId") 33 | .type(AttributeType.STRING) 34 | .build()) 35 | .billingMode(BillingMode.PAY_PER_REQUEST) 36 | .build(); 37 | 38 | // S3 bucket 39 | Bucket bucket = Bucket.Builder.create(this, "ValidationFilesS3Bucket") 40 | .encryption(BucketEncryption.S3_MANAGED) 41 | .versioned(true) 42 | .autoDeleteObjects(true) 43 | .removalPolicy(RemovalPolicy.DESTROY) 44 | .build(); 45 | 46 | 47 | // Lambda function 48 | final Function unicornStockBrokerFunction = Function.Builder.create(this, "UnicornStockBrokerFunction") 49 | .runtime(Runtime.JAVA_11) 50 | .code(Code.fromAsset("../../UnicornStockLambda/target/UnicornStockBroker-1.0-aws.jar")) 51 | .handler("org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest") 52 | .memorySize(2048) 53 | .timeout(Duration.seconds(200)) 54 | .architecture(Architecture.X86_64) 55 | .environment(Map.of( 56 | "TABLE_NAME", table.getTableName(), 57 | "BUCKET_NAME", bucket.getBucketName() 58 | )) 59 | .build(); 60 | 61 | // Permissions 62 | table.grantReadWriteData(unicornStockBrokerFunction); 63 | bucket.grantReadWrite(unicornStockBrokerFunction); 64 | 65 | // API Gateway 66 | LambdaRestApi.Builder.create(this, "UnicornStockBrokerApi") 67 | .handler(unicornStockBrokerFunction) 68 | .build(); 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /code/cloudformation/template-with-snapstart.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: "unicorn-stock-broker - This API allows you to store transactions of your favorite unicorn stocks" 3 | Parameters: 4 | FunctionSourceCodeBucketName: 5 | Type: String 6 | FunctionSourceCodeKey: 7 | Type: String 8 | 9 | Outputs: 10 | UnicornStockBrokerApi: 11 | Description: API Gateway endpoint URL for Prod stage for Unicorn StockBroker function 12 | Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod' 13 | UnicornStockBrokerFunction: 14 | Description: Unicorn StockBroker Lambda Function ARN 15 | Value: !GetAtt 'UnicornStockBrokerFunction.Arn' 16 | UnicornStockBrokerFunctionIamRole: 17 | Description: IAM Role created for Unicorn StockBroker function 18 | Value: !GetAtt 'UnicornStockBrokerFunction.Arn' 19 | UnicornStockBrokerValidationS3Bucket: 20 | Description: S3 Bucket for validation files 21 | Value: !Ref 'ValidationFilesS3Bucket' 22 | Resources: 23 | ServerlessRestApiDeployment: 24 | Type: AWS::ApiGateway::Deployment 25 | Properties: 26 | Description: 'RestApi deployment' 27 | RestApiId: !Ref 'ServerlessRestApi' 28 | StageName: Stage 29 | UnicornStockBrokerFunctionRole: 30 | Type: AWS::IAM::Role 31 | Properties: 32 | AssumeRolePolicyDocument: 33 | Version: '2012-10-17' 34 | Statement: 35 | - Action: 36 | - sts:AssumeRole 37 | Effect: Allow 38 | Principal: 39 | Service: 40 | - lambda.amazonaws.com 41 | ManagedPolicyArns: 42 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 43 | Policies: 44 | - PolicyName: UnicornStockBrokerFunctionRolePolicy0 45 | PolicyDocument: 46 | Statement: 47 | - Action: 48 | - dynamodb:GetItem 49 | - dynamodb:DeleteItem 50 | - dynamodb:PutItem 51 | - dynamodb:Scan 52 | - dynamodb:Query 53 | - dynamodb:UpdateItem 54 | - dynamodb:BatchWriteItem 55 | - dynamodb:BatchGetItem 56 | - dynamodb:DescribeTable 57 | - dynamodb:ConditionCheckItem 58 | Effect: Allow 59 | Resource: 60 | - !Sub 61 | - arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName} 62 | - tableName: !Ref 'TransactionsTable' 63 | - !Sub 64 | - arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}/index/* 65 | - tableName: !Ref 'TransactionsTable' 66 | - PolicyName: UnicornStockBrokerFunctionRolePolicy1 67 | PolicyDocument: 68 | Statement: 69 | - Action: 70 | - s3:GetObject 71 | - s3:ListBucket 72 | - s3:GetBucketLocation 73 | - s3:GetObjectVersion 74 | - s3:GetLifecycleConfiguration 75 | Effect: Allow 76 | Resource: 77 | - !Sub 78 | - arn:${AWS::Partition}:s3:::${bucketName} 79 | - bucketName: !Ref 'ValidationFilesS3Bucket' 80 | - !Sub 81 | - arn:${AWS::Partition}:s3:::${bucketName}/* 82 | - bucketName: !Ref 'ValidationFilesS3Bucket' 83 | ValidationFilesS3Bucket: 84 | Type: AWS::S3::Bucket 85 | DeletionPolicy: Delete 86 | Properties: 87 | VersioningConfiguration: 88 | Status: Enabled 89 | BucketEncryption: 90 | ServerSideEncryptionConfiguration: 91 | - ServerSideEncryptionByDefault: 92 | SSEAlgorithm: AES256 93 | TransactionsTable: 94 | Type: AWS::DynamoDB::Table 95 | Properties: 96 | AttributeDefinitions: 97 | - AttributeName: transactionId 98 | AttributeType: S 99 | KeySchema: 100 | - AttributeName: transactionId 101 | KeyType: HASH 102 | BillingMode: PAY_PER_REQUEST 103 | UnicornStockBrokerFunctionUnicornStockBrokerEventPermissionProd: 104 | Type: AWS::Lambda::Permission 105 | Properties: 106 | Action: lambda:InvokeFunction 107 | FunctionName: !Ref 'UnicornStockBrokerFunctionAliasSnapStart' 108 | Principal: apigateway.amazonaws.com 109 | SourceArn: !Sub 110 | - arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/transactions 111 | - __ApiId__: !Ref 'ServerlessRestApi' 112 | __Stage__: '*' 113 | UnicornStockBrokerFunction: 114 | Type: AWS::Lambda::Function 115 | Properties: 116 | Code: 117 | S3Bucket: !Ref FunctionSourceCodeBucketName 118 | S3Key: !Ref FunctionSourceCodeKey 119 | Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest 120 | MemorySize: 2048 121 | Role: !GetAtt 'UnicornStockBrokerFunctionRole.Arn' 122 | Runtime: java11 123 | Timeout: 200 124 | Environment: 125 | Variables: 126 | TABLE_NAME: !Ref 'TransactionsTable' 127 | BUCKET_NAME: !Ref 'ValidationFilesS3Bucket' 128 | Architectures: 129 | - x86_64 130 | SnapStart: 131 | ApplyOn: PublishedVersions 132 | UnicornStockBrokerFunctionVersion1: 133 | Type: AWS::Lambda::Version 134 | Properties: 135 | FunctionName: !Ref 'UnicornStockBrokerFunction' 136 | UnicornStockBrokerFunctionAliasSnapStart: 137 | Type: AWS::Lambda::Alias 138 | Properties: 139 | Name: SnapStart 140 | FunctionName: !Ref 'UnicornStockBrokerFunction' 141 | FunctionVersion: !GetAtt 'UnicornStockBrokerFunctionVersion1.Version' 142 | ServerlessRestApiProdStage: 143 | Type: AWS::ApiGateway::Stage 144 | Properties: 145 | DeploymentId: !Ref 'ServerlessRestApiDeployment' 146 | RestApiId: !Ref 'ServerlessRestApi' 147 | StageName: Prod 148 | ServerlessRestApi: 149 | Type: AWS::ApiGateway::RestApi 150 | Properties: 151 | Body: 152 | info: 153 | version: '1.0' 154 | title: !Ref 'AWS::StackName' 155 | paths: 156 | /transactions: 157 | post: 158 | x-amazon-apigateway-integration: 159 | httpMethod: POST 160 | type: aws_proxy 161 | uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UnicornStockBrokerFunctionAliasSnapStart}/invocations' 162 | responses: {} 163 | swagger: '2.0' 164 | -------------------------------------------------------------------------------- /code/cloudformation/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: "unicorn-stock-broker - This API allows you to store transactions of your favorite unicorn stocks" 3 | Parameters: 4 | FunctionSourceCodeBucketName: 5 | Type: String 6 | FunctionSourceCodeKey: 7 | Type: String 8 | 9 | Outputs: 10 | UnicornStockBrokerApi: 11 | Description: API Gateway endpoint URL for Prod stage for Unicorn StockBroker function 12 | Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod' 13 | UnicornStockBrokerFunction: 14 | Description: Unicorn StockBroker Lambda Function ARN 15 | Value: !GetAtt 'UnicornStockBrokerFunction.Arn' 16 | UnicornStockBrokerFunctionIamRole: 17 | Description: IAM Role created for Unicorn StockBroker function 18 | Value: !GetAtt 'UnicornStockBrokerFunction.Arn' 19 | UnicornStockBrokerValidationS3Bucket: 20 | Description: S3 Bucket for validation files 21 | Value: !Ref 'ValidationFilesS3Bucket' 22 | Resources: 23 | ServerlessRestApiDeployment: 24 | Type: AWS::ApiGateway::Deployment 25 | Properties: 26 | Description: 'RestApi deployment' 27 | RestApiId: !Ref 'ServerlessRestApi' 28 | StageName: Stage 29 | UnicornStockBrokerFunctionRole: 30 | Type: AWS::IAM::Role 31 | Properties: 32 | AssumeRolePolicyDocument: 33 | Version: '2012-10-17' 34 | Statement: 35 | - Action: 36 | - sts:AssumeRole 37 | Effect: Allow 38 | Principal: 39 | Service: 40 | - lambda.amazonaws.com 41 | ManagedPolicyArns: 42 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 43 | Policies: 44 | - PolicyName: UnicornStockBrokerFunctionRolePolicy0 45 | PolicyDocument: 46 | Statement: 47 | - Action: 48 | - dynamodb:GetItem 49 | - dynamodb:DeleteItem 50 | - dynamodb:PutItem 51 | - dynamodb:Scan 52 | - dynamodb:Query 53 | - dynamodb:UpdateItem 54 | - dynamodb:BatchWriteItem 55 | - dynamodb:BatchGetItem 56 | - dynamodb:DescribeTable 57 | - dynamodb:ConditionCheckItem 58 | Effect: Allow 59 | Resource: 60 | - !Sub 61 | - arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName} 62 | - tableName: !Ref 'TransactionsTable' 63 | - !Sub 64 | - arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}/index/* 65 | - tableName: !Ref 'TransactionsTable' 66 | - PolicyName: UnicornStockBrokerFunctionRolePolicy1 67 | PolicyDocument: 68 | Statement: 69 | - Action: 70 | - s3:GetObject 71 | - s3:ListBucket 72 | - s3:GetBucketLocation 73 | - s3:GetObjectVersion 74 | - s3:GetLifecycleConfiguration 75 | Effect: Allow 76 | Resource: 77 | - !Sub 78 | - arn:${AWS::Partition}:s3:::${bucketName} 79 | - bucketName: !Ref 'ValidationFilesS3Bucket' 80 | - !Sub 81 | - arn:${AWS::Partition}:s3:::${bucketName}/* 82 | - bucketName: !Ref 'ValidationFilesS3Bucket' 83 | ValidationFilesS3Bucket: 84 | Type: AWS::S3::Bucket 85 | DeletionPolicy: Delete 86 | Properties: 87 | VersioningConfiguration: 88 | Status: Enabled 89 | BucketEncryption: 90 | ServerSideEncryptionConfiguration: 91 | - ServerSideEncryptionByDefault: 92 | SSEAlgorithm: AES256 93 | TransactionsTable: 94 | Type: AWS::DynamoDB::Table 95 | Properties: 96 | AttributeDefinitions: 97 | - AttributeName: transactionId 98 | AttributeType: S 99 | KeySchema: 100 | - AttributeName: transactionId 101 | KeyType: HASH 102 | BillingMode: PAY_PER_REQUEST 103 | UnicornStockBrokerFunctionUnicornStockBrokerEventPermissionProd: 104 | Type: AWS::Lambda::Permission 105 | Properties: 106 | Action: lambda:InvokeFunction 107 | FunctionName: !Ref 'UnicornStockBrokerFunction' 108 | Principal: apigateway.amazonaws.com 109 | SourceArn: !Sub 110 | - arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/transactions 111 | - __ApiId__: !Ref 'ServerlessRestApi' 112 | __Stage__: '*' 113 | UnicornStockBrokerFunction: 114 | Type: AWS::Lambda::Function 115 | Properties: 116 | Code: 117 | S3Bucket: !Ref FunctionSourceCodeBucketName 118 | S3Key: !Ref FunctionSourceCodeKey 119 | Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest 120 | MemorySize: 2048 121 | Role: !GetAtt 'UnicornStockBrokerFunctionRole.Arn' 122 | Runtime: java11 123 | Timeout: 200 124 | Environment: 125 | Variables: 126 | TABLE_NAME: !Ref 'TransactionsTable' 127 | BUCKET_NAME: !Ref 'ValidationFilesS3Bucket' 128 | Architectures: 129 | - x86_64 130 | ServerlessRestApiProdStage: 131 | Type: AWS::ApiGateway::Stage 132 | Properties: 133 | DeploymentId: !Ref 'ServerlessRestApiDeployment' 134 | RestApiId: !Ref 'ServerlessRestApi' 135 | StageName: Prod 136 | ServerlessRestApi: 137 | Type: AWS::ApiGateway::RestApi 138 | Properties: 139 | Body: 140 | info: 141 | version: '1.0' 142 | title: !Ref 'AWS::StackName' 143 | paths: 144 | /transactions: 145 | post: 146 | x-amazon-apigateway-integration: 147 | httpMethod: POST 148 | type: aws_proxy 149 | uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UnicornStockBrokerFunction.Arn}/invocations' 150 | responses: {} 151 | swagger: '2.0' 152 | -------------------------------------------------------------------------------- /code/sam/template-with-snapstart.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | unicorn-stock-broker 5 | 6 | This API allows you to store transactions of your favorite unicorn stocks 7 | 8 | Globals: 9 | Function: 10 | Runtime: java11 11 | Architectures: 12 | - x86_64 13 | MemorySize: 2048 14 | Timeout: 200 15 | 16 | Resources: 17 | UnicornStockBrokerFunction: 18 | Type: AWS::Serverless::Function 19 | Properties: 20 | SnapStart: 21 | ApplyOn: PublishedVersions 22 | AutoPublishAlias: SnapStart 23 | CodeUri: ../UnicornStockLambda/ 24 | Runtime: java11 25 | Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest 26 | Policies: 27 | - DynamoDBCrudPolicy: 28 | TableName: !Ref TransactionsTable 29 | - S3ReadPolicy: 30 | BucketName: !Ref ValidationFilesS3Bucket 31 | Environment: 32 | Variables: 33 | TABLE_NAME: !Ref TransactionsTable 34 | BUCKET_NAME: !Ref ValidationFilesS3Bucket 35 | Events: 36 | UnicornStockBrokerEvent: 37 | Type: Api 38 | Properties: 39 | Path: /transactions 40 | Method: post 41 | Metadata: 42 | BuildMethod: makefile 43 | TransactionsTable: 44 | Type: AWS::DynamoDB::Table 45 | Properties: 46 | AttributeDefinitions: 47 | - AttributeName: 'transactionId' 48 | AttributeType: 'S' 49 | KeySchema: 50 | - AttributeName: 'transactionId' 51 | KeyType: 'HASH' 52 | BillingMode: PAY_PER_REQUEST 53 | ValidationFilesS3Bucket: 54 | Type: 'AWS::S3::Bucket' 55 | DeletionPolicy: Delete 56 | Properties: 57 | VersioningConfiguration: 58 | Status: Enabled 59 | BucketEncryption: 60 | ServerSideEncryptionConfiguration: 61 | - ServerSideEncryptionByDefault: 62 | SSEAlgorithm: AES256 63 | Outputs: 64 | UnicornStockBrokerApi: 65 | Description: "API Gateway endpoint URL for Prod stage for Unicorn StockBroker function" 66 | Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod" 67 | UnicornStockBrokerFunction: 68 | Description: "Unicorn StockBroker Lambda Function ARN" 69 | Value: !GetAtt UnicornStockBrokerFunction.Arn 70 | UnicornStockBrokerFunctionIamRole: 71 | Description: "Implicit IAM Role created for Unicorn StockBroker function" 72 | Value: !GetAtt UnicornStockBrokerFunction.Arn 73 | UnicornStockBrokerValidationS3Bucket: 74 | Description: "S3 Bucket for validation files" 75 | Value: !Ref ValidationFilesS3Bucket 76 | 77 | -------------------------------------------------------------------------------- /code/sam/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | unicorn-stock-broker 5 | 6 | This API allows you to store transactions of your favorite unicorn stocks 7 | 8 | Globals: 9 | Function: 10 | Runtime: java11 11 | Architectures: 12 | - x86_64 13 | MemorySize: 2048 14 | Timeout: 200 15 | 16 | Resources: 17 | UnicornStockBrokerFunction: 18 | Type: AWS::Serverless::Function 19 | Properties: 20 | CodeUri: ../UnicornStockLambda/ 21 | Runtime: java11 22 | Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest 23 | Policies: 24 | - DynamoDBCrudPolicy: 25 | TableName: !Ref TransactionsTable 26 | - S3ReadPolicy: 27 | BucketName: !Ref ValidationFilesS3Bucket 28 | Environment: 29 | Variables: 30 | TABLE_NAME: !Ref TransactionsTable 31 | BUCKET_NAME: !Ref ValidationFilesS3Bucket 32 | Events: 33 | UnicornStockBrokerEvent: 34 | Type: Api 35 | Properties: 36 | Path: /transactions 37 | Method: post 38 | Metadata: 39 | BuildMethod: makefile 40 | TransactionsTable: 41 | Type: AWS::DynamoDB::Table 42 | Properties: 43 | AttributeDefinitions: 44 | - AttributeName: 'transactionId' 45 | AttributeType: 'S' 46 | KeySchema: 47 | - AttributeName: 'transactionId' 48 | KeyType: 'HASH' 49 | BillingMode: PAY_PER_REQUEST 50 | ValidationFilesS3Bucket: 51 | Type: 'AWS::S3::Bucket' 52 | DeletionPolicy: Delete 53 | Properties: 54 | VersioningConfiguration: 55 | Status: Enabled 56 | BucketEncryption: 57 | ServerSideEncryptionConfiguration: 58 | - ServerSideEncryptionByDefault: 59 | SSEAlgorithm: AES256 60 | Outputs: 61 | UnicornStockBrokerApi: 62 | Description: "API Gateway endpoint URL for Prod stage for Unicorn StockBroker function" 63 | Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod" 64 | UnicornStockBrokerFunction: 65 | Description: "Unicorn StockBroker Lambda Function ARN" 66 | Value: !GetAtt UnicornStockBrokerFunction.Arn 67 | UnicornStockBrokerFunctionIamRole: 68 | Description: "Implicit IAM Role created for Unicorn StockBroker function" 69 | Value: !GetAtt UnicornStockBrokerFunction.Arn 70 | UnicornStockBrokerValidationS3Bucket: 71 | Description: "S3 Bucket for validation files" 72 | Value: !Ref ValidationFilesS3Bucket 73 | 74 | -------------------------------------------------------------------------------- /code/terraform/with-snapstart/stack-with-snapstart.tf: -------------------------------------------------------------------------------- 1 | provider "aws" {} 2 | data "aws_region" "current" {} 3 | data "aws_caller_identity" "current" {} 4 | variable "SourceCodePath" { 5 | type = string 6 | default = "../../UnicornStockLambda/target/UnicornStockBroker-1.0-aws.jar" 7 | } 8 | 9 | resource "aws_dynamodb_table" "transactions_table" { 10 | 11 | name = "TransactionsTable" 12 | billing_mode = "PAY_PER_REQUEST" 13 | hash_key = "transactionId" 14 | 15 | attribute { 16 | name = "transactionId" 17 | type = "S" 18 | } 19 | } 20 | 21 | resource "aws_api_gateway_rest_api" "unicornstockbroker_apigw" { 22 | name = "unicornstockbroker_apigw" 23 | description = "Unicorn Stock Broker API Gateway" 24 | endpoint_configuration { 25 | types = ["REGIONAL"] 26 | } 27 | } 28 | 29 | resource "aws_api_gateway_resource" "transactions" { 30 | rest_api_id = aws_api_gateway_rest_api.unicornstockbroker_apigw.id 31 | parent_id = aws_api_gateway_rest_api.unicornstockbroker_apigw.root_resource_id 32 | path_part = "transactions" 33 | } 34 | 35 | resource "aws_api_gateway_method" "createtransactions" { 36 | rest_api_id = aws_api_gateway_rest_api.unicornstockbroker_apigw.id 37 | resource_id = aws_api_gateway_resource.transactions.id 38 | http_method = "POST" 39 | authorization = "NONE" 40 | } 41 | 42 | resource "aws_s3_bucket" "validationfiles-bucket" { 43 | bucket = "validationfiless3bucket" 44 | } 45 | 46 | resource "aws_s3_bucket_versioning" "validationfiles-bucket-versioning" { 47 | bucket = aws_s3_bucket.validationfiles-bucket.bucket 48 | versioning_configuration { 49 | status = "Enabled" 50 | } 51 | } 52 | 53 | resource "aws_s3_bucket_server_side_encryption_configuration" "bucketsseconfig"{ 54 | bucket = aws_s3_bucket.validationfiles-bucket.bucket 55 | rule { 56 | apply_server_side_encryption_by_default { 57 | sse_algorithm = "AES256" 58 | } 59 | } 60 | } 61 | 62 | 63 | resource "aws_iam_role" "UnicornStockBrokerFunctionRole" { 64 | name = "UnicornStockBrokerFunctionRole" 65 | assume_role_policy = <