Skip to content

Commit

Permalink
Merge branch 'main' into dev-1983-and-dev-1986
Browse files Browse the repository at this point in the history
  • Loading branch information
tommaso1 authored Dec 2, 2024
2 parents 4096551 + 4556149 commit edcec2a
Show file tree
Hide file tree
Showing 30 changed files with 1,347 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/silly-geese-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"infrastructure": minor
---

Implemented active campaign syncer infrastructure
5 changes: 5 additions & 0 deletions .changeset/soft-socks-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"infrastructure": minor
---

Langfuse infrastructure implemented
79 changes: 79 additions & 0 deletions .github/workflows/deploy_ac_sync_lambda.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Deploy Lambda Active Campaign Syncer

on:
push:
branches:
- "main"
paths:
- "packages/active-campaign-client/**"
- ".github/workflows/deploy_ac_sync_lambda.yaml"
workflow_dispatch:
inputs:
environment:
description: 'Choose environment'
type: choice
required: true
default: dev
options:
- dev
- prod

jobs:
build:
runs-on: ubuntu-22.04

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup node
uses: actions/setup-node@v3
with:
node-version: '20.x'

- name: Install dependencies
shell: bash
run: npm install

- name: Build
working-directory: packages/active-campaign-client
run: npm run build

- name: Package
working-directory: packages/active-campaign-client/dist
run: zip -r function.zip .

- name: Archive build artifacts
uses: actions/upload-artifact@v3
with:
name: active-campaign-client
path: packages/active-campaign-client/dist/function.zip

deploy:
name: Deploy Lambda Active Campaign Syncer
runs-on: ubuntu-22.04
needs: build

environment: ${{ github.event.inputs.environment || 'dev' }}
permissions:
id-token: write
contents: read

steps:
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: active-campaign-client
path: ./packages/active-campaign-client/target

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: ${{ secrets.DEPLOY_IAM_ROLE }}
aws-region: eu-south-1

- name: Deploy Lambda function (${{ github.event.inputs.environment || 'dev' }})
run: |
aws lambda update-function-code \
--function-name ac-${{ github.event.inputs.environment || 'dev' }}-sync-lambda \
--zip-file fileb://packages/active-campaign-client/target/function.zip
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -409,5 +409,8 @@ apps/chatbot/empty_htmls.json

/results

# terraform
apps/infrastructure/src/builds

## Python ##
__pycache__/
11 changes: 11 additions & 0 deletions apps/infrastructure/src/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ module "chatbot" {
security_groups = module.cms.security_groups
dns_domain_name = var.dns_domain_name
ecs_redis = var.chatbot_ecs_redis
ecs_monitoring = var.chatbot_ecs_monitoring
}

module "cicd" {
Expand All @@ -145,3 +146,13 @@ module "cicd" {
website_bucket = module.website.website_bucket
website_cdn = module.website.website_cdn
}

module "active_campaign" {
source = "./modules/active_campaign"

environment = var.environment
tags = var.tags

cognito_user_pool = module.website.cognito_user_pool
webinar_subscriptions_ddb_stream_arn = module.website.webinar_subscriptions_ddb_stream_arn
}
1 change: 1 addition & 0 deletions apps/infrastructure/src/modules/active_campaign/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_caller_identity" "current" {}
67 changes: 67 additions & 0 deletions apps/infrastructure/src/modules/active_campaign/eventbridge.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# EventBridge Pipe for DynamoDB Stream -> SQS FIFO
resource "aws_pipes_pipe" "dynamodb_to_sqs" {
name = "${local.prefix}-webinar-subscriptions-pipe"
source = var.webinar_subscriptions_ddb_stream_arn
target = aws_sqs_queue.fifo_queue.arn
role_arn = aws_iam_role.pipes_role.arn

log_configuration {
include_execution_data = ["ALL"]
level = "ERROR"
cloudwatch_logs_log_destination {
log_group_arn = aws_cloudwatch_log_group.pipe.arn
}
}

source_parameters {
dynamodb_stream_parameters {
batch_size = 1
starting_position = "LATEST"
}
}

target_parameters {
input_template = <<EOF
{
"detail": {
"eventName": "Dynamo<$.eventName>",
"additionalEventData": {
"sub": "<$.dynamodb.Keys.username.S>"
}
},
"webinarId": "<$.dynamodb.Keys.webinarId.S>"
}
EOF
sqs_queue_parameters {
message_group_id = local.sqs_message_group_id
}
}
}

resource "aws_cloudwatch_log_group" "pipe" {
name = "${local.prefix}-webinar-subscriptions-pipe"
retention_in_days = 30
}

# EventBridge Rule to Capture Cognito Events
resource "aws_cloudwatch_event_rule" "cognito_events" {
name = "${local.prefix}-cognito-events-rule"
event_pattern = jsonencode({
source = ["aws.cognito-idp"]
detail-type = ["AWS API Call via CloudTrail"],
detail = {
eventSource = ["cognito-idp.amazonaws.com"],
eventName = ["UpdateUserAttributes", "DeleteUser", "ConfirmSignUp"]
}
})
}

resource "aws_cloudwatch_event_target" "cognito_events_sqs" {
target_id = aws_sqs_queue.fifo_queue.name
rule = aws_cloudwatch_event_rule.cognito_events.name
arn = aws_sqs_queue.fifo_queue.arn

sqs_target {
message_group_id = local.sqs_message_group_id
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports.handler = async (event, context) => {
console.log("EVENT: \n" + JSON.stringify(event, null, 2));
return context.logStreamName;
};
95 changes: 95 additions & 0 deletions apps/infrastructure/src/modules/active_campaign/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
resource "aws_iam_role" "pipes_role" {
name = "${local.prefix}-webinar-subscriptions-pipe-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "pipes.amazonaws.com"
}
}
]
})
}

resource "aws_iam_policy" "pipes" {
name = "${local.prefix}-webinar-subscriptions-pipe-policy"
description = "Policy to allow webinar subscriptions pipe to deploy website"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams"
]
Effect = "Allow"
Resource = [
var.webinar_subscriptions_ddb_stream_arn
]
},
{
Action = [
"sqs:SendMessage"
]
Effect = "Allow"
Resource = [
aws_sqs_queue.fifo_queue.arn
]
},
{
Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
Effect = "Allow",
Resource = aws_cloudwatch_log_group.pipe.arn
}
]
})
}

resource "aws_iam_role_policy_attachment" "pipes" {
role = aws_iam_role.pipes_role.name
policy_arn = aws_iam_policy.pipes.arn
}

# Lambda function
resource "aws_iam_policy" "lambda_policy" {
name = "${local.prefix}-sync-lambda-policy"
description = "Lambda policy for accessing SQS and logging"

policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"],
Effect = "Allow",
Resource = [aws_sqs_queue.fifo_queue.arn, aws_sqs_queue.fifo_dlq_queue.arn]
},
{
Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
Effect = "Allow",
Resource = "arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:log-group:*${local.prefix}*"
},
{
Action = ["ssm:GetParameter", "ssm:GetParameters"]
Effect = "Allow"
Resource = ["arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/ac/*"]
}
]
})
}

resource "aws_iam_role_policy_attachment" "lambda_policy_attach" {
role = module.lambda_sync.lambda_role_name
policy_arn = aws_iam_policy.lambda_policy.arn
}

resource "aws_iam_role_policy_attachment" "lambda_cognito_policy_attach" {
role = module.lambda_sync.lambda_role_name
policy_arn = "arn:aws:iam::aws:policy/AmazonCognitoReadOnly"
}
63 changes: 63 additions & 0 deletions apps/infrastructure/src/modules/active_campaign/lambda.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Lambda Function for SQS FIFO
module "lambda_sync" {
source = "git::github.com/terraform-aws-modules/terraform-aws-lambda.git?ref=9633abb6b6d275d3a28604dbfa755098470420d4" # v6.5.0

function_name = "${local.prefix}-sync-lambda"
description = "Lambda function that syncs Active Campaign"

environment_variables = {
AC_API_KEY_PARAM = module.active_campaign_api_key.ssm_parameter_name
AC_BASE_URL_PARAM = module.active_campaign_base_url.ssm_parameter_name
COGNITO_USER_POOL_ID = var.cognito_user_pool.id
}

runtime = "nodejs20.x"
architectures = ["x86_64"]

handler = "index.handler"
source_path = "${path.module}/functions"
ignore_source_code_hash = true
create_current_version_allowed_triggers = false

timeout = 15
memory_size = 256

event_source_mapping = {
sqs = {
event_source_arn = aws_sqs_queue.fifo_queue.arn
batch_size = 1
scaling_config = {
maximum_concurrency = 2
}
}
}

allowed_triggers = {
sqs = {
principal = "sqs.amazonaws.com"
source_arn = aws_sqs_queue.fifo_queue.arn
}
}

tags = var.tags
}

module "active_campaign_api_key" {
source = "git::https://github.com/terraform-aws-modules/terraform-aws-ssm-parameter.git?ref=77d2c139784197febbc8f8e18a33d23eb4736879" # v1.1.0

name = "/ac/api_key"
value = "Substitute with real api key from the console"
type = "SecureString"
secure_type = true
ignore_value_changes = true
}

module "active_campaign_base_url" {
source = "git::https://github.com/terraform-aws-modules/terraform-aws-ssm-parameter.git?ref=77d2c139784197febbc8f8e18a33d23eb4736879" # v1.1.0

name = "/ac/base_url"
value = "Substitute with real api key from the console"
type = "SecureString"
secure_type = true
ignore_value_changes = true
}
5 changes: 5 additions & 0 deletions apps/infrastructure/src/modules/active_campaign/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
locals {
prefix = "${var.module}-${var.environment}"

sqs_message_group_id = "userEvents"
}
Loading

0 comments on commit edcec2a

Please sign in to comment.