-
Notifications
You must be signed in to change notification settings - Fork 1k
Add lambda-microvm-custom-domain-cdk pattern #3292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| *.js | ||
| !jest.config.js | ||
| *.d.ts | ||
| node_modules | ||
|
|
||
| # CDK asset staging directory | ||
| .cdk.staging | ||
| cdk.out | ||
|
|
||
| # CDK context cache — can contain account-specific lookup data; don't commit | ||
| cdk.context.json | ||
|
|
||
| # Build / deploy logs | ||
| *.log | ||
|
|
||
| # Local env / creds — never commit | ||
| .env | ||
| *.local | ||
|
|
||
| # IDE | ||
| .idea | ||
| .vscode | ||
| *.iml | ||
|
|
||
| # OS | ||
| .DS_Store |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| this software and associated documentation files (the "Software"), to deal in | ||
| the Software without restriction, including without limitation the rights to | ||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| the Software, and to permit persons to whom the Software is furnished to do so. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
| AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,104 @@ | ||||||
| # Custom domains for AWS Lambda MicroVMs with Application Load Balancer | ||||||
|
|
||||||
| This pattern gives each of your [AWS Lambda MicroVMs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html) a domain **you** own — e.g. `92cfc7f9-….microvms.example.com` — instead of exposing the service-generated `92cfc7f9-….lambda-microvm-….on.aws` endpoint directly. | ||||||
|
|
||||||
| It is built entirely from load-balancing and networking primitives: **no CloudFront** and **no compute in the request path** — just an Application Load Balancer (ALB) that rewrites the `Host` header with an [ALB Host header rewrite](https://aws.amazon.com/blogs/networking-and-content-delivery/introducing-url-and-host-header-rewrite-with-aws-application-load-balancers/) and forwards to the MicroVM service over AWS PrivateLink. A wildcard ACM certificate and a Route 53 wildcard record cover every MicroVM id under a single base domain. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| The CDK app is split into two parts, deployed together as one stack: | ||||||
| - **`lib/microvm-custom-domains-stack.ts`** — the reusable core pattern (VPC, interface VPC endpoint, ACM cert, ALB, host-rewrite listener rule, Route 53 wildcard record). This is the only part in the request path. | ||||||
| - **`lib/microvm-demo-app.ts`** — an *optional* demo layer (a single-page app plus an unauthenticated provisioning API on one ALB-invoked Lambda) that makes the pattern easy to try. Remove the `new MicroVmDemoApp(...)` block from `bin/microvm-custom-domains.ts` to deploy the pure networking pattern on its own. | ||||||
|
|
||||||
| Learn more about this pattern at [Serverless Land Patterns](https://serverlessland.com/patterns/lambda-microvm-custom-domain-cdk). | ||||||
|
|
||||||
| Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. | ||||||
|
|
||||||
| > ⚠️ **The optional demo layer is DEMO ONLY — NOT PRODUCTION-SAFE.** Its `POST /api/provision` endpoint is completely unauthenticated, it returns auth tokens to the browser, and it uses wide-open CORS (`Access-Control-Allow-Origin: *`). The **core pattern** (`MicroVmCustomDomainsStack`) is production-oriented networking, but before deploying the demo layer, put real authentication in front of the provisioning API, pin CORS to your own origin, and scope IAM and tokens to the minimum. Deploy the demo only in an isolated, non-production account. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| ## Requirements | ||||||
|
|
||||||
| * [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. | ||||||
| * [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured. | ||||||
| * [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). | ||||||
| * [Node.js 18+](https://nodejs.org/en/download/) and [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) installed (`npx cdk` works; no global install required). | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Node 18 has reached EOL |
||||||
| * An **existing Amazon Route 53 public hosted zone** for your domain (e.g. `example.com`). This stack imports it and adds a wildcard record. | ||||||
| * Access to [AWS Lambda MicroVMs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html) and its regional PrivateLink service (`com.amazonaws.<region>.lambda-microvm`) in your target Region. | ||||||
| * The **ALB Host/URL rewrite (Transforms) feature** available in your account/Region. | ||||||
|
|
||||||
| ## Deployment Instructions | ||||||
|
|
||||||
| 1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: | ||||||
| ``` | ||||||
| git clone https://github.com/aws-samples/serverless-patterns | ||||||
| ``` | ||||||
| 2. Change directory to the pattern directory: | ||||||
| ``` | ||||||
| cd serverless-patterns/lambda-microvm-custom-domain-cdk | ||||||
| ``` | ||||||
| 3. Install dependencies: | ||||||
| ``` | ||||||
| npm install | ||||||
| ``` | ||||||
| 4. Edit the configuration under the `microvm-custom-domains` key in [`cdk.json`](./cdk.json). At minimum set `account`, `region`, `hostedZoneId`, `hostedZoneName`, `customDomainBase`, `microvmEndpointBase`, and `microvmVpceServiceName`. (The `microvmImageArn` and `appDomain` keys are only needed if you keep the optional demo layer.) | ||||||
|
|
||||||
| | Key | Meaning | | ||||||
| | --- | --- | | ||||||
| | `account` / `region` | Where to deploy. Region **must** match the MicroVM PrivateLink service region (PrivateLink is regional). | | ||||||
| | `hostedZoneId` / `hostedZoneName` | Your existing Route 53 public hosted zone. | | ||||||
| | `customDomainBase` | Wildcard base your clients use, e.g. `microvms.example.com`. | | ||||||
| | `microvmEndpointBase` | What `Host` is rewritten **to**, e.g. `lambda-microvm.us-east-2.on.aws`. Everything ahead of this suffix (the MicroVM id, and any future subdomains) is preserved per request. | | ||||||
| | `microvmVpceServiceName` | AWS-managed PrivateLink service, e.g. `com.amazonaws.us-east-2.lambda-microvm`. | | ||||||
| | `corsAllowOrigin` | Value for the `Access-Control-Allow-Origin` header the ALB inserts (`*` for the demo; pin to your origin otherwise). | | ||||||
| | `microvmImageArn` | **Demo only.** MicroVM image the provisioning Lambda launches when no running MicroVM is available. | | ||||||
| | `appDomain` | **Demo only.** Single host under `customDomainBase` that serves the demo page and its `/api/provision` endpoint. | | ||||||
|
|
||||||
| 5. From the command line, deploy the AWS resources for the pattern: | ||||||
| ``` | ||||||
| npx cdk deploy | ||||||
| ``` | ||||||
| Note the outputs — `WildcardDomain`, `AlbDnsName`, `CertificateArn`, and (with the demo layer) `DemoAppUrl`. | ||||||
|
|
||||||
| ## How it works | ||||||
|
|
||||||
| A client sends an HTTPS request to `https://<uuid>.microvms.example.com` (plus the MicroVM `X-aws-proxy-auth` / `X-aws-proxy-port` headers). Route 53 resolves the wildcard record to the ALB. The ALB terminates TLS with a wildcard ACM certificate, then a listener rule: | ||||||
|
|
||||||
| 1. **matches** the incoming host with a regex condition — `^(.+)\.microvms\.example\.com$` — capturing everything ahead of the base domain suffix; | ||||||
| 2. **rewrites** the `Host` header with a `host-header-rewrite` Transform — `$1.lambda-microvm.<region>.on.aws` — swapping only the suffix and preserving everything before it; | ||||||
| 3. **forwards** to an IP target group whose targets are the private ENI IPs of a MicroVM interface VPC endpoint (discovered at deploy time by an `AwsCustomResource`; this is the only Lambda in the package and it never runs in the request path). | ||||||
|
|
||||||
| The request reaches the MicroVM service front-end over PrivateLink, which routes to the correct MicroVM using the rewritten `Host` header and enforces the JWE auth token the client supplied. Because a Transform (not a redirect) performs the rewrite, the customer's domain stays intact end to end — the browser address bar never shows the `.on.aws` URL. | ||||||
|
|
||||||
| CORS is handled entirely at the ALB: `OPTIONS` preflights are answered with a fast `204`, and `Access-Control-Allow-*` headers are inserted on every response via ALB listener header-modification attributes — no change to the application inside the MicroVM. | ||||||
|
|
||||||
| See the source files and code comments for full detail on health-check matchers (`200,403,404`), TLS re-origination, and the optional demo layer. | ||||||
|
|
||||||
| ## Testing | ||||||
|
|
||||||
| The `WildcardDomain` output shows the base domain. Derive a MicroVM's custom domain by taking its service-generated endpoint and **swapping the suffix** — replace `.lambda-microvm.<region>.on.aws` with your `.microvms.example.com` base, keeping everything ahead of the suffix. For example: | ||||||
|
|
||||||
| ``` | ||||||
| 78d01d43-96e8-b9f7-49cf-f152af2532af.lambda-microvm.us-east-2.on.aws | ||||||
| ─────────────── swap suffix ──────────────► | ||||||
| 78d01d43-96e8-b9f7-49cf-f152af2532af.microvms.example.com | ||||||
| ``` | ||||||
|
|
||||||
| Then call the MicroVM through your custom domain, supplying the auth token and port from `create-microvm-auth-token`: | ||||||
|
|
||||||
| ``` | ||||||
| curl "https://78d01d43-96e8-b9f7-49cf-f152af2532af.microvms.example.com/" \ | ||||||
| -H "X-aws-proxy-auth: <JWE-auth-token>" \ | ||||||
| -H "X-aws-proxy-port: 8080" | ||||||
| ``` | ||||||
|
|
||||||
| A missing or expired token returns `403 Forbidden` — the ALB only rewrites `Host`; the client still supplies the token. If you deployed the optional demo layer, open the `DemoAppUrl` output in a browser to provision a MicroVM and call it end to end from a single page. | ||||||
|
|
||||||
| ## Cleanup | ||||||
|
|
||||||
| 1. Delete the stack: | ||||||
| ``` | ||||||
| npx cdk destroy | ||||||
| ``` | ||||||
|
|
||||||
| ---- | ||||||
| Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| SPDX-License-Identifier: MIT-0 | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| #!/usr/bin/env node | ||
| import 'source-map-support/register'; | ||
| import * as cdk from 'aws-cdk-lib'; | ||
| import { MicroVmCustomDomainsStack, MicroVmCustomDomainsConfig } from '../lib/microvm-custom-domains-stack'; | ||
| import { MicroVmDemoApp, MicroVmDemoAppProps } from '../lib/microvm-demo-app'; | ||
|
|
||
| const app = new cdk.App(); | ||
|
|
||
| // All configuration lives under the "microvm-custom-domains" key in cdk.json. | ||
| // Any value can be overridden on the CLI, e.g.: | ||
| // npx cdk deploy -c microvm-custom-domains:hostedZoneId=Z123... | ||
| const cfg = (app.node.tryGetContext('microvm-custom-domains') ?? {}) as Partial<MicroVmCustomDomainsConfig> & | ||
| Partial<Pick<MicroVmDemoAppProps, 'appDomain' | 'microvmImageArn'>> & { | ||
| account?: string; | ||
| region?: string; | ||
| }; | ||
|
|
||
| function required<T>(value: T | undefined | '', name: string): T { | ||
| if (value === undefined || value === '' || value === 'REPLACE_WITH_HOSTED_ZONE_ID') { | ||
| throw new Error( | ||
| `Missing required config "${name}". Set it under the "microvm-custom-domains" key in cdk.json ` + | ||
| `or pass -c microvm-custom-domains:${name}=<value>.`, | ||
| ); | ||
| } | ||
| return value; | ||
| } | ||
|
|
||
| const customDomainBase = required(cfg.customDomainBase, 'customDomainBase'); | ||
| const microvmEndpointBase = required(cfg.microvmEndpointBase, 'microvmEndpointBase'); | ||
|
|
||
| // The core, reusable networking pattern from the blog post: everything in the | ||
| // hot request path, and nothing else. | ||
| const stack = new MicroVmCustomDomainsStack(app, 'MicroVmCustomDomainsStack', { | ||
| env: { | ||
| account: cfg.account ?? process.env.CDK_DEFAULT_ACCOUNT, | ||
| region: cfg.region ?? process.env.CDK_DEFAULT_REGION ?? 'us-east-2', | ||
| }, | ||
| description: | ||
| 'Self-service custom domains for AWS Lambda MicroVMs via ALB Host-header rewrite over PrivateLink (no CloudFront, no request-path compute).', | ||
| config: { | ||
| hostedZoneId: required(cfg.hostedZoneId, 'hostedZoneId'), | ||
| hostedZoneName: required(cfg.hostedZoneName, 'hostedZoneName'), | ||
| customDomainBase, | ||
| microvmEndpointBase, | ||
| microvmVpceServiceName: required(cfg.microvmVpceServiceName, 'microvmVpceServiceName'), | ||
| corsAllowOrigin: cfg.corsAllowOrigin ?? '*', | ||
| }, | ||
| }); | ||
|
|
||
| // The OPTIONAL demo layer (single-page app + provisioning API), deployed | ||
| // together with the core stack by attaching to its HTTPS listener. Remove this | ||
| // block to deploy the pure networking pattern on its own. | ||
| new MicroVmDemoApp(stack, 'DemoApp', { | ||
| listener: stack.httpsListener, | ||
| appDomain: required(cfg.appDomain, 'appDomain'), | ||
| microvmImageArn: required(cfg.microvmImageArn, 'microvmImageArn'), | ||
| customDomainBase, | ||
| microvmEndpointBase, | ||
| }); | ||
|
|
||
| app.synth(); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||
| { | ||||||
| "app": "npx ts-node --prefer-ts-exts bin/microvm-custom-domains.ts", | ||||||
| "watch": { | ||||||
| "include": ["**"], | ||||||
| "exclude": [ | ||||||
| "README.md", | ||||||
| "cdk*.json", | ||||||
| "**/*.d.ts", | ||||||
| "**/*.js", | ||||||
| "tsconfig.json", | ||||||
| "package*.json", | ||||||
| "node_modules", | ||||||
| "test" | ||||||
| ] | ||||||
| }, | ||||||
| "context": { | ||||||
| "@aws-cdk/aws-lambda:recognizeLayerVersion": true, | ||||||
| "@aws-cdk/core:checkSecretUsage": true, | ||||||
| "@aws-cdk/core:target-partitions": ["aws", "aws-cn"], | ||||||
| "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, | ||||||
| "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, | ||||||
| "@aws-cdk/aws-iam:minimizePolicies": true, | ||||||
| "@aws-cdk/core:validateSnapshotRemovalPolicy": true, | ||||||
| "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, | ||||||
| "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, | ||||||
| "@aws-cdk/core:enablePartitionLiterals": true, | ||||||
| "@aws-cdk/aws-route53-patters:useCertificate": true, | ||||||
| "@aws-cdk/customresources:installLatestAwsSdkDefault": false, | ||||||
|
|
||||||
| "microvm-custom-domains": { | ||||||
| "//": "------------------------------------------------------------------", | ||||||
| "//1": "EDIT THESE VALUES, then `npx cdk deploy`. All are overridable with -c.", | ||||||
| "//2": "------------------------------------------------------------------", | ||||||
|
|
||||||
| "account": "111122223333", | ||||||
| "region": "us-east-2", | ||||||
|
|
||||||
| "//zone": "Existing Route53 public hosted zone that will hold the wildcard record.", | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| "hostedZoneId": "Z0123456789ABCDEFGHIJ", | ||||||
| "hostedZoneName": "example.com", | ||||||
|
|
||||||
| "//domain": "The wildcard base under which each <uuid> custom domain is served.", | ||||||
| "customDomainBase": "microvms.example.com", | ||||||
|
|
||||||
| "//origin": "The MicroVM GA endpoint domain requests are rewritten TO. The label before this base (the MicroVM id) is preserved per-request by the Host rewrite regex.", | ||||||
| "microvmEndpointBase": "lambda-microvm.us-east-2.on.aws", | ||||||
|
|
||||||
| "//privatelink": "AWS-managed PrivateLink service for reaching MicroVMs privately (public com.amazonaws.<region>.<svc> name; safe to commit).", | ||||||
| "microvmVpceServiceName": "com.amazonaws.us-east-2.lambda-microvm", | ||||||
|
|
||||||
| "//cors": "Value for the Access-Control-Allow-Origin header the ALB inserts on every response. '*' for the demo.", | ||||||
| "corsAllowOrigin": "*", | ||||||
|
|
||||||
| "//image": "ARN of the MicroVM image the provisioning Lambda launches when no running MicroVM is available.", | ||||||
| "microvmImageArn": "arn:aws:lambda:us-east-2:111122223333:microvm-image:my-microvm-image", | ||||||
|
|
||||||
| "//app": "Single host (a label under customDomainBase) that serves the demo page AND its /api/provision endpoint from one ALB-invoked Lambda. Covered by the wildcard cert/record; matched ahead of the host-rewrite rule.", | ||||||
| "appDomain": "customdomain.microvms.example.com" | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| { | ||
| "title": "Custom domains for AWS Lambda MicroVMs with Application Load Balancer", | ||
| "description": "Serve each AWS Lambda MicroVM under a domain you own using an Application Load Balancer Host header rewrite over PrivateLink, with no CloudFront and no compute in the request path.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. description must be 175 characters or fewer |
||
| "language": "TypeScript", | ||
| "level": "300", | ||
| "framework": "AWS CDK", | ||
| "introBox": { | ||
| "headline": "How it works", | ||
| "text": [ | ||
| "This pattern gives each AWS Lambda MicroVM a domain you own (e.g. <uuid>.microvms.example.com) instead of exposing the service-generated <uuid>.lambda-microvm.<region>.on.aws endpoint. It is built entirely from load-balancing and networking primitives: there is no CloudFront and no compute in the request path.", | ||
| "A client sends HTTPS to <uuid>.microvms.example.com. Route 53 resolves a wildcard record to an Application Load Balancer, which terminates TLS with a wildcard ACM certificate. A listener rule matches the host with a regex condition, then a host-header-rewrite Transform swaps only the base-domain suffix (preserving everything ahead of it) to rewrite Host to <uuid>.lambda-microvm.<region>.on.aws.", | ||
| "The ALB forwards to an IP target group whose targets are the private ENI IPs of a MicroVM interface VPC endpoint, reaching the MicroVM service over AWS PrivateLink. The service routes to the correct MicroVM using the rewritten Host header and enforces the JWE auth token the client supplied. Because a Transform (not a redirect) performs the rewrite, the customer's domain stays intact end to end.", | ||
| "CORS is handled entirely at the ALB (a 204 preflight rule plus inserted Access-Control-Allow-* response headers), so no change is required inside the MicroVM. The CDK app also includes an optional, demo-only single-page app and provisioning API that can be removed to deploy the pure networking pattern." | ||
| ] | ||
| }, | ||
| "gitHub": { | ||
| "template": { | ||
| "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-microvm-custom-domain-cdk", | ||
| "templateURL": "serverless-patterns/lambda-microvm-custom-domain-cdk", | ||
| "projectFolder": "lambda-microvm-custom-domain-cdk", | ||
| "templateFile": "lib/microvm-custom-domains-stack.ts" | ||
| } | ||
| }, | ||
| "resources": { | ||
| "bullets": [ | ||
| { | ||
| "text": "AWS Lambda MicroVMs", | ||
| "link": "https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html" | ||
| }, | ||
| { | ||
| "text": "Introducing URL and Host header rewrite with AWS Application Load Balancers", | ||
| "link": "https://aws.amazon.com/blogs/networking-and-content-delivery/introducing-url-and-host-header-rewrite-with-aws-application-load-balancers/" | ||
| }, | ||
| { | ||
| "text": "AWS PrivateLink interface VPC endpoints", | ||
| "link": "https://docs.aws.amazon.com/vpc/latest/privatelink/interface-endpoints.html" | ||
| } | ||
| ] | ||
| }, | ||
| "deploy": { | ||
| "text": [ | ||
| "npm install", | ||
| "npx cdk deploy" | ||
| ] | ||
| }, | ||
| "testing": { | ||
| "text": [ | ||
| "See the GitHub repo for detailed testing instructions." | ||
| ] | ||
| }, | ||
| "cleanup": { | ||
| "text": [ | ||
| "Delete the stack: <code>npx cdk destroy</code>." | ||
| ] | ||
| }, | ||
| "authors": [ | ||
| { | ||
| "name": "Frank Scarfo", | ||
| "image": "https://avatars.githubusercontent.com/u/8919289?v=4", | ||
| "bio": "Frank Scarfo is a Senior Software Development Engineer at Amazon Web Services.", | ||
| "linkedin": "frank-scarfo-7bba053a", | ||
| "twitter": "" | ||
| } | ||
| ] | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.