|
| 1 | +--- |
| 2 | +name: terraform-lambda |
| 3 | +description: > |
| 4 | + Scaffold a complete AWS Lambda function project using the terraform-aws-lambda |
| 5 | + Terraform module (moritzzimmer/lambda/aws). Generates Terraform configuration, |
| 6 | + runtime-specific build tooling (Makefile), and minimal function code with |
| 7 | + correct event source wiring and IAM setup. Use this skill whenever the user |
| 8 | + wants to create a new Lambda function, scaffold a Lambda project, set up a |
| 9 | + serverless function with Terraform, or asks about using the terraform-aws-lambda |
| 10 | + module. Also trigger when the user mentions "new lambda", "lambda scaffold", |
| 11 | + "lambda boilerplate", or wants to add a Lambda function to their infrastructure. |
| 12 | +argument-hint: "[function-name] [runtime] [event-source]" |
| 13 | +--- |
| 14 | + |
| 15 | +# Create Lambda |
| 16 | + |
| 17 | +Scaffold production-ready AWS Lambda functions using the |
| 18 | +[terraform-aws-lambda](https://registry.terraform.io/modules/moritzzimmer/lambda/aws) |
| 19 | +Terraform module. |
| 20 | + |
| 21 | +## When to use this skill |
| 22 | + |
| 23 | +- User wants to create a new Lambda function |
| 24 | +- User wants to scaffold a Lambda project with Terraform |
| 25 | +- User is setting up serverless infrastructure on AWS with Terraform |
| 26 | +- User asks how to use the `moritzzimmer/lambda/aws` module |
| 27 | + |
| 28 | +## Gather requirements |
| 29 | + |
| 30 | +Before generating anything, establish what the user needs. If they provided |
| 31 | +arguments via `/terraform-lambda`, parse them. Otherwise ask concisely: |
| 32 | + |
| 33 | +1. **Function name** (required) — must be a valid Lambda function name |
| 34 | +2. **Runtime** — Go, Python, Java, .NET, Node.js, or container image (default: Python) |
| 35 | +3. **Event source** — what triggers the function: SQS, SNS, Kinesis, DynamoDB Streams, CloudWatch Events/schedule, API Gateway, S3, or none (default: none) |
| 36 | +4. **Extra features** — VPC, EFS, X-Ray tracing, Lambda Insights, SSM parameters, CloudWatch log retention, snap_start (Java only) |
| 37 | +5. **CI/CD pipeline** — does the user want CodeDeploy-based deployments? If so: |
| 38 | + - S3 or ECR source? |
| 39 | + - **S3 bucket**: Does an S3 bucket already exist (reference via `data` source |
| 40 | + or bucket name), or should the skill create a new one inline? This matters |
| 41 | + for the Terraform setup — ask explicitly. |
| 42 | + - Deployment strategy: canary, linear, or all-at-once? |
| 43 | + - Auto-rollback on failure? |
| 44 | +6. **Target directory** — where to create the project (default: `./<function-name>/`) |
| 45 | + |
| 46 | +If the user gives a one-liner like "create a Python Lambda triggered by SQS called order-processor", extract all info from that — don't ask again for things already stated. |
| 47 | + |
| 48 | +## Generate the project |
| 49 | + |
| 50 | +### Directory layout |
| 51 | + |
| 52 | +``` |
| 53 | +<function-name>/ |
| 54 | +├── Makefile # Build and deploy |
| 55 | +├── terraform/ |
| 56 | +│ ├── main.tf # Module usage + event source resources |
| 57 | +│ ├── variables.tf # Environment-specific variables |
| 58 | +│ ├── outputs.tf # Useful outputs from the module |
| 59 | +│ ├── versions.tf # Terraform and provider version constraints |
| 60 | +│ └── provider.tf # AWS provider configuration |
| 61 | +└── <source code> # Layout is runtime-specific (see references/runtimes.md) |
| 62 | +``` |
| 63 | + |
| 64 | +Source code location varies by runtime — Go puts `main.go` and `go.mod` at the |
| 65 | +project root (idiomatic Go), while Python uses `src/app/`, Java uses `src/`, |
| 66 | +etc. Always consult [references/runtimes.md](references/runtimes.md) for the |
| 67 | +correct layout. |
| 68 | + |
| 69 | +### Terraform files |
| 70 | + |
| 71 | +**versions.tf** — pin providers: |
| 72 | +```hcl |
| 73 | +terraform { |
| 74 | + required_version = ">= 1.5.7" |
| 75 | +
|
| 76 | + required_providers { |
| 77 | + aws = { |
| 78 | + source = "hashicorp/aws" |
| 79 | + version = ">= 6.0" |
| 80 | + } |
| 81 | + } |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +**provider.tf**: |
| 86 | +```hcl |
| 87 | +provider "aws" { |
| 88 | + region = var.region |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +**variables.tf** — always include `region`, add others as needed: |
| 93 | +```hcl |
| 94 | +variable "region" { |
| 95 | + description = "AWS region for all resources" |
| 96 | + type = string |
| 97 | + default = "eu-central-1" |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +**outputs.tf** — expose the most useful module outputs: |
| 102 | +```hcl |
| 103 | +output "function_arn" { |
| 104 | + value = module.<function_name>.arn |
| 105 | +} |
| 106 | +
|
| 107 | +output "function_name" { |
| 108 | + value = module.<function_name>.function_name |
| 109 | +} |
| 110 | +
|
| 111 | +output "role_arn" { |
| 112 | + value = module.<function_name>.role_arn |
| 113 | +} |
| 114 | +
|
| 115 | +output "invoke_arn" { |
| 116 | + value = module.<function_name>.invoke_arn |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +**main.tf** — the module block plus any event source resources. Key rules: |
| 121 | + |
| 122 | +- Module source: `"moritzzimmer/lambda/aws"`, version: `"~> 8.6"` |
| 123 | +- Alphabetical attribute ordering inside the module block |
| 124 | +- Guard `source_code_hash` with `fileexists()` so `terraform validate` works |
| 125 | + without build artifacts: |
| 126 | + ```hcl |
| 127 | + source_code_hash = fileexists(local.artifact) ? filebase64sha256(local.artifact) : null |
| 128 | + ``` |
| 129 | +- Default architecture: `["arm64"]` (Graviton — better price/performance) |
| 130 | +- **Runtime versions**: Do not rely on your training data for Lambda runtime |
| 131 | + identifiers — they go stale quickly (e.g., `java21` is outdated, `java25` |
| 132 | + is current). Before generating code, look up the latest runtime by searching |
| 133 | + the web for "AWS Lambda supported runtimes" or checking |
| 134 | + `https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html`. If you |
| 135 | + cannot verify, leave a `# TODO: verify this is the latest runtime` comment |
| 136 | + next to the runtime value so the user knows to check. |
| 137 | +- Always include `tags = { managed_by = "terraform" }` |
| 138 | + |
| 139 | +For runtime-specific settings, event source patterns, and the full variable |
| 140 | +reference, consult the reference files: |
| 141 | + |
| 142 | +- [references/runtimes.md](references/runtimes.md) — runtime configs, Makefile |
| 143 | + templates, and sample function code for each supported language |
| 144 | +- [references/event-sources.md](references/event-sources.md) — how to wire up |
| 145 | + each event source type with correct Terraform resources |
| 146 | +- [references/variables.md](references/variables.md) — full variable reference |
| 147 | + grouped by feature area, with defaults and IAM implications |
| 148 | +- [references/deployment.md](references/deployment.md) — CodePipeline/CodeDeploy |
| 149 | + CI/CD pipeline setup using the deployment submodule |
| 150 | + |
| 151 | +### CI/CD with the deployment submodule |
| 152 | + |
| 153 | +When the user wants CodeDeploy-based deployments, the setup changes: |
| 154 | + |
| 155 | +1. The main module uses **S3-based packaging** (`s3_bucket`/`s3_key`) instead of |
| 156 | + local `filename`, and sets `ignore_external_function_updates = true` |
| 157 | +2. An **`aws_s3_object` resource** uploads the initial build artifact to S3, and |
| 158 | + the main module references `s3_object_version` from it — this ensures the zip |
| 159 | + exists before the Lambda is created (without this, first apply fails with |
| 160 | + `NoSuchKey`). Use `lifecycle { ignore_changes = [etag] }` so CodePipeline |
| 161 | + deployments don't conflict. |
| 162 | +3. A **Lambda alias** is created with `lifecycle { ignore_changes = [function_version] }` |
| 163 | + — CodeDeploy manages version shifts, not Terraform |
| 164 | +4. The **deployment submodule** (`moritzzimmer/lambda/aws//modules/deployment`) |
| 165 | + creates a CodePipeline + CodeDeploy pipeline |
| 166 | + |
| 167 | +For the full pattern with examples (canary, rollback, alarms), see |
| 168 | +[references/deployment.md](references/deployment.md). |
| 169 | + |
| 170 | +## Important guardrails |
| 171 | + |
| 172 | +These matter because getting them wrong causes hard-to-debug issues: |
| 173 | + |
| 174 | +- **fileexists() guard**: Always wrap `filebase64sha256()` — without it, |
| 175 | + `terraform validate` and `terraform plan` fail when the zip hasn't been built |
| 176 | + yet (e.g., in CI before the build step). |
| 177 | + |
| 178 | +- **arm64 default**: Use `architectures = ["arm64"]` unless the user has a |
| 179 | + reason for x86_64 (e.g., native dependencies that don't support ARM). Graviton |
| 180 | + is ~20% cheaper and generally faster for Lambda. |
| 181 | + |
| 182 | +- **Memory defaults by runtime**: Go/Node.js: 128MB. Python/.NET: 256MB. |
| 183 | + Java: 512MB. These reflect typical cold-start and memory needs — the user can |
| 184 | + always override. |
| 185 | + |
| 186 | +- **snap_start is Java-only**: Setting it for other runtimes silently does |
| 187 | + nothing useful. Only suggest it when runtime is Java. |
| 188 | + |
| 189 | +- **S3 bucket: use `.bucket`, not `.id`**: When passing an S3 bucket to the |
| 190 | + deployment module, always use `aws_s3_bucket.x.bucket` (the name string), |
| 191 | + not `aws_s3_bucket.x.id`. The `.id` attribute can cause "Invalid count |
| 192 | + argument" errors because the deployment module uses |
| 193 | + `count = var.s3_bucket != ""` at plan time. |
| 194 | + |
| 195 | +- **lambda_at_edge + VPC are incompatible**: Lambda@Edge runs at CloudFront |
| 196 | + edge locations and cannot access a VPC. |
| 197 | + |
| 198 | +- **reserved_concurrent_executions = 0 disables the function**: If the user |
| 199 | + wants to limit concurrency, suggest a positive number. Zero means "cannot run." |
| 200 | + |
| 201 | +- **IAM is automatic**: The module attaches the right IAM policies based on |
| 202 | + which features are enabled (VPC, tracing, SSM, event sources, logs). Don't |
| 203 | + create separate IAM resources for these — it's already handled. |
| 204 | + |
| 205 | +## After generation |
| 206 | + |
| 207 | +**Verify the generated code builds.** After writing all files, run `make package` |
| 208 | +(or the equivalent build command) to confirm the project compiles and packages |
| 209 | +successfully. If it fails, fix the issue before presenting the result to the |
| 210 | +user. Common causes: missing `using`/`import` statements, wrong package names |
| 211 | +in build files, or mismatched handler signatures. |
| 212 | + |
| 213 | +Once the files are written: |
| 214 | + |
| 215 | +1. Suggest `make help` to see available targets |
| 216 | +2. `make tf` runs `terraform init` + `terraform plan` |
| 217 | +3. `make tf MODE=apply` to deploy |
| 218 | +4. `make package` to just build the artifact without deploying |
| 219 | + |
| 220 | +If the user wants to add features later (like adding an SQS trigger to an |
| 221 | +existing function), read the current Terraform config and modify it — don't |
| 222 | +regenerate from scratch. |
0 commit comments