DEV Community

Cover image for Automated Access Blocking for FSx for ONTAP — From Ransomware Detection to Storage-Layer Deny

Automated Access Blocking for FSx for ONTAP — From Ransomware Detection to Storage-Layer Deny

Introduction

  • Problem: On Amazon FSx for NetApp ONTAP — a file system running on AWS — how do you automatically stop ransomware from spreading after detection (via ARP/AI, SIEM, or CloudWatch alarm)?
  • Solution: A Lambda function calls ONTAP REST API to immediately block the compromised user/IP at the storage layer and create a protective snapshot — the same containment-phase actions DII Storage Workload Security performs, but triggerable from any detection source, not just DII's own.
  • Scope: This is storage-layer access blocking plus evidence preservation. Host isolation, malware removal, credential rotation, and blocking lateral movement to other systems (eradication/recovery phases) are out of scope and still require human judgment.
  • Mechanism: SMB user blocking via name-mapping + session disconnect (immediate), NFS IP blocking via export-policy rules + NACL deny rules (immediate, network-layer) — all through REST API and AWS VPC APIs.
  • Trigger: Any source that can publish to SNS (CloudWatch Alarm, Datadog Monitor, Elastic SIEM, manual CLI).
  • Deploy: One CloudFormation stack. Tested with 52 unit tests (36 core + 16 network-layer). CLI helper for manual operations.
  • Cost: ~$0.51/month (Lambda + SNS + Secrets Manager). Add ~$14/month if VPC Endpoints are needed.
  • Timing: Under 2 minutes end-to-end (verified). Worst-case with Lambda cold start + VPC ENI attach: under 3 minutes.
  • Where this fits: In NIST CSF 2.0 terms, this module is a Respond-function tool (RS.MI mitigation + RS.AN analysis groundwork). It doesn't touch Govern, or the ML side of Detect — see the dedicated section below. (Companion modules in this repo now cover parts of Recover and Identify too — also covered below.)

GitHub: Yoshiki0705/fsxn-observability-integrations
Template: shared/templates/automated-response.yaml
Module: shared/python/ontap_response.py

This is Part 18 of the Serverless Observability for FSx for ONTAP series. It builds on the detection capabilities from Part 17 (CloudWatch Log Alarm) and Part 3 (ARP + Datadog).


The Gap Between Detection and Response

The previous articles in this series covered detection:

  • Part 3: ARP detects ransomware → EMS event → alert in ~30 seconds
  • Part 17: CloudWatch Log Alarm detects suspicious admin operations → alert in ~90 seconds

But an alert is just information. The real question is: between when detection fires and when a human completes their response, what should the system do automatically?

In a ransomware scenario, every second counts. If ARP detects file encryption and you get a Slack notification, but the SOC analyst is in a meeting, the attacker keeps encrypting files for 15-30 minutes before anyone reacts.

Where This Idea Came From

We have previously recommended dedicated storage security products — such as NetApp DII (Data Infrastructure Insights, formerly Cloud Insights) Storage Workload Security — to close this gap. DII's built-in per-user ML baselines detect anomalies and automatically block users or IPs at the storage layer, using the same ONTAP mechanisms (name-mapping, export-policy rules) this module uses. If you already run DII in your on-premises NetApp ONTAP environment, it remains a valid choice on AWS as well.

The friction shows up in a specific situation this series keeps running into: detection that originates outside DII. Part 3's ARP → Datadog pipeline, Part 17's CloudWatch Log Alarm, or any third-party SIEM monitor produces an alert. Based on DII's publicly available documentation, its response actions are designed around DII's own detection rather than an arbitrary SNS message from your existing observability stack — we didn't find a documented path to trigger a DII block from an external alert, and building one was outside the scope of this AWS-native series. There's also a practical entry-cost question: DII is a capacity-based licensed product with its own SaaS data plane, which is a different investment than "add a Lambda to a stack you already have."

So the question became: "Can the same containment-phase actions — blocking storage access, taking a snapshot, disconnecting sessions — be triggered by any event that can publish to an SNS topic, using only ONTAP REST API and AWS-native services?" That's what shared/python/ontap_response.py and this article implement. It's not a replacement for DII's ML detection — see the comparison table further down this article, and the fuller comparison plus FAQ ("Does this replace DII Storage Workload Security entirely?") in the Automated Response Guide on GitHub — it's a way to get the same storage-layer response when your detection already lives somewhere else.


Architecture

+--------------------------------------------------------------+
| Detection (existing - any source)                            |
|                                                              |
|  CloudWatch Log Alarm --+                                    |
|  ARP EMS -> Monitor ----+                                    |
|  FPolicy -> SIEM -------+-- SNS Trigger Topic                |
|  Manual CLI ------------+                                    |
|                                                              |
+--------------------------------------------------------------+
| Response (NEW - this article)                                |
|                                                              |
|  SNS -> Lambda (VPC) -> ONTAP REST API                       |
|                           |                                  |
|                           +- Block SMB user (name-mapping)   |
|                           +- Block NFS IP (export-policy)    |
|                           +- Block NFS IP (NACL — immediate) |
|                           +- Create snapshot (evidence)      |
|                           +- Disconnect CIFS sessions        |
|                           +- Notify (SNS -> email/PagerDuty) |
|                                                              |
+--------------------------------------------------------------+
Enter fullscreen mode Exit fullscreen mode

The key design choice: detection and response are decoupled via SNS. Any system that can publish a JSON message to an SNS topic can trigger a storage-layer block. This means you're not locked into a single detection product.


How ONTAP User Blocking Works

SMB: Name-Mapping Deny

ONTAP resolves Windows users to UNIX users via name-mapping rules. By mapping a Windows user to an empty UNIX identity (" "), the SID-to-UNIX translation fails and all file operations are denied.

Before: CORP\jdoe → maps to → jdoe (UNIX) → access granted
After:  CORP\jdoe → maps to → " " (empty)  → access DENIED
Enter fullscreen mode Exit fullscreen mode

This is an SVM-wide block — it affects every volume and share within the SVM.

Operational safety note: The deny mapping is inserted at position 1 by default, meaning it's evaluated before any existing name-mappings. If your SVM has existing name-mappings for service accounts or automation, use a higher index (the module uses index 1; customize via ontap_response.py if needed). Always test with health_check and a non-production user first. To immediately undo an accidental block: ./automated-response-cli.sh unblock-smb --domain CORP --user jdoe

ONTAP REST API call:

POST /api/name-services/name-mappings
{
  "direction": "win_unix",
  "index": 1,
  "pattern": "CORP\\jdoe",
  "replacement": " ",
  "svm": {"name": "svm-prod-01"}
}
Enter fullscreen mode Exit fullscreen mode

NFS: Export-Policy Deny Rule

For NFS clients, blocking is done via export-policy rules with ro_rule: never and rw_rule: never:

POST /api/protocols/nfs/export-policies/{policy_id}/rules
{
  "clients": [{"match": "fsxn_auto_response,10.0.5.99"}],
  "ro_rule": ["never"],
  "rw_rule": ["never"],
  "superuser": ["never"],
  "protocols": ["any"],
  "index": 999
}
Enter fullscreen mode Exit fullscreen mode

The fsxn_auto_response marker in the client match makes these rules identifiable and easy to clean up. Use a high index (e.g., 999) to avoid conflicts with existing rules.

Scope note: Both SMB and NFS blocks are SVM-wide — they affect ALL volumes and shares within the target SVM, not just the volume specified in the contain_* action. In multi-tenant SVMs (multiple applications sharing one SVM), this is the intended blast radius for containment. If you need volume-level granularity instead, use create_snapshot (per-volume) and coordinate with your network team for host-level isolation.

NFS: Why Export-Policy Alone Isn't Instant (and How We Fixed It)

The export-policy rule above takes effect on the server side immediately — but Linux NFS clients cache access decisions for up to 60 seconds (actimeo default). During that window, the attacker's existing mount can still read/write despite the ONTAP-layer deny.

Unlike SMB (where disconnect_smb_sessions forces re-authentication), NFS has no equivalent "kill this client's connection" API. (NFSv4 has lease management internally, but ONTAP does not expose a REST API endpoint for forced lease revocation of a specific client.)

Solution: Network-layer blocking via VPC NACL deny rules.

When FsxSubnetId is configured, contain_nfs_threat automatically applies both layers:

Layer Mechanism Effect Bypass?
ONTAP Export-policy deny rule Persistent, survives NACL removal Client cache (up to 60s)
Network NACL deny rule (rule 50-99) Immediate (packet-level) Cannot be bypassed by client
# Deploy with network-layer NFS blocking enabled:
aws cloudformation deploy \
  --template-file shared/templates/automated-response.yaml \
  --stack-name fsxn-automated-response \
  --parameter-overrides \
    ... \
    FsxSubnetId=<subnet-where-fsx-enis-reside> \
  --capabilities CAPABILITY_NAMED_IAM
Enter fullscreen mode Exit fullscreen mode

The NACL rule blocks ALL traffic from the attacker IP at the VPC level — no client-side cache, no retry window. The export-policy rule persists as the long-term block after the NACL is eventually removed during investigation.

Blast radius note: By default, the NACL rule blocks ALL protocols from the IP (not just NFS). If the attacker IP is also used for monitoring or management, set "block_all_ports": false in the SNS message to block only NFS port 2049.

Why NACL and not Security Group? Security Groups are allow-only — you cannot add a deny rule for a specific IP. NACLs support explicit deny and are evaluated before Security Groups, making them the correct mechanism for emergency IP blocking.

VPC Endpoint requirement: The Lambda calls the EC2 API (CreateNetworkAclEntry) to manage NACL rules. If your VPC has a NAT Gateway, this works automatically. If not, add an EC2 Interface VPC Endpoint (com.amazonaws.<region>.ec2) or set CreateVpcEndpoints=true and add EC2 manually. Without network access to the EC2 API, the NACL block will timeout while the ONTAP export-policy block still succeeds.

Session Disconnect

Blocking prevents new operations, but existing CIFS sessions can continue. The composite action also disconnects active sessions:

DELETE /api/protocols/cifs/sessions/{svm_uuid}/{identifier}/{connection_id}
Enter fullscreen mode Exit fullscreen mode

Safety Features

Input Validation

The module validates all inputs before calling ONTAP:

  • Username injection prevention (blocks ;, |, &, `, $, newlines)
  • Protected account denylist (fsxadmin, administrator, vsadmin, system)
  • IP address format validation (valid IPv4 octets 0-255)

Snapshot Storm Prevention

A configurable cooldown (default: 15 minutes) prevents creating multiple snapshots during a sustained attack:

# If a snapshot with our prefix was created <15 min ago → skip
result = client.create_snapshot(
    svm_name="svm-prod",
    volume_name="vol_data",
    cooldown_minutes=15,  # Prevents storm
)
# result["status"] == "skipped" if cooldown active
Enter fullscreen mode Exit fullscreen mode

Marker-Based Cleanup

All response rules include a consistent marker (fsxn_auto_response), making it straightforward to find and remove all automated blocks:

# Find all our rules
export-policy rule show -clientmatch *fsxn_auto_response*
vserver name-mapping show -direction win-unix -replacement " "
Enter fullscreen mode Exit fullscreen mode

Evidence-handling note: The protective snapshot this module creates is evidence, and evidence needs a chain of custody, not just a timestamp. Trigger source, exact UTC time, and post-action API confirmation are already captured in CloudWatch Logs — but pre-action state (what the name-mapping or export-policy looked like before the block) isn't currently queried and logged, and the SNS trigger message itself isn't hashed. If this snapshot might ever need to hold up in an investigation, not just an ops postmortem, review the chain-of-custody gap table in the Security Addendum before treating "snapshot created" as "evidence preserved."

Time-Limited Blocks

Persistent blocks are a real operational risk — a false positive can lock out a legitimate user indefinitely if nobody notices. The companion automated-response-ttl.yaml stack deploys an EventBridge Scheduler that periodically checks for and auto-removes blocks older than a configurable TTL, so a missed alert doesn't turn into a standing lockout. Deploy it alongside the main stack.


Deployment

One Stack Deploy

aws cloudformation deploy \
  --template-file shared/templates/automated-response.yaml \
  --stack-name fsxn-automated-response \
  --parameter-overrides \
    OntapMgmtIp=<management-ip> \
    OntapCredentialsSecretArn=<secret-arn> \
    VpcId=<vpc-id> \
    SubnetIds=<subnet-1>,<subnet-2> \
    SecurityGroupId=<sg-id> \
    DefaultSvmName=svm-prod-01 \
    SharedPythonLayerArn=<layer-arn> \
    NotificationEmail=security-team@example.com \
  --capabilities CAPABILITY_NAMED_IAM
Enter fullscreen mode Exit fullscreen mode

New parameter (from verification): SharedPythonLayerArn — provide the ARN of the fsxn-shared-python Lambda Layer containing ontap_response.py. Without this, the handler fails with ModuleNotFoundError. Build and publish the layer first:

bash shared/python/build-layer.sh
aws lambda publish-layer-version --layer-name fsxn-shared-python \
  --zip-file fileb://shared/python/dist/fsxn-shared-python-layer.zip \
  --compatible-runtimes python3.12 --query 'LayerVersionArn' --output text

The stack creates:

  • SNS Trigger Topic (entry point)
  • SNS Notification Topic (results)
  • Lambda function (VPC, Python 3.12)
  • DLQ with encryption
  • CloudWatch Log Group (365-day retention)
  • DLQ depth alarm
  • VPC Endpoints for Secrets Manager + SNS (if CreateVpcEndpoints=true)

DLQ alarm = urgent: A message in the DLQ means a containment action failed. Unlike most DLQs where retry-later is fine, here it means the attacker may still have access. Treat DLQ depth > 0 as a P1 incident requiring immediate human investigation. See the DLQ Replay Runbook for recovery steps.

Critical: VPC Endpoints Required. Lambda in a VPC cannot reach AWS APIs (Secrets Manager, SNS) without Interface VPC Endpoints or a NAT Gateway. The stack creates these by default (CreateVpcEndpoints=true). If your VPC already has them, set it to false. Without this, Lambda will timeout on every invocation.

Cost note: If your VPC already has a NAT Gateway, set CreateVpcEndpoints=false — the Lambda can reach AWS APIs through NAT without the additional ~$14/month VPC Endpoint cost. The $0.51/month figure is infrastructure cost only; operational cost (tuning detection rules, investigating false positives, running quarterly drills) is the larger ongoing investment.

The CloudFormation template embeds the Lambda code inline for a quick first deployment. For a GitOps-friendly setup, package ontap_response.py as a Lambda Layer instead using build-layer.sh and version it independently of the stack.

Comprehensive deployment guidance: For VPC Endpoint conflict avoidance, parameter file templates, and pre-deployment environment validation, see the Deployment Guide. It includes a pre-flight check script that detects existing VPC Endpoints before you deploy — the single most common source of deployment rollbacks in this project.

Connect Detection Sources

Subscribe the trigger topic to your detection:

Source How to Connect
CloudWatch Log Alarm Set alarm action to trigger topic ARN
Datadog Monitor Use @sns-<topic> in notification
Elastic SIEM Use SNS action in Kibana alert
Manual aws sns publish --topic-arn <arn> --message '<json>'

Alert-tuning note: Whatever you wire to the trigger topic will fire on every match, and every fire generates a notification. A detection rule tuned for "catch everything" rather than "catch what matters" turns this pipeline into another source of alert fatigue — the Reliability note in the Automated Response Guide already flags the self-inflicted-DoS risk of an over-triggering rule; the analyst-facing version of that same risk is that a noisy rule buries the one block that actually mattered in a pile of routine ones. Tune the upstream detection rule's specificity before wiring it here, not after the first pager rotation complains.


CLI Helper

For manual operations and testing, use the included CLI wrapper:

export RESPONSE_TOPIC_ARN="arn:aws:sns:ap-northeast-1:123456789012:fsxn-automated-response-trigger"
export DEFAULT_SVM="svm-prod-01"

# Full containment (snapshot + block + disconnect)
./shared/scripts/automated-response-cli.sh contain-smb \
  --domain CORP --user jdoe --volume vol_data \
  --reason "ARP detection - arw.volume.state alert"

# Block a single IP
./shared/scripts/automated-response-cli.sh block-nfs \
  --ip 10.0.5.99 --reason "Mass deletion from FPolicy"

# Unblock after investigation
./shared/scripts/automated-response-cli.sh unblock-smb \
  --domain CORP --user jdoe

# Dry-run test (no publish)
./shared/scripts/automated-response-cli.sh test
Enter fullscreen mode Exit fullscreen mode

If the same compromised identity or IP has access across multiple SVMs (e.g., a domain user with shares on both production and DR), use automated-response-multi-svm-cli.sh instead — it wraps the single-SVM CLI, fans out the same action across a comma-separated SVM list, and reports per-SVM success/failure:

./shared/scripts/automated-response-multi-svm-cli.sh contain-smb \
  --svms "svm-prod-01,svm-prod-02,svm-dr-01" \
  --domain CORP --user jdoe --volume vol_data \
  --reason "ARP detection - multi-SVM block"
Enter fullscreen mode Exit fullscreen mode

Composite Actions

Individual actions (block_smb_user, block_nfs_ip, create_snapshot, disconnect) can be combined into a single message:

Action Steps Use Case
contain_smb_threat Snapshot → Block SMB user → Disconnect sessions Compromised AD user detected
contain_nfs_threat Snapshot → Block NFS IP Suspicious NFS client activity
contain_multiprotocol_threat Snapshot → Block SMB user → Block NFS IP → Disconnect sessions Volume accessed via both SMB and NFS — a single-protocol block lets the attacker switch protocols and continue

The contain_* naming maps to the Containment phase in NIST SP 800-61's incident handling model. This module only covers storage-layer access blocking and evidence preservation, though. Isolating the compromised host, removing malware, rotating credentials, and blocking lateral movement to other systems (eradication/recovery) remain out of scope and still require a human (or another IR tool) to handle.


Comparison with DII Storage Workload Security

Both approaches use the same underlying ONTAP mechanisms. The difference is where detection intelligence lives:

Aspect DII Storage Workload Security This Approach
Blocking mechanism ONTAP REST API ONTAP REST API (identical)
Detection Built-in ML (per-user baselines) Your choice of SIEM/observability
Context scope Storage only Storage + network + application
Data residency SaaS (vendor cloud) Your AWS VPC
Integration Limited export Native (detection originates from your tools)
Cost model Capacity-based license ~$0.51/month (pay-per-use)
Setup time Days (agent + collector + AD config) 30 minutes (CloudFormation)

Neither approach is "better" — they suit different contexts. If you already have a SIEM with anomaly detection (Datadog ML, Elastic ML Jobs, Splunk MLTK), or if your alert originates outside DII, this approach extends your existing investment to cover storage-layer access blocking. If you already run DII and your detection lives there too, its built-in ML and turnkey containment remain a solid choice — see the Automated Response Guide for the fuller writeup.

The table above compares mechanisms. The next section places both mechanisms inside a wider risk-management frame, because "which tool blocks the user" and "is your organization's ransomware posture actually sound" are different questions.


Where This Fits in Cyber Resilience: NIST CSF 2.0

It's tempting to read a 65-second block-and-snapshot flow as "ransomware handled." It isn't — it's one function, in one framework, among six. NIST CSF 2.0 organizes an organization's entire cybersecurity risk-management program into Govern, Identify, Protect, Detect, Respond, Recover, and NIST's dedicated ransomware profile (NIST IR 8374r1) maps ransomware-specific outcomes onto those six functions. Both AWS (Ransomware Risk Management on AWS Using the NIST CSF) and NetApp (Fortify your cybersecurity defenses with NIST framework) publish their own mappings for the same reason this section exists: to be explicit about which function a given tool covers, and which functions remain the organization's job regardless of tooling.

Placed on that map, this module and DII Storage Workload Security occupy the same narrow slice:

CSF 2.0 Function What It Covers Where This Module (or DII) Sits
Govern Risk strategy, roles, policy, board oversight Out of scope for both — this is an organizational responsibility no storage-layer tool automates
Identify Asset/data inventory, classification Out of scope for this module, but a companion module in the same repo — a Content-Level PII Classification Scanner using Amazon Comprehend — covers text/structured-data content discovery. Office/PDF content extraction is not implemented; DII's parent product line offers broader data classification separately
Protect Safeguards that reduce likelihood/impact Partially covered — ONTAP Snapshot/SnapLock, export-policy, name-mapping are the underlying safeguards both approaches call
Detect Finding anomalies via monitoring Not this module's job — it responds to a detection, it doesn't produce one (see Part 3 and Part 17 for the Detect side)
Respond Mitigation, analysis, reporting on a detected incident ✅ This is what this module does — block, snapshot, disconnect, notify
Recover Restoring systems and coordinating with stakeholders The snapshot this module creates is Respond-phase evidence, not a verified recovery point on its own. A companion Verified-Clean Recovery Point Guide closes part of that gap — see below — though the restore itself and stakeholder-level coordination remain manual

Governance-reporting note: If you're reporting this capability up to a risk committee or board, resist framing it as "ransomware is covered." It's more accurate — and more useful for risk-register purposes — to say "we have automated Respond-phase containment; Govern-phase maturity, and the ML side of Detect, are tracked separately." CloudFormation-as-code and CloudWatch Logs give you the audit evidence (who deployed what, when a block fired and why) that a Govern program consumes as input, but they aren't a substitute for having the program itself.

Privacy note: The Content-Level PII Classification Scanner referenced in the Identify row above is worth a second look if your org is tracking data-minimization obligations. Its findings deliberately record only entity type, count, and confidence per file (EMAIL, SSN, CREDIT_DEBIT_NUMBER, and so on via Amazon Comprehend) — never the matched text itself — so a "this file has 3 SSN-pattern matches" report doesn't itself become a new PII exposure. That's useful for prioritizing where to apply DLP controls, but it isn't a substitute for a DPO's formal data classification review, and it currently can't see inside Office documents or PDFs (no text extraction yet) — plan around that blind spot if your regulated data lives mostly in those formats.

A point worth being precise about on the Recover side, since it's easy to overstate: a snapshot existing is a Protect-phase artifact, not proof that recovery works.

Recovery-sufficiency note: "We took a snapshot" and "we have a verified-clean recovery point" are two different maturity levels. Elastio's mapping of ransomware recovery to CSF 2.0 makes the same point industry-wide: RC.RP (Incident Recovery Plan Execution) is only credible once someone has actually restored from the recovery point and confirmed it's free of compromise — not merely confirmed the snapshot job succeeded. This module alone only delivers the first maturity level (the snapshot). A companion Verified-Clean Recovery Point Guide in this repo now automates a version of the second: it clones the candidate snapshot (FlexClone), scans the clone through an isolated S3 Access Point for ransomware-associated file extensions, and records a pass/fail verdict — without ever touching the production volume.

What "Verified Recovery" Looks Like in Practice

After the containment above creates its protective snapshot, you can verify it before restoring:

Candidate Snapshot
     │
     ▼ FlexClone (copy-on-write, instant, never modifies source)
     │
     ▼ Isolated S3 Access Point (VPC-scoped)
     │
     ▼ Scan for ransomware-associated extensions (.encrypted, .locked, etc.)
     │
     ▼ Verdict: clean / suspicious / error
     │
     ▼ Auto-cleanup (clone + access point deleted)
Enter fullscreen mode Exit fullscreen mode

This is a single Step Functions workflow (5 Lambda functions). Deploy it and run a verification:

# Deploy the verification workflow
aws cloudformation deploy \
  --template-file shared/templates/restore-verification.yaml \
  --stack-name fsxn-restore-verification \
  --parameter-overrides \
    VpcId=<vpc-id> SubnetIds=<subnet-1>,<subnet-2> \
    SecurityGroupId=<sg-id> OntapMgmtIp=<mgmt-ip> \
    OntapCredentialsSecretArn=<secret-arn> \
  --capabilities CAPABILITY_NAMED_IAM

# Verify a specific snapshot before restoring
aws stepfunctions start-execution \
  --state-machine-arn <from stack outputs> \
  --input '{"svm_name":"svm-prod","volume_name":"vol_data","snapshot_name":"incident_response_20260712_005307"}'
Enter fullscreen mode Exit fullscreen mode

The workflow completes in 2-5 minutes (depending on clone creation and access point attachment time). The verdict appears in the execution output and is logged to CloudWatch for audit.

What it doesn't do: This is a fast extension-pattern pre-filter — it flags a volume dominated by renamed/encrypted files. It is not a deep content inspection, and it does not exercise an actual end-to-end restore. Treat a "clean" verdict as a necessary first gate before committing to a restore, and still run periodic full restore drills into an isolated environment separately.

Restore-testing note: Be precise about what that verdict actually certifies, because it's easy to over-claim from the runbook name alone. The scan is a fast extension-pattern pre-filter — it flags a volume dominated by .encrypted/.locked-style renamed files — not a deep content inspection, and it does not exercise an actual restore end-to-end. Treat a "clean" verdict as a necessary first gate before a human commits to a restore, and still run periodic full restore-and-verify drills into an isolated environment separately. Don't let an automated pre-filter quietly become your only recovery test.

This module's protective snapshot, in other words, is Respond-phase evidence preservation, and the verification workflow above is a fast pre-filter toward Recover-phase confidence — neither is a substitute for a tested, human-verified restore. A fuller function-by-function breakdown — including where this repository's other components (ARP, EMS detection, Forensics dashboards, the recovery verification and PII scanning modules) land on Identify/Protect/Detect/Recover — lives in the Cyber Resilience Capability Map.


End-to-End Flow: ARP Detection → Auto-Block

Here's the full flow from ransomware detection to an automated storage-layer block. This flow has been verified end-to-end on ONTAP 9.17.1P7D1 (FSx for ONTAP, ap-northeast-1). Key timings from actual execution:

  • ARP/AI detection: triggered within minutes of ransomware-like file operations (no learning period — ARP/AI in ONTAP 9.16.1+ is immediately active)
  • contain_smb_threat Lambda execution: 1.8 seconds (snapshot + block + session disconnect in a single invocation)
  • SMB access denial confirmed after re-authentication
1. User "jdoe" starts encrypting files on vol_data
   (zip with password → delete original → new extension)
         │
2. ONTAP ARP/AI detects anomaly (entropy + extension changes)
   No learning period required (ONTAP 9.16.1+ / ARP/AI)
         │  Detection within minutes
         ▼
3. EMS event: callhome.arw.activity.seen (severity: alert)
   ONTAP auto-creates Anti_ransomware_attack_backup snapshot
         │
4. EMS Webhook → API Gateway → Lambda → Observability Platform
         │  ~30 seconds
         ▼
5. Observability Monitor fires (ARP alert detected)
         │
6. Monitor → SNS publish (contain_smb_threat)
         │  ~5 seconds
         ▼
7. Response Lambda executes (1.8s measured):
   a) Creates incident_response_20260712_005307 snapshot
   b) Blocks CORP\jdoe via name-mapping (deny on re-authentication)
   c) Attempts CIFS session disconnect
   d) Sends notification to security team
         │
8. Total time: detection + routing (~35s) + response (1.8s) ≈ under 2 minutes
Enter fullscreen mode Exit fullscreen mode

SOC correlation tip: Always include incident_id and detection_source in your SNS message so that the storage-layer block can be correlated with the upstream detection in your SIEM timeline:

{"action":"contain_smb_threat","svm_name":"svm-prod","domain":"CORP",
 "username":"jdoe","volume_name":"vol_data",
 "reason":"ARP alert","incident_id":"INC-2026-0712-001",
 "detection_source":"datadog-monitor-arp"}

How immediate blocking actually works: The contain_smb_threat composite action achieves effective immediate cutoff through a two-step mechanism:

  1. name-mapping deny — blocks all future authentication attempts (evaluated at session setup time, not per-I/O)
  2. disconnect_smb_sessions — forcefully terminates the user's existing active sessions via DELETE /protocols/cifs/sessions/{svm}/{id}/{conn}

When the existing session is terminated, the Windows SMB client automatically attempts to re-establish the connection — at which point the name-mapping deny takes effect and access is refused. The net result: the user is cut off within seconds of the Lambda executing, not at the next natural session expiry.

If the disconnect call returns HTTP 404 (session already gone — e.g., the encrypting process finished before the Lambda fired), that's expected and logged but not treated as an error. The name-mapping deny still prevents any future reconnection.

ARP/AI verification note (ONTAP 9.16.1+): The CLI command security anti-ransomware volume attack simulate referenced in some ONTAP documentation does NOT exist in ONTAP 9.17.1. To trigger ARP/AI detection for testing, perform actual ransomware-like file operations: encrypt files with a password, delete originals, and add a new file extension. ARP/AI detects the high-entropy + deletion + never-seen-extension pattern. Detection threshold: 5+ distinct new extensions within 48 hours. See the ONTAP REST API Quick Reference for details.


Testing

The module has 52 unit tests covering:

Category Tests What's Verified
SMB blocking 3 Success, SVM not found, API error
SMB unblocking 2 Success, not found
NFS blocking 2 Success, policy not found
NFS unblocking 2 Success, not found
Snapshots 5 Success, cooldown active/expired/disabled, volume not found
Session disconnect 3 By user, no sessions, missing params
Composite actions 3 Full sequence, partial failure, NFS containment
Input validation 7 Protected accounts, injection prevention, IP validation
Configurable protected accounts 1 PROTECTED_ACCOUNTS_EXTRA env var
List blocks 2 With results, empty
Health check 3 Success, SVM not found, unreachable
Error handling 3 Error attributes, timeout, malformed response
NACL blocking 16 Block IP, unblock, list active, find NACL, rule number allocation, marker validation
python3 -m pytest shared/python/tests/test_ontap_response.py shared/python/tests/test_network_block.py -v
# 52 passed in 0.06s
Enter fullscreen mode Exit fullscreen mode

Verify Your Deployment

After deploying to your environment, run these checks within the first 30 days:

  1. Day 1: health_check action succeeds (ONTAP reachable, credentials valid)
  2. Day 1: Test create_snapshot on a non-production volume (confirm snapshot appears)
  3. Week 1: Run a full contain_smb_threat drill against a test user on a test SVM
  4. Week 1: Verify TTL cleanup removes the test block after configured minutes
  5. Day 30: Confirm DLQ is empty (no silent failures), CloudWatch dashboard shows expected invocation count

If any of these fail, check the Troubleshooting section in Prerequisites.


Related Posts in This Series


EMS Webhook Integration: Payload Format

When connecting ARP EMS events to your detection pipeline, note the actual ONTAP EMS webhook payload format (verified on ONTAP 9.17.1P7D1):

{
  "message-name": "callhome.arw.activity.seen",
  "message-severity": "alert",
  "message-timestamp": "2026-07-12T00:42:06+00:00",
  "parameters": {
    "vserver-name": "svm-prod",
    "volume-name": "vol_data"
  }
}
Enter fullscreen mode Exit fullscreen mode

Caution: Field names use hyphens (message-name), not camelCase (messageName) or snake_case (message_name). This matters for SIEM parsing rules and Lambda handler field validation.

The EMS event for ARP attack detection is callhome.arw.activity.seen (severity: alert), not arw.volume.state (which is a state-change notification for ARP enable/disable). The callhome.* prefix indicates an ONTAP AutoSupport-class event (internal telemetry classification, not external data transmission). Configure your detection rules to match the correct event name.


Resources

Top comments (0)