OCI Monitoring Should Have Access Denied Enumeration Alarm
More Info:
Detect high frequencies of Unauthorized API errors. This behavior maps to attackers or compromised scripts attempting to enumerate permissions and discover accessible resources
Risk Level
High
Address
Compliance, Security
Compliance Standards
- APRA CPS 234 (Australia)
- AWS Well Architected Framework
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AWS
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- Cloudanix Best Practice
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- HIPAA
- HITRUST CSF
- ISO 27001
- 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
- SOC2
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Using Console
Below are the steps to configure an Access Denied Enumeration alarm with OCI Monitoring using only the OCI Console. The idea is:
- Use Audit logs as source
- Use Service Connector to turn “access denied” events into a custom metric
- Create an Alarm on that custom metric
1. Confirm Audit Logs Are Enabled
Audit is on by default, but verify:
- In the OCI Console, open the Navigation menu.
- Go to Identity & Security → Audit.
- Select your tenancy / compartment.
- Confirm you can see recent audit events.
If not, check compartment/region filters.
2. Create (or Use) a Log for Audit Events
You need the Audit events to be in Logging so Service Connector can use them.
- Go to Logging → Logs.
- Click Create log.
- Choose:
- Log Group: select or create (e.g.,
security-log-group). - Log Name: e.g.,
audit-access-log. - Log Source: choose Service logs → Audit (or equivalent, depending on region/console updates).
- Log Group: select or create (e.g.,
- Save/enable the log.
Make sure the log receives Audit events (you should see entries after a few minutes).
3. Create a Service Connector to Produce a Custom Metric
- Go to Observability & Management → Service Connector Hub.
- Click Create service connector.
A. Basic Info
- Name: e.g.,
access-denied-metric-connector. - Compartment: choose the security/monitoring compartment.
B. Source
- Source type: Logging.
- Log Groups: select the log group used for Audit (e.g.,
security-log-group). - Logs: select your Audit log (e.g.,
audit-access-log).
C. Define Log Filter (only “access denied” events)
In the log filter, use a query that selects denied events, for example (adjust names as per your environment):
data.responseStatus = "FAILURE"
and
(
data.errorCode = "NotAuthorizedOrNotFound"
or data.errorCode = "NotAuthorized"
or data.responseMessage like "%NotAuthorized%"
or data.responseMessage like "%AccessDenied%"
)
(Use whatever fields you actually see in your Audit records; click on a log entry and check its JSON.)
D. Target
- Target type: Monitoring (Metric).
- Metric namespace: e.g.,
custom_security. - Metric name: e.g.,
access_denied_count. - Metric unit: e.g.,
count.
E. Metric Dimensions (recommended)
Add dimensions like:
principal→data.identity.userName(ordata.identity.principalName).sourceIp→data.request.clientIp.service→data.request.serviceName.operation→data.request.action.
(Use “Add dimension” and map them to the appropriate JSON fields via the UI.)
F. Metric Value
- Value expression:
1(each matching log = 1 event). - Aggregation: Sum.
- Review and Create the Service Connector.
- Make sure it’s Enabled and wait a few minutes; generate a few denied actions (e.g., deliberately try something you don’t have permission for) and confirm metrics later.
4. Validate the Custom Metric in Monitoring
- Go to Observability & Management → Monitoring → Metrics explorer.
- Namespace: select
custom_security. - Metric name: select
access_denied_count. - Time period: last 1 hour.
- You should see data points if the Service Connector is working and access-denied events occurred.
5. Create an Alarm on Access Denied Enumeration
- Go to Observability & Management → Alarms.
- Click Create alarm.
A. Basic Details
- Name: e.g.,
Access-Denied-Enumeration-Alarm. - Compartment: choose appropriate (same where metric is visible).
- Severity: e.g., Critical or Warning depending on policy.
B. Alarm Query
Example queries targeting enumeration behavior (lots of denies in a short time):
Simple total count across tenancy:
custom_security, metricName = "access_denied_count"[5m].sum() > 20
This triggers when more than 20 denied events occur in 5 minutes.
Per principal (better for detecting brute-force / enumeration):
custom_security, metricName = "access_denied_count"
{principal = "*"}[5m].sum() > 10
Adjust thresholds and window to your policy (e.g., 10 denies in 5 minutes per principal).
C. Trigger Rule & Window
- Statistic: Sum.
- Interval: e.g., 1 minute.
- Trigger delay: e.g., 1 evaluation period (or as desired).
D. Notifications
-
Under Notification destinations, select or create a Notification Topic (OCI Notifications).
-
If creating a new topic:
- Go to Application Integration → Notifications → Topics (or use the inline option).
- Create topic (e.g.,
security-alerts-topic). - Subscribe an Email, Slack/HTTPS, or PagerDuty endpoint.
- Confirm the subscription by clicking the link in the confirmation email.
-
Back in the alarm, select this topic as the destination.
E. Enable Alarm
- Ensure Alarm state is set to Enabled.
- Click Create alarm.
6. Test the Alarm
- Generate several intentional access-denied events (e.g., use an IAM user with minimal privileges and attempt multiple unauthorized operations).
- Wait for:
- The audit logs to capture events.
- The Service Connector to convert them into metrics (usually within a couple of minutes).
- The alarm to evaluate and potentially fire.
- Confirm you receive a notification and the alarm status changes to FIRING in the console.
If you share your current log sample (an example Audit log JSON) and your preferred threshold (e.g., “more than X denied requests in Y minutes per principal”), I can give an exact filter expression and alarm query tailored to your tenancy.
Using CLI
Below is a practical way to remediate this using OCI Monitoring + OCI CLI: create an alarm on a metric that tracks access‑denied (“AuthorizationFailure”) activity.
Because Monitoring works on metrics, you need either:
- A custom metric that counts access‑denied events from Audit logs, or
- An existing metric from your logging/ SIEM pipeline that already does this.
The CLI part is the same once the metric exists.
1. Prerequisites
- OCI CLI installed and configured
oci iam user whoami
- Notification Topic (for alerts)
- Create a topic if you don’t have one:
oci ons topic create \
--name "security-alerts-topic" \
--compartment-id <COMPARTMENT_OCID> \
--description "Security alerts (access denied enumeration)"
- Note the returned topic OCID, e.g.:
ocid1.onstopic.oc1..aaaa...
- Metric that counts access-denied events
Example (common pattern):
- Namespace:
security_audit - Metric name:
access_denied_count - Dimension: maybe
errorType = "AuthorizationFailure"
(If you don’t already publish such a metric, you must set up a Service Connector from Audit logs ⇒ Functions/Logging ⇒ custom metric first; that setup is separate from Monitoring and not covered in detail here.)
2. Decide alarm logic
Typical query (example):
- Trigger when there are ≥ 10 access‑denied events in 5 minutes:
security_audit.access_denied_count[5m]{errorType = "AuthorizationFailure"}.sum() >= 10
Adjust the namespace/metric/dimension and threshold to match your environment and policy.
3. Create the alarm using OCI CLI
Replace:
<ALARM_COMPARTMENT_OCID>– where the alarm resource lives<METRIC_COMPARTMENT_OCID>– where the metric is emitted<TOPIC_OCID>– your Notifications topic OCID- Adjust
--query-textto your real metric namespace/name/dimensions
oci monitoring alarm create \
--compartment-id <ALARM_COMPARTMENT_OCID> \
--display-name "Access Denied Enumeration Alarm" \
--metric-compartment-id <METRIC_COMPARTMENT_OCID> \
--metric-compartment-id-in-subtree true \
--severity CRITICAL \
--is-enabled true \
--destinations '["<TOPIC_OCID>"]' \
--namespace "security_audit" \
--query-text 'security_audit.access_denied_count[5m]{errorType = "AuthorizationFailure"}.sum() >= 10' \
--resolution "1m" \
--body "Alarm when repeated access-denied events (AuthorizationFailure) are detected, indicating possible enumeration activity." \
--pending-duration "PT5M"
Notes:
--pending-duration "PT5M": alarm must remain in breach 5 minutes before firing (tune as needed).--resolution "1m": evaluate the metric every minute.
If your metric is defined without namespace in the query (older/other style), omit --namespace and use:
--query-text 'access_denied_count[5m]{errorType = "AuthorizationFailure"}.sum() >= 10'
4. Verify the alarm
List alarms:
oci monitoring alarm list \
--compartment-id <ALARM_COMPARTMENT_OCID> \
--all
Get full details:
oci monitoring alarm get --alarm-id <ALARM_OCID>
Test by generating a few controlled “access denied” events (or by temporarily lowering the threshold) and confirm a notification is sent to your configured subscription.
If you tell me:
- the exact namespace, metric name, and dimensions you use for access-denied counts,
I can give you a copy‑paste‑readyoci monitoring alarm createcommand tailored to your setup.
Using Python
Below is a concrete way to remediate this by creating an OCI Monitoring Alarm (Access Denied / Enumeration) using Python + OCI SDK.
1. Prerequisites
- Install OCI Python SDK:
pip install oci
- Make sure you have an OCI config file (usually
~/.oci/config) with:
- Tenancy OCID
- User OCID
- API key
- Region
- Key fingerprint
- IAM policy in the target compartment/tenancy (for the principal you are using):
Allow group <your-group> to manage alarms in compartment <your-compartment-name>
Allow group <your-group> to use metrics in compartment <your-compartment-name>
Allow group <your-group> to use ons-topics in compartment <your-compartment-name>
(If you use OCI Notifications to send email/SMS, you also need permission to manage/use topics.)
2. Choose Metric & Threshold (Access Denied Enumeration)
Use the Identity AuthFailure metric (example – you can adjust):
- Namespace:
oci_iam - Metric name:
AuthFailure - Dimension:
errorCode = "NotAuthorizedOrNotFound"(typical for access denied) - Example threshold: more than 20 denied attempts in 5 minutes
Monitoring query expression (MQL):
AuthFailure[5m]{errorCode = "NotAuthorizedOrNotFound"}.sum() > 20
Adjust values to your environment (namespace/metric/dimensions can be verified in OCI Console → Observability & Management → Metrics Explorer).
3. Python Code to Create the Alarm
This example:
- Creates an alarm named
AccessDeniedEnumerationAlarm - Triggers when denied auth failures exceed the threshold
- Sends notifications to an existing OCI Notifications topic (
topic_id)
import oci
from oci.monitoring.models import CreateAlarmDetails
# ---------------- CONFIG ----------------
config = oci.config.from_file("~/.oci/config", "DEFAULT")
compartment_id = "ocid1.compartment.oc1..xxxxxxxx" # target compartment
topic_id = "ocid1.onstopic.oc1..yyyyyyyy" # existing OCI Notifications topic
# Monitoring alarm settings
alarm_display_name = "AccessDeniedEnumerationAlarm"
alarm_metric_namespace = "oci_iam"
alarm_metric_query = 'AuthFailure[5m]{errorCode = "NotAuthorizedOrNotFound"}.sum() > 20'
alarm_severity = "CRITICAL"
alarm_is_enabled = True
alarm_message_format = "ONS_OPTIMIZED"
alarm_repeat_notification_duration = "PT15M" # repeat every 15 minutes while in alarm
# ---------------- CLIENT ----------------
monitoring_client = oci.monitoring.MonitoringClient(config)
# ---------------- CREATE ALARM ----------------
create_alarm_details = CreateAlarmDetails(
display_name=alarm_display_name,
compartment_id=compartment_id,
is_enabled=alarm_is_enabled,
# Monitoring query
query=alarm_metric_query,
# Where metrics live
namespace=alarm_metric_namespace,
# Notification destinations
destinations=[topic_id],
# Alarm severity
severity=alarm_severity,
# Human-readable description
description="Alarm for detection of potential access denied enumeration (AuthFailure NotAuthorizedOrNotFound).",
# Notification message format
message_format=alarm_message_format,
# How often to repeat notifications while in alarm (ISO 8601 duration)
repeat_notification_duration=alarm_repeat_notification_duration,
)
response = monitoring_client.create_alarm(create_alarm_details)
alarm = response.data
print("Alarm created:")
print(" OCID: ", alarm.id)
print(" Display name:", alarm.display_name)
print(" Query: ", alarm.query)
print(" Namespace: ", alarm.namespace)
4. Validate the Alarm
-
In OCI Console:
- Observability & Management → Alarms
- Check that
AccessDeniedEnumerationAlarmexists and is in the correct compartment. - Verify the query, namespace, and destination topic.
-
Generate test events (or temporarily lower threshold) to verify the alarm changes to FIRING and sends notifications.
If you can share the exact metric/namespace you want to use (e.g., console logins, specific service, or audit-derived metrics), I can adapt the query and code snippet precisely to that metric.
Using Terraform
resource "oci_monitoring_alarm" "access_denied_enumeration" {
# OCID of the compartment in which to create the alarm
compartment_id = "COMPARTMENT_OCID"
# Human‑readable name for the alarm
display_name = "AccessDenied Enumeration – Unauthorized API Errors"
# Metric query that detects high‑frequency unauthorized API errors.
# Replace METRIC_QUERY_FOR_UNAUTHORIZED_ERRORS with the exact query you
# already use or have validated in the OCI Console Monitoring query editor.
#
# Example pattern (do NOT use blindly; validate in Console first):
# "ApiErrors[5m]{errorCode = 'NotAuthorizedOrNotFound'}.sum() > 50"
#
query = "METRIC_QUERY_FOR_UNAUTHORIZED_ERRORS"
# Alarm severity: "CRITICAL", "ERROR", "WARNING", "INFO"
severity = "CRITICAL"
# OCIDs of Notification topics that should receive the alarm notifications
destinations = [
"NOTIFICATION_TOPIC_OCID",
]
# Enable the alarm
is_enabled = true
# How often the alarm should repeat if the condition remains true
# (ISO 8601 duration format, e.g., "PT15M" = 15 minutes)
repeat_notification_duration = "PT15M"
# Optional free‑form and defined tags
freeform_tags = {
"NAME" = "AccessDeniedEnumerationAlarm"
"ENVIRONMENT" = "PRODUCTION"
}
}
Substitute:
COMPARTMENT_OCIDwith the OCID of the compartment where you want the alarm.NOTIFICATION_TOPIC_OCIDwith the OCID of the OCI Notifications topic that should receive alarm notifications.METRIC_QUERY_FOR_UNAUTHORIZED_ERRORSwith the exact Monitoring query that counts unauthorized / access‑denied API errors at the threshold you require (build and validate this in the Monitoring > Metrics console, then paste the working expression here).
This change updates/creates an oci_monitoring_alarm in place and does not force replacement of other resources.
After editing, terraform plan should show either:
+ createof oneoci_monitoring_alarmif it’s new, or~ update in-placeon the existingoci_monitoring_alarmwith thequery,display_name,severity,destinations, oris_enabledarguments changing as configured.