Skip to content

Commit

Permalink
init terraform module
Browse files Browse the repository at this point in the history
  • Loading branch information
dasfmi committed Oct 9, 2024
0 parents commit 23714b3
Show file tree
Hide file tree
Showing 25 changed files with 683 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @SollyzDev
24 changes: 24 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: CI

on: [push]

permissions:
id-token: write
contents: read

env:
YQ_VERSION: "4.25.1"
LAMBDA_ZIP_VERSION: "v1.2.0"
LAMBDA_ZIP_BUCKET: "axiom-cloudformation-dev"
LAMBDA_ZIP_KEY: "axiom-cloudwatch-forwarder/$LAMBDA_ZIP_VERSION/forwarder.zip"

jobs:
terraform:
name: "terraform fmt"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Terraform Format
id: fmt
run: terraform fmt -recursive -check
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Axiom CloudWatch Forwarder

<a href="https://axiom.co">
<picture>
<source media="(prefers-color-scheme: dark) and (min-width: 600px)" srcset="https://axiom.co/assets/github/axiom-github-banner-light-vertical.svg">
<source media="(prefers-color-scheme: light) and (min-width: 600px)" srcset="https://axiom.co/assets/github/axiom-github-banner-dark-vertical.svg">
<source media="(prefers-color-scheme: dark) and (max-width: 599px)" srcset="https://axiom.co/assets/github/axiom-github-banner-light-horizontal.svg">
<img alt="Axiom.co banner" src="https://axiom.co/assets/github/axiom-github-banner-dark-horizontal.svg" align="right">
</picture>
</a>
&nbsp;

[![CI](https://github.com/axiomhq/axiom-cloudwatch-forwarder/actions/workflows/ci.yaml/badge.svg)](https://github.com/axiomhq/axiom-cloudwatch-forwarder/actions/workflows/ci.yaml)

Axiom CloudWatch Forwarder is a set of easy-to-use AWS CloudFormation stacks designed to forward logs from Amazon CloudWatch to [Axiom](https://axiom.co). It includes a Lambda function to handle the forwarding and stacks to create CloudWatch log group subscription filters for both existing and future log groups.

## Documentation

For more information about how to set up and use the Axiom CloudWatch Forwarder, see the [Axiom documentation](https://axiom.co/docs/send-data/cloudwatch).
3 changes: 3 additions & 0 deletions modules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# terraform-aws-axiom

Setup required infrastructure and install Axiom Enterprise on AWS using Terraform.
14 changes: 14 additions & 0 deletions modules/forwarder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Axiom Cloudwatch Forwarder

Forward logs from AWS Cloudwatch to Axiom.

## Setup

```hcl
module "forwarder" {
source = "https://github.com/axiomhq/axiom-cloudwatch-forwarder/tree/main/modules/forwarder"
prefix = "axiom-cloudwatch-forwarder"
axiom_dataset = "DATASET_NAME"
axiom_token = "xaat-***"
}
```
3 changes: 3 additions & 0 deletions modules/forwarder/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "aws_region" "current" {}

data "aws_caller_identity" "current" {}
66 changes: 66 additions & 0 deletions modules/forwarder/forwarder.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
resource "aws_lambda_function" "forwarder" {
s3_bucket = var.lambda_zip_bucket
s3_key = "axiom-cloudwatch-forwarder/v${var.lambda_zip_version}/forwarder.zip"
function_name = "${var.prefix}-forwarder"
logging_config {
log_format = "JSON"
log_group = aws_cloudwatch_log_group.forwarder.name
}
handler = "forwarder.lambda_handler"
runtime = "python3.9"
role = aws_iam_role.forwarder.arn

environment {
variables = {
AXIOM_TOKEN = var.axiom_token
AXIOM_DATASET = var.axiom_dataset
AXIOM_URL = var.axiom_url
}
}

tags = {
PartOf = var.prefix
Platform = "Axiom"
Component = "axiom-cloudwatch-forwarder"
}
}

resource "aws_iam_role" "forwarder" {
name = "${var.prefix}-forwarder-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = "sts:AssumeRole"
},
]
})

tags = {
PartOf = var.prefix
Platform = "Axiom"
Component = "axiom-cloudwatch-forwarder"
}
}

resource "aws_cloudwatch_log_group" "forwarder" {
name = "/aws/axiom/${var.prefix}-forwarder"
retention_in_days = 1
tags = {
PartOf = var.prefix
Platform = "Axiom"
Component = "axiom-cloudwatch-forwarder"
}
}

resource "aws_lambda_permission" "allow_cloudwatch" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.forwarder.function_name
principal = "logs.amazonaws.com"
source_arn = format("arn:aws:logs:%s:%s:log-group:*:*", data.aws_region.current.name, data.aws_caller_identity.current.account_id)
}
3 changes: 3 additions & 0 deletions modules/forwarder/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "lambda_arn" {
value = aws_lambda_function.forwarder.arn
}
8 changes: 8 additions & 0 deletions modules/forwarder/terraform.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
34 changes: 34 additions & 0 deletions modules/forwarder/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
variable "prefix" {
type = string
description = "Prefix for resources, defaults to axiom-cloudwatch"
default = "axiom-cloudwatch"
}

variable "lambda_zip_bucket" {
type = string
description = "Name of the S3 bucket where Lambda code is stored"
default = "axiom-cloudformation"
}

variable "lambda_zip_version" {
type = string
description = "Version of the Axiom Lambda"
default = "1.2.0"
}

variable "axiom_dataset" {
type = string
description = "Axiom dataset to forward logs to"
}

variable "axiom_token" {
type = string
description = "Axiom token for the dataset"
}

variable "axiom_url" {
type = string
description = "Axiom's API URL"
default = "https://api.axiom.co"
}

14 changes: 14 additions & 0 deletions modules/listener/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Axiom Cloudwatch Forwarder - Listener

This module sets up a lambda function that listens to Cloudwatch logs and subscribers the Axiom's Forwarder to these groups.

## Setup

```hcl
module "listener" {
source = "https://github.com/axiomhq/axiom-cloudwatch-forwarder/tree/main/modules/listener"
prefix = "axiom-cloudwatch-forwarder"
forwarder_lambda_arn = module.forwarder.lambda_arn
log_groups_prefix = "/aws/lambda/"
}
```
1 change: 1 addition & 0 deletions modules/listener/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_caller_identity" "current" {}
116 changes: 116 additions & 0 deletions modules/listener/listener.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
resource "aws_lambda_function" "listener" {
s3_bucket = var.lambda_zip_bucket
s3_key = "axiom-cloudwatch-forwarder/v${var.lambda_zip_version}/forwarder.zip"
function_name = "${var.prefix}-listener"
description = "Axiom CloudWatch Automatic log groups listener lambda"
logging_config {
log_format = "JSON"
log_group = aws_cloudwatch_log_group.listener.name
}
handler = "listener.lambda_handler"
runtime = "python3.9"
role = aws_iam_role.listener.arn
timeout = 300

environment {
variables = {
"AXIOM_CLOUDWATCH_FORWARDER_LAMBDA_ARN" = var.forwarder_lambda_arn
"LOG_GROUP_PREFIX" : var.log_groups_prefix
}
}

tags = {
PartOf = var.prefix
Platform = "Axiom"
Component = "axiom-cloudwatch-listener"
}
}

resource "aws_lambda_permission" "allow_cloudwatch" {
statement_id = "AllowExecutionFromEventBridge-${var.prefix}"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.listener.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.logs.arn
}

resource "aws_iam_role" "listener" {
name = "${var.prefix}-listener-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = "sts:AssumeRole"
},
]
})

tags = {
PartOf = var.prefix
Platform = "Axiom"
Component = "axiom-cloudwatch-listener"
}
}

data "aws_iam_policy_document" "listener" {
statement {
actions = [
"logs:DescribeSubscriptionFilters",
"logs:DeleteSubscriptionFilter",
"logs:PutSubscriptionFilter",
"logs:DescribeLogGroups",
"logs:CreateLogStream",
"logs:PutLogEvents",
"lambda:AddPermission",
"lambda:RemovePermission",
"lambda:InvokeFunction",
"lambda:GetFunction",
"logs:DescribeLogStreams",
"logs:DescribeSubscriptionFilters",
"logs:FilterLogEvents",
"logs:GetLogEvents",
"logs:CreateLogStream",
"logs:PutLogEvents"
]

resources = ["*"]
}
}
resource "aws_iam_role_policy" "listener" {
name = "default"
role = aws_iam_role.listener.id
policy = data.aws_iam_policy_document.listener.json
}

resource "aws_cloudwatch_log_group" "listener" {
name = "/aws/axiom/${var.prefix}-listener"
retention_in_days = 1
tags = {
PartOf = var.prefix
Platform = "Axiom"
Component = "axiom-cloudwatch-listener"
}
}

resource "aws_cloudwatch_event_rule" "logs" {
name = "${var.prefix}-log-groups-auto-subscription-rule"
description = "Axiom log group auto subscription event rule."
event_pattern = jsonencode({
source = ["aws.logs"]
detail-type = ["AWS API Call via CloudTrail"]
detail = {
eventSource = ["logs.amazonaws.com"]
eventName = ["CreateLogGroup"]
}
})
}

resource "aws_cloudwatch_event_target" "listener" {
target_id = aws_lambda_function.listener.function_name
arn = aws_lambda_function.listener.arn
rule = aws_cloudwatch_event_rule.logs.name
}
8 changes: 8 additions & 0 deletions modules/listener/terraform.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
28 changes: 28 additions & 0 deletions modules/listener/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
variable "prefix" {
type = string
default = "axiom-cloudwatch"
description = "Prefix for resources, defaults to axiom-cloudwatch"
}

variable "lambda_zip_bucket" {
type = string
description = "Name of the S3 bucket where Lambda code is stored"
default = "axiom-cloudformation"
}

variable "lambda_zip_version" {
type = string
description = "Version of the Axiom Lambda"
default = "1.2.0"
}

variable "forwarder_lambda_arn" {
type = string
description = "The ARN of the Lambda function that forwards logs to Axiom"
}

variable "log_groups_prefix" {
type = string
description = "The prefix of the CloudWatch log groups that will trigger the Axiom CloudWatch Forwarder Lambda"
default = ""
}
15 changes: 15 additions & 0 deletions modules/subscriber/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Axiom Cloudwatch Forwarder - Subscriber

Creates a Lambda function that subscribers the Forwarder to AWS Cloudwatch log groups.

## Setup

```hcl
module "subscriber" {
source = "https://github.com/axiomhq/axiom-cloudwatch-forwarder/tree/main/modules/subscriber"
prefix = "axiom-cloudwatch-forwarder"
axiom_dataset = "DATASET_NAME"
log_groups_prefix = "/aws/lambda/"
forwarder_lambda_arn = module.forwarder.lambda_arn
}
```
15 changes: 15 additions & 0 deletions modules/subscriber/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
output "lambda_arn" {
value = aws_lambda_function.subscriber.arn
}

output "log_groups_names" {
value = var.log_groups_names
}

output "log_groups_prefix" {
value = var.log_groups_prefix
}

output "log_groups_pattern" {
value = var.log_groups_pattern
}
Loading

0 comments on commit 23714b3

Please sign in to comment.