Skip to content

nexthink-oss/lambda

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lambda

A simple, idiomatic Go CLI tool for triggering AWS Lambda functions with JSON output, for inclusion in distroless/minimal images.

Features

  • 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

Installation

go install github.com/nexthink-oss/lambda@latest

Or build from source:

git clone https://github.com/nexthink-oss/lambda.git
cd lambda
go build -o lambda

Usage

Basic Syntax

lambda [flags] [function-arn]

The function ARN can be provided as an argument or via the LAMBDA_FUNCTION_ARN environment variable.

Flags

Payload Flags:

  • --payload <json>: JSON payload to send (inline JSON, file path, or file:// 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: -v for INFO, -vv for DEBUG)
  • -q, --quiet: Quiet mode - only show errors
  • --log-format <format>: Log format: text (default) or json
  • --log-file <path>: Write logs to file instead of stderr (appends to existing file)

Environment Variables

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

Examples

Synchronous Invocation with Inline Payload

lambda --payload '{"key":"value"}' arn:aws:lambda:us-east-1:123456789012:function:my-function

Output:

{
  "success": true,
  "status_code": 200,
  "payload": {
    "result": "success"
  },
  "function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}

Asynchronous Invocation

lambda --async --payload '{"key":"value"}' arn:aws:lambda:us-east-1:123456789012:function:my-function

Output:

{
  "success": true,
  "status_code": 202,
  "function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}

Read Payload from File

# 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 Output to File

# 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-function

Read Payload from Stdin

echo '{"key":"value"}' | lambda --stdin arn:aws:lambda:us-east-1:123456789012:function:my-function

Or with heredoc:

lambda --stdin arn:aws:lambda:us-east-1:123456789012:function:my-function <<EOF
{
  "key": "value",
  "nested": {
    "data": true
  }
}
EOF

Logging Levels

# 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.log

By 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).

Custom Timeout

lambda --timeout 30s --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-function

Empty Payload

If no payload is specified, an empty JSON object {} is sent:

lambda arn:aws:lambda:us-east-1:123456789012:function:my-function

Role Assumption for Cross-Account Access

# 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-function

Role Assumption with Environment Variables

export 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 '{}'

jq Filtering Examples

Filter the JSON output using jq expressions to extract specific fields:

Extract Only the Payload

lambda --jq '.payload' --payload '{"test":"data"}' arn:aws:lambda:us-east-1:123456789012:function:my-function

Output:

{
  "result": "success"
}

Extract Status Code

lambda --jq '.status_code' --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-function

Output:

200

Extract Nested Fields

lambda --jq '.payload.result' --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-function

Output:

"success"

Combine with Environment Variables

export LAMBDA_JQ='.payload'
lambda --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-function

JSONL Batch Processing

Process multiple Lambda invocations in parallel from newline-delimited JSON input:

Sequential Processing (One at a Time)

cat payloads.jsonl | lambda --stdin --jsonl arn:aws:lambda:us-east-1:123456789012:function:my-function

Example 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}

Parallel Processing (5 Workers)

cat large-batch.jsonl | lambda --stdin --jsonl --parallel 5 arn:aws:lambda:us-east-1:123456789012:function:my-function

JSONL with jq Filtering

Extract only successful payloads:

cat payloads.jsonl | lambda --stdin --jsonl --jq '.payload' arn:aws:lambda:us-east-1:123456789012:function:my-function

JSONL with File Output

Save 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-function

Error Handling

JSONL 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}

Raw Binary Payloads

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-function

Note: Lambda receives the exact bytes sent. The Lambda function is responsible for interpreting the binary format.

Environment Variable Examples

Complete Configuration via Environment

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
lambda

Mix Environment Variables and Flags

export 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"}'

CI/CD Integration

# 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'

Output Format

Success Response

{
  "success": true,
  "status_code": 200,
  "payload": {
    // Lambda function response
  },
  "function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}

Error Response

{
  "success": false,
  "error": "error message here",
  "function_arn": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
}

Lambda Function Error

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"
}

AWS Authentication

This tool uses the AWS SDK v2 default credential chain, which checks the following sources in order:

  1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)
  2. Shared credentials file (~/.aws/credentials)
  3. Shared configuration file (~/.aws/config)
  4. IAM role for Amazon EC2
  5. IAM role for Amazon ECS tasks
  6. IAM role for AWS Lambda functions

Set your AWS credentials using any of these methods before using the tool.

Example: Using Environment Variables

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-function

Example: Using AWS Profile

export AWS_PROFILE=my-profile

lambda --payload '{}' arn:aws:lambda:us-east-1:123456789012:function:my-function

IAM Role Assumption

The 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

Requirements

To use role assumption, ensure:

  1. Base credentials have sts:AssumeRole permission for the target role
  2. Target role has a trust policy allowing your principal to assume it
  3. Target role has lambda:InvokeFunction permission for the function
  4. Role ARN follows the format: arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME

Configuration

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

How It Works

  1. Load default credentials via AWS SDK credential chain
  2. If --role-arn is specified, call STS AssumeRole with base credentials
  3. Cache assumed role credentials (automatic by AWS SDK)
  4. Create Lambda client with assumed role credentials
  5. Invoke Lambda function using assumed role permissions

Examples

Cross-Account Lambda Invocation

# 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

Temporary Elevated Permissions

# 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

CI/CD Pipeline with Role Assumption

# 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"}'

Debug Role Assumption

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-function

Error Handling

Common 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

Trust Policy Example

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"
    }
  ]
}

Exit Codes

  • 0: Success
  • 1: Error (details in JSON output)

Use Cases

Integration Testing

#!/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

CI/CD Pipeline

# .github/workflows/test.yml
- name: Trigger Lambda Test
  run: |
    lambda --payload '{"env":"staging"}' ${{ secrets.LAMBDA_ARN }} | jq

Batch Processing

# Process multiple payloads
for payload in payloads/*.json; do
  lambda --payload "$payload" arn:aws:lambda:us-east-1:123456789012:function:batch-processor
done

Async Fire-and-Forget

# Trigger Lambda without waiting for result
lambda --async --payload '{"notification":"sent"}' arn:aws:lambda:us-east-1:123456789012:function:notifier

Development

Build

go build -o lambda

Run Tests

go test ./...

Install Locally

go install

Project Structure

lambda/
├── 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

Requirements

  • Go 1.25.4 or later
  • AWS credentials configured
  • Lambda function ARN with appropriate IAM permissions

License

[Add your license here]

Contributing

[Add contribution guidelines here]

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages