mirror of
https://github.com/Sea-Haven-Industries/engineering-handbook.git
synced 2026-09-30 19:43:14 +00:00
114 lines
3.2 KiB
Markdown
114 lines
3.2 KiB
Markdown
|
|
# Lambda Starter Template
|
||
|
|
|
||
|
|
Minimal SAM scaffold for a new Python Lambda. Drop into `template.yaml` and adjust names. Follows the defaults in [aws-infrastructure.md](aws-infrastructure.md#lambda-defaults).
|
||
|
|
|
||
|
|
## Project Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
my-stack/
|
||
|
|
├── template.yaml
|
||
|
|
├── samconfig.toml.example
|
||
|
|
├── src/
|
||
|
|
│ └── handler/
|
||
|
|
│ ├── app.py
|
||
|
|
│ └── requirements.txt
|
||
|
|
└── .gitignore
|
||
|
|
```
|
||
|
|
|
||
|
|
See [sam-project-layout.md](sam-project-layout.md) for the full directory convention.
|
||
|
|
|
||
|
|
## template.yaml
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
AWSTemplateFormatVersion: "2010-09-09"
|
||
|
|
Transform: AWS::Serverless-2016-10-31
|
||
|
|
Description: my-stack — one-line purpose
|
||
|
|
|
||
|
|
Globals:
|
||
|
|
Function:
|
||
|
|
Runtime: python3.12
|
||
|
|
Architecture: arm64
|
||
|
|
Timeout: 30
|
||
|
|
MemorySize: 256
|
||
|
|
LoggingConfig:
|
||
|
|
LogFormat: JSON
|
||
|
|
|
||
|
|
Resources:
|
||
|
|
HandlerFunction:
|
||
|
|
Type: AWS::Serverless::Function
|
||
|
|
Properties:
|
||
|
|
FunctionName: my-stack-handler
|
||
|
|
CodeUri: src/handler/
|
||
|
|
Handler: app.handler
|
||
|
|
Environment:
|
||
|
|
Variables:
|
||
|
|
CONFIG_SECRET: my-stack/config
|
||
|
|
Policies:
|
||
|
|
- AWSLambdaBasicExecutionRole
|
||
|
|
- Statement:
|
||
|
|
- Effect: Allow
|
||
|
|
Action: secretsmanager:GetSecretValue
|
||
|
|
Resource: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:my-stack/*
|
||
|
|
|
||
|
|
HandlerLogGroup:
|
||
|
|
Type: AWS::Logs::LogGroup
|
||
|
|
Properties:
|
||
|
|
LogGroupName: !Sub /aws/lambda/${HandlerFunction}
|
||
|
|
RetentionInDays: 60
|
||
|
|
|
||
|
|
Outputs:
|
||
|
|
HandlerArn:
|
||
|
|
Description: Handler Lambda ARN
|
||
|
|
Value: !GetAtt HandlerFunction.Arn
|
||
|
|
```
|
||
|
|
|
||
|
|
Key points:
|
||
|
|
|
||
|
|
- `Globals.Function` sets runtime, architecture, and JSON logging once for the whole template.
|
||
|
|
- The `LogGroup` is declared **explicitly** with `RetentionInDays: 60`. Omit it and CloudWatch creates the log group on first invocation with no retention — logs accumulate forever.
|
||
|
|
- IAM scopes `secretsmanager:GetSecretValue` to the stack's secret prefix only. Add specific permissions as needed; never use `AdministratorAccess`.
|
||
|
|
|
||
|
|
## src/handler/app.py
|
||
|
|
|
||
|
|
```python
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
|
||
|
|
import boto3
|
||
|
|
|
||
|
|
_secrets_client = boto3.client("secretsmanager")
|
||
|
|
_config = None
|
||
|
|
|
||
|
|
|
||
|
|
def _get_config():
|
||
|
|
global _config
|
||
|
|
if _config is None:
|
||
|
|
resp = _secrets_client.get_secret_value(SecretId=os.environ["CONFIG_SECRET"])
|
||
|
|
_config = json.loads(resp["SecretString"])
|
||
|
|
return _config
|
||
|
|
|
||
|
|
|
||
|
|
def handler(event, context):
|
||
|
|
config = _get_config()
|
||
|
|
# ... your logic ...
|
||
|
|
return {"statusCode": 200, "body": json.dumps({"ok": True})}
|
||
|
|
```
|
||
|
|
|
||
|
|
The module-level `_config` global caches the secret across warm invocations. The first call per cold start hits Secrets Manager; subsequent calls reuse the cached value. See [secrets-and-config.md](secrets-and-config.md) for the rationale.
|
||
|
|
|
||
|
|
## src/handler/requirements.txt
|
||
|
|
|
||
|
|
Keep this file in every function directory even when empty — SAM looks for it during `sam build`.
|
||
|
|
|
||
|
|
```
|
||
|
|
# Per-function dependencies. Leave empty if the function uses only boto3 and stdlib.
|
||
|
|
```
|
||
|
|
|
||
|
|
## Naming Reminders
|
||
|
|
|
||
|
|
- `FunctionName` must be kebab-case and start with the stack name (`my-stack-handler`).
|
||
|
|
- Secret IDs use `stack-name/secret-name`.
|
||
|
|
- Stack name itself is set in `samconfig.toml`, not the template — match the repo name.
|
||
|
|
|
||
|
|
See [naming-conventions.md](naming-conventions.md).
|