Skip to content
This repository was archived by the owner on Aug 7, 2025. It is now read-only.

Commit cc78821

Browse files
authored
Add cloud pods collaborative debugging tutorial (#1126)
1 parent 00f2905 commit cc78821

File tree

9 files changed

+333
-2
lines changed

9 files changed

+333
-2
lines changed

content/en/references/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ See [here](#opensearch).
170170
| Variable | Example Values | Description |
171171
| - | - | - |
172172
| `ENFORCE_IAM` | `0` (default)\|`1` | Enable IAM policy evaluation and enforcement. If this is disabled (the default), IAM policies will have no effect to your requests. |
173-
| `IAM_SOFT_MODE` | `0` (default)\|`1` | Enable IAM soft mode. This leads to policy evaluation without actually denying access. Needs `ENFORCE_IAM` enabled as well. For more information, see [Identity and Access Management]({{< ref "iam" >}}).|
173+
| `IAM_SOFT_MODE` | `0` (default)\|`1` | Enable IAM soft mode. This leads to policy evaluation without actually denying access. Needs `ENFORCE_IAM` enabled as well. For more information, see [Identity and Access Management]({{< ref "user-guide/aws/iam" >}}).|
174174

175175
### Kinesis
176176

103 KB
Loading
129 KB
Loading
2.36 MB
Loading
311 KB
Loading
126 KB
Loading
281 KB
Loading
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
---
2+
title: "How To: Collaborative AWS local development with LocalStack’s Cloud Pods"
3+
linkTitle: "How To: Collaborative AWS local development with LocalStack’s Cloud Pods"
4+
weight: 7
5+
description: >
6+
Replicating development environments ensures that all developers, regardless of their local machine configurations or operating systems, work within an environment that closely mirrors production. This consistency helps identify and solve environment-specific issues early in the development cycle, reducing the "it works on my machine" problem where code behaves differently on different developers' machines.
7+
type: tutorials
8+
teaser: ""
9+
services:
10+
- iam
11+
- ddb
12+
- agw
13+
- lmb
14+
platform:
15+
- Java
16+
deployment:
17+
- Terraform
18+
tags:
19+
- Cloud Pods
20+
- Terraform
21+
- API Gateway
22+
- Lambda
23+
- DynamoDb
24+
- IAM
25+
- CloudWatch
26+
pro: true
27+
leadimage: "collab-debugging-cloud-pod.png"
28+
---
29+
30+
# **Introduction**
31+
32+
By replicating environments, teams can share the exact conditions under which a bug occurs.
33+
34+
For developing AWS applications locally, the tool of choice is LocalStack, which can sustain a full-blown comprehensive stack.
35+
However, when issues appear, and engineers need a second opinion from a colleague, recreating the environment from scratch can leave
36+
details slipping through the cracks. This is where Cloud Pods come in, to encapsulate the state of the LocalStack instance and allow for seamless
37+
collaboration. While databases have snapshots, similarly, LocalStack uses Cloud Pods for reproducing state and data.
38+
39+
In this tutorial, we will explore a common situation where a basic IAM misconfiguration causes unnecessary delays in finding the right solution.
40+
We will also discuss the best practices to prevent this and review some options for configuring Cloud Pod storage.
41+
The full sample application can be found [on GitHub](https://github.com/localstack-samples/cloud-pods-collaboration-demo) to clone, for following along more easily.
42+
43+
### **Prerequisites**
44+
45+
- [LocalStack CLI](https://docs.localstack.cloud/getting-started/installation/#localstack-cli) (preferably using `pip`)
46+
- [Docker](https://docs.docker.com/engine/install/)
47+
- [Terraform](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) or [OpenTofu](https://opentofu.org/docs/intro/install/) and [terraform-local](https://docs.localstack.cloud/user-guide/integrations/terraform/#install-the-tflocal-wrapper-script)
48+
- Optional for Lambda build & editing: [Maven 3.9.4](https://maven.apache.org/install.html) & [Java 21](https://www.java.com/en/download/help/download_options.html)
49+
50+
- Basic knowledge of AWS services (API Gateway, Lambda, DynamoDB, IAM)
51+
- Basic understanding of Terraform for provisioning AWS resources
52+
53+
In this demo scenario, a new colleague, Bob, joins the company, clones the application repository, and starts working on the Lambda code. He will add the necessary
54+
resources in the Terraform configuration file and some IAM policies that the functions need in order to access the database.
55+
He is following good practice rules, where the resource has only the necessary permissions. However, Bob encounters an error despite this.
56+
57+
### Architecture Overview
58+
59+
The stack consists of an API Gateway that exposes endpoints and integrates with two Lambda functions responsible for adding and fetching
60+
products from a DynamoDB database. IAM policies are enforced to ensure compliance with the
61+
**[principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege)**, and the logs will be sent to the CloudWatch service.
62+
63+
### Note
64+
65+
This demo application is suitable for AWS and behaves the same as on LocalStack. You can try this out by running the Terraform configuration file against the AWS platform.
66+
67+
![Application Diagram](cloud-pod-collab.png)
68+
69+
### Starting LocalStack
70+
71+
In the root directory, there is a `docker-compose.yml` file that will spin up version 3.3.0 of LocalStack, with an
72+
important configuration flag, `ENFORCE_IAM=1`, which will facilitate IAM policy evaluation and enforcement. For this
73+
example, a `LOCALSTACK_AUTH_TOKEN` is needed, which you can find in the LocalStack web app on the
74+
[Getting Started](https://app.localstack.cloud/getting-started) page.
75+
76+
{{< command >}}
77+
$ export LOCALSTACK_AUTH_TOKEN=<YOUR_LOCALSTACK_AUTH_TOKEN>
78+
$ docker compose up
79+
{{</ command >}}
80+
81+
### The Terraform Configuration File
82+
83+
The entire Terraform configuration file for setting up the application stack is available in the same repository at
84+
https://github.com/localstack-samples/cloud-pods-collaboration-demo/blob/main/terraform/main.tf. To deploy all the resources on LocalStack,
85+
navigate to the project's root folder and use the following commands:
86+
87+
{{< command >}}
88+
$ cd terraform
89+
$ tflocal init
90+
$ tflocal plan
91+
$ tflocal apply --auto-approve
92+
{{</ command >}}
93+
94+
`tflocal` is a small wrapper script to run Terraform against LocalStack. The endpoints for all services are configured to point to the
95+
LocalStack API, which allows you to deploy your unmodified Terraform scripts against LocalStack.
96+
97+
- **`init`**: This command initializes the Terraform working directory, installs any necessary plugins, and sets up the backend.
98+
- **`plan`**: Creates an execution plan, which allows you to review the actions Terraform will take to change your infrastructure.
99+
- **`apply`**: Finally, the **`apply`** command applies the changes required to reach the desired state of the configuration.
100+
If **`-auto-approve`** is used, it bypasses the interactive approval step normally required.
101+
102+
As mentioned previously, there is something missing from this configuration, and that is the **`GetItem`** operation permission
103+
for one of the Lambda functions:
104+
105+
```java
106+
resource "aws_iam_policy" "lambda_dynamodb_policy" {
107+
name = "LambdaDynamoDBAccess"
108+
description = "IAM policy for accessing DynamoDB from Lambda"
109+
110+
policy = jsonencode({
111+
Version = "2012-10-17"
112+
Statement = [
113+
{
114+
Action = [
115+
"dynamodb:Scan",
116+
"dynamodb:Query",
117+
"dynamodb:UpdateItem",
118+
"dynamodb:PutItem",
119+
]
120+
Effect = "Allow"
121+
Resource = "*"
122+
},
123+
]
124+
})
125+
}
126+
```
127+
128+
Bob has mistakenly used `dynamodb:Scan` and `dynamodb:Query`, but missed adding the `dynamodb:GetItem` action to the policy document above.
129+
130+
### Reproducing the issue locally
131+
132+
Let’s test out the current state of the application. The Terraform configuration file outputs the REST API ID of the API Gateway.
133+
We can capture that value and use it further to invoke the **`add-product`** Lambda:
134+
135+
{{< command >}}
136+
$ export rest_api_id=$(cd terraform; tflocal output --raw rest_api_id)
137+
{{</ command >}}
138+
139+
The endpoint for the API Gateway is constructed similarly to the one on AWS:
140+
141+
**`
142+
https://<apiId>.execute-api.localhost.localstack.cloud:4566/<stageId>/<path>
143+
`**
144+
145+
So adding two products to the database is straightforward using `curl`:
146+
147+
{{< command >}}
148+
$ curl --location "http://$rest_api_id.execute-api.localhost.localstack.cloud:4566/dev/productApi" \
149+
--header 'Content-Type: application/json' \
150+
--data '{
151+
"id": "34534",
152+
"name": "EcoFriendly Water Bottle",
153+
"description": "A durable, eco-friendly water bottle designed to keep your drinks cold for up to 24 hours and hot for up to 12 hours. Made from high-quality, food-grade stainless steel, it'\''s perfect for your daily hydration needs.",
154+
"price": "29.99"
155+
}'
156+
157+
$ curl --location "http://$rest_api_id.execute-api.localhost.localstack.cloud:4566/dev/productApi?id=82736" \
158+
--header 'Content-Type: application/json' \
159+
--data '{
160+
"id": "82736",
161+
"name": "Sustainable Hydration Flask",
162+
"description": "This sustainable hydration flask is engineered to maintain your beverages at the ideal temperature—cold for 24 hours and hot for 12 hours. Constructed with premium, food-grade stainless steel, it offers an environmentally friendly solution to stay hydrated throughout the day.",
163+
"price": "31.50"
164+
}'
165+
{{</ command >}}
166+
167+
The response is the one that we expect: `Product added/updated successfully.`
168+
169+
However, retrieving one of the products does not return the desired result:
170+
171+
{{< command >}}
172+
$ curl --location "http://$rest_api_id.execute-api.localhost.localstack.cloud:4566/dev/productApi?id=34534"
173+
<disable-copy>
174+
Internal server error⏎
175+
</disable-copy>
176+
{{</ command >}}
177+
178+
179+
An `Internal server error⏎` does not give out too much information. Bob does not know for sure what could be
180+
causing this. The Lambda code and the configurations look fine to him.
181+
182+
## Using Cloud Pods for collaborative debugging
183+
184+
### Creating a Cloud Pod
185+
186+
To share this exact environment and issue with Alice, a more experienced colleague, Bob only needs to run a simple `localstack pod` command:
187+
188+
{{< command >}}
189+
$ localstack pod save cloud-pod-product-app
190+
<disable-copy>
191+
Cloud Pod `cloud-pod-product-app` successfully created ✅
192+
Version: 1
193+
Remote: platform
194+
Services: sts,iam,apigateway,dynamodb,lambda,s3,cloudwatch,logs
195+
</disable-copy>
196+
{{</ command >}}
197+
198+
LocalStack provides a remote storage backend that can be used to store the state of your application and share it with your team members.
199+
200+
The Cloud Pods CLI is included in the LocalStack CLI installation, so there’s no need for additional plugins to begin using it.
201+
The `LOCALSTACK_AUTH_TOKEN` needs to be set as an environment variable.
202+
203+
Additionally, there are other commands for managing Cloud Pods included in the CLI:
204+
205+
{{< command >}}
206+
$ localstack pod --help
207+
<disable-copy>
208+
Usage: localstack pod [OPTIONS] COMMAND [ARGS]...
209+
210+
Manage the state of your instance via Cloud Pods.
211+
212+
Options:
213+
-h, --help Show this message and exit.
214+
215+
Commands:
216+
delete Delete a Cloud Pod
217+
list List all available Cloud Pods
218+
load Load the state of a Cloud Pod into the application runtime
219+
remote Manage Cloud Pod remotes
220+
save Create a new Cloud Pod
221+
versions List all available versions for a Cloud Pod
222+
</disable-copy>
223+
{{</ command >}}
224+
225+
226+
### Pulling and Loading the Cloud Pod
227+
228+
The workflow between Alice and Bob is incredibly easy:
229+
230+
![Bob and Alice Collab](bob-alice-cloud-pod-collab.png)
231+
232+
Now, in a fresh LocalStack instance, Alice can immediately load the Cloud Pod, because she's part of the
233+
same organization:
234+
235+
{{< command >}}
236+
$ localstack pod load cloud-pod-product-app
237+
<disable-copy>
238+
Cloud Pod cloud-pod-product-app successfully loaded
239+
</disable-copy>
240+
{{</ command >}}
241+
242+
### Debugging and Resolving the Issue
243+
244+
Not only can Alice easily reproduce the bug now, but she also has access to the state and data of the services
245+
involved, meaning that the Lambda logs are still in the CloudWatch log groups.
246+
247+
![CloudWatch Logs](cloudwatch-logs.png)
248+
249+
By spotting the error message, there’s an instant starting point for checking the source of the problem. The error message displayed in the logs is very specific:
250+
251+
`"Error: User: arn:aws:sts::000000000000:assumed-role/productRole/get-product is not authorized to perform: dynamodb:GetItem on resource: arn:aws:dynamodb:us-east-1:000000000000:table/Products because no identity-based policy allows the dynamodb:GetItem action (Service: DynamoDb, Status Code: 400, Request ID: d50e9dad-a01a-4860-8c21-e844a930ba7d)"`
252+
253+
### Identifying the Misconfiguration
254+
255+
The error points to a permissions issue related to accessing DynamoDB. The action **`dynamodb:GetItem`** is
256+
not authorized for the role, preventing the retrieval of a product by its ID. This kind of error was not foreseen as one
257+
of the exceptions to be handled in the application. IAM policies are not always easy and straightforward, so it's a well known fact that
258+
these configurations are prone to mistakes.
259+
260+
To confirm the finding, Alice now has the exact same environment to reproduces the error in. There are no machine specific configurations and
261+
no other manual changes. This leads to the next step in troubleshooting: **inspecting the Terraform configuration file** responsible
262+
for defining the permissions attached to the Lambda role for interacting with DynamoDB.
263+
264+
### Fixing the Terraform Configuration
265+
266+
Upon review, Alice discovers that the Terraform configuration does not include the necessary permission **`dynamodb:GetItem`** in the
267+
policy attached to the Lambda role. This oversight explains the error message. The Terraform configuration file acts as a
268+
blueprint for AWS resource permissions, and any missing action can lead to errors related to authorization.
269+
270+
This scenario underscores the importance of thorough review and testing of IAM roles and policies when working with AWS resources.
271+
It's easy to overlook a single action in a policy, but as we've seen, such an omission can significantly impact application
272+
functionality. By carefully checking the Terraform configuration files and ensuring that all necessary permissions are included,
273+
developers can avoid similar issues and ensure a smoother, error-free interaction with AWS services.
274+
275+
The action list should now look like this:
276+
277+
{{< command >}}
278+
resource "aws_iam_policy" "lambda_dynamodb_policy" {
279+
name = "LambdaDynamoDBAccess"
280+
description = "IAM policy for accessing DynamoDB from Lambda"
281+
282+
policy = jsonencode({
283+
Version = "2012-10-17"
284+
Statement = [
285+
{
286+
Action = [
287+
"dynamodb:GetItem",
288+
"dynamodb:UpdateItem",
289+
"dynamodb:PutItem",
290+
]
291+
Effect = "Allow"
292+
Resource = "*"
293+
},
294+
]
295+
})
296+
}
297+
{{</ command >}}
298+
299+
To double-check, Alice creates the stack on AWS, and observes that the issue is the same, related to policy
300+
misconfiguration:
301+
302+
![AWS CloudWatch Logs](aws-cloudwatch-logs.png)
303+
304+
### Impact on the team
305+
306+
Alice has updated the infrastructure and deployed a new version of the Cloud Pod with the necessary fixes. Bob will
307+
access the updated infrastructure and proceed with his tasks. Meanwhile, Carol is developing integration tests for the
308+
CI pipeline. She will use the stable version of the infrastructure to ensure that the workflows function effectively from
309+
start to finish.
310+
311+
![Carol writes tests](carol-bob-alice-cloud-pod-collab.png)
312+
313+
### Other Remote Options
314+
315+
For organizations with specific data regulations, LocalStack offers multiple remote storage options for Cloud Pods,
316+
allowing full control with on-premises storage if needed.
317+
That way, Bob, Alice and Carol could collaborate using either an S3 bucket remote storage or an ORAS (OCI Registry as Storage) remote storage.
318+
The Cloud Pods command-line interface enables users to manage these remotes with ease, by following the instructions in the
319+
[documentation](https://docs.localstack.cloud/user-guide/state-management/cloud-pods/#remotes).
320+
321+
## Conclusion
322+
323+
Cloud Pods play a crucial role in team collaboration, significantly speeding up development processes. The multiple and
324+
versatile options for remote storage can support different business requirements for companies that prefer using the
325+
environments they control. Cloud Pods are not just for teamwork; they also excel in other areas, such as creating
326+
resources in Continuous Integration (CI) for ultra-fast testing pipelines.
327+
328+
## Additional resources
329+
330+
- [Cloud Pods documentation](https://docs.localstack.cloud/user-guide/state-management/cloud-pods/)
331+
- [Terraform for AWS](https://developer.hashicorp.com/terraform/tutorials/aws-get-started)

content/en/tutorials/lambda-ecr-container-images/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ The command provided includes several flags to create the Lambda function. Here'
209209
- `package-type`: Sets the package type to Image to indicate that the Lambda function will be created using a container image.
210210
- `function-name`: Specifies the name of the Lambda function you want to create.
211211
- `runtime`: Defines the runtime environment for the Lambda function. In this case, it's specified as provided, indicating that the container image will provide the runtime.
212-
- `role`: Sets the IAM role ARN that the Lambda function should assume. In the example, a mock role ARN is used. For an actual role, please refer to the [IAM documentation]({{< ref "iam" >}}).
212+
- `role`: Sets the IAM role ARN that the Lambda function should assume. In the example, a mock role ARN is used. For an actual role, please refer to the [IAM documentation]({{< ref "user-guide/aws/iam" >}}).
213213

214214
To invoke the Lambda function, you can use the `invoke` command:
215215

0 commit comments

Comments
 (0)