OCI Monitoring Notification Topics Should Have Active
More Info:
Notification topics must have at least one active subscription (e.g., Email, Slack, PagerDuty). An un-subscribed topic creates a black hole where critical security alerts are dropped.
Risk Level
Medium
Address
Compliance, Security
Compliance Standards
- APRA CPS 234 (Australia)
- AWS Well Architected Framework
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Using Console
To remediate “Monitoring Notification Topics Should Have Active Subscriptions” in OCI Alerting using the OCI Console, you need to add and confirm at least one active subscription to each Notification Topic used by alarms.
1. Identify the affected Notification Topics
- Sign in to the OCI Console.
- From the left menu, go to Observability & Management → Alarms.
- Check your alarms and note the Notification Topic (OCID or name) used in each alarm that is flagged in your scan/report.
2. Open the Notification Topic
- In the Console, go to Developer Services → Application Integration → Notifications
(in some UIs: Application Integration → Notifications directly). - Ensure the correct Compartment is selected.
- Click Topics.
- Locate and click the Topic used by your alarm (by name or OCID).
3. Create a Subscription for the Topic
- Inside the Topic details page, go to the Subscriptions tab.
- Click Create Subscription.
- Choose a Protocol, for example:
- PagerDuty
- Slack
- HTTPS (custom webhook)
- Function (OCI Functions)
- Enter the appropriate endpoint:
- Email: the email address that should receive alerts.
- HTTPS: the webhook URL.
- Slack/PagerDuty: the integration endpoint.
- Click Create.
4. Confirm/Activate the Subscription
The subscription must be confirmed for it to be considered active.
For Email:
- The specified address receives a confirmation email from OCI.
- Open the email and click the Confirm subscription link.
- After confirmation, go back to the Topic → Subscriptions tab and verify the Status is Active.
For HTTPS/Slack/PagerDuty:
- Ensure the endpoint correctly responds to OCI’s confirmation/handshake (if required).
- Check that the subscription status in OCI moves from Pending to Active.
- If it remains Pending, verify networking, SSL certificates, and endpoint behavior.
5. (Optional) Test the Alert Path
- From the Topic page, click Publish Message (or Publish to Topic) if available.
- Send a test message and confirm it reaches the configured endpoint (email, webhook, etc.).
6. Re‑run Compliance/Scan
Re-run your security/compliance tool or check after its next cycle to verify the finding is cleared: the topic now has at least one Active subscription.
Using CLI
Below are concise, CLI-focused steps to identify and remediate “OCI Monitoring Notification Topics Should Have Active Subscriptions” using the OCI CLI.
1. Prerequisites
- OCI CLI installed and configured (
oci setup configdone). - OCID of the compartment where topics exist.
- Appropriate IAM permissions for Notifications and Monitoring.
Assume:
COMPARTMENT_OCID="ocid1.compartment.oc1..xxxxx"
REGION="us-ashburn-1"
2. Find Notification Topics
oci ons topic list \
--compartment-id "$COMPARTMENT_OCID" \
--region "$REGION" \
--all \
--output table
This shows all topics and their OCIDs.
3. Check Topics for Active Subscriptions
For each topic, check subscriptions and their lifecycle state:
TOPIC_OCID="ocid1.onstopic.oc1..xxxxx"
oci ons subscription list \
--topic-id "$TOPIC_OCID" \
--region "$REGION" \
--all \
--output table
Look at lifecycle-state:
PENDING– not confirmed (email/SMS not activated).ACTIVE– good.- No subscriptions or none
ACTIVE– non-compliant.
To find non-compliant topics programmatically:
oci ons topic list \
--compartment-id "$COMPARTMENT_OCID" \
--region "$REGION" \
--all \
--raw-output \
--query "data[].{\"name\":name,\"id\":id}" > topics.json
while read -r line; do
TOPIC_ID=$(echo "$line" | jq -r '.id')
NAME=$(echo "$line" | jq -r '.name')
ACTIVE_COUNT=$(oci ons subscription list \
--topic-id "$TOPIC_ID" \
--region "$REGION" \
--all \
--raw-output \
--query "length(data[?\"lifecycle-state\"=='ACTIVE'])")
if [ "$ACTIVE_COUNT" -eq 0 ]; then
echo "Topic with no ACTIVE subscriptions: $NAME ($TOPIC_ID)"
fi
done <<<"$(jq -c '.[]' topics.json)"
4. Create a Subscription (Remediation)
4.1 Email Subscription Example
TOPIC_OCID="ocid1.onstopic.oc1..xxxxx"
EMAIL_ADDRESS="alerts@example.com"
oci ons subscription create \
--topic-id "$TOPIC_OCID" \
--protocol "EMAIL" \
--subscription-endpoint "$EMAIL_ADDRESS" \
--region "$REGION" \
--wait-for-state ACTIVE \
--wait-interval-seconds 5 \
--max-wait-seconds 300
Notes:
- The subscription will initially be
PENDING. - The recipient must click the confirmation link in the email for it to become
ACTIVE. - Using
--wait-for-state ACTIVEonly works once the confirmation is done; otherwise it will time out.
If you prefer not to wait:
oci ons subscription create \
--topic-id "$TOPIC_OCID" \
--protocol "EMAIL" \
--subscription-endpoint "$EMAIL_ADDRESS" \
--region "$REGION" \
--output table
4.2 Other Protocols (e.g., HTTPS)
oci ons subscription create \
--topic-id "$TOPIC_OCID" \
--protocol "HTTPS" \
--subscription-endpoint "https://your-endpoint.example.com/notify" \
--region "$REGION" \
--output table
5. Confirm Subscription Is Active
After confirming (via email or endpoint), check status:
oci ons subscription list \
--topic-id "$TOPIC_OCID" \
--region "$REGION" \
--all \
--query "data[].{\"endpoint\":\"endpoint\",\"protocol\":\"protocol\",\"state\":\"lifecycle-state\"}" \
--output table
Ensure at least one subscription shows state: ACTIVE.
6. (Optional) Bulk Remediation: Add a Standard Email to All Non-Compliant Topics
DEFAULT_EMAIL="alerts@example.com"
oci ons topic list \
--compartment-id "$COMPARTMENT_OCID" \
--region "$REGION" \
--all \
--raw-output \
--query "data[].id" > topic_ids.txt
while read -r TOPIC_ID; do
ACTIVE_COUNT=$(oci ons subscription list \
--topic-id "$TOPIC_ID" \
--region "$REGION" \
--all \
--raw-output \
--query "length(data[?\"lifecycle-state\"=='ACTIVE'])")
if [ "$ACTIVE_COUNT" -eq 0 ]; then
echo "Creating subscription on topic $TOPIC_ID"
oci ons subscription create \
--topic-id "$TOPIC_ID" \
--protocol "EMAIL" \
--subscription-endpoint "$DEFAULT_EMAIL" \
--region "$REGION" \
--output table
fi
done < topic_ids.txt
7. Validate Monitoring Alarms Use These Topics
List alarms and their destinations:
oci monitoring alarm list \
--compartment-id "$COMPARTMENT_OCID" \
--region "$REGION" \
--all \
--query "data[].{\"name\":display-name,\"topic\":destinations}" \
--output table
Ensure each topic OCID has at least one ACTIVE subscription as verified above.
These steps will remediate the policy “Notification Topics Should Have Active Subscriptions” for OCI Monitoring Alerting using the OCI CLI.
Using Python
To remediate “OCI Monitoring Notification Topics Should Have Active Subscriptions” using Python, you essentially need to:
- Find notification topics used by Monitoring (Alarm) rules.
- Check each topic’s subscriptions for at least one
ACTIVEsubscription. - For topics with no active subscriptions, create a new subscription (e.g., email or HTTPS).
Below is a concise step‑by‑step guide and example Python script using the OCI Python SDK.
1. Prerequisites
-
Python and SDK
pip install oci -
OCI Config
- Have
~/.oci/configconfigured with:- tenancy
- user
- fingerprint
- key_file
- region
- Or use instance principal / resource principal if running on OCI.
- Have
-
Permissions The principal (user or instance) must have policies that allow:
allow group <group-name> to read metrics-family in tenancyallow group <group-name> to manage ons-family in tenancyallow group <group-name> to read alarms in tenancy
2. High-Level Logic
- List all alarms (or alarms in a specific compartment).
- Extract the
destinations(OCIDs of notification topics) from each alarm. - For each topic:
- List subscriptions.
- Check if any subscription has
lifecycle_state == "ACTIVE".
- If no active subscription:
- Create a new subscription with:
protocol: e.g.,"EMAIL"or"HTTPS".endpoint: your email or webhook URL.
- Create a new subscription with:
Note: Email subscriptions require manual confirmation via the email link. Programmatically you can only create them; activation happens when the user clicks the link.
3. Example Python Script
Adjust the values in the CONFIG section to your environment.
import oci
from oci.monitoring import MonitoringClient
from oci.ons import NotificationControlPlaneClient
from oci.monitoring.models import ListAlarmsDetails
# ---------------- CONFIG ----------------
COMPARTMENT_OCID = "<your-compartment-ocid>" # alarms compartment
REGION = "<your-region>" # e.g., "us-ashburn-1"
# For remediation: what kind of subscription to create for empty topics
DEFAULT_SUB_PROTOCOL = "EMAIL" # or "HTTPS"
DEFAULT_SUB_ENDPOINT = "your-email@example.com" # or webhook URL
# ----------------------------------------
def get_client(config, service_client):
return service_client(config=config)
def list_alarm_topics(monitoring_client, compartment_id):
"""
Return a set of topic OCIDs used as destinations in all alarms in the compartment.
"""
topic_ocids = set()
list_alarms_details = oci.monitoring.models.ListAlarmsDetails(
compartment_id=compartment_id
)
response = monitoring_client.list_alarms(
compartment_id=compartment_id,
lifecycle_state="ACTIVE",
limit=1000,
)
for alarm in response.data:
# alarm.destinations is a list of topic OCIDs
if alarm.destinations:
for topic_ocid in alarm.destinations:
topic_ocids.add(topic_ocid)
return topic_ocids
def get_active_subscriptions(ons_client, topic_ocid):
"""
Return a list of ACTIVE subscriptions for the given topic.
"""
subs = []
list_subs_response = oci.pagination.list_call_get_all_results(
ons_client.list_subscriptions, topic_id=topic_ocid
)
for sub in list_subs_response.data:
if sub.lifecycle_state == "ACTIVE":
subs.append(sub)
return subs
def create_subscription_if_needed(ons_client, topic_ocid, protocol, endpoint):
"""
If topic has no ACTIVE subscriptions, create one using the given protocol and endpoint.
"""
active_subs = get_active_subscriptions(ons_client, topic_ocid)
if active_subs:
print(f"Topic {topic_ocid} already has {len(active_subs)} ACTIVE subscription(s).")
return
print(f"Topic {topic_ocid} has no ACTIVE subscriptions. Creating one...")
create_sub_details = oci.ons.models.CreateSubscriptionDetails(
topic_id=topic_ocid,
protocol=protocol,
endpoint=endpoint,
)
response = ons_client.create_subscription(create_sub_details)
sub = response.data
print(f"Created subscription {sub.id} with protocol={protocol}, endpoint={endpoint}")
print("NOTE: If protocol is EMAIL, the recipient must confirm via email for it to become ACTIVE.")
def main():
# Load config
config = oci.config.from_file("~/.oci/config", "DEFAULT")
config["region"] = REGION
# Create clients
monitoring_client = get_client(config, MonitoringClient)
ons_client = get_client(config, NotificationControlPlaneClient)
# 1. Get topics used by alarms
topics_in_alarms = list_alarm_topics(monitoring_client, COMPARTMENT_OCID)
print(f"Found {len(topics_in_alarms)} topic(s) referenced by alarms.")
# 2. Check each topic and remediate if needed
for topic_ocid in topics_in_alarms:
create_subscription_if_needed(
ons_client,
topic_ocid,
DEFAULT_SUB_PROTOCOL,
DEFAULT_SUB_ENDPOINT,
)
if __name__ == "__main__":
main()
4. How to Use
- Replace:
COMPARTMENT_OCIDREGIONDEFAULT_SUB_PROTOCOLDEFAULT_SUB_ENDPOINT
- Ensure your OCI config/policies are correct.
- Run:
python remediate_oci_topics.py
This will:
- Inspect all active alarms in the specified compartment.
- Identify their notification topics.
- Ensure each of those topics has at least one ACTIVE subscription (or at least a newly created one waiting for confirmation if email).
Using Terraform
# Create a notification topic (if not already managed in Terraform)
resource "oci_ons_notification_topic" "security_alerts_topic" {
compartment_id = var.COMPARTMENT_OCID # replace with your compartment OCID
name = "security-alerts" # replace with your topic display name
description = "Security alerts from OCI Monitoring"
}
# Add at least one active subscription to the topic (e.g., email)
resource "oci_ons_subscription" "security_alerts_email" {
compartment_id = var.COMPARTMENT_OCID # replace with your compartment OCID
topic_id = oci_ons_notification_topic.security_alerts_topic.id
protocol = "EMAIL" # or "HTTPS", "SLACK", "PAGERDUTY", etc.
endpoint = "SECURITY_TEAM_EMAIL@example.com" # replace with the destination address/URL
# Optional: freeform or defined tags if your org requires them
# freeform_tags = {
# Owner = "SECURITY_TEAM"
# }
}
# Example: wire Monitoring Alarm to use this topic
resource "oci_monitoring_alarm" "critical_security_alarm" {
compartment_id = var.COMPARTMENT_OCID
display_name = "critical-security-alarm"
namespace = "oci_vcn" # replace as appropriate
query = "CpuUtilization[1m].mean() > 90" # replace with your query
severity = "CRITICAL"
is_enabled = true
destinations = [
oci_ons_notification_topic.security_alerts_topic.id
]
# other required arguments...
}
Substitute:
var.COMPARTMENT_OCIDwith your compartment OCID (or a literal OCID string).SECURITY_TEAM_EMAIL@example.comwith the real email (or HTTPS/Slack/PagerDuty endpoint).- Adjust the alarm’s
namespaceandqueryto match your actual Monitoring configuration.
No existing topics are destroyed; adding oci_ons_subscription is non‑destructive and does not force replacement of the topic or alarms.
For verification, terraform plan should show:
- Creation of one or more
oci_ons_subscriptionresources attached to eachoci_ons_notification_topicthat previously had no subscriptions, and - No planned destruction or recreation of the existing
oci_ons_notification_topicresources.