OCI Incident Response Hardening

Overview

This page covers Oracle Cloud Infrastructure incident response across the surfaces that decide whether a tenancy can detect, contain, and reconstruct an active compromise before the attacker exhausts the blast radius the cloud control plane makes reachable. Scope is the commercial OCI realms (OC1); OCI Government Cloud and dedicated-region tenancies inherit the same controls but expose realm-specific endpoints, region availability, and Identity Domain federation constraints — re-verify region availability and the relevant docs.oracle.com realm-endpoint documentation before applying any of the IaC below to a sovereign or dedicated-region deployment. CIS sub-IDs and NIST / ISO mappings throughout this page reference the CIS Oracle Cloud Infrastructure Foundations Benchmark v2.0.0 (accessed 2026-05) unless explicitly annotated as a post-v2.0.0 feature or a best-practice recommendation that the v2.0.0 benchmark has not yet codified. CIS published the Oracle Cloud Infrastructure Foundations Benchmark v3.1.0 in 2026; this site cites v2.0.0 throughout the corpus for consistency with the locked compliance-table contract. The crosswalk page at compliance frameworks describes how the seven pinned framework columns relate to each other. The authoritative IR lifecycle reference is NIST SP 800-61 rev 3 — Computer Security Incident Handling Guide, April 2025 release (accessed 2026-05), which restructures rev 2's four-phase model around the CSF 2.0 community profile (Govern / Identify / Protect / Detect / Respond / Recover) — pre-2025 runbooks built against rev 2's Preparation → Detection → Containment-Eradication-Recovery → Post-Incident structure remain valid; the rev 3 mapping is a re-framing, not a contradiction.

The OCI IR surface is the product of a small set of primitives and the runbooks that compose them. Cloud Guard responder recipes own the automated-containment path: detector findings (problems) trigger responder rules that disable users, isolate Compute instances via NSG swap, revoke API keys, and snapshot disks within seconds — the detective half of this loop lives on the OCI Logging page as oci-log-03-cloud-guard, which this page strictly pair-links to. Notifications + Functions own custom-playbook automation: a Notifications topic subscribed to a Cloud Guard problem stream invokes an OCI Function that performs containment actions Cloud Guard's stock responders do not cover (revoke Vault key permissions, freeze instance pool auto-scaling, post to PagerDuty + the security on-call channel). Audit search owns forensic queries: the Audit service Search API filters events by user, resource, event-name, and time range, and the longer-term archive lives in a dedicated Object Storage bucket — the archive sink is canonically owned by oci-log-08-audit-archive, which this page strictly pair-links to. Block Volume backup + Object Storage forensic bucket with LOCKED retention owns evidence preservation: a forensic snapshot policy captures boot and data volumes at incident-declaration time, and a forensic Object Storage bucket with a locked retention rule (the OCI analog of S3 Object Lock COMPLIANCE / Azure Immutable Blob Storage with locked time-based retention / GCP Bucket Lock LOCKED) holds evidence for one year or more without the possibility of early deletion even by a tenancy admin — the LOCKED retention pattern is canonically owned by oci-data-08-object-retention, which this page strictly pair-links to. Bastion Service owns forensic instance access: a per-session time-limited SSH or managed-port-forwarding session to an isolated instance with no public IP, used by responders to capture in-memory artefacts before the instance is destroyed. Identity Domains user disable + API key delete + session enumeration own the compromised-identity runbook: a single workflow disables the user, deletes every API key fingerprint the user owns, enumerates and revokes active sessions inside the Identity Domain (formerly IDCS — see OCI IAM for the canonical Identity Domains treatment), and rotates every Vault secret the user could read. Cross-cutting principles — preparation, containment, forensics, recovery / post-incident, and tabletops — are owned by the General Incident Response page; this page maps them to OCI primitives.

Order and scope matter. Control 01 pre-positions the break-glass tenancy-admin identities that make every later step possible — the IdP that federates day-to-day administrators is exactly the surface the incident may take out, and creating a non-federated admin during the incident is structurally impossible. Control 02 is the Cloud Guard responder + Notifications + Functions automation chain that closes the detection-to-containment gap to seconds rather than the 15-to-45-minute pager-to-keyboard window. Control 03 captures forensic evidence — Block Volume backups for in-memory and on-disk state, plus an Object Storage forensic bucket whose locked retention rule cannot be reduced even by a tenancy admin under attacker control. Control 04 is the Audit search and longer-term archive that lets a responder reconstruct who did what, when, from which IP, against which resource. Control 05 is the documented Compute isolation runbook for the surfaces Cloud Guard's stock responders do not cover. Control 06 is the compromised-identity runbook for the API-key + session-revoke + secret-rotate cycle. Control 07 is the quarterly tabletop exercise that keeps the runbook from rotting between incidents. The admin-no-API-keys invariant (canonical on the OCI IAM page) is the prevention pair to oci-ir-06's response; the tenancy-wide Audit retention control is the detection pair to oci-ir-04's forensic search. Severity is assigned from the methodology severity rubric; equivalence callouts at the bottom of each control point at the matching control on the AWS, Azure, and GCP sibling pages.

oci-ir-01-tenant-recovery ! CRITICAL PREVENTIVE

Pre-provision two to four named break-glass tenancy-admin identities that live inside the default Identity Domain as local accounts — explicitly not federated from the organisation's primary IdP (Okta, Entra ID, Ping, Google Workspace, or an Identity Domain federation to another identity provider). Each break-glass identity is protected by a FIDO2 hardware key (YubiKey 5 series or equivalent) physically stored in a locked safe; two safes in two separate buildings is the canonical two-person-integrity pattern. Every sign-in by a break-glass account fires an Events rule on the com.oraclecloud.identitycontrolplane.signin event type that publishes to a Notifications topic the security on-call subscribes to via email, PagerDuty webhook, and Slack webhook within seconds (OCI — API key management documentation (accessed 2026-05)). The principle is reinforced in General IR — preparation: the first incident that takes out the IdP is exactly the scenario IR exists to handle, and an IdP-only access model has zero recovery path in that scenario. Quarterly access tests — a named responder retrieves their FIDO2 key from the safe, signs into the tenancy, performs a single read-only API call, signs out — keep the credential, the hardware token, and the alarm pipeline all known-working; tests not performed in the last 90 days are tracked on the security team's drift dashboard.

The control is typed CRITICAL PREVENTIVE, not RESPONSIVE: the control is the pre-positioning that makes response possible. Creating a break-glass identity during the incident that just took out the Identity Domain federation is structurally impossible — the responder needs an unfederated local-domain account to sign in at all. This mirrors the typing decisions on aws-ir-01, azure-ir-01, and gcp-ir-01: every provider's first IR control is the pre-positioning the rest of the runbook depends on. The tenancy-recovery runbook itself — what to do when the primary IdP is compromised — documents the steps to disable the federation trust, replace the SAML/OIDC provider, and re-enable federation under a new IdP without losing the audit trail of which break-glass identity performed which step.

Remediation — OCI CLI

# oci CLI (v3.x)
# Step 1: create the named break-glass user as a local Identity Domain account.
# This is a tenancy-admin identity; it MUST NOT be created via federation.
oci iam user create \
  --compartment-id "$TENANCY_OCID" \
  --name breakglass-admin-01 \
  --email-address ir-pager+bg01@example.com \
  --description "Tenancy break-glass; FIDO2 only; do not federate"

# Step 2: place the break-glass user into the tenancy-admin group.
oci iam group add-user \
  --user-id "$BG_USER_OCID" \
  --group-id "$TENANCY_ADMIN_GROUP_OCID"

# Step 3: enrol the FIDO2 device. The hardware-key enrolment uses the OCI
# Console (Identity Domain user security factors page); CLI enrolment of FIDO2
# devices is not currently supported and must be completed interactively by the
# named human responder during initial setup.

# Step 4: create the Events rule that alarms on every break-glass sign-in.
oci events rule create \
  --compartment-id "$TENANCY_OCID" \
  --display-name "break-glass-signin" \
  --is-enabled true \
  --condition '{
    "eventType":["com.oraclecloud.identitycontrolplane.signin"],
    "data":{"identity":{"principalName":["breakglass-admin-01","breakglass-admin-02"]}}
  }' \
  --actions '{"actions":[{"actionType":"ONS","topicId":"'"$IR_NOTIFICATIONS_TOPIC_OCID"'","isEnabled":true}]}'

# Step 5: subscribe the on-call rotation to the Notifications topic.
oci ons subscription create \
  --compartment-id "$TENANCY_OCID" \
  --topic-id "$IR_NOTIFICATIONS_TOPIC_OCID" \
  --protocol PAGERDUTY \
  --subscription-endpoint "https://events.pagerduty.com/integration/$PAGERDUTY_KEY/enqueue"

Remediation — Terraform

# Terraform OCI provider ~> 5.0
# Break-glass tenancy-admin identities inside the default Identity Domain.
# These accounts MUST NOT be sourced from the federated IdP.
resource "oci_identity_user" "break_glass" {
  for_each       = toset(["breakglass-admin-01", "breakglass-admin-02"])
  compartment_id = var.tenancy_ocid
  name           = each.key
  email          = "ir-pager+${each.key}@example.com"
  description    = "Tenancy break-glass; FIDO2 only; do not federate"
}

resource "oci_identity_user_group_membership" "break_glass_admins" {
  for_each = oci_identity_user.break_glass
  user_id  = each.value.id
  group_id = var.tenancy_admin_group_ocid
}

# Notifications topic the on-call rotation subscribes to.
resource "oci_ons_notification_topic" "ir_alerts" {
  compartment_id = var.tenancy_ocid
  name           = "ir-break-glass-alerts"
  description    = "Every break-glass sign-in alarms here"
}

resource "oci_ons_subscription" "ir_pagerduty" {
  compartment_id = var.tenancy_ocid
  topic_id       = oci_ons_notification_topic.ir_alerts.id
  protocol       = "PAGERDUTY"
  endpoint       = "https://events.pagerduty.com/integration/${var.pagerduty_key}/enqueue"
}

# Events rule that fires on every break-glass sign-in.
resource "oci_events_rule" "break_glass_signin" {
  compartment_id = var.tenancy_ocid
  display_name   = "break-glass-signin"
  is_enabled     = true
  condition = jsonencode({
    eventType = ["com.oraclecloud.identitycontrolplane.signin"]
    data = {
      identity = {
        principalName = [for u in oci_identity_user.break_glass : u.name]
      }
    }
  })
  actions {
    actions {
      action_type = "ONS"
      topic_id    = oci_ons_notification_topic.ir_alerts.id
      is_enabled  = true
    }
  }
}

Remediation — OCI Resource Manager

# Submit the Terraform block above to OCI Resource Manager via a configured
# Git source-provider. Variables are entered through the Console UI (schema-driven
# by an optional schema.yaml); state is stored in OCI Object Storage automatically.
# This is an INVOCATION snippet — the .tf body is the existing Terraform block
# on this same control-box (do NOT duplicate HCL here).
oci resource-manager stack create-from-git-provider \
  --compartment-id "$COMPARTMENT_OCID" \
  --config-source-provider-id "$CONFIG_SRC_PROVIDER_OCID" \
  --repository-url "https://example.com/org/hardening-iac" \
  --branch-name "main" \
  --working-directory "modules/oci-ir-01-tenant-recovery" \
  --display-name "oci-ir-01-tenant-recovery" \
  --terraform-version "1.5.x"

# Plan + apply via the ORM job lifecycle (state stored in OCI automatically).
STACK_OCID=$(oci resource-manager stack list \
  --compartment-id "$COMPARTMENT_OCID" \
  --display-name "oci-ir-01-tenant-recovery" \
  --query 'data[0].id' --raw-output)
PLAN_JOB_OCID=$(oci resource-manager job create-plan-job \
  --stack-id "$STACK_OCID" --query 'data.id' --raw-output)
oci resource-manager job create-apply-job \
  --stack-id "$STACK_OCID" \
  --execution-plan-strategy FROM_PLAN_JOB \
  --execution-plan-job-id "$PLAN_JOB_OCID"

Remediation — Pulumi (TypeScript)

import * as pulumi from "@pulumi/pulumi";
import * as oci from "@pulumi/oci";

// Break-glass tenancy recovery account: separate IdP, hardware MFA, audited.
const cfg = new pulumi.Config();
const tenancyOcid = cfg.require("tenancyOcid");
const breakGlassDomainOcid = cfg.require("breakGlassIdentityDomainOcid");
const breakGlassIdcsEndpoint = cfg.require("breakGlassIdcsEndpoint");

// Break-glass user in dedicated Identity Domain (not the default one).
const breakGlassUser = new oci.identity.DomainsUser("tenant-recovery", {
  idcsEndpoint: breakGlassIdcsEndpoint,
  schemas: ["urn:ietf:params:scim:schemas:core:2.0:User"],
  userName: "break-glass-recovery",
  active: true,
  emails: [{
    value: "break-glass@example.com",
    type: "work",
    primary: true,
  }],
  // No password — hardware FIDO2 only, enrolled via separate out-of-band workflow.
});

// Emergency Administrators policy — invokable only by break-glass identity domain users.
const breakGlassPolicy = new oci.identity.Policy("break-glass-admin", {
  compartmentId: tenancyOcid,
  name: "break-glass-tenancy-recovery",
  description: "Emergency-only tenancy admin via dedicated identity domain",
  statements: [
    "Allow group BreakGlassAdmins to manage all-resources in tenancy where request.user.identityDomain='break-glass-domain'",
  ],
});

export const breakGlassUserOcid = breakGlassUser.id;

Compliance mapping

CIS AWS Foundations v3.0.0 CIS Microsoft Azure Foundations v3.0.0 CIS GCP Foundation v4.0.0 CIS OCI Foundation v2.0.0 NIST SP 800-53 rev5 ISO/IEC 27001:2022 ISO/IEC 27017:2015
n/an/an/a(best-practices) IR-4; AC-2(8); AC-6A.5.24; A.5.26CLD.9.5.1

Log signals

  • OCI Logging Analytics records where 'Log Source' = 'OCI Audit Logs' with eventName in (CreateApiKey, UpdateAuthToken, CreateOAuth2ClientCredential) targeting the documented break-glass user OCID.
  • Console-tier sign-on events under the break-glass identity outside the documented annual exercise window.
  • Identity Domain Sessions records showing the break-glass user holding an active session — these must be zero outside drills.

Query

'Log Source' = 'OCI Audit Logs'
          and 'Service Name' = 'identity'
          and (data.identity.principalId = '$BREAK_GLASS_USER_OCID'
               or data.target.user.id = '$BREAK_GLASS_USER_OCID')
          | stats count by 'User Name', eventName, 'Compartment Name'

The break-glass identity is a single OCID with explicit out-of-band credentials; any audit-feed activity on it is an event of interest.

Alert threshold

  • Any audit event naming the break-glass OCID — page on first event; the only legitimate occurrences are scheduled drills and emergencies.
  • Identity Domain sessions for the break-glass user lasting longer than 8 hours — page; emergency sessions must be short and explicit.

Initial response

  1. If the activity is not a scheduled drill, contact the on-call security lead via the secondary paging channel and confirm whether an emergency is in progress.
  2. Terminate the break-glass session via the Identity Domain admin console session inventory; rotate the break-glass user's console password and FIDO2 enrolment immediately.
  3. Triage every action taken under the break-glass session in the OCI Audit feed and produce an incident report per general/ir.html.

References

Equivalent on: AWS · Azure · GCP

oci-ir-02-cloud-guard-remediation ! HIGH RESPONSIVE

Configure a custom Cloud Guard responder recipe that overrides the Oracle-managed defaults for the small set of responders the security team has decided to run in AUTOACTION mode rather than USERACTION mode — disable user, isolate Compute instance via NSG swap, revoke API key, snapshot Block Volume — and bind that recipe to the tenancy-root target so it covers every compartment subtree. The detector half of the loop lives on the OCI Logging page as oci-log-03-cloud-guard (DETECTIVE pair); without Cloud Guard enabled tenancy-wide with the standard detector recipes, this control has nothing to respond to. The responder recipe is the contract: Cloud Guard problem severity and risk score trigger a responder rule that performs a deterministic remediation action against the resource named in the problem payload, end-to-end in seconds (OCI — Cloud Guard responder recipes (accessed 2026-05)). The custom-playbook half — for containment actions Cloud Guard's stock responders do not cover, such as revoking a Vault key permission, freezing an Instance Pool's auto-scaling, or paging the on-call channel — lives in a Notifications topic that subscribes to the Cloud Guard problem stream and invokes an OCI Function with the problem payload as input. The Function performs the custom action with a resource principal that has only the IAM permissions it needs (least-privilege; cross-link to oci-iam-08).

Cloud Guard's responder recipes are the natural automation layer because they give the security team a programmable handoff per detector: the recipe binds a detector rule to a responder rule, the responder mode (AUTOACTION runs immediately; USERACTION requires console approval) is set per rule, and the condition groups filter which problems fire which responders by compartment, by resource OCID prefix, by risk score, or by an arbitrary JMESPath expression on the problem payload. Time-to-contain on the auto-remediation chain is bounded by Cloud Guard's problem-emission latency (low single-digit minutes from the underlying Audit / Configuration / VSS / Threat-Intelligence detector firing) plus the responder action's own latency (seconds for a user disable or an NSG swap; tens of seconds for a Block Volume snapshot). Compared to the manual path — finding sits in the Cloud Guard problems view until a human triages it, the human signs in, the human runs the remediation — automation collapses the time-to-contain window from tens of minutes to seconds or low single-digit minutes.

Remediation — OCI CLI

# oci CLI (v3.x)
# Step 1: clone the Oracle-managed responder recipe into a custom one.
oci cloud-guard responder-recipe create \
  --compartment-id "$TENANCY_OCID" \
  --display-name "ir-auto-contain" \
  --description "Auto-disable users, isolate instances, revoke keys" \
  --source-responder-recipe-id "$ORACLE_MANAGED_RESPONDER_RECIPE_OCID"

# Step 2: enable the DISABLE_USER responder rule in AUTOACTION mode.
oci cloud-guard responder-recipe-responder-rule update \
  --responder-recipe-id "$CUSTOM_RECIPE_OCID" \
  --responder-rule-id DISABLE_USER \
  --details '{
    "isEnabled": true,
    "mode": "AUTOACTION",
    "conditionGroups": [{
      "compartmentId": "'"$TENANCY_OCID"'",
      "conditionType": "FILTERS",
      "condition": "{\"kind\":\"COMPOSITE\",\"leftOperand\":{\"kind\":\"SIMPLE\",\"parameter\":\"riskScore\",\"operator\":\"GREATER_THAN_OR_EQUAL_TO\",\"value\":\"7\",\"valueType\":\"VALUE\"},\"compositeOperator\":\"AND\",\"rightOperand\":{\"kind\":\"SIMPLE\",\"parameter\":\"problemLifecycleState\",\"operator\":\"IN\",\"value\":\"[\\\"OPEN\\\"]\",\"valueType\":\"MULTI_VALUE\"}}"
    }]
  }'

# Step 3: rebind the Cloud Guard target on the tenancy root to use the custom recipe.
oci cloud-guard target update \
  --target-id "$TENANCY_ROOT_TARGET_OCID" \
  --target-responder-recipes '[{"responderRecipeId":"'"$CUSTOM_RECIPE_OCID"'"}]'

# Step 4: Notifications topic + Function for custom-playbook containment.
oci ons topic create \
  --compartment-id "$IR_COMPARTMENT_OCID" \
  --name ir-cloud-guard-problems \
  --description "Cloud Guard problem stream for Function playbooks"

# Subscribe the Function to the topic; the Function receives the full problem payload.
oci ons subscription create \
  --compartment-id "$IR_COMPARTMENT_OCID" \
  --topic-id "$CG_TOPIC_OCID" \
  --protocol ORACLE_FUNCTIONS \
  --subscription-endpoint "$IR_FUNCTION_OCID"

Remediation — Terraform

# Terraform OCI provider ~> 5.0
# Source: OCI Cloud Guard responder recipes (accessed 2026-05)

resource "oci_cloud_guard_responder_recipe" "ir_auto_contain" {
  compartment_id                       = var.tenancy_ocid
  display_name                         = "ir-auto-contain"
  description                          = "Auto-disable users, isolate instances, revoke keys"
  source_responder_recipe_id           = var.oracle_managed_responder_recipe_ocid
  responder_rules {
    responder_rule_id = "DISABLE_USER"
    details {
      is_enabled = true
      mode       = "AUTOACTION"
      condition  = jsonencode({
        kind             = "COMPOSITE"
        compositeOperator = "AND"
        leftOperand = {
          kind = "SIMPLE", parameter = "riskScore", operator = "GREATER_THAN_OR_EQUAL_TO", value = "7", valueType = "VALUE"
        }
        rightOperand = {
          kind = "SIMPLE", parameter = "problemLifecycleState", operator = "IN", value = "[\"OPEN\"]", valueType = "MULTI_VALUE"
        }
      })
    }
  }
}

# Rebind the tenancy-root Cloud Guard target onto the custom responder recipe.
resource "oci_cloud_guard_target" "tenancy_root" {
  compartment_id      = var.tenancy_ocid
  display_name        = "tenancy-root"
  target_resource_id  = var.tenancy_ocid
  target_resource_type = "COMPARTMENT"
  target_responder_recipes {
    responder_recipe_id = oci_cloud_guard_responder_recipe.ir_auto_contain.id
  }
}

# Custom-playbook Function fired from a Notifications topic on the problem stream.
resource "oci_ons_notification_topic" "cg_problems" {
  compartment_id = var.ir_compartment_ocid
  name           = "ir-cloud-guard-problems"
  description    = "Cloud Guard problem stream for Function playbooks"
}

resource "oci_functions_function" "ir_playbook" {
  application_id = var.ir_functions_application_ocid
  display_name   = "ir-playbook"
  image          = "${var.region_key}.ocir.io/${var.tenancy_namespace}/ir/playbook:latest"
  memory_in_mbs  = 256
}

resource "oci_ons_subscription" "playbook" {
  compartment_id = var.ir_compartment_ocid
  topic_id       = oci_ons_notification_topic.cg_problems.id
  protocol       = "ORACLE_FUNCTIONS"
  endpoint       = oci_functions_function.ir_playbook.id
}

Remediation — OCI Resource Manager

# Submit the Terraform block above to OCI Resource Manager via a configured
# Git source-provider. Variables are entered through the Console UI (schema-driven
# by an optional schema.yaml); state is stored in OCI Object Storage automatically.
# This is an INVOCATION snippet — the .tf body is the existing Terraform block
# on this same control-box (do NOT duplicate HCL here).
oci resource-manager stack create-from-git-provider \
  --compartment-id "$COMPARTMENT_OCID" \
  --config-source-provider-id "$CONFIG_SRC_PROVIDER_OCID" \
  --repository-url "https://example.com/org/hardening-iac" \
  --branch-name "main" \
  --working-directory "modules/oci-ir-02-cloud-guard-remediation" \
  --display-name "oci-ir-02-cloud-guard-remediation" \
  --terraform-version "1.5.x"

# Plan + apply via the ORM job lifecycle (state stored in OCI automatically).
STACK_OCID=$(oci resource-manager stack list \
  --compartment-id "$COMPARTMENT_OCID" \
  --display-name "oci-ir-02-cloud-guard-remediation" \
  --query 'data[0].id' --raw-output)
PLAN_JOB_OCID=$(oci resource-manager job create-plan-job \
  --stack-id "$STACK_OCID" --query 'data.id' --raw-output)
oci resource-manager job create-apply-job \
  --stack-id "$STACK_OCID" \
  --execution-plan-strategy FROM_PLAN_JOB \
  --execution-plan-job-id "$PLAN_JOB_OCID"

Compliance mapping

CIS AWS Foundations v3.0.0 CIS Microsoft Azure Foundations v3.0.0 CIS GCP Foundation v4.0.0 CIS OCI Foundation v2.0.0 NIST SP 800-53 rev5 ISO/IEC 27001:2022 ISO/IEC 27017:2015
n/an/an/a(best-practices) IR-4(1); IR-4(7); SI-4(7)A.5.26CLD.12.4.5

Log signals

  • OCI Logging Analytics records where 'Log Source' = 'OCI Audit Logs' and 'Service Name' = 'cloud-guard' with eventName = 'UpdateResponderRecipe' whose payload flips a responder rule isEnabled from true to false.
  • Cloud Guard problem records that should have triggered an auto-remediation responder but show responderActivities as empty.
  • Service Connector Hub events that disable the connector wiring Cloud Guard problems into the Functions auto-remediation handler.

Query

'Log Source' = 'OCI Audit Logs'
          and 'Service Name' = 'cloud-guard'
          and eventName in ('UpdateResponderRecipe', 'TriggerResponder')
          | eval disabled = if(data.request.payload.responderRules like '%isEnabled":false%', 'YES', 'NO')
          | where disabled = 'YES'
          | stats count by 'User Name', data.target.responderRecipe.id, eventName

Responder rule mutations are infrequent; the gate fires on disable-events at any rule level.

Alert threshold

  • Any responder rule disabled outside the documented Cloud Guard tuning window — page.
  • Cloud Guard problem record without a matching responder activity in the next 5 minutes — page; auto-remediation pipeline broke.

Initial response

  1. Re-enable the responder rule via the recipe REST endpoint; Cloud Guard re-evaluates pending problems and applies the responder action on the next scan.
  2. Restore the Service Connector Hub binding via Resource Manager; SCH replays buffered problems into the Functions responder.
  3. Manually remediate any problem that was open while the responder was off and document per general/ir.html.

References

Equivalent on: AWS · Azure · GCP

oci-ir-03-forensic-snapshot ! CRITICAL RESPONSIVE

Capture forensic evidence at incident-declaration time and preserve it in an Object Storage bucket whose retention rule is LOCKED — meaning the rule cannot be reduced or deleted even by a tenancy admin under attacker control. The capture surface is the Block Volume backup API (FULL backups of boot and data volumes, tagged with a defined-tag Forensics namespace carrying incident_id, captured_by, and capture_timestamp for chain-of-custody); the preservation surface is a dedicated Object Storage forensic bucket in an IR-owned compartment with a retention rule whose time_rule_locked is set to a time at least 14 days in the past so the rule is immediately locked at creation — the OCI analog of S3 Object Lock COMPLIANCE mode (aws-ir-03), Azure Immutable Blob Storage with locked time-based retention (azure-ir-03), and GCP Bucket Lock LOCKED mode (gcp-ir-03). The LOCKED retention pattern itself — the mechanism by which a retention rule becomes immutable — is canonically owned by oci-data-08-object-retention; this control consumes that pattern for the forensic-evidence use case (OCI — Block Volume backups documentation (accessed 2026-05)).

The defined-tag Forensics namespace is the chain-of-custody contract. Three required tag keys — incident_id (the security team's case identifier), captured_by (the OCID of the responder who initiated the capture), and capture_timestamp (ISO-8601 UTC) — are applied to every Block Volume backup and every Object Storage object stored in the forensic bucket. The tag-namespace itself is owned by the IR compartment and scoped so only the IR-responder dynamic group may write tags within it; tampering with the chain-of-custody requires escalating into a separate compartment with a separate policy path that the incident-response runbook itself logs. The Object Storage forensic bucket carries the same Vault key as the rest of the IR compartment's storage (cross-link to oci-data-02-vault-byok) so evidence is encrypted at rest under a key whose use is itself audited; deleting the bucket while a locked retention rule is in force is structurally blocked by OCI even for a tenancy admin until the rule expires, which is the design intent. The runbook step that ships volume images into the forensic bucket is itself a Function fired from a Notifications topic the responder writes to during the incident — there is no console step in the forensic-preservation path so the chain-of-custody is auditable.

Remediation — OCI CLI

# oci CLI (v3.x)
# Step 1: capture a FULL Block Volume backup at incident-declaration time.
INCIDENT_ID="INC-2026-0142"
NOW=$(date -u +%Y%m%dT%H%M%SZ)

oci bv volume-backup create \
  --volume-id "$COMPROMISED_VOLUME_OCID" \
  --display-name "incident-${INCIDENT_ID}-volume-${NOW}" \
  --type FULL \
  --defined-tags '{
    "Forensics": {
      "incident_id":"'"$INCIDENT_ID"'",
      "captured_by":"'"$RESPONDER_OCID"'",
      "capture_timestamp":"'"$NOW"'"
    }
  }'

# Step 2: create the forensic bucket (in the IR compartment, with Vault CMK).
oci os bucket create \
  --compartment-id "$IR_COMPARTMENT_OCID" \
  --name forensic-evidence \
  --namespace "$TENANCY_NAMESPACE" \
  --public-access-type NoPublicAccess \
  --versioning Enabled \
  --kms-key-id "$IR_VAULT_KEY_OCID"

# Step 3: apply a LOCKED retention rule. The time_rule_locked timestamp must be
# in the past at apply time so the rule is locked immediately on creation; once
# locked, the rule cannot be reduced or deleted even by a tenancy admin.
oci os retention-rule create \
  --bucket-name forensic-evidence \
  --namespace "$TENANCY_NAMESPACE" \
  --display-name "forensic-1y-locked" \
  --duration '{"timeAmount":365,"timeUnit":"DAYS"}' \
  --time-rule-locked "$(date -u -d '-1 day' --iso-8601=seconds)"

Remediation — Terraform

# Terraform OCI provider ~> 5.0
# Forensic defined-tag namespace; written only by the IR-responder dynamic group.
resource "oci_identity_tag_namespace" "forensics" {
  compartment_id = var.ir_compartment_ocid
  name           = "Forensics"
  description    = "Chain-of-custody tags for incident-response captures"
}

resource "oci_identity_tag" "incident_id" {
  tag_namespace_id = oci_identity_tag_namespace.forensics.id
  name             = "incident_id"
  description      = "Security team's case identifier (e.g. INC-2026-0142)"
}

resource "oci_identity_tag" "captured_by" {
  tag_namespace_id = oci_identity_tag_namespace.forensics.id
  name             = "captured_by"
  description      = "OCID of the responder who initiated the capture"
}

resource "oci_identity_tag" "capture_timestamp" {
  tag_namespace_id = oci_identity_tag_namespace.forensics.id
  name             = "capture_timestamp"
  description      = "ISO-8601 UTC timestamp of capture"
}

# Block Volume backup policy that fires forensic FULL backups on demand.
resource "oci_core_volume_backup_policy" "forensic" {
  compartment_id = var.ir_compartment_ocid
  display_name   = "forensic-on-demand"
  # No schedules: this policy is assigned at incident-declaration time and the
  # backup is then created out-of-band via the CLI block above. The policy
  # exists so chain-of-custody tagging and KMS-key assignment are pre-positioned.
  destination_region = var.home_region
}

# Forensic Object Storage bucket with LOCKED retention.
resource "oci_objectstorage_bucket" "forensic" {
  compartment_id = var.ir_compartment_ocid
  namespace      = var.tenancy_namespace
  name           = "forensic-evidence"
  access_type    = "NoPublicAccess"
  versioning     = "Enabled"
  kms_key_id     = var.ir_vault_key_ocid

  retention_rules {
    display_name = "forensic-1y-locked"
    duration {
      time_amount = 365
      time_unit   = "DAYS"
    }
    # time_rule_locked in the past => locked immediately; once locked, OCI
    # blocks any reduction or deletion of the rule for the duration of its term.
    time_rule_locked = timeadd(timestamp(), "-24h")
  }
}

Remediation — OCI Resource Manager

# Submit the Terraform block above to OCI Resource Manager via a configured
# Git source-provider. Variables are entered through the Console UI (schema-driven
# by an optional schema.yaml); state is stored in OCI Object Storage automatically.
# This is an INVOCATION snippet — the .tf body is the existing Terraform block
# on this same control-box (do NOT duplicate HCL here).
oci resource-manager stack create-from-git-provider \
  --compartment-id "$COMPARTMENT_OCID" \
  --config-source-provider-id "$CONFIG_SRC_PROVIDER_OCID" \
  --repository-url "https://example.com/org/hardening-iac" \
  --branch-name "main" \
  --working-directory "modules/oci-ir-03-forensic-snapshot" \
  --display-name "oci-ir-03-forensic-snapshot" \
  --terraform-version "1.5.x"

# Plan + apply via the ORM job lifecycle (state stored in OCI automatically).
STACK_OCID=$(oci resource-manager stack list \
  --compartment-id "$COMPARTMENT_OCID" \
  --display-name "oci-ir-03-forensic-snapshot" \
  --query 'data[0].id' --raw-output)
PLAN_JOB_OCID=$(oci resource-manager job create-plan-job \
  --stack-id "$STACK_OCID" --query 'data.id' --raw-output)
oci resource-manager job create-apply-job \
  --stack-id "$STACK_OCID" \
  --execution-plan-strategy FROM_PLAN_JOB \
  --execution-plan-job-id "$PLAN_JOB_OCID"

Remediation — Pulumi (TypeScript)

import * as pulumi from "@pulumi/pulumi";
import * as oci from "@pulumi/oci";

// Forensic-quality block volume snapshot with KMS-CMK + retention lock.
const cfg = new pulumi.Config();
const compartmentId = cfg.require("compartmentOcid");
const sourceVolumeOcid = cfg.require("sourceVolumeOcid");
const forensicKmsKeyOcid = cfg.require("forensicKmsKeyOcid");

const forensicBackup = new oci.core.VolumeBackup("forensic-evidence", {
  volumeId: sourceVolumeOcid,
  displayName: pulumi.interpolate`forensic-${Date.now()}`,
  type: "FULL",
  kmsKeyId: forensicKmsKeyOcid,
  freeformTags: {
    "evidence-class": "forensic",
    "chain-of-custody": "preserved",
    "do-not-delete-before": "2030-01-01",
  },
});

// Forensic Object Storage bucket — retention-locked, write-once.
const forensicBucket = new oci.objectstorage.Bucket("forensic-archive", {
  compartmentId: compartmentId,
  name: "forensic-evidence-archive",
  accessType: "NoPublicAccess",
  kmsKeyId: forensicKmsKeyOcid,
  versioning: "Enabled",
  retentionRules: [{
    displayName: "forensic-retention-7yr",
    duration: { timeAmount: 7, timeUnit: "YEARS" },
    timeRuleLocked: "2030-01-01T00:00:00Z",  // hard-lock retention rule itself
  }],
});

export const forensicBackupOcid = forensicBackup.id;

Compliance mapping

CIS AWS Foundations v3.0.0 CIS Microsoft Azure Foundations v3.0.0 CIS GCP Foundation v4.0.0 CIS OCI Foundation v2.0.0 NIST SP 800-53 rev5 ISO/IEC 27001:2022 ISO/IEC 27017:2015
n/an/an/a(best-practices) AU-11; IR-4(7); SI-7A.5.28; A.8.13CLD.12.4.5

Log signals

  • OCI Logging Analytics records where 'Log Source' = 'OCI Audit Logs' and 'Service Name' = 'core' with eventName in (CreateVolumeBackup, CreateBootVolumeBackup) covering the IR-flagged volume OCIDs within 5 minutes of an isolation event.
  • Forensic-bucket Object Storage upload events confirming the boot-volume image + memory dump (where collected via guest agent) landed in the IR-tagged bucket.
  • Lifecycle-rule retention assertion on the forensic bucket — the gate fails if the rule is absent at evidence-collection time.

Query

'Log Source' = 'OCI Audit Logs'
          and 'Service Name' = 'core'
          and eventName in ('CreateVolumeBackup', 'CreateBootVolumeBackup')
          | eval ir_tag = data.target.volume.freeformTags.IRStatus
          | where ir_tag = 'isolated'
          | stats count by 'User Name', data.target.volume.id, eventName

Tag isolated resources IRStatus = isolated via the same Functions handler that performs the isolation; the forensic-snapshot pipeline keys off that tag.

Alert threshold

  • Volume tagged IRStatus = isolated without an accompanying volume-backup event in the next 5 minutes — page; forensic snapshot pipeline broke.
  • Forensic bucket missing its retention rule at snapshot time — page; the evidence-chain integrity contract requires immutable retention.

Initial response

  1. Manually trigger the volume backup via oci bv volume-backup create --type FULL --volume-id and the boot-volume backup via the corresponding boot-volume endpoint.
  2. Mirror the backup OCID into the forensic bucket via oci os object copy after the backup reaches AVAILABLE state.
  3. Re-apply the bucket retention rule via Resource Manager if absent, and record the evidence chain-of-custody in the IR ticket per general/ir.html.

References

Equivalent on: AWS · Azure · GCP

oci-ir-05-instance-isolation ! HIGH RESPONSIVE

Document the Compute instance isolation runbook as a four-step contract responders execute under incident pressure: (a) snapshot the boot volume and every attached Block Volume via the forensic capture path in oci-ir-03 so evidence is preserved before any mutating action; (b) swap the instance's NSG attachment to a pre-built quarantine NSG that denies all ingress and egress except a single allow-rule to the forensic capture subnet — pre-positioned as a standard fixture in every VCN exactly so it is available at incident time; (c) update the dynamic-group matching rule that grants the instance resource-principal access to OCI APIs so the compromised instance OCID is explicitly excluded — the instance can no longer call oci iam, oci os, oci vault, or any other API authenticated via the instance principal; (d) tag the instance with the defined-tag Forensics namespace (the same namespace oci-ir-03 uses for chain-of-custody on volume backups) carrying incident_id and isolated_at. The runbook is an operator workflow, not a Terraform resource — the quarantine NSG itself is pre-built infrastructure shipped via Terraform, but the four-step isolation is executed against a specific compromised instance OCID during the incident.

The pre-built quarantine NSG is the key pre-positioning. Provisioned in every VCN as standard fixture infrastructure (one quarantine NSG per VCN), it has an explicit deny-all posture: no ingress rules at all (NSGs are allow-list, so absence of allow rules means no traffic admitted), and an egress rule list whose only entry permits TCP traffic to the forensic-capture subnet's CIDR. Swapping a compromised instance's NSG attachment onto the quarantine NSG cuts off lateral movement to peer VCNs, cuts off egress to the internet (NAT gateway path no longer reachable), and cuts off egress to OCI managed services (Service Gateway path no longer reachable) — except for the single forensic-capture path the responder uses to collect in-memory artefacts via the Bastion service. The dynamic-group exclusion is the second axis: even if the attacker still has a network path, the instance's resource principal can no longer authenticate to OCI APIs, so the attacker cannot pivot via the instance's IAM reach.

Remediation — OCI CLI

# oci CLI (v3.x)
# Step 0: capture forensic snapshots first (see oci-ir-03).

# Step 1: swap the instance's NSG attachment to the pre-built quarantine NSG.
oci compute instance update \
  --instance-id "$COMPROMISED_INSTANCE_OCID" \
  --nsg-ids '["'"$QUARANTINE_NSG_OCID"'"]'

# Step 2: exclude the compromised instance from the dynamic group that grants
# it resource-principal reach. The matching rule below is the standard pattern;
# replace the OCID list with the actual list maintained for the dynamic group.
oci iam dynamic-group update \
  --dynamic-group-id "$WORKLOAD_DYNAMIC_GROUP_OCID" \
  --matching-rule "ALL {instance.id != '$COMPROMISED_INSTANCE_OCID', instance.compartment.id = '$WORKLOAD_COMPARTMENT_OCID'}"

# Step 3: tag the instance for chain-of-custody. The Forensics tag namespace is
# the same namespace oci-ir-03 uses for volume backups.
oci compute instance update \
  --instance-id "$COMPROMISED_INSTANCE_OCID" \
  --defined-tags '{
    "Forensics": {
      "incident_id":"'"$INCIDENT_ID"'",
      "isolated_at":"'"$(date -u +%Y%m%dT%H%M%SZ)"'"
    }
  }'

# Step 4: open a Bastion session into the isolated instance to collect in-memory
# artefacts before destroying it. The Bastion target uses the same workload VCN
# but reaches the instance via the forensic-capture path the quarantine NSG admits.
oci bastion session create-managed-ssh \
  --bastion-id "$IR_BASTION_OCID" \
  --display-name "forensic-${INCIDENT_ID}" \
  --target-resource-details '{
    "sessionType":"MANAGED_SSH",
    "targetResourceId":"'"$COMPROMISED_INSTANCE_OCID"'",
    "targetResourceOperatingSystemUserName":"opc",
    "targetResourcePort":22
  }' \
  --key-details '{"publicKeyContent":"ssh-ed25519 ..."}' \
  --session-ttl 10800

Remediation — Terraform

# Terraform OCI provider ~> 5.0
# Pre-built quarantine NSG, present in every VCN as standard fixture infrastructure.
# The isolation steps in the CLI block above swap a compromised instance's NSG
# attachment ONTO this NSG; this Terraform block ensures the NSG exists ahead
# of time so it is available the moment the runbook runs.

resource "oci_core_network_security_group" "quarantine_deny_all" {
  for_each       = toset(var.vcn_ocids)
  compartment_id = var.workload_compartment_ocid
  vcn_id         = each.value
  display_name   = "ir-quarantine-deny-all"
}

# Egress allow only to the forensic-capture subnet CIDR; no ingress rules at all.
resource "oci_core_network_security_group_security_rule" "quarantine_egress_forensic" {
  for_each                  = oci_core_network_security_group.quarantine_deny_all
  network_security_group_id = each.value.id
  direction                 = "EGRESS"
  protocol                  = "6" # TCP
  destination_type          = "CIDR_BLOCK"
  destination               = var.forensic_capture_subnet_cidr
  tcp_options {
    destination_port_range {
      min = 22
      max = 22
    }
  }
}

Remediation — OCI Resource Manager

# Submit the Terraform block above to OCI Resource Manager via a configured
# Git source-provider. Variables are entered through the Console UI (schema-driven
# by an optional schema.yaml); state is stored in OCI Object Storage automatically.
# This is an INVOCATION snippet — the .tf body is the existing Terraform block
# on this same control-box (do NOT duplicate HCL here).
oci resource-manager stack create-from-git-provider \
  --compartment-id "$COMPARTMENT_OCID" \
  --config-source-provider-id "$CONFIG_SRC_PROVIDER_OCID" \
  --repository-url "https://example.com/org/hardening-iac" \
  --branch-name "main" \
  --working-directory "modules/oci-ir-05-instance-isolation" \
  --display-name "oci-ir-05-instance-isolation" \
  --terraform-version "1.5.x"

# Plan + apply via the ORM job lifecycle (state stored in OCI automatically).
STACK_OCID=$(oci resource-manager stack list \
  --compartment-id "$COMPARTMENT_OCID" \
  --display-name "oci-ir-05-instance-isolation" \
  --query 'data[0].id' --raw-output)
PLAN_JOB_OCID=$(oci resource-manager job create-plan-job \
  --stack-id "$STACK_OCID" --query 'data.id' --raw-output)
oci resource-manager job create-apply-job \
  --stack-id "$STACK_OCID" \
  --execution-plan-strategy FROM_PLAN_JOB \
  --execution-plan-job-id "$PLAN_JOB_OCID"

Compliance mapping

CIS AWS Foundations v3.0.0 CIS Microsoft Azure Foundations v3.0.0 CIS GCP Foundation v4.0.0 CIS OCI Foundation v2.0.0 NIST SP 800-53 rev5 ISO/IEC 27001:2022 ISO/IEC 27017:2015
n/an/an/a(best-practices) IR-4(2); IR-4(7)A.5.26CLD.9.5.1

Log signals

  • OCI Logging Analytics records where 'Log Source' = 'OCI Audit Logs' and 'Service Name' = 'core' with eventName = 'UpdateVnic' binding an isolation-NSG to the affected instance's primary VNIC.
  • Cloud Guard responder activity events confirming the isolation Function fired against the target instance OCID.
  • VCN Flow Logs showing all inbound and outbound flows for the instance dropping to zero within 60 seconds of the isolation event.

Query

'Log Source' = 'OCI Audit Logs'
          and 'Service Name' = 'core'
          and eventName = 'UpdateVnic'
          | eval iso_nsg = if(data.request.payload.nsgIds like '%isolation-nsg%', 'YES', 'NO')
          | where iso_nsg = 'YES'
          | stats count by 'User Name', data.target.vnic.id, 'Compartment Name'

The isolation NSG is a pre-staged tenancy resource whose security rules deny all ingress and egress; binding it is a single VNIC update.

Alert threshold

  • Any VNIC isolation NSG binding outside the IR-automation Function principal — page; manual isolations must be ticketed.
  • Flow Logs continuing to show traffic for an isolated instance after 60 seconds — page; the isolation NSG rule set may be misconfigured.

Initial response

  1. Verify the isolation NSG ingress/egress rules deny all-protocols from 0.0.0.0/0 via oci network nsg rules list; correct the NSG if drift is detected.
  2. Detach the instance from its OKE node pool (if applicable) and disable its instance-pool auto-recovery so the orchestrator does not replace it.
  3. Hand off to the forensic-snapshot runbook oci-ir-03 to collect evidence before instance termination per general/ir.html.

References

Equivalent on: AWS · Azure · GCP

oci-ir-06-api-key-revoke ! HIGH RESPONSIVE

Document the compromised-identity runbook as a five-step contract: (a) disable the user immediately via oci iam user update --is-active false so no new authentication can succeed; (b) delete every API key fingerprint the user owns via oci iam user api-key delete so existing signed requests cannot be replayed; (c) enumerate active sessions inside the user's Identity Domain (Identity Domains, formerly IDCS) via oci identity-domains session list and revoke each via oci identity-domains session delete so console / SDK sessions that authenticated before disable still die; (d) rotate every Vault secret the user could read in the last 90 days via oci vault secret rotate — the rotation list comes from the audit-search saved query in oci-ir-04 filtered on the user's principal OCID against secret-read events; (e) audit the user's recent actions via the same audit-search to scope the blast radius (which resources were modified, which API keys were created for persistence, which IAM policies were updated). The prevention pair is oci-iam-05 on the OCI IAM page (admin-no-API-keys invariant — admin identities never own API keys, only delegated session credentials; the canonical Phase 5 control), which makes this runbook necessary only for non-admin identities (OCI — API key management (accessed 2026-05)).

Identity Domains terminology is used consistently throughout. The user lives inside an Identity Domain (formerly IDCS) which is the OCI IAM service surface for identity lifecycle; the oci identity-domains session family of commands is the canonical surface for session enumeration and revocation against domain users (OCI — Identity Domains session management (accessed 2026-05)). Federated users — those whose primary identity record lives in an upstream IdP and is referenced by an Identity Domain federation — additionally require the upstream IdP to revoke its own session for the same identity; the OCI side disables the user's domain shadow record, but the IdP-side session may need a separate revoke action against the upstream provider. Vault secret rotation is the explicit complement to user disable: a disabled user's reachable secrets are still reachable to anyone holding the secret value, so rotating every secret the user could read in the recent window is the only way to close the secret-exfiltration loop. The list of secrets to rotate is constrained by Vault key policy (cross-link to oci-data-05-vault-policy) — least-privilege at the key level bounds the rotation surface.

Remediation — OCI CLI

# oci CLI (v3.x)
# Step 1: disable the user so no new authentication can succeed.
oci iam user update \
  --user-id "$COMPROMISED_USER_OCID" \
  --is-active false

# Step 2: delete every API key fingerprint the user owns. Existing signed
# requests can no longer be replayed once the fingerprint is gone.
for FP in $(oci iam user api-key list --user-id "$COMPROMISED_USER_OCID" \
              --query 'data[].fingerprint' --raw-output | jq -r '.[]'); do
  oci iam user api-key delete \
    --user-id "$COMPROMISED_USER_OCID" \
    --fingerprint "$FP" \
    --force
done

# Step 3: enumerate active sessions inside the user's Identity Domain (formerly
# IDCS — Identity Domains is current). --idcs-endpoint is the Identity Domain endpoint URL.
oci identity-domains session list \
  --idcs-endpoint "$IDENTITY_DOMAIN_ENDPOINT" \
  --attribute-sets all \
  --filter "userId.value eq \"$COMPROMISED_USER_DOMAIN_ID\""

# For each session id returned:
for SID in $(oci identity-domains session list \
               --idcs-endpoint "$IDENTITY_DOMAIN_ENDPOINT" \
               --filter "userId.value eq \"$COMPROMISED_USER_DOMAIN_ID\"" \
               --query 'data.resources[].id' --raw-output | jq -r '.[]'); do
  oci identity-domains session delete \
    --idcs-endpoint "$IDENTITY_DOMAIN_ENDPOINT" \
    --session-id "$SID"
done

# Step 4: rotate every Vault secret the user could read in the last 90 days.
# The list comes from the audit-search saved query in oci-ir-04.
for SECRET_OCID in $(oci audit event list \
                       --compartment-id "$TENANCY_OCID" \
                       --start-time "$(date -u -d '90 days ago' --iso-8601=seconds)" \
                       --end-time   "$(date -u --iso-8601=seconds)" \
                       --query "data[?eventName=='GetSecretBundle' && data.identity.principalId=='$COMPROMISED_USER_OCID'].data.resourceId" \
                       --raw-output | jq -r '.[]' | sort -u); do
  oci vault secret rotate --secret-id "$SECRET_OCID"
done

# Step 5: scope the blast radius via audit-search (see oci-ir-04).
oci audit event list \
  --compartment-id "$TENANCY_OCID" \
  --start-time "$(date -u -d '90 days ago' --iso-8601=seconds)" \
  --end-time   "$(date -u --iso-8601=seconds)" \
  --query "data[?data.identity.principalId=='$COMPROMISED_USER_OCID'].{time:eventTime, action:eventName, resource:data.resourceName}"

Remediation — Terraform

# Terraform OCI provider ~> 5.0
# The compromised-identity runbook is an operator workflow against a live user
# OCID under incident pressure; it is NOT modelled as Terraform. This block
# documents the only Terraform-managed pre-positioning the runbook depends on:
# a documented Identity Domain (formerly IDCS) reachable via the canonical
# --idcs-endpoint URL, and a Vault that holds the secrets the rotation step
# touches. The prevention pair is canonically owned by iam.html#oci-iam-05-api-key-rotation.

data "oci_identity_domains_domain" "primary" {
  domain_id = var.primary_identity_domain_ocid
}

output "identity_domain_endpoint" {
  description = "Identity Domain (formerly IDCS) endpoint URL for the --idcs-endpoint flag in the runbook"
  value       = data.oci_identity_domains_domain.primary.url
}

Remediation — OCI Resource Manager

# Submit the Terraform block above to OCI Resource Manager via a configured
# Git source-provider. Variables are entered through the Console UI (schema-driven
# by an optional schema.yaml); state is stored in OCI Object Storage automatically.
# This is an INVOCATION snippet — the .tf body is the existing Terraform block
# on this same control-box (do NOT duplicate HCL here).
oci resource-manager stack create-from-git-provider \
  --compartment-id "$COMPARTMENT_OCID" \
  --config-source-provider-id "$CONFIG_SRC_PROVIDER_OCID" \
  --repository-url "https://example.com/org/hardening-iac" \
  --branch-name "main" \
  --working-directory "modules/oci-ir-06-api-key-revoke" \
  --display-name "oci-ir-06-api-key-revoke" \
  --terraform-version "1.5.x"

# Plan + apply via the ORM job lifecycle (state stored in OCI automatically).
STACK_OCID=$(oci resource-manager stack list \
  --compartment-id "$COMPARTMENT_OCID" \
  --display-name "oci-ir-06-api-key-revoke" \
  --query 'data[0].id' --raw-output)
PLAN_JOB_OCID=$(oci resource-manager job create-plan-job \
  --stack-id "$STACK_OCID" --query 'data.id' --raw-output)
oci resource-manager job create-apply-job \
  --stack-id "$STACK_OCID" \
  --execution-plan-strategy FROM_PLAN_JOB \
  --execution-plan-job-id "$PLAN_JOB_OCID"

Compliance mapping

CIS AWS Foundations v3.0.0 CIS Microsoft Azure Foundations v3.0.0 CIS GCP Foundation v4.0.0 CIS OCI Foundation v2.0.0 NIST SP 800-53 rev5 ISO/IEC 27001:2022 ISO/IEC 27017:2015
n/an/an/a(best-practices) IR-4; IA-5; AC-2(13)A.5.26; A.5.17CLD.9.5.1

Log signals

  • OCI Logging Analytics records where 'Log Source' = 'OCI Audit Logs' with eventName in (DeleteApiKey, DeleteAuthToken, DeleteOAuth2ClientCredential) targeting the suspect user OCID during an active IR window.
  • Identity Domain session-termination events for the suspect principal — these must be paired with the credential-revocation events to fully cut access.
  • Audit events showing the suspect principal's signing-key fingerprint still in use after the revocation — surface late-replay attempts.

Query

'Log Source' = 'OCI Audit Logs'
          and 'Service Name' = 'identity'
          and eventName in ('DeleteApiKey', 'DeleteAuthToken', 'DeleteOAuth2ClientCredential')
          and data.target.user.id = '$SUSPECT_USER_OCID'
          | stats count by 'User Name', eventName, data.target.fingerprint

The revocation gate confirms credential-deletion intent landed; the late-replay gate fires on continued use of an already-revoked fingerprint.

Alert threshold

  • Credential-revocation events absent on the suspect user OCID within 10 minutes of incident declaration — page; IR runbook step did not execute.
  • Continued audit-event activity bearing a fingerprint that appears in the credential-deletion event list — page; possible OCI control-plane caching delay or audit timestamp skew worth investigating.

Initial response

  1. Revoke all API keys, auth tokens, and OAuth2 credentials for the suspect user via the matching oci iam user *-delete commands.
  2. Terminate all active Identity Domain sessions for the suspect user via the admin console session inventory, then disable the user account with oci iam user update --is-active false.
  3. Rotate any downstream secrets the suspect principal may have accessed (Vault keys, ADB wallets) and brief the secrets-team per general/ir.html.

References

Equivalent on: AWS · Azure · GCP

oci-ir-07-tabletop ! MEDIUM PREVENTIVE

Run quarterly tabletop exercises against a fixed library of OCI-specific scenarios so the runbooks oci-ir-01 through oci-ir-06 are exercised before, not during, the next real incident. Four canonical scenarios cover the realistic exposure surface: (a) public Object Storage bucket leak detected via Cloud Guard — Cloud Guard's Public Bucket detector fires, the responder verifies, scopes the data exposed via the audit-search saved query for GetObject events against the bucket, and walks through Notifications routing; (b) leaked API key in commit history — a GitHub Secret-Scanner alert (or equivalent) names an API key fingerprint, the responder identifies the owning user via oci iam user api-key list aggregated across the tenancy, executes oci-ir-06 against that user, and reviews audit-search for any actions the leaked key already performed; (c) Cloud Guard CRITICAL problem (admin-action-from-untrusted-IP) — a tenancy-admin action is observed from an IP not on the allowlist, oci-ir-02's responder recipe auto-disables the principal, and the responder verifies the auto-action fired correctly and reconstructs the action via audit-search; (d) mass Object Storage download anomaly — VCN Flow Logs or Cloud Guard's Anomaly detector indicates bulk egress, the responder identifies the principal via audit-search aggregating GetObject count by principal in the last 24 hours, and walks through forensic capture and isolation. Mean-time-to-contain (MTC) is tracked across exercises and the trend is reported quarterly to the security leadership.

Oracle Support engagement is part of the tabletop, not a paper contract. Once a year (annual rotation, separate from the quarterly tabletop rotation), the on-call team opens a Severity-1 ticket against Oracle Support — a routine test ticket, clearly marked as a test in the subject — and verifies the named technical account manager (TAM) is reachable, the engagement path responds within the expected window, and the contact list the security team has on file matches the contact list Oracle Support has on file. The engagement-works test is the control: a paper contract for a Severity-1 IR engagement that the security team has never actually exercised cannot be relied on in the moment. The control is typed MEDIUM PREVENTIVE per the Phase 6/7/8 ir-07 precedent (aws-ir-07, azure-ir-07, gcp-ir-07) — the value is in preventing the decay of the rest of the runbooks before the next incident, not in responding to one. Cross-link General IR — tabletops for the cross-provider treatment and the NIST SP 800-61 rev 3 reference for tabletop expectations.

Remediation — OCI CLI

# oci CLI (v3.x)
# Tabletop scenarios are dry-runs of the controls oci-ir-01 through oci-ir-06.
# The scenarios themselves are workshop exercises; the CLI below is the
# instrumentation that runs each quarter to validate that the runbook surfaces
# are still reachable from the security-tooling environment.

# Scenario validation 1: Cloud Guard problem search returns recent CRITICAL problems.
oci cloud-guard problem list \
  --compartment-id "$TENANCY_OCID" \
  --compartment-id-in-subtree true \
  --risk-level-greater-than-or-equal-to CRITICAL \
  --time-last-detected-greater-than-or-equal-to "$(date -u -d '90 days ago' --iso-8601=seconds)" \
  --query 'data.items | length(@)'

# Scenario validation 2: Audit search returns events for the last incident window.
oci audit event list \
  --compartment-id "$TENANCY_OCID" \
  --start-time "$(date -u -d '90 days ago' --iso-8601=seconds)" \
  --end-time   "$(date -u --iso-8601=seconds)" \
  --query 'length(data)'

# Scenario validation 3: forensic bucket retention rule is still LOCKED.
oci os retention-rule list \
  --bucket-name forensic-evidence \
  --namespace "$TENANCY_NAMESPACE" \
  --query "data.items[?\"time-rule-locked\" != null].{name:\"display-name\", locked:\"time-rule-locked\"}"

# Scenario validation 4: every named break-glass identity still resolves.
for BG in breakglass-admin-01 breakglass-admin-02; do
  oci iam user list --compartment-id "$TENANCY_OCID" \
    --query "data[?name=='$BG'].{name:name,active:\"is-active\"}"
done

# Annual Oracle Support engagement test (manually opened Severity-1 ticket).
# Track ticket ID, response time, and TAM contact-list parity in the IR runbook
# repository; no CLI surface — this is a Console / My Oracle Support action.

Remediation — Terraform

# Terraform OCI provider ~> 5.0
# Tabletop exercises are workshop processes; they are not modelled as Terraform.
# This block documents the only durable artefact: a defined-tag namespace the
# security team uses to track tabletop runs (date, scenario, MTC) on a
# dedicated dummy resource so the timeline is auditable.

resource "oci_identity_tag_namespace" "tabletop" {
  compartment_id = var.ir_compartment_ocid
  name           = "Tabletop"
  description    = "Quarterly tabletop exercise run-log (date, scenario, MTC)"
}

resource "oci_identity_tag" "exercise_date" {
  tag_namespace_id = oci_identity_tag_namespace.tabletop.id
  name             = "exercise_date"
  description      = "ISO-8601 date the exercise was run"
}

resource "oci_identity_tag" "scenario" {
  tag_namespace_id = oci_identity_tag_namespace.tabletop.id
  name             = "scenario"
  description      = "One of: public-bucket, leaked-key, cloudguard-critical, mass-download"
}

resource "oci_identity_tag" "mtc_minutes" {
  tag_namespace_id = oci_identity_tag_namespace.tabletop.id
  name             = "mtc_minutes"
  description      = "Mean-time-to-contain in minutes for the scenario"
}

Remediation — OCI Resource Manager

# Submit the Terraform block above to OCI Resource Manager via a configured
# Git source-provider. Variables are entered through the Console UI (schema-driven
# by an optional schema.yaml); state is stored in OCI Object Storage automatically.
# This is an INVOCATION snippet — the .tf body is the existing Terraform block
# on this same control-box (do NOT duplicate HCL here).
oci resource-manager stack create-from-git-provider \
  --compartment-id "$COMPARTMENT_OCID" \
  --config-source-provider-id "$CONFIG_SRC_PROVIDER_OCID" \
  --repository-url "https://example.com/org/hardening-iac" \
  --branch-name "main" \
  --working-directory "modules/oci-ir-07-tabletop" \
  --display-name "oci-ir-07-tabletop" \
  --terraform-version "1.5.x"

# Plan + apply via the ORM job lifecycle (state stored in OCI automatically).
STACK_OCID=$(oci resource-manager stack list \
  --compartment-id "$COMPARTMENT_OCID" \
  --display-name "oci-ir-07-tabletop" \
  --query 'data[0].id' --raw-output)
PLAN_JOB_OCID=$(oci resource-manager job create-plan-job \
  --stack-id "$STACK_OCID" --query 'data.id' --raw-output)
oci resource-manager job create-apply-job \
  --stack-id "$STACK_OCID" \
  --execution-plan-strategy FROM_PLAN_JOB \
  --execution-plan-job-id "$PLAN_JOB_OCID"

Compliance mapping

CIS AWS Foundations v3.0.0 CIS Microsoft Azure Foundations v3.0.0 CIS GCP Foundation v4.0.0 CIS OCI Foundation v2.0.0 NIST SP 800-53 rev5 ISO/IEC 27001:2022 ISO/IEC 27017:2015
n/an/an/a(best-practices) IR-2; IR-3; IR-3(2)A.5.24; A.5.27n/a

Log signals

  • OCI Logging Analytics records correlating tabletop-exercise actions in the staging tenancy — the audit-event sequence the exercise produced becomes the regression baseline for the next exercise.
  • Exercise-day calendar entries cross-referenced against actual audit-event timestamps to measure detection-to-action latency for each runbook step.
  • Post-exercise gap-tracker spreadsheet rows that have not been closed within their documented SLA — drives the next exercise's scope.

Query

'Log Source' = 'OCI Audit Logs'
          and 'Compartment Name' = 'IR-Tabletop-Sandbox'
          and 'Time' between dateRelative('48hours') and now()
          | stats earliest('Time') as start_event, latest('Time') as last_event, count by 'Service Name'
          | eval exercise_minutes = (last_event - start_event)/60

Run the post-exercise reconstruction over the dedicated tabletop sandbox compartment so production audit data is not contaminated.

Alert threshold

  • Quarterly tabletop exercise not run within the prior 100 days — page the security-program owner; this is a programmatic deadline, not a runtime event.
  • Any post-exercise gap-tracker row whose remediation slipped past 90 days — page the gap owner.

Initial response

  1. Schedule the next tabletop exercise within 14 days; nominate participants spanning the IR-on-call rota, the Cloud Guard custodian, and the workload-team representatives most affected by the prior incident class.
  2. Reset the tabletop sandbox compartment to a known-good state via Resource Manager destroy/apply before exercise day.
  3. Capture the timed detection-to-action sequence during the exercise and feed corrections back into the matching runbook (the canonical place the gap will not recur) per general/ir.html.

References

Equivalent on: AWS · Azure · GCP

Sources