Jira Event Forwarder

An AWS Lambda function that receives Jira Automation webhook events and forwards them to an SNS topic with structured metadata for filtering. Validates Bearer token authentication and restricts access to Atlassian egress IP ranges via an API Gateway resource policy.

The original Jira JSON payload is forwarded unchanged as the SNS message body.

Features

  • Bearer Token Authentication: Validates Authorization: Bearer <token> headers with constant-time comparison, supporting multiple tokens for zero-downtime rotation
  • Atlassian IP Restriction: API Gateway resource policy restricts access to Atlassian egress IP ranges (IPv4 and IPv6), fetched dynamically at deploy time
  • Structured Metadata: Extracts event type, project key, and issue type as SNS message attributes
  • SNS Subscription Filtering: Enables precise event routing to subscribers
  • Custom Domain: Optional custom domain with automatic TLS certificate management via ACM and Route53

Architecture

Single Lambda function handles the webhook processing:

  1. Handler - API Gateway endpoint (/webhook) that validates the Bearer token, extracts metadata from the Jira payload and request headers, and publishes to SNS

Prerequisites

  • AWS CLI configured with appropriate credentials (IAM permissions for Lambda, API Gateway, SNS, CloudFormation, CloudWatch Logs, and optionally Route53/ACM for custom domain)
  • Podman or Docker (for containerized SAM build/deploy)
  • Python 3.11 or later (for development)

Deployment

Build and deploy using containerized AWS SAM CLI:

cd jira-event-forwarder
make build     # Build Lambda package
make deploy    # First deployment (interactive/guided)
make redeploy  # Subsequent deployments (non-interactive)

Deployment outputs: ApiEndpoint - API Gateway endpoint URL (<api-endpoint>)

Custom Domain

Optional custom domain with automatic TLS certificate management (ACM + Route53). Requires a Route53 hosted zone. Deploy with CustomDomainName and HostedZoneId parameters - CloudFormation handles certificate creation, DNS validation, and configuration. Certificate validation takes 5-30 minutes; allow up to 1 hour for DNS propagation.

Parameters

Parameter Description Default
ResourcePrefix Prefix for resources myapp-prod
SnsTopicArn SNS topic ARN (required)
JiraWebhookTokens Jira webhook tokens (JSON array) []
SentryDsn Optional Sentry DSN ``
AtlassianIpv4Cidrs Atlassian egress IPv4 CIDRs (comma-list) ``
AtlassianIpv6Cidrs Atlassian egress IPv6 CIDRs (comma-list) ``
CustomDomainName Custom domain name ``
HostedZoneId Route53 hosted zone ``

Resource naming: Lambda and API resources follow {ResourcePrefix}-{type}-{name} pattern (e.g., myapp-prod-lambda-handler, myapp-prod-api).

Prerequisites: Requires an existing SNS topic. Deploy hummingbird-events-topic first to create the topic, then use its ARN for the SnsTopicArn parameter.

Usage

Jira Automation allows only one trigger per rule, and the “Multiple issue events” trigger does not expose which event fired. Since each event needs a distinct X-Jira-Event-Type header, configure 6 separate automation rules — one per event type:

Trigger X-Jira-Event-Type value
Created issue_created
Updated issue_updated
Deleted issue_deleted
Assigned issue_assigned
Transitioned issue_transitioned
Moved issue_moved

Each rule’s “Send web request” action:

  • URL: <api-endpoint>
  • Method: POST
  • Headers:
    • Authorization: Bearer <token> — enter the token value and click “Hidden” to mask it in the Jira Automation UI
    • X-Jira-Event-Type: <value from table above>
  • Body: “Issue data (Jira format)”

SNS Subscription Filter Examples:

All Jira issue events:

{
  "source": ["jira"]
}

Specific Jira event types:

{
  "source": ["jira"],
  "event_type": ["issue_created", "issue_updated"]
}

Events from a specific project:

{
  "source": ["jira"],
  "project_key": ["HUM"]
}

Development

See the main README for development workflows.

make setup     # Install dependencies
make check     # Lint code (ruff)
make fmt       # Format code
make test      # Run unit tests
make coverage  # Run tests with coverage

Configuration

Lambda function receives configuration via environment variables (automatically set by CloudFormation):

Variable Description
SNS_TOPIC_ARN SNS topic ARN
JIRA_WEBHOOK_TOKENS Jira webhook tokens (JSON array)
SENTRY_DSN Optional Sentry DSN
AWS_REGION AWS region (auto-set)

Event Metadata

The Lambda function extracts metadata from Jira webhook events and request headers, adding them as SNS message attributes:

Attribute Description Example
source Always "jira" jira
event_type From X-Jira-Event-Type header issue_created
project_key Jira project key HUM
issue_type Issue type name Story, Bug
content_encoding Compression format gzip+base64

The event_type attribute is set from the X-Jira-Event-Type request header. Each Jira Automation rule hardcodes the appropriate value for its trigger type in this header (see Usage). If the header is absent, the event_type attribute is omitted from the SNS message.

Security & Limitations

Security:

  • Bearer token validation via Authorization header with constant-time comparison (hmac.compare_digest)
  • API Gateway resource policy restricting source IPs to Atlassian egress ranges (IPv4 and IPv6 CIDRs both via aws:SourceIp), fetched dynamically at deploy time from ip-ranges.atlassian.com
  • Supports multiple active tokens for zero-downtime rotation
  • Missing or invalid tokens return HTTP 401; no configured tokens returns HTTP 500
  • SNS topic follows least privilege principle
  • CloudWatch logs capture all webhook deliveries (7-day retention)
  • Sentry integration for error tracking

Limitations:

  • Lambda timeout: 30 seconds
  • Lambda memory: 256 MB
  • Webhook payload size: Up to 6 MB (API Gateway limit)
  • SNS limits the compressed and base64-encoded message plus attributes to 256 KiB

The forwarder compresses the original JSON for SNS transport. Consumers that decode gzip+base64 receive the unchanged webhook payload.

License

This project is licensed under the GNU General Public License v3.0 or later - see the LICENSE file for details.