AWS ClickOps Notifier Terraform Module
repository·main·Indexed 43 days ago
https://github.com/cloudandthings/terraform-aws-clickops-notifierA Terraform module that monitors CloudTrail logs to detect and notify users via Slack and MS Teams webhooks when manual actions are taken in the AWS Management Console. Supports both Organizational mode for AWS ControlTower Log Archive accounts and Standalone mode for single-account monitoring. Requires Terraform >= 0.15.0, AWS provider ~> 6.0, and Random provider ~> 3.4.
What's inside AWS ClickOps Notifier
- AWS ClickOps Notifier is a Terraform module designed to notify you when users perform actions directly in the AWS Management Console (often referred to as 'ClickOps'). It monitors CloudTrail events to detect manual console interactions.
Choose between Organizational and Standalone mode
mainThe module supports two deployment modes depending on your AWS architecture:
Organizational Mode: Designed for AWS ControlTower environments. It is intended to be deployed in the Log Archive account. Ensure your AWS credentials are configured for the Log Archive account before deployment.
Standalone Mode: Use this if your account is not part of an AWS Organization using centralized CloudTrail logging, or if you only want to monitor ClickOps within a single specific account.
Requirements for Standalone Mode:
- CloudTrail must be enabled in the account.
- CloudTrail must be configured to write logs to a CloudWatch Log Group.
- The deployment identity must have sufficient permissions to create a subscription filter on that CloudWatch Log Group.
Implement Hive-style dynamic partitioning in Kinesis Firehose
mainWhen setting up the
aws_kinesis_firehose_delivery_streamto work with the ClickOps Notifier, usedynamic_partitioning_configurationandprocessing_configurationto organize logs in S3 using Hive-style paths (e.g.,recipientAccountId=!{partitionKey...}).To achieve this, you must:
- Enable
dynamic_partitioning_configuration. - Use a
MetadataExtractionprocessor with aMetadataExtractionQuery(using JQ) to extract fields likerecipientAccountIdandawsRegionfrom the JSON log. - Use a
RecordDeAggregationprocessor if the input records are aggregated. - Use an
AppendDelimiterToRecordprocessor to ensure valid record separation in S3. - Define a
prefixusing Firehose interpolation variables to build the folder structure.
resource "aws_kinesis_firehose_delivery_stream" "extended_s3_stream" { name = local.naming_prefix destination = "extended_s3" extended_s3_configuration { # ... role and bucket config ... dynamic_partitioning_configuration { enabled = "true" } prefix = join("/", [ "data", "recipientAccountId=!{partitionKeyFromQuery:recipientAccountId}", "awsRegion=!{partitionKeyFromQuery:awsRegion}", "year=!{timestamp:yyyy}", "month=!{timestamp:MM}", "day=!{timestamp:dd}", "hour=!{timestamp:HH}", "" ]) processing_configuration { enabled = "true" processors { type = "RecordDeAggregation" parameters { parameter_name = "SubRecordType" parameter_value = "JSON" } } processors { type = "MetadataExtraction" parameters { parameter_name = "JsonParsingEngine" parameter_value = "JQ-1.6" } parameters { parameter_name = "MetadataExtractionQuery" parameter_value = "{recipientAccountId:.recipientAccountId, awsRegion:.awsRegion}" } } processors { type = "AppendDelimiterToRecord" } } } }- Enable
Deploy the ClickOps Notifier in Standalone Mode
mainTo use the ClickOps Notifier as a standalone module (rather than in organizational mode), you must set the
standaloneinput totrue. In this mode, you are responsible for providing the CloudTrail log group name and configuring your webhook endpoints for Slack and MS Teams.Key requirements for standalone mode:
- Set
standalone = true. - Provide
cloudtrail_log_group(the name of the CloudWatch Log Group used by your CloudTrail). - Define
webhooks_for_slack_notificationsandwebhooks_for_msteams_notificationsas maps where the key is a notification identifier and the value is the webhook URL. - Ensure the module
depends_onthe CloudTrail infrastructure to ensure logs are available.
module "clickops_notifications" { source = "../.." standalone = true naming_prefix = "my-prefix" webhooks_for_slack_notifications = { my-first-notification : "https://fake.com" } webhooks_for_msteams_notifications = { my-second-notification : "https://fake.com" } tags = { usage = "testing" } cloudtrail_log_group = "my-cloudtrail-log-group" depends_on = [ module.aws_cloudtrail ] }- Set
Configure SNS topic encryption with KMS
mainTo encrypt the SNS topic created by the module, you must provide a
kms_key_id_for_sns_topic. This requires creating anaws_kms_keyand anaws_iam_policy_documentthat grants the necessary permissions to the S3 bucket (to generate/decrypt data keys) and the root account (to manage the key).# To encrypt the SNS topic data "aws_caller_identity" "current" {} data "aws_iam_policy_document" "clickops_sns_topic" { statement { sid = "Enable IAM User Permissions" principals { type = "AWS" identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"] } actions = ["kms:*"] resources = ["*"] } statement { principals { type = "Service" identifiers = ["s3.amazonaws.com"] } actions = [ "kms:GenerateDataKey*", "kms:Decrypt" ] resources = ["*"] condition { test = "ArnEquals" variable = "aws:SourceArn" values = [aws_s3_bucket.test_bucket.arn] } condition { test = "StringEquals" variable = "aws:SourceAccount" values = [data.aws_caller_identity.current.account_id] } } } resource "aws_kms_key" "clickops_sns_topic" { description = "KMS key for SNS topic ${local.naming_prefix}" deletion_window_in_days = 7 policy = data.aws_iam_policy_document.clickops_sns_topic.json tags = local.tags }Customize excluded scoped actions
mainBy default, certain actions are excluded from alerts because they are either common console operations or can only be performed via the console.
You can modify this behavior using the following variables:
excluded_scoped_actions: A list of actions to exclude from notifications.excluded_scoped_actions_effect: Determines the effect of the exclusion (e.g., whether to allow or deny the exclusion logic).
Basic usage of the clickops_notifications module
mainThis example demonstrates how to implement a basic setup of the
clickops_notificationsmodule. It includes configuring Slack and MS Teams webhooks, providing a CloudTrail S3 bucket name, and optionally encrypting the SNS topic using a custom KMS key.Key configuration steps:
- Provide a
run_idto ensure resource uniqueness. - Set
cloudtrail_bucket_nameto the S3 bucket where CloudTrail logs are stored. - Define
webhooks_for_slack_notificationsandwebhooks_for_msteams_notificationsas maps of notification names to webhook URLs. - (Optional) Provide
kms_key_id_for_sns_topicto encrypt the SNS topic.
module "clickops_notifications" { source = "../../" naming_prefix = local.naming_prefix cloudtrail_bucket_name = aws_s3_bucket.test_bucket.id webhooks_for_slack_notifications = { my-first-notification : "https://fake.com" } webhooks_for_msteams_notifications = { my-second-notification : "https://fake.com" } tags = local.tags # Optional kms_key_id_for_sns_topic = aws_kms_key.clickops_sns_topic.arn }- Provide a
Use the clickops_notifications module to monitor an existing IAM role
mainThe
clickops_notificationsmodule can be configured to monitor an existing IAM role instead of creating a new one. To do this, setcreate_iam_role = falseand provide the existing role's ARN via theiam_role_arnargument. You must also provide thecloudtrail_bucket_namewhere logs are stored and arun_idto ensure resource uniqueness.module "clickops_notifications" { source = "../../" naming_prefix = local.naming_prefix cloudtrail_bucket_name = aws_s3_bucket.test_bucket.id webhooks_for_slack_notifications = { my-first-notification : "https://fake.com" } webhooks_for_msteams_notifications = { my-second-notification : "https://fake.com" } tags = local.tags create_iam_role = false iam_role_arn = aws_iam_role.test_role.arn }Configure the ClickOps Notifier in Standalone Mode
mainTo use the
clickops-notifiermodule in a standalone configuration (rather than within an organizational structure), set thestandalone = trueargument. You must provide anaming_prefixand link the module to your existing CloudTrail and Kinesis Firehose infrastructure.Key configuration requirements:
standalone = true: Enables standalone mode.naming_prefix: A string used to prefix resources.webhooks_for_slack_notifications: A map of notification names to Slack webhook URLs.webhooks_for_msteams_notifications: A map of notification names to MS Teams webhook URLs.cloudtrail_log_group: The name of the CloudWatch Log Group associated with your CloudTrail.firehose_delivery_stream_name: The name of the Kinesis Firehose delivery stream used for processing logs.
module "clickops_notifications" { source = "../.." standalone = true naming_prefix = local.naming_prefix webhooks_for_slack_notifications = { my-first-notification : "https://fake.com" } webhooks_for_msteams_notifications = { my-second-notification : "https://fake.com" } tags = local.tags cloudtrail_log_group = local.naming_prefix_cloudtrail firehose_delivery_stream_name = aws_kinesis_firehose_delivery_stream.extended_s3_stream.name depends_on = [ module.aws_cloudtrail ] }Configure webhook notifications for Slack and MS Teams
mainThe module allows sending notifications to multiple Slack and MS Teams webhooks. You provide these via maps where the key is a descriptive name for the notification and the value is the webhook URL.
webhooks_for_slack_notifications: A map of Slack webhook names to URLs.webhooks_for_msteams_notifications: A map of MS Teams webhook names to URLs.
webhooks_for_slack_notifications = { my-first-notification : "https://fake.com" } webhooks_for_msteams_notifications = { my-second-notification : "https://fake.com" }Filter events by Account and User
mainThe notifier allows fine-grained control over which events trigger notifications using environment variables:
Account Filtering
EXCLUDED_ACCOUNTS: A JSON array of account identifiers to ignore. If an account matches an entry here, it is skipped.INCLUDED_ACCOUNTS: A JSON array of account identifiers to include. If this list is not empty, only accounts in this list will trigger notifications.
User Filtering
EXCLUDED_USERS: A JSON array of user emails to ignore.INCLUDED_USERS: A JSON array of user emails to include. If this list is not empty, only users in this list will trigger notifications.
Scoped Action Filtering
EXCLUDED_SCOPED_ACTIONS: A JSON array of specific actions to exclude from being flagged as ClickOps.
Configure the Firehose Delivery Stream
mainTo enable long-term storage or further processing of the detected ClickOps events, specify a Kinesis Data Firehose stream name using the
FIREHOSE_DELIVERY_STREAM_NAMEenvironment variable.If you want to disable Firehose delivery, set the environment variable to
__NONE__.FIREHOSE_DELIVERY_STREAM_NAME="my-clickops-delivery-stream" # OR to disable: FIREHOSE_DELIVERY_STREAM_NAME="__NONE__"