A simple, idiomatic Go CLI tool for triggering AWS Lambda functions with JSON output, for inclusion in distroless/minimal images.
- AWS SDK v2: Uses the standard AWS Go SDK v2 with default credential chain
- Chained IAM Role Assumption: Assume IAM roles for cross-account access and privilege elevation
- Synchronous & Asynchronous: Support for both RequestResponse and Event invocation types
- Flexible Payload Input: Accept JSON payload via flag, file path,
file://URL, or stdin - File Output Support: Write JSON responses to files with overwrite or append modes
- JSON Output: All responses (success and errors) formatted as JSON
- JSONL Batch Processing: Process multiple invocations in parallel from newline-delimited JSON
- Environment Variable Configuration: Configure all options via environment variables
- jq Filtering: Filter JSON output using jq expressions
- Structured Logging: Configurable log levels with slog (WARN, INFO, DEBUG) and formats (text, JSON)
- Configuration Options: Custom timeout and multi-level verbosity
- Idiomatic Go: Built with Cobra CLI framework following Go best practices
go install github.com/nexthink-oss/lambda@latestOr build from source:
git clone https://github.com/nexthink-oss/lambda.git
cd lambda
go build -o lambdalambda [flags] [function-arn]The function ARN can be provided as an argument or via the LAMBDA_FUNCTION_ARN environment variable.
Payload Flags:
--payload <json>: JSON payload to send (inline JSON, file path, orfile://URL)--stdin: Read payload from stdin--raw: Send payload as raw bytes without JSON validation--jsonl: Treat stdin as JSONL format (one invocation per line, requires--stdin)--parallel <n>: Number of parallel workers for JSONL processing (default: 1, requires--jsonl)
Invocation Flags:
--async: Use asynchronous invocation (Event type, default is RequestResponse)--timeout <duration>: Timeout for Lambda invocation (default: 5m)--role-arn <arn>: IAM role ARN to assume before invoking Lambda--role-session-name <name>: Session name for assumed role (default:lambda-cli)
Output Flags:
--jq <expression>: jq expression to filter JSON output (e.g.,.payload)--out-file <path>: Write JSON output to file instead of stdout--append: Append to output file instead of overwriting (requires--out-file)
Logging Flags:
-v, --verbosity: Increase logging verbosity (repeatable:-vfor INFO,-vvfor DEBUG)-q, --quiet: Quiet mode - only show errors--log-format <format>: Log format:text(default) orjson--log-file <path>: Write logs to file instead of stderr (appends to existing file)
All flags can be configured via environment variables:
| Environment Variable | Description | Example |
|---|---|---|
LAMBDA_FUNCTION_ARN |
Target Lambda function ARN | arn:aws:lambda:us-east-1:123456789012:function:my-function |
LAMBDA_ROLE_ARN |
IAM role ARN to assume | arn:aws:iam::123456789012:role/LambdaInvoker |
LAMBDA_ROLE_SESSION_NAME |
Session name for assumed role | lambda-cli (default) |
LAMBDA_PAYLOAD |
JSON payload | '{"key":"value"}' |
LAMBDA_STDIN |
Read from stdin | true or false |
LAMBDA_RAW |
Send raw bytes (no validation) | true or false |
LAMBDA_JSONL |
JSONL batch processing | true or false |
LAMBDA_PARALLEL |
Parallel workers for JSONL | 1-100 (default: 1) |
LAMBDA_ASYNC |
Async invocation | true or false |
LAMBDA_TIMEOUT |
Timeout duration | 5m, 30s, etc. |
LAMBDA_VERBOSITY |
Verbosity level | 0 (warn), 1 (info), 2 (debug) |
LAMBDA_QUIET |
Quiet mode (errors only) | true or false |
LAMBDA_LOG_FORMAT |
Log output format | text (default) or json |
LAMBDA_LOG_FILE |
Log file path | /path/to/log/file.log |
LAMBDA_OUT_FILE |
Output file path | /path/to/output.json |
LAMBDA_APPEND |
Append to output file | true or false |
LAMBDA_JQ |
jq filter expression | .payload, .status_code, etc. |
Priority: Command-line flags > Environment variables > Defaults
lambda --payload '{"key":"value"}' arn:aws:lambda:us-east-1:123456789012:function:my-functionOutput:
{
"success": true,
"status_code": 200,
"payload": {
"result": "success"
},
"function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}lambda --async --payload '{"key":"value"}' arn:aws:lambda:us-east-1:123456789012:function:my-functionOutput:
{
"success": true,
"status_code": 202,
"function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}# Auto-detected file path
lambda --payload ./payload.json arn:aws:lambda:us-east-1:123456789012:function:my-function
# Explicit file:// URL (absolute path)
lambda --payload file:///path/to/payload.json arn:aws:lambda:us-east-1:123456789012:function:my-function
# Explicit file:// URL (relative path)
lambda --payload file://./payload.json arn:aws:lambda:us-east-1:123456789012:function:my-function# Write response to file (overwrites existing)
lambda --payload '{"key":"value"}' --out-file response.json arn:aws:lambda:us-east-1:123456789012:function:my-function
# Append multiple responses to same file
lambda --payload '{"id":1}' --out-file results.json --append arn:aws:lambda:us-east-1:123456789012:function:my-function
lambda --payload '{"id":2}' --out-file results.json --append arn:aws:lambda:us-east-1:123456789012:function:my-function
# Combine with jq filtering
lambda --payload '{}' --out-file filtered.json --jq '.payload' arn:aws:lambda:us-east-1:123456789012:function:my-function
# Via environment variable
export LAMBDA_OUT_FILE=/tmp/lambda-output.json
export LAMBDA_APPEND=true
lambda --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionecho '{"key":"value"}' | lambda --stdin arn:aws:lambda:us-east-1:123456789012:function:my-functionOr with heredoc:
lambda --stdin arn:aws:lambda:us-east-1:123456789012:function:my-function <<EOF
{
"key": "value",
"nested": {
"data": true
}
}
EOF# Default: WARN level (warnings and errors only)
lambda --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# INFO level: operational information
lambda -v --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# DEBUG level: detailed debugging including AWS SDK calls
lambda -vv --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# Quiet mode: errors only
lambda -q --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# JSON structured logging
lambda -v --log-format json --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# Write logs to file (appends to existing file)
lambda -v --log-file=/tmp/lambda.log --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# JSON logs to file
lambda -vv --log-file=/tmp/lambda.log --log-format=json --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function
# Tee behavior (logs to both file and stderr) using shell redirection
lambda -v --payload '{"test":true}' arn:aws:lambda:us-east-1:123456789012:function:my-function 2>&1 | tee lambda.logBy default, all logs go to stderr and JSON responses to stdout. With --log-file, logs are redirected to the specified file (appending to existing content).
lambda --timeout 30s --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionIf no payload is specified, an empty JSON object {} is sent:
lambda arn:aws:lambda:us-east-1:123456789012:function:my-function# Assume role in different account before invoking
lambda --role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
--payload '{"key":"value"}' \
arn:aws:lambda:us-east-1:123456789012:function:my-functionexport LAMBDA_ROLE_ARN="arn:aws:iam::123456789012:role/LambdaInvoker"
export LAMBDA_ROLE_SESSION_NAME="deployment-script"
lambda arn:aws:lambda:us-east-1:123456789012:function:my-function --payload '{}'Filter the JSON output using jq expressions to extract specific fields:
lambda --jq '.payload' --payload '{"test":"data"}' arn:aws:lambda:us-east-1:123456789012:function:my-functionOutput:
{
"result": "success"
}lambda --jq '.status_code' --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionOutput:
200lambda --jq '.payload.result' --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionOutput:
"success"export LAMBDA_JQ='.payload'
lambda --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionProcess multiple Lambda invocations in parallel from newline-delimited JSON input:
cat payloads.jsonl | lambda --stdin --jsonl arn:aws:lambda:us-east-1:123456789012:function:my-functionExample payloads.jsonl:
{"userId": 1, "action": "login"}
{"userId": 2, "action": "logout"}
{"userId": 3, "action": "purchase", "amount": 99.99}Output (JSONL format with line numbers):
{"success":true,"status_code":200,"payload":{"result":"ok"},"function_arn":"arn:aws:lambda:...","line_number":1}
{"success":true,"status_code":200,"payload":{"result":"ok"},"function_arn":"arn:aws:lambda:...","line_number":2}
{"success":true,"status_code":200,"payload":{"result":"ok"},"function_arn":"arn:aws:lambda:...","line_number":3}cat large-batch.jsonl | lambda --stdin --jsonl --parallel 5 arn:aws:lambda:us-east-1:123456789012:function:my-functionExtract only successful payloads:
cat payloads.jsonl | lambda --stdin --jsonl --jq '.payload' arn:aws:lambda:us-east-1:123456789012:function:my-functionSave batch processing results to file:
# Write all results to file
cat batch.jsonl | lambda --stdin --jsonl --out-file results.jsonl arn:aws:lambda:us-east-1:123456789012:function:my-function
# Parallel processing with file output
cat large-batch.jsonl | lambda --stdin --jsonl --parallel 10 --out-file results.jsonl arn:aws:lambda:us-east-1:123456789012:function:my-functionJSONL processing continues on errors, collecting all results:
{"valid": "json"}
invalid json here
{"another": "valid"}Output shows both successes and errors with line numbers:
{"success":true,"status_code":200,"payload":{"result":"ok"},"function_arn":"arn:aws:lambda:...","line_number":1}
{"success":false,"error":"invalid JSON","function_arn":"arn:aws:lambda:...","line_number":2}
{"success":true,"status_code":200,"payload":{"result":"ok"},"function_arn":"arn:aws:lambda:...","line_number":3}Send binary data without JSON validation using --raw:
# Send raw text
echo "plain text data" | lambda --stdin --raw arn:aws:lambda:us-east-1:123456789012:function:my-function
# Send binary file
cat image.png | lambda --stdin --raw arn:aws:lambda:us-east-1:123456789012:function:my-function
# Send protobuf data
cat message.pb | lambda --stdin --raw arn:aws:lambda:us-east-1:123456789012:function:my-functionNote: Lambda receives the exact bytes sent. The Lambda function is responsible for interpreting the binary format.
export LAMBDA_FUNCTION_ARN="arn:aws:lambda:us-east-1:123456789012:function:my-function"
export LAMBDA_PAYLOAD='{"key":"value"}'
export LAMBDA_ASYNC=true
export LAMBDA_JQ='.status_code'
# Simply run without any arguments
lambdaexport LAMBDA_FUNCTION_ARN="arn:aws:lambda:us-east-1:123456789012:function:my-function"
export LAMBDA_VERBOSITY=1
# Override payload via flag
lambda --payload '{"override":"data"}'# Set in CI/CD environment
export LAMBDA_FUNCTION_ARN="${DEPLOY_LAMBDA_ARN}"
export LAMBDA_TIMEOUT="2m"
# Run tests
lambda --payload '{"test":"suite"}' --jq '.payload.success'{
"success": true,
"status_code": 200,
"payload": {
// Lambda function response
},
"function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}{
"success": false,
"error": "error message here",
"function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}When the Lambda function executes but returns an error:
{
"success": false,
"status_code": 200,
"payload": {
"errorMessage": "Function error details",
"errorType": "ErrorType"
},
"error": "Lambda function error: Unhandled",
"function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}This tool uses the AWS SDK v2 default credential chain, which checks the following sources in order:
- Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN) - Shared credentials file (
~/.aws/credentials) - Shared configuration file (
~/.aws/config) - IAM role for Amazon EC2
- IAM role for Amazon ECS tasks
- IAM role for AWS Lambda functions
Set your AWS credentials using any of these methods before using the tool.
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_REGION=us-east-1
lambda --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionexport AWS_PROFILE=my-profile
lambda --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-functionThe CLI supports assuming an IAM role before invoking Lambda functions. This is useful for:
- Cross-account access: Invoke Lambda functions in different AWS accounts
- Temporary privilege elevation: Assume roles with specific permissions
- Least-privilege patterns: Use minimal base credentials, assume roles as needed
- Audit trails: Session names appear in CloudTrail for accountability
To use role assumption, ensure:
- Base credentials have
sts:AssumeRolepermission for the target role - Target role has a trust policy allowing your principal to assume it
- Target role has
lambda:InvokeFunctionpermission for the function - Role ARN follows the format:
arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME
Specify the role via flag or environment variable:
# Using flag
lambda --role-arn arn:aws:iam::123456789012:role/LambdaInvoker \
arn:aws:lambda:us-east-1:123456789012:function:my-function
# Using environment variable
export LAMBDA_ROLE_ARN="arn:aws:iam::123456789012:role/LambdaInvoker"
lambda arn:aws:lambda:us-east-1:123456789012:function:my-function
# Custom session name (appears in CloudTrail)
lambda --role-arn arn:aws:iam::123456789012:role/LambdaInvoker \
--role-session-name "deployment-pipeline" \
arn:aws:lambda:us-east-1:123456789012:function:my-function- Load default credentials via AWS SDK credential chain
- If
--role-arnis specified, call STS AssumeRole with base credentials - Cache assumed role credentials (automatic by AWS SDK)
- Create Lambda client with assumed role credentials
- Invoke Lambda function using assumed role permissions
# Invoke function in account 999999999999 from account 111111111111
lambda --role-arn arn:aws:iam::999999999999:role/CrossAccountLambdaRole \
--payload '{"key":"value"}' \
arn:aws:lambda:us-east-1:999999999999:function:my-function# Assume admin role for privileged operation
lambda --role-arn arn:aws:iam::123456789012:role/LambdaAdmin \
--payload '{}' \
arn:aws:lambda:us-east-1:123456789012:function:admin-function# In CI/CD environment with minimal base credentials
export LAMBDA_ROLE_ARN="arn:aws:iam::123456789012:role/DeploymentRole"
export LAMBDA_ROLE_SESSION_NAME="github-actions-${GITHUB_RUN_ID}"
lambda arn:aws:lambda:us-east-1:123456789012:function:my-function \
--payload '{"env":"production"}'Use verbose mode to see role assumption details in logs:
lambda -v --role-arn arn:aws:iam::123456789012:role/TestRole \
arn:aws:lambda:us-east-1:123456789012:function:my-functionCommon errors and solutions:
| Error | Cause | Solution |
|---|---|---|
Invalid ARN format |
ARN doesn't match arn:aws:iam::ACCOUNT:role/NAME |
Verify ARN format |
AccessDenied (STS) |
Base credentials lack sts:AssumeRole permission |
Add sts:AssumeRole to base credentials policy |
AccessDenied (Lambda) |
Assumed role lacks lambda:InvokeFunction |
Add permission to target role |
Not authorized to perform: sts:AssumeRole |
Role trust policy doesn't allow your principal | Update role trust policy |
The target role needs a trust policy allowing your principal to assume it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/deployer"
},
"Action": "sts:AssumeRole"
}
]
}0: Success1: Error (details in JSON output)
#!/bin/bash
result=$(lambda --payload '{"test":"data"}' arn:aws:lambda:us-east-1:123456789012:function:test-function)
success=$(echo "$result" | jq -r '.success')
if [ "$success" == "true" ]; then
echo "Test passed"
exit 0
else
echo "Test failed"
exit 1
fi# .github/workflows/test.yml
- name: Trigger Lambda Test
run: |
lambda --payload '{"env":"staging"}' ${{ secrets.LAMBDA_ARN }} | jq# Process multiple payloads
for payload in payloads/*.json; do
lambda --payload "$payload" arn:aws:lambda:us-east-1:123456789012:function:batch-processor
done# Trigger Lambda without waiting for result
lambda --async --payload '{"notification":"sent"}' arn:aws:lambda:us-east-1:123456789012:function:notifiergo build -o lambdago test ./...go installlambda/
├── main.go # CLI entry point
├── cmd/
│ └── root.go # Cobra root command with flags
├── internal/
│ ├── lambda/
│ │ └── client.go # AWS Lambda client wrapper
│ └── output/
│ └── json.go # JSON output formatting
├── go.mod
├── go.sum
└── README.md
- Go 1.25.4 or later
- AWS credentials configured
- Lambda function ARN with appropriate IAM permissions
[Add your license here]
[Add contribution guidelines here]