Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f156b21
Add custom policies to S3 buckets, SQS queues, and Lambda functions
cursoragent Nov 3, 2025
1d47a73
Add custom policies to buckets, queues, and lambdas
cursoragent Nov 3, 2025
23b31c1
Refactor custom policy resource definitions
cursoragent Nov 3, 2025
759c89b
Refactor: Default principal to '*' and update docs
cursoragent Nov 3, 2025
92bbcb5
feat: Add custom policies example for lambda, queue, and bucket
cursoragent Nov 3, 2025
086fa0e
feat: add custom policies support to lambdas and queues
scartill Nov 3, 2025
0475865
refactor(example): simplify resource names in custom policies example
scartill Nov 3, 2025
b6b4ff8
refactor: comment out custom policies in example configs
scartill Nov 3, 2025
73ea936
feat(policies): remove bucket and queue custom policy support
scartill Nov 7, 2025
5eeda9e
feat: add invoke permission support for lambda functions
scartill Nov 7, 2025
e7268cf
Merge pull request #12 from adsight-app/feat/custom-policies
scartill Nov 9, 2025
7bf0f74
refactor(deploy): rename cliparams to toolparams across modules
scartill Nov 9, 2025
2dadaf6
refactor: convert triple quotes to double quotes and update f-strings
scartill Nov 9, 2025
cd6dbaf
feat(cli): refactor context loading to support deployment overrides
scartill Nov 9, 2025
bed312e
multideploy: default contexts reside in the 'default' folder
scartill Nov 9, 2025
f3b42aa
refactor(deploy): extract deployment logic into context-aware helper
scartill Nov 9, 2025
90720bb
multiregion: example stub
scartill Nov 9, 2025
bdbc539
refactor(cli): rename --context-file to --with-context option
scartill Nov 9, 2025
aea9db0
multiregion: generation
scartill Nov 9, 2025
1638fd5
multiregion: deployment - WIP
scartill Nov 9, 2025
564c8c5
feat(deploy): add region parameter support for multi-region deployment
scartill Nov 9, 2025
cb0836b
docs(multiregion): update CLI command with multiple context files
scartill Nov 9, 2025
cfdf0c0
feat(deploy): add default SAM tool and improve parameter handling
scartill Nov 10, 2025
0166ac2
refactor: remove mergedeep dependency and use benedict merge
scartill Nov 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# 1.6.0
# Unreleased

- Added support for the AWS Bedrock permissions
- Changed `init` command to work in the current directory (requires `uv init` to be run first)
- Custom policy support for lambda functions
- Invoke permission support for lambda functions
- Changed `init` command to work in the current directory
- Added `--prismarine` option to `init` command for scaffolding minimal Prismarine applications
- Removed `app-name` argument from `init` command

# 1.5.1

Expand Down
4 changes: 4 additions & 0 deletions CURSOR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Python Code Generation

* Use `ruff` for linting and formatting.
* Use `flake8` for linting.
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,24 @@ tables:

```yaml
buckets:
- name: String (e.g., my-bucket)
public Boolean Optional (e.g., true), means Public read policy
my-bucket:
public: Boolean Optional (e.g., true), means Public read policy
extaccesspolicy: Optional String referencing an external managed policy prefix
```

Bucket custom policies are no longer supported. For external access requirements, attach policies via `extaccesspolicy` or create the policy outside of `easysam`.

### Queue Definitions

```yaml
queues:
- name: String (e.g., my-queue)
my-queue: null # Simple queue definition
# OR
my-queue: {} # Explicit empty queue configuration
```

Queue custom policies are no longer supported. Use IAM roles or separate CloudFormation stacks if you require additional resource policies.

### Stream Definitions

```yaml
Expand All @@ -118,7 +125,8 @@ streams:
## Lambda Definition

```yaml
- name: String (e.g., my-lambda)
functions:
my-lambda:
uri: String (i.e., local path to the source)
tables:
- String (e.g., Items)
Expand All @@ -131,8 +139,14 @@ streams:
services:
- comprehend # Grants ComprehendBasicAccessPolicy
- bedrock # Grants bedrock:InvokeModel permission
custompolicies: Optional Array of custom IAM policies
- action: String or Array (e.g., "s3:GetObject" or ["s3:GetObject", "s3:PutObject"])
effect: String Optional (e.g., "allow" or "deny", default: "allow")
resource: String Optional (e.g., "arn:aws:s3:::my-bucket/*" or "any" for "*", default: "any")
```

Custom policies are added to the Lambda function's IAM execution role as inline policy statements. The `resource` value of "any" translates to "*" (any resource). Note that IAM role policies do not include a `Principal` field (they are identity-based policies attached to the role).

### API Gateway Definition

#### Lambda Function Integration
Expand Down Expand Up @@ -193,14 +207,18 @@ lambda:
- <queue>
polls:
- <stream>
custompolicies: Optional Array of custom IAM policies
- action: String or Array (e.g., "s3:GetObject" or ["s3:GetObject", "s3:PutObject"])
effect: String Optional (e.g., "allow" or "deny", default: "allow")
resource: String Optional (e.g., "arn:aws:s3:::my-bucket/*" or "any" for "*", default: "any")
integration:
path: <path>
open: <boolean>
greedy: <boolean>
authorizer: <authorizer-lambda-name>
```

Locally-defined lambda URI is set to the path of the `easysam.yaml` file.
Locally-defined lambda URI is set to the path of the `easysam.yaml` file. Custom policies work the same way as in the main `resources.yaml` file.

#### Local Import

Expand Down Expand Up @@ -260,10 +278,10 @@ overrides:
buckets/my-bucket/public: true
```

Use the `--context-file` option to specify the deploy context file.
Use the `--with-context` option to specify the deploy context file.

```pwsh
easysam deploy <app-directory> --environment <aws-environment-name> --context-file deploy-context.yaml
easysam deploy <app-directory> --environment <aws-environment-name> --with-context deploy-context.yaml
```
The deploy context file is a YAML file that contains the overrides.

Expand Down
4 changes: 4 additions & 0 deletions example/custompolicies/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build
template.yml
template.yaml
.aws-sam
41 changes: 41 additions & 0 deletions example/custompolicies/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Custom Policies Example

This example demonstrates the use of `custompolicies` for lambdas.

## Features Demonstrated

### Lambda Custom Policies
The `myfunction` lambda has custom IAM policies that grant:
- `logs:CreateLogGroup` on any log group ARN
- `logs:CreateLogStream` and `logs:PutLogEvents` on any resource (`*`)

These are identity-based policies attached to the Lambda execution role, so they don't include a `Principal` field.

> Bucket and queue custom policies have been removed from `easysam`. Use separate CloudFormation resources or IAM roles if you need resource-based policies for those services.

## File Structure

```
custompolicies/
??? resources.yaml # Main resources file importing the lambda example
??? backend/
? ??? function/
? ??? myfunction/
? ??? easysam.yaml # Lambda definition with custom policies
? ??? index.py # Lambda function code
??? common/
??? utils.py # Common utilities
```

## Key Points

- **Lambda policies**: Identity-based, no `Principal` field, `resource` can be `"any"` (translates to `"*"`)
- **Buckets/queues**: Resource-based custom policies are no longer managed by `easysam`

## Deployment

```bash
easysam deploy custompolicies --environment dev --tag Environment=dev
```

Note: Update the principal ARNs in `resources.yaml` to match your AWS account IDs.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
common
10 changes: 10 additions & 0 deletions example/custompolicies/backend/function/myfunction/easysam.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
lambda:
name: myfunction
custompolicies:
- action: ec2:CreateSecurityGroup
effect: allow
allowinvoke: arn:aws:iam::123456789012:root
integration:
path: /process
open: true
greedy: false
52 changes: 52 additions & 0 deletions example/custompolicies/backend/function/myfunction/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import json
import boto3
import os

s3 = boto3.client('s3')
sqs = boto3.client('sqs')


def handler(event, context):
'''
Example Lambda function demonstrating custom policies usage.
This function has custom IAM policies that allow:
- Creating CloudWatch Logs groups and streams
- Putting log events

The function can also access:
- S3 bucket 'documents' (via bucket resource definition)
- SQS queue 'notifications' (via send resource definition)
'''
bucket_name = os.environ.get('DOCUMENTS_BUCKET_NAME', '')
queue_url = os.environ.get('NOTIFICATIONS_QUEUE_URL', '')

# Example: List objects in the documents bucket
try:
response = s3.list_objects_v2(Bucket=bucket_name, MaxKeys=5)
objects = [obj['Key'] for obj in response.get('Contents', [])]
except Exception as e:
objects = []
print(f'Error listing bucket: {e}')

# Example: Send message to notifications queue
try:
sqs.send_message(
QueueUrl=queue_url,
MessageBody=json.dumps({'status': 'processed', 'timestamp': '2024-01-01T00:00:00Z'})
)
except Exception as e:
print(f'Error sending message: {e}')

return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*'
},
'body': json.dumps({
'message': 'Function executed successfully',
'bucket_objects_count': len(objects),
'note': 'This function uses custom IAM policies for CloudWatch Logs access'
})
}
3 changes: 3 additions & 0 deletions example/custompolicies/common/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def get_bucket_info():
'''Example utility function'''
return 'Custom policies example'
4 changes: 4 additions & 0 deletions example/custompolicies/resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
prefix: cpol

import:
- backend
1 change: 1 addition & 0 deletions example/custompolicies/thirdparty/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
boto3>=1.34.0
4 changes: 4 additions & 0 deletions example/multiregion/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build
template.yml
template.yaml
.aws-sam
11 changes: 11 additions & 0 deletions example/multiregion/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Deploy to multiple regions

This example shows how to deploy a EasySAM application to multiple regions. It assumes that you have an AWS profile named `easysam-a` that has access to the regions `eu-west-1` and `eu-west-2`.

## CLI Deployment

```
uv run easysam --environment easysamdev --with-context .\example\multiregion\on_eu_west_1.yaml --with-context .\example\multiregion\on_eu_west_2.yaml deploy .\example\multiregion\
```

Note that all paths here are relative to the root of the EasySAM project. Amend accordingly to your project structure.
1 change: 1 addition & 0 deletions example/multiregion/backend/function/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/common/
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lambda:
name: myfunction
13 changes: 13 additions & 0 deletions example/multiregion/backend/function/myfunction/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import json


def handler(event, context):
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*'
},
'body': json.dumps({'data': 'Hello, World!'})
}
3 changes: 3 additions & 0 deletions example/multiregion/on_eu_west_1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: on_eu_west_1
target_profile: easysam-a
target_region: eu-west-1
3 changes: 3 additions & 0 deletions example/multiregion/on_eu_west_2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: on_eu_west_2
target_profile: easysam-a
target_region: eu-west-2
4 changes: 4 additions & 0 deletions example/multiregion/resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
prefix: Onelambda

import:
- backend
24 changes: 24 additions & 0 deletions example/multiregion/test/invoke_lambda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import boto3
import json

import click


@click.command()
@click.option('--env', default='dev')
@click.argument('message', default='{"message": "Hello, World!"}')
def send_message(message, env):
lambda_client = boto3.client('lambda')

response = lambda_client.invoke(
FunctionName=f'myfunction-{env}',
Payload=json.dumps(message),
)

answer = json.loads(response['Payload'].read())
body = json.loads(answer['body'])
click.echo(json.dumps(body, indent=2))


if __name__ == '__main__':
send_message()
2 changes: 2 additions & 0 deletions example/multiregion/thirdparty/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
boto3

1 change: 0 additions & 1 deletion example/myapp/thirdparty/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
boto3

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ dependencies = [
"click>=8.2.0",
"jinja2-cli[yaml]>=0.8.2",
"jsonschema>=4.23.0",
"mergedeep>=1.3.4",
"python-benedict[yaml]>=0.34.1",
"rich>=13.9.4",
"prismarine>=1.4.1",
Expand Down
Loading