Skip to content

Commit

Permalink
feature: API Audit Logs (#824)
Browse files Browse the repository at this point in the history
  • Loading branch information
bryan-robitaille authored Sep 16, 2024
1 parent a3988e8 commit 401d6b9
Show file tree
Hide file tree
Showing 22 changed files with 461 additions and 150 deletions.
2 changes: 1 addition & 1 deletion aws/alarms/athena.tf
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ resource "aws_iam_role_policy" "athena_dynamodb_policy" {
"dynamodb:Scan",
"dynamodb:PartiQLSelect"
],
"Resource" : ["${var.dynamodb_audit_logs_arn}", "${lower(var.dynamodb_audit_logs_arn)}"]
"Resource" : ["${var.dynamodb_app_audit_logs_arn}", "${lower(var.dynamodb_app_audit_logs_arn)}"]
"Effect" : "Allow"
},
{
Expand Down
51 changes: 51 additions & 0 deletions aws/alarms/cloudwatch_api.tf
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,54 @@ resource "aws_cloudwatch_metric_alarm" "api_response_time_warn" {
}
}
}

#
# Audit Log Dead Letter Queue
#
resource "aws_cloudwatch_metric_alarm" "api_audit_log_dead_letter_queue_warn" {
alarm_name = "ApiAuditLogDeadLetterQueueWarn"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
threshold = "0"
alarm_description = "Detect when a message is sent to the API Audit Log Dead Letter Queue"
alarm_actions = [var.sns_topic_alert_warning_arn]

metric_query {
id = "e1"
expression = "RATE(m2+m1)"
label = "Error Rate"
return_data = "true"
}

metric_query {
id = "m1"

metric {
metric_name = "ApproximateNumberOfMessagesVisible"
namespace = "AWS/SQS"
period = "60"
stat = "Sum"
unit = "Count"

dimensions = {
QueueName = var.sqs_api_audit_log_deadletter_queue_arn
}
}
}

metric_query {
id = "m2"

metric {
metric_name = "ApproximateNumberOfMessagesNotVisible"
namespace = "AWS/SQS"
period = "60"
stat = "Sum"
unit = "Count"

dimensions = {
QueueName = var.sqs_api_audit_log_deadletter_queue_arn
}
}
}
}
4 changes: 2 additions & 2 deletions aws/alarms/cloudwatch_app.tf
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ resource "aws_cloudwatch_metric_alarm" "audit_log_dead_letter_queue_warn" {
unit = "Count"

dimensions = {
QueueName = var.sqs_audit_log_deadletter_queue_arn
QueueName = var.sqs_app_audit_log_deadletter_queue_arn
}
}
}
Expand All @@ -235,7 +235,7 @@ resource "aws_cloudwatch_metric_alarm" "audit_log_dead_letter_queue_warn" {
unit = "Count"

dimensions = {
QueueName = var.sqs_audit_log_deadletter_queue_arn
QueueName = var.sqs_app_audit_log_deadletter_queue_arn
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions aws/alarms/inputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,16 @@ variable "sqs_reliability_deadletter_queue_arn" {
type = string
}

variable "sqs_audit_log_deadletter_queue_arn" {
variable "sqs_app_audit_log_deadletter_queue_arn" {
description = "ARN of the Audit Log queue's SQS Dead Letter Queue"
type = string
}

variable "sqs_api_audit_log_deadletter_queue_arn" {
description = "ARN of the API Audit Log queue's SQS Dead Letter Queue"
type = string
}

variable "threshold_ecs_cpu_utilization_high" {
description = "ECS cluster CPU average use threshold, above which an alarm is triggered (4 minute period)"
type = string
Expand Down Expand Up @@ -251,7 +256,7 @@ variable "ecr_repository_url_notify_slack_lambda" {
type = string
}

variable "dynamodb_audit_logs_arn" {
variable "dynamodb_app_audit_logs_arn" {
description = "Audit Logs table ARN"
type = string
}
Expand Down
16 changes: 15 additions & 1 deletion aws/api/ecs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ module "api_ecs" {
data.aws_iam_policy_document.api_ecs_kms_vault.json,
data.aws_iam_policy_document.api_ecs_dynamodb_vault.json,
data.aws_iam_policy_document.api_ecs_s3_vault.json,
data.aws_iam_policy_document.api_ecs_secrets_manager_runtime.json
data.aws_iam_policy_document.api_ecs_secrets_manager_runtime.json,
data.aws_iam_policy_document.api_sqs.json
]

task_exec_role_policy_documents = [
Expand Down Expand Up @@ -158,3 +159,16 @@ data "aws_iam_policy_document" "api_ecs_secrets_manager" {
]
}
}
data "aws_iam_policy_document" "api_sqs" {
statement {
effect = "Allow"
actions = [
"sqs:GetQueueUrl",
"sqs:SendMessage"
]

resources = [
var.sqs_api_audit_log_queue_arn
]
}
}
7 changes: 6 additions & 1 deletion aws/api/inputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,9 @@ variable "rds_connection_url_secret_arn" {
description = "The RDS connection URL secret used by the ECS task"
type = string
sensitive = true
}
}
variable "sqs_api_audit_log_queue_arn" {
description = "SQS audit log queue ARN"
type = string
}

2 changes: 1 addition & 1 deletion aws/app/ecs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ data "template_file" "form_viewer_task" {
email_address_contact_us = var.email_address_contact_us
email_address_support = var.email_address_support
reprocess_submission_queue = var.sqs_reprocess_submission_queue_id
audit_log_queue_url = var.sqs_audit_log_queue_id
audit_log_queue_url = var.sqs_app_audit_log_queue_id
zitadel_provider = var.zitadel_provider
zitadel_administration_key = var.zitadel_administration_key_secret_arn
sentry_api_key = var.sentry_api_key_secret_arn
Expand Down
2 changes: 1 addition & 1 deletion aws/app/ecs_iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ data "aws_iam_policy_document" "forms_sqs" {

resources = [
var.sqs_reprocess_submission_queue_arn,
var.sqs_audit_log_queue_arn
var.sqs_app_audit_log_queue_arn
]
}
}
Expand Down
4 changes: 2 additions & 2 deletions aws/app/inputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,12 @@ variable "sqs_reprocess_submission_queue_id" {
type = string
}

variable "sqs_audit_log_queue_arn" {
variable "sqs_app_audit_log_queue_arn" {
description = "SQS audit log queue ARN"
type = string
}

variable "sqs_audit_log_queue_id" {
variable "sqs_app_audit_log_queue_id" {
description = "SQS audit log queue URL"
type = string
}
Expand Down
53 changes: 53 additions & 0 deletions aws/dynamodb/dynamo.tf
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,56 @@ resource "aws_dynamodb_table" "audit_logs" {
enabled = var.env == "local" ? false : true
}
}

resource "aws_dynamodb_table" "api_audit_logs" {
name = "ApiAuditLogs"
billing_mode = "PAY_PER_REQUEST"
hash_key = "UserID"
range_key = "Event#SubjectID#TimeStamp"
deletion_protection_enabled = true
stream_enabled = false # Can be removed in the future when this gets applied to production

attribute {
name = "UserID"
type = "S"
}

attribute {
name = "Event#SubjectID#TimeStamp"
type = "S"
}

attribute {
name = "TimeStamp"
type = "N"
}

attribute {
name = "Status"
type = "S"
}

global_secondary_index {
name = "UserByTime"
hash_key = "UserID"
range_key = "TimeStamp"
projection_type = "KEYS_ONLY"
}

global_secondary_index {
name = "StatusByTimestamp"
hash_key = "Status"
range_key = "TimeStamp"
projection_type = "ALL"
}

server_side_encryption {
enabled = true
kms_key_arn = var.kms_key_dynamodb_arn
}

point_in_time_recovery {
enabled = var.env == "local" ? false : true
}
}

18 changes: 14 additions & 4 deletions aws/dynamodb/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,22 @@ output "dynamodb_vault_stream_arn" {
value = aws_dynamodb_table.vault.stream_arn
}

output "dynamodb_audit_logs_arn" {
description = "Audit Logs table ARN"
output "dynamodb_app_audit_logs_arn" {
description = "App Audit Logs table ARN"
value = aws_dynamodb_table.audit_logs.arn
}

output "dynamodb_audit_logs_table_name" {
description = "Audit Logs table name"
output "dynamodb_app_audit_logs_table_name" {
description = "App Audit Logs table name"
value = aws_dynamodb_table.audit_logs.name
}

output "dynamodb_api_audit_logs_arn" {
description = "API Audit Logs table ARN"
value = aws_dynamodb_table.api_audit_logs.arn
}

output "dynamodb_api_audit_logs_table_name" {
description = "API Audit Logs table name"
value = aws_dynamodb_table.api_audit_logs.name
}
19 changes: 15 additions & 4 deletions aws/lambdas/audit_log.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ resource "aws_lambda_function" "audit_logs" {

environment {
variables = {
REGION = var.region
LOCALSTACK = var.localstack_hosted
REGION = var.region
LOCALSTACK = var.localstack_hosted
APP_AUDIT_LOGS_SQS_ARN = var.sqs_app_audit_log_queue_arn
API_AUDIT_LOGS_SQS_ARN = var.sqs_api_audit_log_queue_arn
}
}

Expand All @@ -31,8 +33,17 @@ resource "aws_lambda_function" "audit_logs" {
}
}

resource "aws_lambda_event_source_mapping" "audit_logs" {
event_source_arn = var.sqs_audit_log_queue_arn
resource "aws_lambda_event_source_mapping" "app_audit_logs" {
event_source_arn = var.sqs_app_audit_log_queue_arn
function_name = aws_lambda_function.audit_logs.arn
function_response_types = ["ReportBatchItemFailures"]
batch_size = 10
maximum_batching_window_in_seconds = 30
enabled = true
}

resource "aws_lambda_event_source_mapping" "api_audit_logs" {
event_source_arn = var.sqs_api_audit_log_queue_arn
function_name = aws_lambda_function.audit_logs.arn
function_response_types = ["ReportBatchItemFailures"]
batch_size = 10
Expand Down
2 changes: 1 addition & 1 deletion aws/lambdas/audit_logs_archiver.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ resource "aws_lambda_function" "audit_logs_archiver" {
variables = {
REGION = var.region
LOCALSTACK = var.localstack_hosted
AUDIT_LOGS_DYNAMODB_TABLE_NAME = var.dynamodb_audit_logs_table_name
AUDIT_LOGS_DYNAMODB_TABLE_NAME = var.dynamodb_app_audit_logs_table_name
AUDIT_LOGS_ARCHIVE_STORAGE_S3_BUCKET = var.audit_logs_archive_storage_id
}
}
Expand Down
6 changes: 4 additions & 2 deletions aws/lambdas/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,10 @@ data "aws_iam_policy_document" "lambda_dynamodb" {
var.dynamodb_vault_arn,
"${var.dynamodb_vault_arn}/index/*",
var.dynamodb_vault_stream_arn,
var.dynamodb_audit_logs_arn,
"${var.dynamodb_audit_logs_arn}/index/*"
var.dynamodb_app_audit_logs_arn,
"${var.dynamodb_app_audit_logs_arn}/index/*",
var.dynamodb_api_audit_logs_arn,
"${var.dynamodb_api_audit_logs_arn}/index/*"
]
}
}
Expand Down
21 changes: 18 additions & 3 deletions aws/lambdas/inputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ variable "sqs_reprocess_submission_queue_arn" {
type = string
}

variable "sqs_audit_log_queue_arn" {
variable "sqs_app_audit_log_queue_arn" {
description = "SQS audit log queue ARN"
type = string
}

variable "sqs_api_audit_log_queue_arn" {
description = "SQS Api audit log queue ARN"
type = string
}

variable "kms_key_cloudwatch_arn" {
description = "CloudWatch KMS key ARN, used by the ECS task's CloudWatch log group"
type = string
Expand Down Expand Up @@ -79,16 +84,26 @@ variable "dynamodb_relability_queue_arn" {
type = string
}

variable "dynamodb_audit_logs_arn" {
variable "dynamodb_app_audit_logs_arn" {
description = "Audit Logs table ARN"
type = string
}

variable "dynamodb_audit_logs_table_name" {
variable "dynamodb_app_audit_logs_table_name" {
description = "Audit Logs DynamodDB table name"
type = string
}

variable "dynamodb_api_audit_logs_arn" {
description = "API Audit Logs table ARN"
type = string
}

variable "dynamodb_api_audit_logs_table_name" {
description = "API Audit Logs DynamodDB table name"
type = string
}

variable "sns_topic_alert_critical_arn" {
description = "SNS topic ARN that critical alerts are sent to"
type = string
Expand Down
Loading

0 comments on commit 401d6b9

Please sign in to comment.