Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: API Audit Logs #824

Merged
merged 11 commits into from
Sep 16, 2024
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 @@ -110,3 +110,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 @@ -174,7 +174,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
bryan-robitaille marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand All @@ -190,7 +190,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