|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "API Gateway Stage-Specific Lambda Functions - A Tale of Debugging Permissions" |
| 4 | +date: 2021-03-15 09:00:00 +0900 |
| 5 | +categories: [Development, DevOps] |
| 6 | +tags: [AWS, API Gateway, Lambda, Stages, Serverless] |
| 7 | +author: "Kevin Park" |
| 8 | +lang: en |
| 9 | +excerpt: "I wanted API Gateway to call different Lambda functions per stage — dev, staging, prod. The docs made it look simple. It wasn't." |
| 10 | +--- |
| 11 | + |
| 12 | +# API Gateway Stage-Specific Lambda Functions |
| 13 | + |
| 14 | +## What I Wanted |
| 15 | + |
| 16 | +After [getting into AWS](/2020/09/10/getting-into-aws-en/) and [passing the Developer Associate cert](/2020/12/15/aws-developer-certification-en/), I started applying it to real projects. |
| 17 | + |
| 18 | +One thing I needed was calling different Lambda functions per API Gateway stage. Dev, staging, and production environments each needed their own function. Sounds straightforward, right? |
| 19 | + |
| 20 | +The desired setup: |
| 21 | + |
| 22 | +``` |
| 23 | +API Gateway |
| 24 | +├── dev stage → my-function-dev |
| 25 | +├── staging stage → my-function-staging |
| 26 | +└── prod stage → my-function-prod |
| 27 | +``` |
| 28 | + |
| 29 | +## First Attempt - Stage Variables |
| 30 | + |
| 31 | +API Gateway has a feature called Stage Variables. You can set different variable values per stage and reference them in the Lambda integration. |
| 32 | + |
| 33 | +In the Lambda integration config, set the function name to: |
| 34 | + |
| 35 | +``` |
| 36 | +my-function-${stageVariables.env} |
| 37 | +``` |
| 38 | + |
| 39 | +Then set the `env` variable to `dev`, `staging`, or `prod` in each stage. |
| 40 | + |
| 41 | +The official docs cover this much. But if you stop here, it simply won't work. |
| 42 | + |
| 43 | +## The Permissions Problem |
| 44 | + |
| 45 | +It fails because of Lambda's resource-based policy. |
| 46 | + |
| 47 | +For API Gateway to invoke a Lambda function, the function needs a policy saying "API Gateway is allowed to invoke me." When you set up the integration through the console normally, this permission is added automatically. But with stage variables, the automatic permission doesn't get created. |
| 48 | + |
| 49 | +Why? Because the console adds permission for a specific function name, and `${stageVariables.env}` isn't resolved to an actual name yet. |
| 50 | + |
| 51 | +You need to manually add permissions to each Lambda function: |
| 52 | + |
| 53 | +```bash |
| 54 | +aws lambda add-permission \ |
| 55 | + --function-name my-function-dev \ |
| 56 | + --statement-id apigateway-dev \ |
| 57 | + --action lambda:InvokeFunction \ |
| 58 | + --principal apigateway.amazonaws.com \ |
| 59 | + --source-arn "arn:aws:execute-api:ap-northeast-2:123456789:api-id/*/GET/resource" |
| 60 | +``` |
| 61 | + |
| 62 | +Run this for dev, staging, and prod functions individually. |
| 63 | + |
| 64 | +## This Had Me Stuck for Hours |
| 65 | + |
| 66 | +The official docs say "you can specify Lambda functions using stage variables" but the part about manually adding permissions was buried in a small note. Finding proper explanations online wasn't easy either. |
| 67 | + |
| 68 | +The error message wasn't helpful: "Execution failed due to configuration error: Invalid permissions on Lambda function." No clear indication of what to fix. |
| 69 | + |
| 70 | +I ended up digging through CloudWatch logs, Stack Overflow, and AWS forums before figuring it out. |
| 71 | + |
| 72 | +## Alternative Approach - Lambda Aliases |
| 73 | + |
| 74 | +Instead of stage variables, you can use Lambda Aliases. |
| 75 | + |
| 76 | +Deploy multiple versions of a single function and attach aliases to each: |
| 77 | + |
| 78 | +``` |
| 79 | +my-function:dev |
| 80 | +my-function:staging |
| 81 | +my-function:prod |
| 82 | +``` |
| 83 | + |
| 84 | +This way you manage one function instead of three. Deployments are cleaner too — just update the alias. |
| 85 | + |
| 86 | +The permissions issue is the same though. Each alias needs its own permission grant. |
| 87 | + |
| 88 | +## Takeaway |
| 89 | + |
| 90 | +The core issue was **permissions**. The functionality itself is simple — it's the authorization that breaks things. |
| 91 | + |
| 92 | +Working with AWS, I've come to feel that IAM permissions account for roughly half of total learning time. Setting up "who can call whom" is harder than the services themselves. |
| 93 | + |
| 94 | +Still, getting it working felt great. Now the dev-to-prod deployment pipeline runs cleanly. |
| 95 | + |
| 96 | +This was the first real-world case where studying for the certification actually paid off. Education doesn't betray you... or so I'd like to believe. |
0 commit comments