Skip to main content
emnode / learn
Compliance

Configure event notifications and subscriptions

One capability across RDS clusters, instances, parameter groups, security groups and S3 buckets: wire the events that signal trouble into a destination something is actually listening to, so nobody finds out about a problem from a customer first.

13 min·10 sections·AWS

Last reviewed

Remediates AWS Security Hub: RDS.19RDS.20RDS.21RDS.22RDS.27S3.11

Event notifications: the basics

What does it mean for a resource to announce that something happened to it?

AWS resources constantly emit events about what is happening to them. RDS publishes engine-level events (a failover started, storage ran low, a parameter changed, an instance failed, a database was deleted) categorised under tags like availability, failure, maintenance, configuration change, deletion and low storage. S3 buckets emit object-level events when something is created, removed, restored or transitioned. By default these go nowhere useful: the RDS events land in a console event log nobody opens, and the S3 events evaporate. An event subscription or notification configuration is what pipes a chosen set of those events into a destination (an SNS topic, an SQS queue, a Lambda function, or EventBridge) where they can page on-call, post to Slack, or trigger automation.

AWS Security Hub turns this into several controls, which is why a single estate can fail multiple notification checks at once. RDS.27 checks whether the account has any RDS event subscription at all for critical instance events. RDS.19, RDS.20, RDS.21 and RDS.22 are the targeted versions: they evaluate existing subscriptions per source type and fail if the subscription omits the categories that matter for that type (clusters need maintenance and failure; instances need maintenance, configuration change and failure; parameter groups need configuration change; security groups need configuration change and failure). S3.11 checks whether a general-purpose bucket has any event notification configuration at all. They look like separate findings, but they are one capability: make sure the events that signal trouble are wired to something that is listening.

They are flagged because a silent resource is a detection blind spot. The whole point of the logging-and-monitoring category is that you cannot respond to what you cannot see. Most RDS incidents are visible to AWS minutes before they become customer-visible (the low storage warning fires hours before the disk fills), and an S3 bucket that cannot tell you when objects change cannot trigger a quarantine workflow or feed an audit trail. The dangerous state is sometimes not "no subscription" but "a subscription that looks complete but quietly omits the failure events."

In this lesson you will learn how AWS expresses events across RDS source types and S3 buckets, which categories actually matter on-call, and how to wire the right events to a destination something is listening to without breaking anything. You will see why RDS.27 (any subscription exists) differs from the targeted RDS.19 through RDS.22 controls, why the dangerous state is sometimes a subscription that exists but omits the failure events, and how EventBridge is the lowest-friction destination for S3. The Controls this lesson covers section lists every Security Hub control in this capability, each linking to a deep page with the exact check and a copy-and-paste fix.

Fun fact

The subscription that listened for everything except failures

RDS event categories are oddly granular: there are over a dozen for instances alone, including availability, backup, deletion, low storage, read replica and recovery. A team can build a perfectly real subscription that fires on backup and notification events and feel thoroughly monitored, while the failure category, the one that fires when an instance cannot recover, sits unchecked. AWS observed this pattern often enough to write a control for it: the dangerous state is not "no subscription", it is "a subscription that looks complete but quietly omits the events that signal a real incident." Separately, S3 event delivery has always been at-least-once with no hard latency guarantee, so the teams that get burned are the ones who watched a notification work once in a demo and assumed exactly-once, in-order delivery they were never promised.

Finding notification gaps across an estate

Marco is the database lead at a fintech. Security Hub fires notification findings across the estate: several production accounts have no RDS event subscription at all (RDS.27), one account has a subscription scoped to instances but missing the failure categories (RDS.20), and a customer-uploads bucket has no S3 event notifications (S3.11). The on-call team has been finding out about failovers from support tickets for months.

Before creating anything he reads what is already there, because the most common trap is a subscription that exists and looks like coverage but quietly omits the events that signal an incident.

Inspect every RDS event subscription and read the source type and the categories actually configured on each.

$ aws rds describe-event-subscriptions --query 'EventSubscriptionsList[].{Name:CustSubscriptionId,Source:SourceType,Enabled:Enabled,Categories:EventCategoriesList}' --output json
"Name": "rds-prod-alerts",
"Source": "db-instance",
"Enabled": true,
"Categories": [ "availability", "notification" ]
# Source is db-instance (correct), but maintenance, configuration change
# and failure are all missing, so RDS.20 fails on this subscription.

The subscription exists and is enabled, but its category list omits every category RDS.20 requires. A subscription existing is not the same as a subscription being useful.

How AWS evaluates event notificationsdeep dive

RDS publishes events from the control plane, the same stream that powers the console event log. A subscription is a server-side filter: pick a SourceType (db-instance, db-cluster, db-parameter-group, db-security-group), optionally pin to specific source IDs, and pick from a fixed list of event categories; matching events publish to your SNS topic. The controls evaluate the AWS::RDS::EventSubscription resource. RDS.27 is the broad check: it fails an account that has no critical-event subscription at all. RDS.19 through RDS.22 are targeted set-membership tests per source type: clusters must carry maintenance and failure, instances maintenance, configuration change and failure, parameter groups configuration change, security groups configuration change and failure. The exact category strings matter (RDS expects the space in configuration change), and satisfying all four targeted controls typically means four separate subscriptions, one per source type.

Two behaviours catch teams on the RDS side. First, the targeted controls pass vacuously when no subscription of that source type exists, so a brand-new account can look compliant with zero monitoring; the first subscription you create must carry the required categories or the finding fires immediately. Second, omitting --source-ids makes the subscription cover every current and future resource of that source type in the account, which is what makes these cheap to satisfy in perpetuity: one subscription per source type, never touched again.

S3.11 is a different shape: it evaluates a bucket's single notification configuration resource and fails when it is empty. Any one valid destination satisfies the base control. The permissions model is where first attempts fail: for SNS and SQS you must grant s3.amazonaws.com permission on the destination's own resource policy (scoped with aws:SourceArn to the bucket) before the put call will validate; for Lambda you add a resource-based permission. EventBridge is the exception and the lowest-friction destination, because enabling it (an empty configuration block) needs no destination policy at all. One optional parameter is worth knowing: an administrator can set a custom eventTypes list on S3.11, in which case a bucket that notifies but does not cover those exact event types still fails.

What is the impact of running without event notifications?

The first impact is mean-time-to-recovery. A Multi-AZ failover takes seconds to a couple of minutes, during which writes fail; AWS publishes the failover event the moment it begins. With a subscription the on-call is paged before customer reports arrive; without one, the first signal is usually an application error-rate alert minutes later, with no context about why. A low storage event fires hours before the disk fills and writes freeze; missed, it becomes an outage instead of a planned storage bump.

The second impact is silent risk. RDS deletion events fire when somebody runs a delete against production; an S3 bucket with no notifications cannot tell anyone when a sensitive object is overwritten or lands where it should not. Caught in seconds, a deleted database can be restored from the final snapshot and a suspicious upload quarantined; discovered later, the recovery window may already be narrowing or the modification already exploited. These notifications are also the unlock for whole classes of automation (virus-scanning uploads, triggering pipelines, replicating or indexing objects), so a silent resource is a capability gap as well as a detection gap.

On the compliance side, these controls map to continuous-monitoring requirements: SOC 2 CC7.2, ISO 27001 A.12.4, PCI DSS, and the NIST 800-53 CA-7 and SI-4 families. Auditors increasingly ask specifically about RDS event subscriptions and S3 event notifications as evidence, and "we check the console" is no longer a passing answer. There is no AWS bill impact, because the notifications are free; the cost is entirely operational and reputational, the cost of finding out about your own problems from your customers.

How do you wire up event notifications safely?

Work the capability as one loop. The order matters: see what exists, make sure the destination is real and confirmed, wire the events that matter, test the route end-to-end, and bake it into provisioning so the gap does not return.

1. Inventory existing subscriptions, notifications and destinations

Run describe-event-subscriptions across every region you run RDS in (subscriptions are regional) and read each one's source type and category list, not just whether it exists. Check each general-purpose bucket's notification configuration for the empty state that fails S3.11. While you are there, identify which SNS topic ops already uses for paging so you do not create a duplicate, and remember that a clean account with zero subscriptions passes the targeted RDS controls vacuously, which is compliant but not safe.

2. Wire the events that actually matter, account-wide

For RDS, create one subscription per source type (omitting --source-ids so it auto-covers current and future resources) carrying the required categories: instances need maintenance, configuration change and failure (RDS.20); clusters maintenance and failure (RDS.19); parameter groups configuration change (RDS.21); security groups configuration change and failure (RDS.22). For S3, route the bucket to EventBridge (an empty configuration block) where you want the lowest-friction fix and a central detection bus, or to SQS / Lambda / SNS for direct processing, granting the destination permission to S3 first.

3. Test the route end-to-end before you trust it

Do not trust a green API response. Trigger a harmless event and confirm the page or message actually arrives: reboot a non-production database to emit an availability event, or upload a test object to the bucket and watch the destination receive it. If nothing arrives, the gap is downstream (an SNS topic policy, an unconfirmed subscription, a broken PagerDuty integration), and you want to find it now rather than during a real incident. A configured-but-untested subscription is a false assurance.

4. Bake it into provisioning so the gap cannot return

Fix the source, not just the resources. Add the RDS event subscriptions to your account landing-zone template so new accounts have them from day one, and bake notification configuration into the bucket module so new buckets get at least EventBridge by default. Keep the matching AWS Config rules enabled so any drift (a deleted subscription, a new region without one, a new bucket with an empty configuration) generates a finding within minutes. Provisioning the monitoring before the resource is what stops these findings reappearing.

# One SNS topic, then one RDS subscription per source type with the required categories.
TOPIC=$(aws sns create-topic --name ops-pager --query TopicArn --output text)

aws rds create-event-subscription --subscription-name rds-instance-critical \
  --sns-topic-arn "$TOPIC" --source-type db-instance \
  --event-categories "maintenance" "configuration change" "failure" --enabled   # RDS.20

aws rds create-event-subscription --subscription-name rds-cluster-critical \
  --sns-topic-arn "$TOPIC" --source-type db-cluster \
  --event-categories "maintenance" "failure" --enabled                           # RDS.19

aws rds create-event-subscription --subscription-name rds-pg-critical \
  --sns-topic-arn "$TOPIC" --source-type db-parameter-group \
  --event-categories "configuration change" --enabled                            # RDS.21

aws rds create-event-subscription --subscription-name rds-sg-critical \
  --sns-topic-arn "$TOPIC" --source-type db-security-group \
  --event-categories "configuration change" "failure" --enabled                  # RDS.22

# S3: EventBridge is the lowest-friction destination, no per-bucket policy needed.
aws s3api put-bucket-notification-configuration --bucket acme-customer-uploads \
  --notification-configuration '{"EventBridgeConfiguration":{}}'                 # S3.11

# Then smoke-test the wire: reboot a non-prod DB and confirm the page lands.
aws rds reboot-db-instance --db-instance-identifier staging-postgres-1

Quick quiz

Question 1 of 5

Security Hub shows notification failures across RDS (RDS.27 and RDS.20) and S3 (S3.11). What is the most efficient way to think about them?

You can now treat event notifications as one capability rather than a scatter of findings: inventory what exists across RDS source types and S3 buckets, wire the events that signal trouble to a destination something is actually listening to, test the route end-to-end rather than trusting a green API response, and bake the configuration into account and bucket provisioning so the gap cannot return. The Controls this lesson covers section below links every control in this group to its deep page and fix.

Back to the library

Controls this lesson covers

One capability, many AWS Security Hub controls. This lesson is the shared playbook; each control below keeps its own deep page with the exact check, severity and a copy-and-paste fix.