<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</title>
    <description>The latest articles on DEV Community by Yoshiki Fujiwara(藤原 善基)@AWS Community Builder (@yoshikifujiwara).</description>
    <link>https://dev.to/yoshikifujiwara</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1143688%2F2e0886ff-292c-4e8f-a588-bc7629c2321b.jpeg</url>
      <title>DEV Community: Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</title>
      <link>https://dev.to/yoshikifujiwara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yoshikifujiwara"/>
    <language>en</language>
    <item>
      <title>S3 Burst on ONTAP Files — Collect via S3 API, Consume via FlexCache NFS/SMB</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Mon, 10 Aug 2026 01:06:17 +0000</pubDate>
      <link>https://dev.to/aws-builders/s3-burst-on-ontap-files-collect-via-s3-api-consume-via-flexcache-nfssmb-23nb</link>
      <guid>https://dev.to/aws-builders/s3-burst-on-ontap-files-collect-via-s3-api-consume-via-flexcache-nfssmb-23nb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;You have an S3 ingestion pipeline. But the consumers only see an NFS mount. Sound familiar?&lt;/p&gt;

&lt;p&gt;You want to deliver driving logs to a HiL test bench, stage design jobs for an EDA toolchain, push rendering assets to production nodes, or feed genomic sequencer output to an HPC cluster. In each case the writer speaks S3 API in the cloud while the reader speaks NFS/SMB on physical hardware. Without a way to connect these directly, you end up adding a sync job in between — and with it comes latency, cost, and one more thing to monitor.&lt;/p&gt;

&lt;p&gt;This structure spans industries: automotive, semiconductor, media/VFX, oil and gas, life sciences, manufacturing, remote work, and IoT (see the full table in When This Pattern Fits below).&lt;/p&gt;

&lt;p&gt;This post introduces a pattern that removes that sync job. Write to an Amazon FSx for NetApp ONTAP (hereafter FSx for ONTAP) S3 Access Point, and the data appears on a FlexCache NFS mount. No copy job, no configuration between the two. I measured all four directions to see how fast the visibility propagates.&lt;/p&gt;

&lt;p&gt;Here's the conclusion up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 PutObject → FlexCache NFS read visibility: p50 8 ms.&lt;/strong&gt; No copy job, no configuration&lt;/li&gt;
&lt;li&gt;FlexCache overhead is +5 ms (vs. reading origin directly) — nearly transparent for same-region VPC peering&lt;/li&gt;
&lt;li&gt;Reverse direction (NFS write → S3 AP read) is p50 44 ms, dominated by S3 API overhead. Not the main path in this design&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FlexCache duality (NAS bucket S3 reads on FlexCache volumes) works, but only after &lt;code&gt;-is-s3-enabled true&lt;/code&gt; is set on the cache volume&lt;/strong&gt; in advanced privilege. My first attempt returned &lt;code&gt;AccessDenied&lt;/code&gt; because that step was missing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files" rel="noopener noreferrer"&gt;Yoshiki0705/s3-burst-on-ontap-files&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdxibfen6060p4uh6bh9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdxibfen6060p4uh6bh9g.png" alt="S3 Burst on ONTAP Files — Architecture Overview" width="800" height="249"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[S3 Client] --PutObject--&amp;gt; [S3 Access Point] --&amp;gt; [Origin Volume]
                                                       |
                                                  FlexCache
                                                       |
                                                [NFS/SMB Client]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Collect (write)&lt;/td&gt;
&lt;td&gt;S3 Access Point on FSx for ONTAP&lt;/td&gt;
&lt;td&gt;S3 API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source of truth&lt;/td&gt;
&lt;td&gt;Origin volume&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distribution&lt;/td&gt;
&lt;td&gt;FlexCache&lt;/td&gt;
&lt;td&gt;Cluster/SVM peering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consume (read)&lt;/td&gt;
&lt;td&gt;Cache volumes&lt;/td&gt;
&lt;td&gt;NFS/SMB only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The S3 Access Point attaches to the origin only. Cache volumes serve NFS/SMB. This single decision simplifies the design considerably:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One write path. The origin is authoritative; writes always go through the S3 AP&lt;/li&gt;
&lt;li&gt;No S3 implementation differences pushed to the edge&lt;/li&gt;
&lt;li&gt;Cache side requires only FlexCache + NFS/SMB — fewer platform constraints to hit&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test Environment
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;2026-08-09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP version&lt;/td&gt;
&lt;td&gt;9.18.1P3D1 (both clusters)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration&lt;/td&gt;
&lt;td&gt;SINGLE_AZ_1, 128 MBps × 2 clusters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connectivity&lt;/td&gt;
&lt;td&gt;VPC peering (same region, same account)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mount&lt;/td&gt;
&lt;td&gt;NFSv3, &lt;code&gt;actimeo=0&lt;/code&gt; (client cache disabled)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object size&lt;/td&gt;
&lt;td&gt;64 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method&lt;/td&gt;
&lt;td&gt;boto3 persistent session, same host, 30 iterations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why NFS First
&lt;/h3&gt;

&lt;p&gt;The initial measurements used NFS. Three reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client cache control.&lt;/strong&gt; NFS &lt;code&gt;actimeo=0&lt;/code&gt; fully disables kernel attribute caching, isolating storage-side visibility latency. SMB oplocks/leases let the client cache independently, making it harder to measure the same thing at the same granularity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Access Point requirement.&lt;/strong&gt; The FSx for ONTAP S3 AP attaches to UNIX security-style volumes. SMB access on a UNIX volume is possible (via name-mapping + permission mapping), but NFS is the simplest consumption path for this architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary use-case distribution.&lt;/strong&gt; HiL test benches, rendering farms, and IoT analysis appliances are predominantly Linux + NFS. When the read side is SMB-dominant (Windows workstations in a production studio), the origin security style changes to NTFS — a different design path (see &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/design-first-decisions.md" rel="noopener noreferrer"&gt;First Decisions&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  SMB Shows Identical Results
&lt;/h3&gt;

&lt;p&gt;I ran a separate verification with SMB (&lt;code&gt;mount -t cifs&lt;/code&gt;, &lt;code&gt;cache=none&lt;/code&gt;) on the same architecture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Mount method&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;th&gt;p90&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SMB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mount -t cifs&lt;/code&gt;, &lt;code&gt;cache=none&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8 ms&lt;/td&gt;
&lt;td&gt;9 ms&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mount -t nfs&lt;/code&gt;, &lt;code&gt;actimeo=0&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8 ms&lt;/td&gt;
&lt;td&gt;15 ms&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;With persistent mounts, SMB and NFS have identical visibility latency.&lt;/strong&gt; No protocol difference.&lt;/p&gt;

&lt;p&gt;Note: &lt;code&gt;smbclient&lt;/code&gt; (establishing a new session per request) showed p50 43 ms. This is SMB session setup overhead — the same structural problem as the AWS CLI cold-start that inflated our first NFS→S3 measurement to 873 ms. &lt;strong&gt;Production environments with persistent connections won't see this.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SMB Considerations
&lt;/h3&gt;

&lt;p&gt;FlexCache serves both NFS and SMB. This architecture doesn't exclude SMB — but note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With a UNIX security-style origin, SMB clients receive UNIX permission-based access control, not NTFS ACLs&lt;/li&gt;
&lt;li&gt;For SMB-primary workloads, NTFS security style is more natural, but S3 AP attaches to UNIX-style volumes. This is a genuine tradeoff for "collect via S3, consume via SMB" scenarios&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mixed&lt;/code&gt; security style is available in the API but &lt;a href="https://aws.amazon.com/blogs/storage/enabling-multiprotocol-workloads-with-amazon-fsx-for-netapp-ontap/" rel="noopener noreferrer"&gt;officially not recommended by AWS&lt;/a&gt; — it's labeled "advanced users only." Permission type is determined by the last client that wrote, making troubleshooting difficult. This architecture doesn't use it&lt;/li&gt;
&lt;li&gt;SMB requires Active Directory (FSx for ONTAP does not support workgroup mode)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recommendation for this architecture: &lt;strong&gt;Origin uses UNIX security style&lt;/strong&gt; (S3 AP requirement). SMB readers use name-mapping and accept UNIX permission-based access. If your workload requires NTFS ACL granularity for Windows clients, this architecture isn't the best fit.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;actimeo=0&lt;/code&gt; measures the minimum visibility latency by disabling client-side caching. Production deployments should use appropriate &lt;code&gt;actimeo&lt;/code&gt; values for their workload — the default (~60 s) means subsequent reads hit kernel cache at ~0.05 ms, but changes aren't visible during that window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results — All Four Directions
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;th&gt;p90&lt;/th&gt;
&lt;th&gt;p99&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;S3 AP PutObject → FlexCache NFS read&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9 ms&lt;/td&gt;
&lt;td&gt;19 ms&lt;/td&gt;
&lt;td&gt;19 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;S3 AP PutObject → Origin NFS read (direct)&lt;/td&gt;
&lt;td&gt;3 ms&lt;/td&gt;
&lt;td&gt;5 ms&lt;/td&gt;
&lt;td&gt;8 ms&lt;/td&gt;
&lt;td&gt;8 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;NFS write (Origin) → FlexCache NFS read&lt;/td&gt;
&lt;td&gt;6 ms&lt;/td&gt;
&lt;td&gt;7 ms&lt;/td&gt;
&lt;td&gt;25 ms&lt;/td&gt;
&lt;td&gt;25 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;NFS write (Origin) → S3 AP GetObject&lt;/td&gt;
&lt;td&gt;44 ms&lt;/td&gt;
&lt;td&gt;49 ms&lt;/td&gt;
&lt;td&gt;328 ms&lt;/td&gt;
&lt;td&gt;328 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What the Numbers Say
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Direction 1 is the main path.&lt;/strong&gt; S3 write, FlexCache NFS read: p50 8 ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The +5 ms gap between directions 1 and 2 is FlexCache overhead.&lt;/strong&gt; For same-region VPC peering, FlexCache is nearly transparent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Direction 3 is faster than 1 (6 ms &amp;lt; 8 ms).&lt;/strong&gt; NFS writes commit directly to the origin — no S3 API overhead — and FlexCache propagation alone is faster than the full S3-to-cache path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Direction 4 (reverse) is slowest at 44 ms.&lt;/strong&gt; S3 read-side processing dominates. This design keeps reads on NFS/SMB, so direction 4 isn't the main path.&lt;/p&gt;

&lt;h3&gt;
  
  
  NFS Client Cache Effect
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;actimeo=0&lt;/code&gt; (cache disabled)&lt;/td&gt;
&lt;td&gt;7 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;actimeo=60&lt;/code&gt; (subsequent access)&lt;/td&gt;
&lt;td&gt;0.05 ms (kernel cache hit)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With defaults, reads within 60 seconds of the last attribute check hit the kernel cache. The tradeoff: you won't see changes during that window. Tune per workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  FlexCache Duality — It Works (With One Extra Step)
&lt;/h2&gt;

&lt;p&gt;ONTAP 9.14.1 introduced NAS buckets on FlexCache volumes (FlexCache duality) — S3 reads from the cache side. I tested this on FSx for ONTAP 9.18.1P3D1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result: Works After Enabling &lt;code&gt;-is-s3-enabled true&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;My initial test returned &lt;code&gt;AccessDenied&lt;/code&gt; and I concluded it didn't work. After additional investigation, I found &lt;strong&gt;missing configuration step&lt;/strong&gt;: S3 access must be explicitly enabled on the FlexCache volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-privilege&lt;/span&gt; advanced
flexcache config modify &lt;span class="nt"&gt;-vserver&lt;/span&gt; &amp;lt;svm&amp;gt; &lt;span class="nt"&gt;-volume&lt;/span&gt; &amp;lt;fcache_vol&amp;gt; &lt;span class="nt"&gt;-is-s3-enabled&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After applying this setting:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Before (missing setting)&lt;/th&gt;
&lt;th&gt;After (-is-s3-enabled true)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HeadBucket&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ListObjectsV2&lt;/td&gt;
&lt;td&gt;❌ AccessDenied&lt;/td&gt;
&lt;td&gt;✅ KeyCount=1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GetObject&lt;/td&gt;
&lt;td&gt;❌ AccessDenied&lt;/td&gt;
&lt;td&gt;✅ Content verified&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;fsxadmin&lt;/code&gt; role on FSx for ONTAP has access to advanced privilege commands including &lt;code&gt;flexcache config modify&lt;/code&gt;. Documented at &lt;a href="https://docs.netapp.com/us-en/ontap/flexcache/enable-flexcache-duality.html" rel="noopener noreferrer"&gt;NetApp: Enable FlexCache duality&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Implication
&lt;/h3&gt;

&lt;p&gt;FlexCache duality works, which means S3 reads from the cache side are possible. However, this architecture still recommends &lt;strong&gt;NFS/SMB on the cache side&lt;/strong&gt; because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ONTAP native S3 (NAS buckets) and AWS-managed S3 Access Points are &lt;strong&gt;different mechanisms&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;NAS buckets are read-only (no PutObject)&lt;/li&gt;
&lt;li&gt;Requires additional configuration (advanced privilege + S3 user management)&lt;/li&gt;
&lt;li&gt;No IAM integration or access point policy governance like S3 AP provides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FlexCache duality becomes an option when "S3 reads at the cache site" is a hard requirement. For AWS service integration (Lambda, Bedrock, etc.), the origin-side S3 AP remains the better fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  When This Pattern Fits
&lt;/h2&gt;

&lt;p&gt;"Collect via S3 API in the cloud, consume via NFS/SMB at the edge" — this structure exists across industries.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Industry&lt;/th&gt;
&lt;th&gt;Collect side&lt;/th&gt;
&lt;th&gt;Consume side&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Automotive (AV/ADAS)&lt;/td&gt;
&lt;td&gt;Driving logs and sensor data ingested to S3&lt;/td&gt;
&lt;td&gt;HiL test benches replay via NFS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/industries/accelerating-hil-testing-for-av-adas-with-a-hybrid-cloud-approach-aws-and-netapp/" rel="noopener noreferrer"&gt;AWS + NetApp: Hybrid Cloud HiL&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semiconductor (EDA)&lt;/td&gt;
&lt;td&gt;Design job I/O staged via S3&lt;/td&gt;
&lt;td&gt;Toolchains (Synopsys, Cadence) run on NFS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/cn/blogs/industries/eda-scale-with-fsx-for-netapp-ontap-and-ibm-lsf/" rel="noopener noreferrer"&gt;EDA Scale with FSx for ONTAP&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Media and VFX&lt;/td&gt;
&lt;td&gt;Rendering assets collected to S3&lt;/td&gt;
&lt;td&gt;Artist workstations mount SMB/NFS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.netapp.com/data-storage/what-is-flex-cache/" rel="noopener noreferrer"&gt;FlexCache: distributed product development&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oil and Gas&lt;/td&gt;
&lt;td&gt;Seismic survey data uploaded to S3&lt;/td&gt;
&lt;td&gt;Interpretation workstations mount NFS&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/solutions/deploying-vdi-for-subsurface-oil-and-gas-on-aws/index.html" rel="noopener noreferrer"&gt;VDI for Subsurface O&amp;amp;G&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Life Sciences&lt;/td&gt;
&lt;td&gt;Genome sequencer output stored in S3&lt;/td&gt;
&lt;td&gt;Bioinformatics HPC processes via NFS&lt;/td&gt;
&lt;td&gt;Sequencer → S3 → NFS pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manufacturing / QA&lt;/td&gt;
&lt;td&gt;Inspection camera images collected to S3&lt;/td&gt;
&lt;td&gt;Line-side inspection software reads via NFS&lt;/td&gt;
&lt;td&gt;Image → judgment → archive flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote Work&lt;/td&gt;
&lt;td&gt;Central design data updated via S3&lt;/td&gt;
&lt;td&gt;Remote-site WorkSpaces access FlexCache NFS/SMB&lt;/td&gt;
&lt;td&gt;&lt;a href="https://community.netapp.com/t5/Tech-ONTAP-Blogs/Accelerating-Remote-Work-Harnessing-FlexCache-in-AWS-WorkSpaces-for-Data/ba-p/451852" rel="noopener noreferrer"&gt;FlexCache in AWS WorkSpaces&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IoT / Edge&lt;/td&gt;
&lt;td&gt;Sensor data streamed to S3&lt;/td&gt;
&lt;td&gt;On-site analysis appliances read via NFS&lt;/td&gt;
&lt;td&gt;Factory gateway → cloud → shopfloor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Common structure: &lt;strong&gt;Few write sites (often one), multiple read sites. Writes are bursty; reads touch only what's needed.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When It Doesn't Fit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Need full S3 semantics&lt;/strong&gt; (versioning, event notifications, lifecycle): Use S3 natively&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object names aren't NAS-friendly&lt;/strong&gt; (flat namespace, millions of keys with no directory separators): Performance degrades as root directory grows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumers need S3 reads at the cache site&lt;/strong&gt;: Not supported on FlexCache today&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need write-back from the cache&lt;/strong&gt;: This pattern keeps cache read-centric&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need conditional writes (If-None-Match)&lt;/strong&gt;: Returns 501 NotImplemented. Handle exclusion at the application layer&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  S3 Access Point Design Notes
&lt;/h2&gt;

&lt;p&gt;A few things to know when using the S3 AP as the collect layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  S3 AP ≠ Amazon S3
&lt;/h3&gt;

&lt;p&gt;The FSx for ONTAP S3 AP supports a subset of S3 operations. GetObject, PutObject, ListObjectsV2, HeadObject, DeleteObject, and MultipartUpload work. The following do not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 Event Notifications (use FPolicy + EventBridge instead)&lt;/li&gt;
&lt;li&gt;Lifecycle rules (use FabricPool)&lt;/li&gt;
&lt;li&gt;Versioning (use ONTAP Snapshots)&lt;/li&gt;
&lt;li&gt;Conditional writes If-None-Match (returns 501)&lt;/li&gt;
&lt;li&gt;S3 Select, SSE-S3/KMS, Cross-AP Copy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Throughput is shared with NFS/SMB
&lt;/h3&gt;

&lt;p&gt;S3 AP, NFS, and SMB all consume the same FSx for ONTAP provisioned throughput. In this architecture, origin and cache are separate clusters so this rarely matters — but if NFS clients also access the origin directly, account for the shared bandwidth. Rule of thumb: 128 MBps supports 2–5 concurrent S3 requests, 512 MBps supports 10–20.&lt;/p&gt;

&lt;h3&gt;
  
  
  Directory design matters
&lt;/h3&gt;

&lt;p&gt;S3 PutObject keys map directly to directory structure. Beyond 100K files per directory, ListObjectsV2 slows down. Partition by date, tenant, or hash prefix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This directly affects NFS usability.&lt;/strong&gt; If you flat-dump millions of objects without hierarchy, FlexCache NFS clients will struggle with &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;find&lt;/code&gt;. Design your S3 keys with "how does this look when I &lt;code&gt;ls&lt;/code&gt; on NFS?" in mind.&lt;/p&gt;

&lt;p&gt;Key recommendations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Date-based partitioning (&lt;code&gt;year=YYYY/month=MM/day=DD/&lt;/code&gt;) to keep directories under 10K files&lt;/li&gt;
&lt;li&gt;Separate ingest volumes from consumption volumes; apply FlexCache only to consumption&lt;/li&gt;
&lt;li&gt;On the NFS side, use manifest files or path generation instead of directory traversal (&lt;code&gt;find&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For full details, see the &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/reference/limits/s3ap-design-guide.md" rel="noopener noreferrer"&gt;S3 AP Design Guide&lt;/a&gt; in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Costs — Egress First, Requests Second
&lt;/h2&gt;

&lt;p&gt;I framed this section around S3 request pricing when I first wrote it. That was the wrong axis, and the modelling I did afterwards says so plainly. Corrected below.&lt;/p&gt;

&lt;p&gt;The cost that hurts when your readers sit outside AWS is &lt;strong&gt;data transfer&lt;/strong&gt;. Egress is charged on bytes leaving the Region, so reading the same file ten times moves ten times the bytes and pays ten times over. A cache removes the multiplier: it carries the working set once and every later read is served locally over NFS or SMB, never becoming an S3 request at all.&lt;/p&gt;

&lt;p&gt;A worked case — 20 TiB dataset, 2 TiB monthly working set, 4 MiB objects, each file read 30 times, internet egress from &lt;code&gt;ap-northeast-1&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Monthly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read S3 directly from on premises&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$6,211&lt;/strong&gt; — egress alone is $5,693 (92%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copy the whole dataset down with DataSync&lt;/td&gt;
&lt;td&gt;$2,847&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSx for ONTAP + FlexCache&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$1,333&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Storage and requests are rounding errors next to transfer here.&lt;/p&gt;

&lt;h3&gt;
  
  
  The read count decides it
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reads per file per month&lt;/th&gt;
&lt;th&gt;Direct&lt;/th&gt;
&lt;th&gt;This architecture&lt;/th&gt;
&lt;th&gt;Ratio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$746&lt;/td&gt;
&lt;td&gt;$1,333&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.6x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;$1,680&lt;/td&gt;
&lt;td&gt;$1,333&lt;/td&gt;
&lt;td&gt;1.3x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;$2,593&lt;/td&gt;
&lt;td&gt;$1,333&lt;/td&gt;
&lt;td&gt;1.9x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;$6,211&lt;/td&gt;
&lt;td&gt;$1,333&lt;/td&gt;
&lt;td&gt;4.7x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;$18,451&lt;/td&gt;
&lt;td&gt;$1,333&lt;/td&gt;
&lt;td&gt;13.8x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At one read per file the direct path wins — the same bytes move either way and there is no reason to carry a file system's fixed cost. The crossover is between five and ten. &lt;strong&gt;Where it falls is a property of your workload, not of the products.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Requests matter too, but only below a certain object size
&lt;/h3&gt;

&lt;p&gt;I had assumed S3 GET charges were a co-equal problem. At 4 MiB objects they are not: the entire 5.2 million reads in the ten-read case cost &lt;strong&gt;$1.94&lt;/strong&gt;, about a thousandth of the transfer bill. Through an access point it is $0.31, and through FlexCache $0.16 — the reads are NFS and SMB, so they generate no S3 requests, and only the origin-side capacity pool fetch on cache fill remains.&lt;/p&gt;

&lt;p&gt;Where the assumption does hold is small objects. Holding bytes read constant and varying object size:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Object size&lt;/th&gt;
&lt;th&gt;Reads/month&lt;/th&gt;
&lt;th&gt;GET charges&lt;/th&gt;
&lt;th&gt;Share of that option's transfer bill&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8 KiB&lt;/td&gt;
&lt;td&gt;2.68 B&lt;/td&gt;
&lt;td&gt;$993&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;48%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64 KiB&lt;/td&gt;
&lt;td&gt;336 M&lt;/td&gt;
&lt;td&gt;$124&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;256 KiB&lt;/td&gt;
&lt;td&gt;84 M&lt;/td&gt;
&lt;td&gt;$31&lt;/td&gt;
&lt;td&gt;1.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 MiB&lt;/td&gt;
&lt;td&gt;5.2 M&lt;/td&gt;
&lt;td&gt;$1.94&lt;/td&gt;
&lt;td&gt;0.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So both charges need designing for, and they respond to opposite remedies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transfer&lt;/strong&gt; falls by carrying fewer bytes — cache the working set, move the readers into AWS, or drop the unit rate with Direct Connect ($0.041/GB against $0.114 for the first 10 TB of internet egress). Making objects bigger does &lt;em&gt;not&lt;/em&gt; help; the byte count is unchanged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requests&lt;/strong&gt; fall by making fewer calls — batch at collection time so files are larger, and serve reads over a file protocol so they never become S3 calls. Negotiating transfer rates does not help when the money is on the request side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Batch too far and you hit the collection side: a single &lt;code&gt;PutObject&lt;/code&gt; caps at 5 GiB and a whole object at 50 GiB, and the 50 GiB check happens at &lt;code&gt;CompleteMultipartUpload&lt;/code&gt; — after the entire payload has been transferred and paid for. Batching past the consumer's read unit also sends bytes nobody reads. The repository's &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/reference/limits/s3ap-design-guide.md" rel="noopener noreferrer"&gt;design guide&lt;/a&gt; sets the consumer's read unit as the reference for how far to go, with the measurement and monitoring steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  If the readers can move, move them
&lt;/h3&gt;

&lt;p&gt;Worth stating because it outweighs every storage choice. In-Region transfer is free, so putting the consumers in AWS deletes the entire egress line — $2,079 at ten reads on this workload. Reading S3 directly from EC2 comes to $514/month; &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-files.html" rel="noopener noreferrer"&gt;S3 Files&lt;/a&gt; costs $515, ninety-four cents more, because 4 MiB objects sit above its size threshold and never reach its high-performance storage; FSx for ONTAP in the same Region is $1,053, twice the direct path, since the transfer gap that justified it is gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S3 Files cannot serve this architecture's consumers.&lt;/strong&gt; It speaks NFSv4.1 and NFSv4.2 only — no NFSv3, no SMB — so an appliance pinned to v3 and any Windows stage are out, and the documented compute targets are EC2, Lambda, EKS and ECS. It belongs in the picture as the option you get &lt;em&gt;after&lt;/em&gt; migrating the readers, not as a substitute for a cache.&lt;/p&gt;

&lt;p&gt;This architecture is for the cases where the readers cannot move: equipment on site, proximity to whatever is being measured, capital already spent on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  On the distribution side
&lt;/h3&gt;

&lt;p&gt;A FlexCache cache volume &lt;strong&gt;cannot be tiered&lt;/strong&gt; — an origin with FabricPool tiering can be cached, but the cache itself never tiers, so it sits entirely on SSD. That is affordable because it is sparse: NetApp's guidance is at least 10% of origin, which is also the create default. At 10% the distribution side runs 2.7x to 6.1x below a full second copy, with the copy given its capacity pool discount. Size it like a copy and it inverts — at 100% it costs more than the copy, precisely because it cannot tier.&lt;/p&gt;

&lt;p&gt;Cache volumes are writable, which I understated earlier. Write-around is the default and withholds the client acknowledgement until the origin has committed; write-back, from ONTAP 9.15.1, commits at the cache and propagates asynchronously. The default being synchronous with respect to the origin matters for freshness: there is no window where a cache-side write is missing from the canonical copy.&lt;/p&gt;

&lt;p&gt;One assumption drives more of these numbers than any other, so treat it carefully. &lt;strong&gt;Background storage efficiency does not run on data once it has been tiered&lt;/strong&gt; — only savings applied while the block was on SSD are preserved, and a block tiered before efficiency ran keeps none (&lt;a href="https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/manage-vol-SE.html" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;, &lt;a href="https://kb.netapp.com/Advice_and_Troubleshooting/Data_Storage_Software/ONTAP_OS/Does_ONTAP_apply_efficiencies_to_blocks_that_are_tiered-out_to_Fabricpool%3F" rel="noopener noreferrer"&gt;NetApp&lt;/a&gt;). Expecting better than 40% on a tiering-enabled volume is optimistic. The model takes the SSD rate from AWS's published per-workload figures, assumes the pool tier retains half of it, and carries a sensitivity table — because the assumption only ever flatters this architecture: ONTAP deduplication does not reduce an S3 storage bill.&lt;/p&gt;

&lt;p&gt;Full breakdown, every rate with its effective date, the workload models and the cross-layer pitfalls: &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/reference/comparison/finops-s3-vs-s3ap.md" rel="noopener noreferrer"&gt;FinOps cost structure&lt;/a&gt; and the &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/reference/limits/s3ap-design-guide.md" rel="noopener noreferrer"&gt;S3 AP Design Guide&lt;/a&gt; (Japanese). Cost tables are generated from a model in the repository, so a price change moves one declaration rather than fifty typed totals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;

&lt;p&gt;CloudFormation and Terraform templates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files" rel="noopener noreferrer"&gt;Yoshiki0705/s3-burst-on-ontap-files&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;"Collect via S3, consume via NFS" — one volume, no copy jobs. FSx for ONTAP S3 Access Point + FlexCache. Main path p50 8 ms. FlexCache adds ~5 ms for same-region — nearly transparent.&lt;/p&gt;

&lt;p&gt;This verification was done entirely on AWS (FSx for ONTAP to FSx for ONTAP over VPC peering), but the cache side isn't limited to AWS. On-premises NetApp AFF/FAS, ONTAP Select, Cloud Volumes ONTAP, Azure NetApp Files, Google Cloud NetApp Volumes cache volumes— any ONTAP-based environment can potentially serve as a FlexCache target for this same architecture. The repository's &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/portability.md" rel="noopener noreferrer"&gt;Portability&lt;/a&gt; and &lt;a href="https://github.com/Yoshiki0705/s3-burst-on-ontap-files/blob/main/docs/ja/support-matrix.md" rel="noopener noreferrer"&gt;Support Matrix&lt;/a&gt; pages track what's confirmed and what's next. Cross-platform verification is on the roadmap.&lt;/p&gt;

&lt;p&gt;FlexCache duality (S3 reads on the cache side) does work, once S3 access is enabled on the cache volume itself with &lt;code&gt;-is-s3-enabled true&lt;/code&gt; in advanced privilege. The earlier &lt;code&gt;AccessDenied&lt;/code&gt; was a missing setting, not a platform limitation. The architecture still keeps cache-side access to NFS/SMB, because ONTAP native S3 and the AWS-managed access point are separate mechanisms and the NAS bucket is a read-only view without IAM integration.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;All test resources torn down. Numbers are from a specific test environment and vary by workload and configuration.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>fsxforontap</category>
      <category>s3accesspoints</category>
      <category>fileburst</category>
    </item>
    <item>
      <title>Embedding AI Agents into a File Portal — From AgentCore MCP to Multi-Agent Teams (Part 3)</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Mon, 03 Aug 2026 10:21:40 +0000</pubDate>
      <link>https://dev.to/aws-builders/embedding-ai-agents-into-a-file-portal-from-agentcore-mcp-to-multi-agent-teams-part-3-19m1</link>
      <guid>https://dev.to/aws-builders/embedding-ai-agents-into-a-file-portal-from-agentcore-mcp-to-multi-agent-teams-part-3-19m1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Let an AI agent work the NAS, with a human approving&lt;/strong&gt; — Amazon Bedrock AgentCore and MCP (part 3 of 3)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Japanese version of this article is available: &lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-3-ai-agent-mcp" rel="noopener noreferrer"&gt;日本語版&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-1-browser-access" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt; I built the file portal foundation on the S3 Access Points of Amazon FSx for NetApp ONTAP (hereafter FSx for ONTAP), and in &lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-2-ransomware-worm" rel="noopener noreferrer"&gt;Part 2&lt;/a&gt; I embedded storage operations (ARP/AI incident response, Tamperproof Snapshots, regulatory retention management). At that point the UI was sufficient for anyone who already knew which button to press — but a different kind of friction was still there. "Where did I put last week's simulation results?" "Summarize the key points of this PDF in three lines." The intent is perfectly clear; the cost of translating it into system operations was what stayed high.&lt;/p&gt;

&lt;p&gt;So I integrated AI agents into the portal. Express your intent in natural language, and the agent finds the files, reads them, analyzes the content, and proposes storage management operations when needed. Because storage management includes irreversible operations, the execution decision stays with a human through a Human-in-the-Loop (HITL) flow.&lt;/p&gt;

&lt;p&gt;Here's the conclusion up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combining the Amazon Bedrock Converse API with MCP tools lets you explore and analyze files on an S3 AP in natural language&lt;/li&gt;
&lt;li&gt;Connecting a Bedrock Knowledge Base directly to an S3 AP means you can reach a file through semantic search without knowing its name&lt;/li&gt;
&lt;li&gt;Wrapping destructive operations in a HITL approval modal keeps agent autonomy and safety in the same design&lt;/li&gt;
&lt;li&gt;Multi-agent collaboration pays off only for tasks with several phases — "discover → analyze → judge"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I'll cover the 3-mode AgentChat design, file access via MCP tools, the HITL flow, and the implementation patterns for multi-agent collaboration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9601cfniv0xfuub2v4wk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9601cfniv0xfuub2v4wk.png" alt="The overall architecture for adding AI agents to the file portal. The web browser reaches an agent-execution AWS Lambda through AWS Amplify and AWS AppSync; that Lambda runs inference on Amazon Bedrock (Converse API) and calls Amazon Bedrock AgentCore over MCP. The MCP tool Lambda that AgentCore invokes reads files on Amazon FSx for NetApp ONTAP through an Amazon S3 Access Point using the S3 API" width="800" height="1143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part3-ai-agent-overview-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available, and every figure is listed in the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/architecture-diagrams.en.md" rel="noopener noreferrer"&gt;architecture diagram index&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/solutions/amplify-portal" rel="noopener noreferrer"&gt;solutions/amplify-portal/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Terminology note&lt;/strong&gt;: "MCP" in this article refers to &lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; — a standard protocol that allows AI models to invoke external tools (file operations, database queries, etc.). AgentCore Gateway acts as the MCP server, exposing Lambda-based tools to the AI model.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  If You're Already Using ChatGPT / Copilot / Claude for Document Analysis
&lt;/h2&gt;

&lt;p&gt;When using general-purpose AI assistants (ChatGPT, GitHub Copilot, Claude, etc.) for file analysis, the typical flow is "upload file → AI analyzes → returns results." The portal agent takes a different approach.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;ChatGPT / Copilot (upload-based)&lt;/th&gt;
&lt;th&gt;Portal Agent (NAS-connected)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File access&lt;/td&gt;
&lt;td&gt;Manual upload (one file at a time)&lt;/td&gt;
&lt;td&gt;Direct access to files on NAS (via S3 AP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;Only uploaded files&lt;/td&gt;
&lt;td&gt;Cross-volume search across entire storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage operations&lt;/td&gt;
&lt;td&gt;Not possible&lt;/td&gt;
&lt;td&gt;Proposes SnapLock enable, user block, etc. (with HITL approval)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP-specific features&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;ARP/AI status checks, Snapshot operations, export-policy changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data movement&lt;/td&gt;
&lt;td&gt;File content sent to external service&lt;/td&gt;
&lt;td&gt;File content processed within same-region Bedrock (VPC-contained possible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destructive operation safety&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;HITL modal for human approve/reject&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;This portal does not attempt to replace general-purpose AI assistants.&lt;/strong&gt; It adds NAS-connected file intelligence — file discovery, content understanding, and storage operation proposals. For general Q&amp;amp;A, ChatGPT and Copilot remain well-suited tools for those tasks.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Verification status&lt;/strong&gt;: how far each feature in this article has actually been confirmed is recorded in &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/verification-results.en.md" rel="noopener noreferrer"&gt;verification results&lt;/a&gt;, split four ways (live E2E / live read / tests only / DemoMode). Agent and team execution sits in the "tests only" category: handler and component tests pass, but it has not been driven from a browser against a real system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;The portal moved from "browse files and check operational state" to "ask in natural language, and the agent finds files, understands content, and proposes storage operations." Here's what was added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AgentChat&lt;/strong&gt;: Multi-tool AI chat with 3 switchable modes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SemanticSearch&lt;/strong&gt;: Vector search via Bedrock Knowledge Base — resolves "where did I put that file?" in natural language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Directory / Creator&lt;/strong&gt;: Define custom agents and share them with your team&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Teams&lt;/strong&gt;: Run multiple agents in collaboration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ActionApproval (HITL)&lt;/strong&gt;: Insert a human approval flow before destructive operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multimodal input&lt;/strong&gt;: Drag and drop an image into the chat for file analysis&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Embed AI Agents in the Portal
&lt;/h2&gt;

&lt;p&gt;The admin features from Part 2 work well for people who already know "what to operate and how." But what I actually hear in practice sounds more like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Where did I put last week's simulation results?"&lt;/li&gt;
&lt;li&gt;"Can you summarize what caused the error in this log file?"&lt;/li&gt;
&lt;li&gt;"I want to run legal review on the contracts folder, but I don't know the steps"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't cases of "not knowing how to operate the system." They're cases of "I know what I want, but translating that intent into system operations is tedious." This applies equally to non-technical team members:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Where's the attachment for last month's expense report?"&lt;/li&gt;
&lt;li&gt;"Summarize this PDF in 3 lines"&lt;/li&gt;
&lt;li&gt;"Compile a file list from this folder for my weekly report"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The motivation for embedding AI agents was to eliminate this translation cost entirely. Express your intent in natural language, and the agent finds files, reads them, analyzes content, and proposes admin operations if needed. Users only need to think about "what they want to accomplish."&lt;/p&gt;

&lt;p&gt;However, giving an agent unrestricted authority in a storage management context is dangerous. Enabling SnapLock is irreversible. Modifying an export-policy immediately cuts off user access. So I combine the Human-in-the-Loop (HITL) pattern: "the agent proposes, but humans approve execution."&lt;/p&gt;




&lt;h2&gt;
  
  
  AgentChat — 3-Mode Integrated Chat
&lt;/h2&gt;

&lt;p&gt;A persistent AI chat in the portal's right panel, fully replacing the previous "Bedrock Q&amp;amp;A" (single-file question-answering).&lt;/p&gt;

&lt;h3&gt;
  
  
  3 Modes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Icon&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🧠 Knowledge&lt;/td&gt;
&lt;td&gt;KB&lt;/td&gt;
&lt;td&gt;Cross-volume semantic search. Answers "where's that file?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📁 File Agent&lt;/td&gt;
&lt;td&gt;agent&lt;/td&gt;
&lt;td&gt;File read/list/analyze. Accesses S3 AP via MCP tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🤖 Multi-Agent&lt;/td&gt;
&lt;td&gt;multi&lt;/td&gt;
&lt;td&gt;Multiple agents collaborate. File discovery → content analysis → operation proposal in sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Modes switch via pill buttons below the header. Welcome screen task cards change per mode, showing "what you can do in this mode."&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser (React)
    ↓ AppSync Query (agentQuery)
Lambda: Agent Orchestrator (outside VPC)
    ├── mode=kb   → Bedrock KB RetrieveAndGenerate
    ├── mode=agent → Bedrock Converse + MCP Tools
    └── mode=multi → Multi-agent collaboration
                         ↓ MCP Client
                    AgentCore Gateway
                         ↓ Lambda Invoke
                    MCP Tool Lambda (list_files / read_file / search_files)
                         ↓ S3 API
                    FSx for ONTAP S3 Access Point
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftqfwn0jvb0ipij4wos8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftqfwn0jvb0ipij4wos8m.png" alt="The three AgentChat modes and file access via MCP tools. A request arriving at the AgentChat AWS Lambda from AWS AppSync branches into mode=kb (semantic search only, using kb_search against Amazon Bedrock Knowledge Bases), mode=agent (file tools only), and mode=multi (all tools, coordinated). The latter two go through Amazon Bedrock and Amazon Bedrock AgentCore to the MCP tool Lambda, which runs list / read / search against the Amazon S3 Access Point" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part3-agentchat-modes-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The VPC split principle applies here too. The Agent Orchestrator Lambda is placed outside VPC, accessing Bedrock API and S3 AP (Internet-origin). Admin operations calling ONTAP REST API are handled by a separate VPC-internal Lambda.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tool Execution Visibility
&lt;/h3&gt;

&lt;p&gt;When the agent invokes tools, a timeline appears in the chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔧 Tool Calls (3)                          2.1s
├── ✅ 🔍 file-explorer: list_files         {"prefix": "/engineering/"}
├── ✅ 📄 file-explorer: read_file          {"key": "/engineering/thermal-spec-v3.pdf"}
└── ✅ 🧠 knowledge-analyst: analyze_file   {"key": "...", "question": "..."}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each tool's input/output examples:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Input Example&lt;/th&gt;
&lt;th&gt;Output Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_files&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{"prefix": "/engineering/", "max_keys": 20}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File path list + size + last modified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;read_file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{"key": "/engineering/thermal-spec-v3.pdf"}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File content (text-extracted)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_files&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{"query": "thermal limit exceeded"}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Matched files + relevant snippets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Displayed in &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; — expanded by default when 3 or fewer tool calls, collapsed when 4+. This balances Nielsen's "visibility of system status" with Wroblewski's "progressive disclosure."&lt;/p&gt;

&lt;h3&gt;
  
  
  Chat History Persistence
&lt;/h3&gt;

&lt;p&gt;Conversation sessions auto-save to DynamoDB (2-second debounce). Past sessions can be recalled from the history panel to continue questioning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Auto-save: 2 seconds after message change → DynamoDB&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;currentSessionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;saveCurrentSession&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentSessionId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rationale: forcing an explicit "Save" button interrupts the natural flow of chat. Close the browser, and next time you open it, you can pick up from "where we left off yesterday."&lt;/p&gt;

&lt;h3&gt;
  
  
  Multimodal Input
&lt;/h3&gt;

&lt;p&gt;Drag-and-drop images into the chat for Bedrock Vision analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Circuit diagram image → "Where's the bottleneck in this circuit?"&lt;/li&gt;
&lt;li&gt;Screenshot → "What's causing this error screen?"&lt;/li&gt;
&lt;li&gt;Graph image → "Explain this performance degradation trend"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supports JPEG/PNG/GIF/WebP under 5MB. Base64-encoded and sent to Bedrock Converse API.&lt;/p&gt;




&lt;h2&gt;
  
  
  SemanticSearch — Vector Search
&lt;/h2&gt;

&lt;p&gt;Keyword search on file names has limits. When you want to find "the spec document about thermal design limits," you might find &lt;code&gt;thermal-spec-v3.pdf&lt;/code&gt; by name, but &lt;code&gt;TC-2024-0089.pdf&lt;/code&gt;? No chance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyword / Semantic Mode Toggle
&lt;/h3&gt;

&lt;p&gt;Mode toggle pills in the search bar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔍 [Search files...                        ] [🔍]
   [📂 Keyword]  [🧠 Semantic]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keyword mode&lt;/strong&gt;: S3 AP ListObjectsV2 + prefix filter. Auto-searches with 500ms debounce after 2+ characters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic mode&lt;/strong&gt;: Bedrock Knowledge Base RetrieveAndGenerate API. Vectorizes natural language queries for similarity search&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bedrock Knowledge Base Integration
&lt;/h3&gt;

&lt;p&gt;FSx for ONTAP's S3 AP can be specified directly as a Knowledge Base data source (&lt;a href="https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/tutorial-build-rag-with-bedrock.html" rel="noopener noreferrer"&gt;AWS official tutorial&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FSx for ONTAP Volume
    ↓ S3 AP (Data Source)
Bedrock Knowledge Base
    ↓ Embeddings (Titan V2)
OpenSearch Serverless (Vector Store)
    ↓ RetrieveAndGenerate
Results: related chunks + source file path + relevance score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29ngw4t1oz7b4hq2sbb3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29ngw4t1oz7b4hq2sbb3.png" alt="Semantic search with Bedrock Knowledge Bases. The search query flows from AWS AppSync to an AWS Lambda function, which calls RetrieveAndGenerate on Amazon Bedrock (Knowledge Bases). Knowledge Bases runs the vector search on Amazon OpenSearch Service and generates embeddings with Amazon Bedrock (Titan Text Embeddings V2). The data source is Amazon FSx for NetApp ONTAP through an Amazon S3 Access Point" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part3-semantic-search-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Results include scores (percentage display) and snippets. Clicking a result navigates to the file in the All Files view.&lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic Search Input Examples
&lt;/h3&gt;

&lt;p&gt;When KB is unconfigured, help text guides users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;💡 Semantic search examples:
• "Files with anomalies in last month's sales reports"
• "Test results exceeding thermal design specifications"
• "Description of the approval process for contract renewal"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Constraints
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;KB sync is asynchronous (minutes to tens of minutes lag after file changes)&lt;/li&gt;
&lt;li&gt;Large file environments incur OpenSearch Serverless indexing costs&lt;/li&gt;
&lt;li&gt;PDF/Office text extraction accuracy depends on file quality&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;bedrockKbId&lt;/code&gt; is empty in &lt;code&gt;portal-config.ts&lt;/code&gt;, semantic mode shows a "KB not configured" error&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;KB sync detection&lt;/strong&gt;: Data source sync status can be checked via the &lt;code&gt;bedrock-agent:GetIngestionJob&lt;/code&gt; API. Periodic sync can be scheduled in the Bedrock console. If immediate search reflection after file changes is required, consider an EventBridge + &lt;code&gt;StartIngestionJob&lt;/code&gt; API configuration for on-demand sync triggers.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Agent Directory — Agent Catalog
&lt;/h2&gt;

&lt;p&gt;A UI for discovering "what agents are available."&lt;/p&gt;

&lt;h3&gt;
  
  
  Preset Agents
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Icon&lt;/th&gt;
&lt;th&gt;Specialty&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;file-explorer&lt;/td&gt;
&lt;td&gt;📁&lt;/td&gt;
&lt;td&gt;File operations (list, read, search)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;knowledge-analyst&lt;/td&gt;
&lt;td&gt;🧠&lt;/td&gt;
&lt;td&gt;Vector search + document analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;safety-controller&lt;/td&gt;
&lt;td&gt;🛡️&lt;/td&gt;
&lt;td&gt;ARP status checks + containment action proposals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;compliance-auditor&lt;/td&gt;
&lt;td&gt;📋&lt;/td&gt;
&lt;td&gt;Retention period and SnapLock configuration audits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ops-advisor&lt;/td&gt;
&lt;td&gt;⚙️&lt;/td&gt;
&lt;td&gt;EMS event analysis + operational recommendations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Custom Agent Creation (Agent Creator)
&lt;/h3&gt;

&lt;p&gt;When presets aren't enough, define your own agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent Creation Wizard:
1. Set name and icon
2. Write system prompt
3. Select tools to use (checkboxes)
4. Test execution
5. Sharing settings (personal only / team-shared)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Created agents appear in the Agent Directory, available to team members (when shared). This lets you codify patterns like "this department frequently does this kind of analysis" as reusable agents.&lt;/p&gt;




&lt;h2&gt;
  
  
  Agent Teams — Multi-Agent Collaboration
&lt;/h2&gt;

&lt;p&gt;For complex tasks that a single agent can't handle alone, multiple agents collaborate.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Use Multi-Agent vs Single Agent
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Summarize this PDF"&lt;/td&gt;
&lt;td&gt;Single agent&lt;/td&gt;
&lt;td&gt;Completes with one tool (read_file + analysis)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Analyze all files in engineering/ and report security issues"&lt;/td&gt;
&lt;td&gt;Multi-agent&lt;/td&gt;
&lt;td&gt;Requires file discovery → content analysis → security judgment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Audit files changed last month for compliance violations"&lt;/td&gt;
&lt;td&gt;Multi-agent&lt;/td&gt;
&lt;td&gt;File identification → content reading → regulatory assessment → report generation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Decision criteria&lt;/strong&gt;: Multi-agent is effective when the task has multiple phases ("discover → analyze → judge") requiring different expertise at each phase. For simple tasks, multi-agent adds cost and latency without benefit — use single agent instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Team Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Team: "Security Audit Team"
├── 🔍 file-explorer (Collaborator): Identify target files
├── 🛡️ safety-controller (Supervisor): Verify ARP/security state
└── 📋 compliance-auditor (Reviewer): Final compliance judgment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Roles
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supervisor&lt;/td&gt;
&lt;td&gt;Manages overall task progress. Directs other agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collaborator&lt;/td&gt;
&lt;td&gt;Performs work based on instructions (file ops, analysis, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewer&lt;/td&gt;
&lt;td&gt;Reviews work results. Quality checks and approve/reject&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Team Creation Wizard
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Enter team name and description&lt;/li&gt;
&lt;li&gt;Add agents from Agent Directory (minimum 2)&lt;/li&gt;
&lt;li&gt;Assign roles to each agent&lt;/li&gt;
&lt;li&gt;Sharing settings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Team execution flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User: "Analyze all simulation results in the engineering/ folder"
    ↓
Supervisor (safety-controller):
    → Instructs file-explorer: "Get file listing for engineering/"
    ↓
Collaborator (file-explorer):
    → list_files → read_file (multiple)
    → Result: 12 files found, 8 are simulation results
    ↓
Supervisor:
    → Instructs knowledge-analyst: "Create summaries for each file"
    ↓
Collaborator (knowledge-analyst):
    → Analyzes each file, generates summaries
    ↓
Reviewer (compliance-auditor):
    → "Verify no PHI data is included"
    → Result: 2 files may contain personal information → recommends guardrail application
    ↓
Final response to user:
    "Analyzed 8 of 12 files. Summaries below.
     Note: 2 files were filtered due to potential personal information."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dp2yos0ed3oenf78rs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dp2yos0ed3oenf78rs5.png" alt="Multi-agent coordination led by a Supervisor. On a user request, the Supervisor (safety-controller) hands exploration to a Collaborator (file-explorer), analysis to a Collaborator (knowledge-analyst), and review to a Reviewer (compliance-auditor), then returns the consolidated answer to the user" width="798" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part3-agent-teams-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each agent leverages its specialty while the Supervisor coordinates the overall flow. From the user's perspective, a single chat message completes a complex task.&lt;/p&gt;




&lt;h2&gt;
  
  
  ActionApproval — Human-in-the-Loop
&lt;/h2&gt;

&lt;p&gt;When the AI agent proposes a destructive or irreversible operation, a modal requesting human approval appears before execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why HITL Matters
&lt;/h3&gt;

&lt;p&gt;In a storage management context, some operations are irreversible or have immediate impact. Enabling SnapLock can never be undone. A SnapMirror break severs the replication relationship. If an AI agent autonomously executes these, recovery may be impossible. The HITL pattern ensures the agent "proposes" but the final execution decision rests with a human.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which Operations Require Approval
&lt;/h3&gt;

&lt;p&gt;Operations flagged with &lt;code&gt;isDestructive: true&lt;/code&gt; or &lt;code&gt;isReversible: false&lt;/code&gt; require approval:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Icon&lt;/th&gt;
&lt;th&gt;Irreversible?&lt;/th&gt;
&lt;th&gt;Why Approval is Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File deletion&lt;/td&gt;
&lt;td&gt;🗑️&lt;/td&gt;
&lt;td&gt;△ (recoverable from snapshot)&lt;/td&gt;
&lt;td&gt;Prevent unintended bulk deletion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SnapLock enable&lt;/td&gt;
&lt;td&gt;🔐&lt;/td&gt;
&lt;td&gt;◎ (completely irreversible)&lt;/td&gt;
&lt;td&gt;Once enabled, cannot be disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SnapMirror break&lt;/td&gt;
&lt;td&gt;🔗&lt;/td&gt;
&lt;td&gt;◎ (relationship must be re-established)&lt;/td&gt;
&lt;td&gt;Replication severance requires manual recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User block&lt;/td&gt;
&lt;td&gt;🚫&lt;/td&gt;
&lt;td&gt;○ (reversible but immediate impact)&lt;/td&gt;
&lt;td&gt;Risk of business disruption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IP block&lt;/td&gt;
&lt;td&gt;🚫&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;Risk of service disruption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retention period change&lt;/td&gt;
&lt;td&gt;⏱️&lt;/td&gt;
&lt;td&gt;△ (can only extend, never shorten)&lt;/td&gt;
&lt;td&gt;Shortening is not possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Threat containment&lt;/td&gt;
&lt;td&gt;🛡️&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;May affect multiple users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  How the Approval Flow Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Agent proposes a destructive operation
2. UI displays modal (showing action, target, reason)
3. User reviews the details
4. [Approve] → operation executes / [Reject] → operation cancelled, agent notified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example: SnapMirror Break Approval Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User: "Execute failover to the DR site"
    ↓
Agent: Determines SnapMirror break is required
    ↓
┌──────────────────────────────────────────┐
│ ⚠️  The agent is requesting approval     │
├──────────────────────────────────────────┤
│                                          │
│ Action:  SnapMirror break                │
│ Target:  vol_production → vol_dr         │
│ Reason:  DR failover execution           │
│                                          │
│ 🔴 This operation severs the replication │
│    relationship. Re-sync requires manual │
│    intervention.                         │
│                                          │
│ [❌ Reject]              [✅ Approve]     │
└──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  UI Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────┐
│ ⚠️  The agent is requesting approval     │
├──────────────────────────────────────────┤
│                                          │
│ Action:  User block                      │
│ Target:  DOMAIN\suspicious_user          │
│ Reason:  ARP detected abnormal write     │
│          patterns                        │
│                                          │
│ ⚠️ This operation will immediately cut   │
│    off the target user's SMB access      │
│                                          │
│ [❌ Reject]              [✅ Approve]     │
└──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Safe-side default&lt;/strong&gt;: &lt;code&gt;Reject&lt;/code&gt; button has &lt;code&gt;autoFocus&lt;/code&gt;. Reflexively pressing Enter falls to the safe side. Clicking outside the modal also triggers "reject."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Irreversibility warning&lt;/strong&gt;: Operations with &lt;code&gt;isReversible: false&lt;/code&gt; show a red warning bar, ensuring users visually recognize the severity of the operation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bedrock Guardrails — Response Filtering
&lt;/h2&gt;

&lt;p&gt;Bedrock Guardrails are applied to all AgentChat responses. While the PHI guardrail (Part 2) blocks based on path patterns, Guardrails filter response content itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applied Checks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PII detection&lt;/td&gt;
&lt;td&gt;Input/Output&lt;/td&gt;
&lt;td&gt;Masking (&lt;code&gt;***-****-****&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Harmful content&lt;/td&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Block + substitute message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Topic denial&lt;/td&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Refuse response to specific topics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grounding check&lt;/td&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Suppress ungrounded answers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When Guardrails are applied, a 🛡️ badge appears on the message. Users see "some information was filtered" with filter reason details available via tooltip.&lt;/p&gt;




&lt;h2&gt;
  
  
  Model, Cost, and Fallback
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Model Configuration
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Changeable&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;&lt;code&gt;amazon.nova-lite-v1:0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;Lowest cost. Use Claude 3.5 Haiku for quality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max tokens&lt;/td&gt;
&lt;td&gt;4096 (output)&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;Increase for long analyses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;History sent&lt;/td&gt;
&lt;td&gt;Last 10 messages&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;Balance with token consumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per request&lt;/td&gt;
&lt;td&gt;~$0.001–$0.01&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;For Nova Lite. Larger context from file reads increases cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Model is configurable via &lt;code&gt;bedrockModelId&lt;/code&gt; in &lt;code&gt;portal-config.ts&lt;/code&gt;. Recommended: Nova Lite for testing, Claude 3.5 Haiku for production.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: Token cost per conversation depends on tool call count and file sizes. A typical "file search + summarize" conversation costs ~$0.005–$0.02 with Nova Lite. To control context window size, adjust &lt;code&gt;maxHistoryMessages&lt;/code&gt; in &lt;code&gt;portal-config.ts&lt;/code&gt; (default: 10). Reducing history lowers cost but loses conversation context in longer sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data residency note&lt;/strong&gt;: When using Bedrock in ap-northeast-1 (Tokyo), input data processing completes within the same region. Deploying FSx for ONTAP, the portal, and Bedrock in the same region ensures file contents never leave the region. Important for financial institutions and healthcare organizations with data residency requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: File contents are included in Bedrock API request bodies, but a VPC-contained configuration is possible. Bedrock does not use request data for model training (&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/data-protection.html" rel="noopener noreferrer"&gt;AWS Bedrock Data Protection&lt;/a&gt;). With VPC endpoint routing, data never leaves the VPC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Bedrock KB Configuration Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Recommended&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embedding Model&lt;/td&gt;
&lt;td&gt;Titan Embeddings V2&lt;/td&gt;
&lt;td&gt;Japanese support, cost-efficient&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chunk Size&lt;/td&gt;
&lt;td&gt;512 tokens&lt;/td&gt;
&lt;td&gt;Appropriate granularity for file-level search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chunk Overlap&lt;/td&gt;
&lt;td&gt;64 tokens&lt;/td&gt;
&lt;td&gt;Prevents context loss at chunk boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Top K&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Balance of precision and cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector Store&lt;/td&gt;
&lt;td&gt;OpenSearch Serverless&lt;/td&gt;
&lt;td&gt;Auto-provisioned with Managed KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are starting-point recommendations. Adjust based on average file size and content characteristics.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Chunk Size tradeoff&lt;/strong&gt;: Smaller chunks (256 tokens) improve recall but fragment context, reducing precision. Larger chunks (1024 tokens) provide richer context but allow irrelevant content to mix in. 512 tokens balances well for "file-level search." For technical documents (long sections), consider 768–1024.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Fallback Behavior
&lt;/h3&gt;

&lt;p&gt;When Bedrock API is unavailable (regional outage, throttling, etc.), the agent chat displays "Cannot connect. Please use conventional search" and falls back to keyword search. The design ensures "agent unavailable ≠ portal unavailable."&lt;/p&gt;

&lt;h3&gt;
  
  
  Chat History Retention Policy
&lt;/h3&gt;

&lt;p&gt;Set TTL on DynamoDB conversation history. Default: auto-deleted after 90 days. If auditing "who asked what" is required, separately retain CloudTrail API call logs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Right to deletion&lt;/strong&gt;: If a user requests deletion of their chat history, administrators can manually delete the relevant DynamoDB sessions. For GDPR/privacy law environments, implementing a self-service "Clear history" button is recommended.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Design Tradeoffs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Tradeoff&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AppSync Query (not Subscription)&lt;/td&gt;
&lt;td&gt;Simple implementation, single Cold Start&lt;/td&gt;
&lt;td&gt;No streaming response (waits for full completion)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Orchestrator outside VPC&lt;/td&gt;
&lt;td&gt;Short Cold Start (no ENI)&lt;/td&gt;
&lt;td&gt;Cannot call ONTAP REST API (delegates to VPC Lambda)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB session storage&lt;/td&gt;
&lt;td&gt;History shared across browsers&lt;/td&gt;
&lt;td&gt;Cost (write capacity), TTL management needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HITL via modal&lt;/td&gt;
&lt;td&gt;Reliably blocks destructive ops&lt;/td&gt;
&lt;td&gt;UX interruption, reduced agent autonomy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mode pill toggle (3 modes)&lt;/td&gt;
&lt;td&gt;Optimal agent for each purpose&lt;/td&gt;
&lt;td&gt;Learning cost of mode concept&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock Guardrails always-on&lt;/td&gt;
&lt;td&gt;Structural PII leak prevention&lt;/td&gt;
&lt;td&gt;Latency increase (hundreds of ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-agent (Agent Teams)&lt;/td&gt;
&lt;td&gt;Handles complex tasks&lt;/td&gt;
&lt;td&gt;Harder debugging, increased cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  On Streaming Responses
&lt;/h3&gt;

&lt;p&gt;The current implementation uses AppSync Query (synchronous), so agent responses display only after full generation completes. For long responses (file analysis, etc.), users wait several seconds.&lt;/p&gt;

&lt;p&gt;Token-level streaming via AppSync Subscription (WebSocket) is technically possible, but implementation complexity (reconnection handling, partial response parsing, error management) increases substantially. I've deferred this as a next step for when latency becomes a problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Model (AI Agent Specific)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Intent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Cognito Groups (authenticated)&lt;/td&gt;
&lt;td&gt;All authenticated users can use chat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool permissions&lt;/td&gt;
&lt;td&gt;Agent autonomously executes read-only tools&lt;/td&gt;
&lt;td&gt;Write operations require HITL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input filter&lt;/td&gt;
&lt;td&gt;Bedrock Guardrails (input)&lt;/td&gt;
&lt;td&gt;Prompt injection countermeasure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output filter&lt;/td&gt;
&lt;td&gt;Bedrock Guardrails (output)&lt;/td&gt;
&lt;td&gt;PII masking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHI path&lt;/td&gt;
&lt;td&gt;isPhiPath() check&lt;/td&gt;
&lt;td&gt;Don't pass &lt;code&gt;/dicom/&lt;/code&gt; etc. file contents to agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost control&lt;/td&gt;
&lt;td&gt;Only last 10 messages sent as history&lt;/td&gt;
&lt;td&gt;Token consumption cap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;CloudTrail + DynamoDB session logs&lt;/td&gt;
&lt;td&gt;Track "who asked what"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;p&gt;Recommended operational metrics:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Alert Threshold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent Orchestrator error rate&lt;/td&gt;
&lt;td&gt;Lambda CloudWatch Metrics&lt;/td&gt;
&lt;td&gt;&amp;gt; 5% warrants investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response latency (p99)&lt;/td&gt;
&lt;td&gt;Lambda Duration&lt;/td&gt;
&lt;td&gt;&amp;gt; 10s check model or tool side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock Throttling&lt;/td&gt;
&lt;td&gt;Bedrock CloudWatch Metrics&lt;/td&gt;
&lt;td&gt;ThrottledCount &amp;gt; 0 consider provisioned throughput&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB write throttling&lt;/td&gt;
&lt;td&gt;DynamoDB ConsumedWriteCapacityUnits&lt;/td&gt;
&lt;td&gt;On-demand auto-scales, typically no issue&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key design decision&lt;/strong&gt;: The agent can propose &lt;code&gt;storage-admin&lt;/code&gt; operations, but execution is authorized against the user's Cognito Group. If a regular user asks the agent "enable SnapLock," it fails with an authorization error. The agent explains "you don't have permission for this operation."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Compliance note&lt;/strong&gt;: When acting on AI responses about regulated data, the final judgment responsibility lies with the human who approved the operation. Agent responses are "assistive information" — not substitutes for legal or regulatory judgment. Audit trail via CloudTrail + DynamoDB session logs records "who asked what, and what was approved."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The following addresses common questions from different perspectives.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: "What's the token cost per conversation? How do I control context window size?" — With Nova Lite, ~$0.005–$0.02/conversation (varies by tool call count). Adjust &lt;code&gt;maxHistoryMessages&lt;/code&gt; to balance cost vs. context retention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: "What data leaves the VPC? Can Bedrock see file contents?" — File contents are included in Bedrock API requests, but Bedrock does not use data for model training. With VPC endpoint configuration, data stays within the VPC. S3 AP access in Internet-origin configuration also completes within the same region.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operations note&lt;/strong&gt;: "How do I add a new MCP tool? What's the deploy process?" — New tools are implemented as Lambda functions and registered as targets in AgentCore Gateway. Deploy via &lt;code&gt;sam deploy&lt;/code&gt; or Amplify CI/CD pipeline. See &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/agentcore-mcp-tools.md" rel="noopener noreferrer"&gt;AgentCore MCP Tools Reference&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;End-user note&lt;/strong&gt;: "Can I just ask 'find my expense report from last month' and it works?" — Yes. With Knowledge mode and semantic search enabled, you can search by intent without knowing file names. File Agent mode can also traverse folder structures to locate files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaling note&lt;/strong&gt;: "How does this work with multiple Knowledge Bases across departments?" — KB data sources can be specified per-volume via S3 AP, so you can create separate KBs per department volume. The agent switches target KB via &lt;code&gt;bedrockKbId&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Front-end note&lt;/strong&gt;: "How do I customize the chat UI? Can I add my own components?" — The chat UI is implemented as a React component (&lt;code&gt;AgentChat.tsx&lt;/code&gt;), supporting style customization and custom message renderers. Tool call result displays are also extensible via the &lt;code&gt;ToolCallTimeline&lt;/code&gt; component.&lt;/p&gt;




&lt;h2&gt;
  
  
  Staged Adoption Steps
&lt;/h2&gt;

&lt;p&gt;All AI agent features support DemoMode. They work without FSx for ONTAP for evaluation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: No KB, No Agent (File Search Only)
&lt;/h3&gt;

&lt;p&gt;Leave &lt;code&gt;bedrockKbId&lt;/code&gt; empty in &lt;code&gt;portal-config.ts&lt;/code&gt;. Only keyword search available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add Bedrock Knowledge Base
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Register FSx for ONTAP S3 AP as KB data source&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;bedrockKbId&lt;/code&gt; in &lt;code&gt;portal-config.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Semantic search mode becomes active&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Enable AgentChat (File Agent Mode)
&lt;/h3&gt;

&lt;p&gt;Deploy MCP tool Lambda. &lt;code&gt;list_files&lt;/code&gt;, &lt;code&gt;read_file&lt;/code&gt;, &lt;code&gt;search_files&lt;/code&gt; become available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Multi-Agent Mode and HITL
&lt;/h3&gt;

&lt;p&gt;Add admin operation tools (block_user, enable_snaplock, etc.). HITL modal activates automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Agent Teams and Custom Agents
&lt;/h3&gt;

&lt;p&gt;Define team-specific analysis patterns as agents. Share via Agent Directory.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/solutions/amplify-portal" rel="noopener noreferrer"&gt;GitHub: solutions/amplify-portal/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/IMPLEMENTATION.md" rel="noopener noreferrer"&gt;Implementation Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/GETTING-STARTED.md" rel="noopener noreferrer"&gt;Getting Started Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/agentcore-mcp-tools.md" rel="noopener noreferrer"&gt;AgentCore MCP Tools Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/quick-desktop-mcp-setup.md" rel="noopener noreferrer"&gt;Quick Desktop MCP Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-scaling-guide.md" rel="noopener noreferrer"&gt;Scaling Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/tutorial-build-rag-with-bedrock.html" rel="noopener noreferrer"&gt;AWS: Build RAG with Bedrock KB + FSx for ONTAP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html" rel="noopener noreferrer"&gt;AWS: Bedrock Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-1-browser-access" rel="noopener noreferrer"&gt;Part 1: Putting a File Portal on FSx for ONTAP S3 Access Points&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-2-ransomware-worm" rel="noopener noreferrer"&gt;Part 2: From ARP/AI Incident Response to Regulatory Retention Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary and Next Steps
&lt;/h2&gt;

&lt;p&gt;I integrated AI agents into the "file portal + storage operations" foundation built in Parts 1 and 2:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What became possible&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AgentChat (3 modes)&lt;/td&gt;
&lt;td&gt;Complete file operations, analysis, and admin ops in natural language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SemanticSearch&lt;/td&gt;
&lt;td&gt;Solve "where did I put that file?" with vector search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Directory/Creator&lt;/td&gt;
&lt;td&gt;Codify team-specific analysis patterns as agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Teams&lt;/td&gt;
&lt;td&gt;Collaboratively process complex tasks with multiple agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HITL (ActionApproval)&lt;/td&gt;
&lt;td&gt;Execute destructive operations only after human approval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock Guardrails&lt;/td&gt;
&lt;td&gt;Structurally prevent PII leaks and harmful responses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This three-part series documented the portal's evolution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Part 1&lt;/strong&gt; covered the file portal foundation (S3 AP + Amplify Gen2 / Nextcloud)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 2&lt;/strong&gt; added storage operations (ARP/AI, Tamperproof, regulatory retention)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 3&lt;/strong&gt; integrated AI agents (natural language operations, semantic search, multi-agent)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Through the progression of "browse files" → "manage storage" → "talk to AI," the portal reached a point where daily operations and data utilization complete in the browser — without opening ONTAP System Manager or the CLI.&lt;/p&gt;

&lt;p&gt;All code is published in the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/solutions/amplify-portal" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For next steps, I'd suggest starting with keyword search in DemoMode, then adding a Bedrock Knowledge Base for semantic search, and layering on MCP tools and HITL after that. When you move on to a production connection, see the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this post helps someone out there.&lt;/p&gt;

&lt;p&gt;See you next time.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>bedrock</category>
      <category>ai</category>
      <category>netapp</category>
    </item>
    <item>
      <title>Embedding Storage Operations into a File Portal — From ARP/AI Incident Response to Regulatory Retention Management (Part 2)</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Mon, 03 Aug 2026 10:20:41 +0000</pubDate>
      <link>https://dev.to/aws-builders/embedding-storage-operations-into-a-file-portal-from-arpai-incident-response-to-regulatory-1oih</link>
      <guid>https://dev.to/aws-builders/embedding-storage-operations-into-a-file-portal-from-arpai-incident-response-to-regulatory-1oih</guid>
      <description>&lt;p&gt;&lt;strong&gt;Run detection through containment from the screen&lt;/strong&gt; — ARP/AI, SnapLock, audit logs (part 2 of 3)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Japanese version of this article is available: &lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-2-ransomware-worm" rel="noopener noreferrer"&gt;日本語版&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-1-browser-access" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;, I looked at putting a file portal on top of the S3 Access Point of Amazon FSx for NetApp ONTAP (hereafter FSx for ONTAP S3 AP, or S3 AP), comparing Amplify Gen2 and Nextcloud as two approaches. The portal at that point stopped at "browse the files" — the moment you wanted to know something about the storage layer, you had to go back to the ONTAP CLI or the REST API.&lt;/p&gt;

&lt;p&gt;Once people started using it, the first two things that came back were "I want to check whether ARP has detected anything myself" and "is this snapshot actually locked?" Both requests came from team members outside storage administration, and the sticking point was the same: you cannot check any of it without a VPN connection to the management LIF. So I added ONTAP operations features to the Amplify Gen2 portal, up to the point where health checks and incident first response can be done entirely in a browser.&lt;/p&gt;

&lt;p&gt;Here's the conclusion up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ONTAP System Manager-equivalent admin operations can be executed from a browser through AppSync + Lambda&lt;/li&gt;
&lt;li&gt;Separating &lt;code&gt;storage-admin&lt;/code&gt; from regular users with Cognito Groups gives you a safe split between read-only viewing and change operations&lt;/li&gt;
&lt;li&gt;Managing ransomware response as four states — Detected → Contained → Investigating → Resolved — removes the hesitation from first response&lt;/li&gt;
&lt;li&gt;Turning regulatory retention periods (FISC 7 years / SOX 5 years / HIPAA 6 years) into presets prevents day-count mistakes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I'll cover the design of the storage operations features embedded in the portal, the ONTAP REST API implementation behind them, and the points I was careful about when handling irreversible operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmf2ttr6dk25dfvvir4zp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmf2ttr6dk25dfvvir4zp.png" alt="The admin operation path for the storage operations features in the portal. The user's web browser reaches AWS Amplify over HTTPS, Amazon Cognito handles authentication and group checks, and AWS AppSync invokes an AWS Lambda function inside the VPC. That Lambda reads credentials from AWS Secrets Manager and drives the ONTAP REST API on Amazon FSx for NetApp ONTAP" width="800" height="1213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part2-admin-operations-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available, and every figure is listed in the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/architecture-diagrams.en.md" rel="noopener noreferrer"&gt;architecture diagram index&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Relationship to existing tools&lt;/strong&gt;: This portal makes the same storage management operations previously available only through the ONTAP CLI or REST API accessible from a browser with Cognito authentication. It is not a replacement for those — it's an additional layer that opens the same operations to people who should not hold cluster-administrator credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verification status&lt;/strong&gt;: how far each feature in this article has actually been confirmed is recorded in &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/verification-results.en.md" rel="noopener noreferrer"&gt;verification results&lt;/a&gt;, split four ways (live E2E / live read / tests only / DemoMode). Features made reachable after this article first went out — agent and team execution, folder watch, file rename/trash/restore, upload links, the Glue catalog, document analysis — sit in the "tests only" category: handler and component tests pass, but none has been driven from a browser against a real system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The features added are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Storage Dashboard&lt;/strong&gt;: a 4-card health overview&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ARP/AI Incident Lifecycle&lt;/strong&gt;: managed as four states — Detected → Contained → Investigating → Resolved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Object Lock Configuration UI&lt;/strong&gt;: select a bucket, specify a retention mode, apply&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHI Guardrail&lt;/strong&gt;: structurally blocks AI processing for paths such as &lt;code&gt;/dicom/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EMS Events&lt;/strong&gt;: real-time ONTAP alert display&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regulatory Retention Presets&lt;/strong&gt;: FISC 7-year / SOX 5-year / HIPAA 6-year&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Welcome Modal&lt;/strong&gt;: first-time user onboarding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Log&lt;/strong&gt;: file access trail via CloudTrail, viewable in the UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FlexClone Restore&lt;/strong&gt;: one-click recovery from snapshots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Athena Query&lt;/strong&gt;: SQL analysis on NAS data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scope: this article is an implementation record of adding "operations features usable by members outside storage administration" to the file portal built in Part 1. Part 3 covers AI agent integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/solutions/amplify-portal" rel="noopener noreferrer"&gt;solutions/amplify-portal/&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Embed Admin Operations in a Portal
&lt;/h2&gt;

&lt;p&gt;For FSx for ONTAP, the management interfaces you can reach without routing through an additional third-party SaaS are three: the AWS Management Console / FSx API, the ONTAP CLI over SSH, and the ONTAP REST API. ONTAP System Manager is not among them — System Manager support for FSx for ONTAP is delivered through the vendor's SaaS console, and that SaaS covers FSx for ONTAP only in its SaaS-connected mode (sources in &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/fsx-ontap-management-interfaces.md" rel="noopener noreferrer"&gt;management interfaces&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;So learning anything about the ONTAP side means SSH to the ONTAP CLI or a REST call, both of which assume cluster-administrator credentials. When team members outside storage administration (security staff, compliance officers, data protection teams) want to "check ARP status" or "verify whether a snapshot is locked," the way to let them is to hand over an SSH key.&lt;/p&gt;

&lt;p&gt;Motivation for embedding admin operations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Security staff should be able to instantly check ransomware detection state and execute containment actions&lt;/li&gt;
&lt;li&gt;Compliance officers should be able to verify retention settings and audit logs themselves&lt;/li&gt;
&lt;li&gt;Operations teams should be able to check ONTAP alerts without opening another tool&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cognito Groups (&lt;code&gt;storage-admin&lt;/code&gt; / &lt;code&gt;authenticated&lt;/code&gt;) separate authorization — regular users are read-only, only admins can execute changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Used to Do vs What You Can Do Now
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Previous Method&lt;/th&gt;
&lt;th&gt;Portal Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check ARP threats and contain&lt;/td&gt;
&lt;td&gt;CLI: &lt;code&gt;security anti-ransomware volume show&lt;/code&gt; → block by hand&lt;/td&gt;
&lt;td&gt;Dashboard detection → one-click containment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WORM-lock a snapshot&lt;/td&gt;
&lt;td&gt;CLI: &lt;code&gt;volume snapshot modify-retention&lt;/code&gt; or direct REST API call&lt;/td&gt;
&lt;td&gt;Lock panel → select preset → apply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DR failover with SnapMirror&lt;/td&gt;
&lt;td&gt;CLI: &lt;code&gt;snapmirror break&lt;/code&gt; / &lt;code&gt;snapmirror resync&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Status list → click action button&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Storage Dashboard — Admin Landing Page
&lt;/h2&gt;

&lt;p&gt;The first thing admins see after login is a 4-card health dashboard. This follows ONTAP System Manager's "dashboard first" pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│ 💾 12       │  │ 🛡️ 8         │  │ 🔐 5        │  │ 📊 3.2x 　   │
│ Volumes     │  │ARP Protected│  │ Locked Snaps│  │ Efficiency  │
│ Avg: 62%    │  │✅ No threats│  │ Tamperproof │  │ 69% saved   │
└─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The 4 Cards
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card&lt;/th&gt;
&lt;th&gt;Shows&lt;/th&gt;
&lt;th&gt;Navigates to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Volume Capacity&lt;/td&gt;
&lt;td&gt;Volume count + average utilization&lt;/td&gt;
&lt;td&gt;Volume Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARP/AI Protection&lt;/td&gt;
&lt;td&gt;Protected volumes + threat count&lt;/td&gt;
&lt;td&gt;ARP Admin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locked Snapshots&lt;/td&gt;
&lt;td&gt;Locked snapshot count&lt;/td&gt;
&lt;td&gt;Snapshot Admin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage Efficiency&lt;/td&gt;
&lt;td&gt;Dedup/compression ratio + savings&lt;/td&gt;
&lt;td&gt;Efficiency Panel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;Four APIs fetched in parallel with &lt;code&gt;Promise.allSettled&lt;/code&gt;. If one fails (e.g., ARP not configured), remaining cards still render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;volResp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arpResp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapResp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;effResp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allSettled&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="nf"&gt;adminQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;listVolumes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nf"&gt;adminQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;listArpVolumes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nf"&gt;protectionQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;listSnapshots&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;maxResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nf"&gt;adminQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getEfficiencyStats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why &lt;code&gt;Promise.allSettled&lt;/code&gt; over &lt;code&gt;Promise.all&lt;/code&gt;: with &lt;code&gt;Promise.all&lt;/code&gt;, one failure rejects everything. On a storage dashboard, "ARP not configured" is a normal state, not an error.&lt;/p&gt;




&lt;h2&gt;
  
  
  ARP/AI Incident Lifecycle
&lt;/h2&gt;

&lt;p&gt;After ONTAP Autonomous Ransomware Protection (ARP/AI) detects a threat, the response flow is managed across 4 states.&lt;/p&gt;

&lt;h3&gt;
  
  
  State Transitions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔴 Detected
  → 🟠 Contained
    → 🟡 Investigating
      → 🟢 Resolved
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnynn5v32lh5j92dq06gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnynn5v32lh5j92dq06gb.png" alt="The ARP/AI incident lifecycle tracked as four states. Detected moves to Contained on containment, then to Investigating, and finally to Resolved. The notes list what each state records" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part2-arp-incident-lifecycle-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Recorded at Each State
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Timestamp&lt;/th&gt;
&lt;th&gt;Additional Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Detected&lt;/td&gt;
&lt;td&gt;detectedAt&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contained&lt;/td&gt;
&lt;td&gt;containedAt&lt;/td&gt;
&lt;td&gt;blockedUsers[], blockedIps[], snapshotName&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Investigating&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;notes (free text)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolved&lt;/td&gt;
&lt;td&gt;resolvedAt&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Containment Actions
&lt;/h3&gt;

&lt;p&gt;Actions executable directly from the portal:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;ONTAP REST API&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Block SMB User&lt;/td&gt;
&lt;td&gt;name-mapping deny (win→unix)&lt;/td&gt;
&lt;td&gt;Immediately denies target user's SMB access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block NFS IP&lt;/td&gt;
&lt;td&gt;export-policy deny rule&lt;/td&gt;
&lt;td&gt;Immediately denies NFS access from target IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full Containment&lt;/td&gt;
&lt;td&gt;snapshot + block + disconnect&lt;/td&gt;
&lt;td&gt;Preserves snapshot + blocks all + disconnects sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unblock&lt;/td&gt;
&lt;td&gt;delete name-mapping/export-policy rules&lt;/td&gt;
&lt;td&gt;Recovery after investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This implements the equivalent of NetApp DII Storage Workload Security blocking directly via ONTAP REST API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useIncidentState hook — persists per-volume in localStorage&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IncidentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;detected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contained&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;investigating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resolved&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIncidentState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;volumeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;incident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIncident&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IncidentRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;loadIncident&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;volumeName&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;markContained&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;ips&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contained&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;snapshotName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;blockedUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;blockedIps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ips&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI displays a state badge with the next action button changing dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[🔴 Detected] → [Execute Containment] button
[🟠 Contained] → [Start Investigation] button
[🟡 Investigating] → [Resolve] button
[🟢 Resolved] → (complete)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Current limitation&lt;/strong&gt;: Incident state is stored in &lt;code&gt;localStorage&lt;/code&gt; and not shared across browsers. There is also a risk of losing incident state if the browser crashes. DynamoDB persistence is recommended for production use so that multiple members see the same state.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Incident response note&lt;/strong&gt;: After executing containment actions, integrate with your existing incident runbooks (PagerDuty, OpsGenie, etc.). Portal containment is a first-response action and should be positioned as part of your full incident management workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: Executing containment actions (SMB block, NFS IP block) requires membership in the &lt;code&gt;storage-admin&lt;/code&gt; group. Unblocking requires the same privilege, so even if a regular user's browser session is compromised, the attacker cannot lift a block. Compromise of a &lt;code&gt;storage-admin&lt;/code&gt; account itself is guarded by Cognito MFA.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-tenant note&lt;/strong&gt;: When multiple teams (tenants) share the same portal, ensure tenant A cannot view tenant B's ARP alerts by combining Cognito Groups with volume-level access control. In the current implementation, all &lt;code&gt;storage-admin&lt;/code&gt; group members can view ARP status for all volumes. If tenant isolation is required, consider deploying separate portal instances per SVM.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  PHI Guardrail — Structurally Blocking AI Processing
&lt;/h2&gt;

&lt;p&gt;Prevents the "accidentally sent PHI data to an external AI" scenario at the UI level in HIPAA environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;Files in paths containing &lt;code&gt;/dicom/&lt;/code&gt;, &lt;code&gt;/phi/&lt;/code&gt;, &lt;code&gt;/pii/&lt;/code&gt;, &lt;code&gt;/hipaa/&lt;/code&gt;, or &lt;code&gt;/protected-health/&lt;/code&gt; have their AI processing button automatically disabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPhiPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\/(&lt;/span&gt;&lt;span class="sr"&gt;dicom|phi|pii|hipaa|protected-health&lt;/span&gt;&lt;span class="se"&gt;)[\/&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
         &lt;span class="nx"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dicom/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;phi/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pii/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UI display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Normal folder: [⚡ Run AI Processing]     ← clickable
PHI folder:    [🚫 PHI — AI Blocked]      ← disabled, not clickable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Design Intent
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Guardrail, not detect-and-respond&lt;/strong&gt;: rather than "processed it, then discovered it was PHI," this prevents processing from starting at all&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cannot be bypassed even by admins&lt;/strong&gt;: the button itself is disabled regardless of permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Depends on folder naming convention&lt;/strong&gt;: path-pattern based, so it presupposes organizational folder structure rules&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important limitation&lt;/strong&gt;: This guardrail blocks based on folder path only — it does NOT scan file contents. A file like &lt;code&gt;/contracts/sensitive-patient.pdf&lt;/code&gt; placed outside PHI paths will not be blocked. For content-based PHI detection, combine with Bedrock Guardrails (response filtering) described in Part 3. Path guardrail + content filtering gives you ideal 2-layer defense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HIPAA note&lt;/strong&gt;: Using this portal in a HIPAA environment presupposes a Business Associate Agreement (BAA) with AWS. Cognito, Lambda, S3, Step Functions, and Bedrock are all &lt;a href="https://aws.amazon.com/compliance/hipaa-eligible-services-reference/" rel="noopener noreferrer"&gt;HIPAA eligible services&lt;/a&gt;. The PHI guardrail is an additional UI-level defense — both the BAA and technical controls are required.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  S3 Object Lock — WORM Protection for Output Buckets
&lt;/h2&gt;

&lt;p&gt;AI processing results and compliance reports are stored in standard S3 buckets outside FSx for ONTAP. The portal provides a UI to configure S3 Object Lock on these output buckets.&lt;/p&gt;

&lt;h3&gt;
  
  
  3-Tab Lock Panel
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tab&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP SnapLock&lt;/td&gt;
&lt;td&gt;Volumes&lt;/td&gt;
&lt;td&gt;WORM protection for NAS data (shared across NFS/SMB/S3 AP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 Object Lock&lt;/td&gt;
&lt;td&gt;S3 Buckets&lt;/td&gt;
&lt;td&gt;WORM protection for AI processing results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tamperproof Snapshot&lt;/td&gt;
&lt;td&gt;Snapshots&lt;/td&gt;
&lt;td&gt;Tamper prevention for specific snapshots&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  S3 Object Lock Configuration Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Fetch bucket list → select from dropdown
2. Choose mode:
   - Governance: Authorized users can override (recommended for AI output)
   - Compliance: No one, including root, can delete until retention expires (regulatory archives)
3. Specify retention days
4. [Apply] sets Object Lock Configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When to Use SnapLock vs S3 Object Lock
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characteristic&lt;/th&gt;
&lt;th&gt;ONTAP SnapLock&lt;/th&gt;
&lt;th&gt;S3 Object Lock&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Target&lt;/td&gt;
&lt;td&gt;Files on NAS volumes&lt;/td&gt;
&lt;td&gt;Objects in S3 buckets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access protocols&lt;/td&gt;
&lt;td&gt;NFS/SMB/S3 AP&lt;/td&gt;
&lt;td&gt;S3 API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use case&lt;/td&gt;
&lt;td&gt;Source data WORM protection&lt;/td&gt;
&lt;td&gt;AI results/reports protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regulatory&lt;/td&gt;
&lt;td&gt;SEC 17a-4, FISC, HIPAA, NARA&lt;/td&gt;
&lt;td&gt;SEC 17a-4, HIPAA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Combining both achieves "source data AND processing results both tamper-proof."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Compliance framework note&lt;/strong&gt;: The AWS services used by this portal (Cognito, Lambda, S3, Step Functions, Bedrock, AppSync) are in scope for &lt;a href="https://aws.amazon.com/compliance/ismap/" rel="noopener noreferrer"&gt;ISMAP&lt;/a&gt; and &lt;a href="https://aws.amazon.com/compliance/soc-faqs/" rel="noopener noreferrer"&gt;SOC 2&lt;/a&gt;. FedRAMP environments for US government agencies require deployment in AWS GovCloud regions. Confirm compliance requirements with your legal and compliance teams — this portal is a technical implementation pattern and does not provide compliance judgments.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Regulatory Retention Period Presets
&lt;/h2&gt;

&lt;p&gt;The Tamperproof Snapshot lock form offers retention periods as dropdown selections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preset List
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Preset&lt;/th&gt;
&lt;th&gt;Retention Days&lt;/th&gt;
&lt;th&gt;Regulatory Basis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;Short-term validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;90 days&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;Quarterly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 year&lt;/td&gt;
&lt;td&gt;365&lt;/td&gt;
&lt;td&gt;Annual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SOX/J-SOX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,825 (5 years)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Securities Exchange Act — financial records retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HIPAA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2,192 (6 years)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medical records minimum retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FISC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2,557 (7 years)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Center for Financial Industry Information Systems standard, Chapter 9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Compliance note&lt;/strong&gt;: FISC/SOX/HIPAA presets are provided for technical convenience. Whether the regulatory mapping and retention periods apply to your organization's specific situation should be validated with your legal and compliance teams. Regulatory interpretation varies by industry, business scope, and jurisdiction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why Presets Are Needed
&lt;/h3&gt;

&lt;p&gt;SnapLock retention settings are &lt;strong&gt;irreversible&lt;/strong&gt;. Once a snapshot is locked, the retention period cannot be shortened.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents "how many days is 5 years?" calculation errors&lt;/li&gt;
&lt;li&gt;Each preset shows a tooltip with regulatory basis&lt;/li&gt;
&lt;li&gt;Minimizes risk of incorrect selection (can extend but never shorten)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{1825}&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"SOX/J-SOX: Financial records must be retained for 5 years"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  1,825 days — SOX/J-SOX (5 years)
&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{2192}&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"HIPAA: Medical records require minimum 6-year retention"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  2,192 days — HIPAA (6 years)
&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{2557}&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"FISC: Financial institution data requires 7-year retention"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  2,557 days — FISC (7 years)
&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  EMS Events — ONTAP Alert Viewer
&lt;/h2&gt;

&lt;p&gt;Retrieves events from ONTAP's Event Management System (EMS) with severity alert/error/emergency and displays them in the admin panel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_ems_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;ONTAP REST: GET /api/support/ems/events&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;max_records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxRecords&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;severity_filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alert,error,emergency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/support/ems/events?max_records=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_records&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;severity=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;severity_filter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;order_by=time desc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;fields=time,severity,message.name,message.text,node.name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_ontap_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messageName&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messageText&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;records&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;events&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Events
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Message Name&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;emergency&lt;/td&gt;
&lt;td&gt;ha.takeover.byPartner&lt;/td&gt;
&lt;td&gt;HA partner takeover&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alert&lt;/td&gt;
&lt;td&gt;raid.disk.predictiveFailure&lt;/td&gt;
&lt;td&gt;Disk predictive failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;scsiblade.san.netLIFDown&lt;/td&gt;
&lt;td&gt;SAN LIF down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alert&lt;/td&gt;
&lt;td&gt;arw.volume.attack&lt;/td&gt;
&lt;td&gt;ARP detected ransomware attack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Storage administrators can check recent alerts directly in the portal without opening an ONTAP CLI session.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Refresh frequency note&lt;/strong&gt;: EMS events are fetched on demand when the dashboard is displayed (not by periodic polling). If you need real-time alerting, push EMS events via EventBridge + SNS instead (see &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;fsxn-observability-integrations&lt;/a&gt;). The portal is for "checking recent events"; for "detecting in real time," consider pairing it with a separate observability stack.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Welcome Modal — First-Time Onboarding
&lt;/h2&gt;

&lt;p&gt;First-time users see a 3-step guided tour.&lt;/p&gt;

&lt;h3&gt;
  
  
  3 Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;📂 &lt;strong&gt;File Browsing&lt;/strong&gt; — Browse and search NAS files from your browser&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;AI Processing&lt;/strong&gt; — Select files and trigger AI/ML workflows&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Data Protection&lt;/strong&gt; — Snapshots, WORM locks, ransomware protection&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WelcomeModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dismissed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDismissed&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;portal-welcome-dismissed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dismissed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 3-step carousel with dot navigation&lt;/span&gt;
  &lt;span class="c1"&gt;// "Don't show again" checkbox → localStorage persistence&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Design Intent
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Standard onboarding pattern in SaaS products&lt;/li&gt;
&lt;li&gt;Often omitted in internal tools, but highly effective for conveying "what this portal can do" in 10 seconds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;localStorage&lt;/code&gt; state management, works without backend changes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Resource Management — 20-Panel Card-Grid Admin
&lt;/h2&gt;

&lt;p&gt;ONTAP admin operations organized into 5 categories × 20 panels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Structure
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Panels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🗄️ Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Volumes / 🧬 FlexClone / ⚡ FlexCache / Qtrees / Quotas / Efficiency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🔐 Access Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Export Policies / SMB Shares / 👤 Local Users / 🔀 Name Mapping / QoS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🛡️ Data Protection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ARP/AI / Snapshots / SnapLock / 📡 FPolicy / 🦠 Vscan / 🪞 SnapMirror&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🖥️ Cluster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;🔗 Peering / 🖥️ Cluster Information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🤖 Services&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI Settings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each panel displays as a card grid, clicking navigates to the detail view. Follows System Manager's card-based navigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmv0m6qcfzhdo2wlspo2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmv0m6qcfzhdo2wlspo2m.png" alt="The Resource management landing page in the portal. A storage health row of four cards sits above five categories — Storage, Access control, Data protection, Cluster and AI services — holding twenty panel cards in total" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Cluster category covers the part the AWS Management Console does not expose. Cluster peering and SVM peering had to be done from the ONTAP CLI or by hand-writing REST calls, which is a real operational cost for an AWS-centric team that otherwise never leaves the console.&lt;/p&gt;

&lt;h3&gt;
  
  
  New Panel Highlights
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Vscan — "Zero to Configured" Setup Guidance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vscan (antivirus scanning) has the highest setup barrier of any ONTAP feature — it requires external Windows/Linux servers and antivirus vendor licenses. When unconfigured, the Vscan panel displays a 5-step guided wizard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vendor selection (6-vendor comparison table with license page links)&lt;/li&gt;
&lt;li&gt;NetApp Antivirus Connector download&lt;/li&gt;
&lt;li&gt;EC2 deployment (architecture diagram + AWS Blog/GitHub samples)&lt;/li&gt;
&lt;li&gt;ONTAP CLI commands (scanner-pool / policy / enable)&lt;/li&gt;
&lt;li&gt;Verification in this panel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even someone starting from "what is Vscan?" can follow the setup path directly from the portal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlmggqb924k6jonmhg4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlmggqb924k6jonmhg4t.png" alt="The Vscan panel with the setup guide expanded. It lists interoperable products with links to their license pages, where to obtain the connector, an architecture line, and example ONTAP CLI commands for scanner-pool, on-access-policy and enable" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One correction from the first version of this panel: the guidance only rendered while Vscan was disabled, so it disappeared the moment Vscan came up — exactly when you still want the scanner-side steps and the interoperability matrix link. It now stays reachable from a toolbar toggle in both states.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FlexClone — Instant Zero-Copy Clones&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create and split volume clones from the UI for ransomware recovery, forensics, or dev/test. Metadata-only copy completes in seconds with near-zero additional capacity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SnapMirror — Replication Lifecycle Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Monitor DR and cross-region replication relationships in the browser and execute actions (sync, break, resync, quiesce, resume, delete). Click a relationship to expand the last 10 transfer records (size, duration, success/failure). Lag times exceeding your RPO target display in red so they are noticed immediately.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DR planning note&lt;/strong&gt;: SnapMirror Break/Resync operations are executable from the browser, but understand the RPO impact before clicking Break. After a break, the replication relationship is severed and resync requires delta transfer. For production environments, pair the confirmation dialog (implemented) with your team's DR runbook procedures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;FlexCache — Remote Read Cache CRUD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create FlexCache volumes (async, with prepopulate path support), view the list (origin→cache arrow display), and delete (automated 3-step: unmount→offline→delete). When unconfigured, guidance is displayed with a datalist for selecting origin volumes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Async polling note&lt;/strong&gt;: FlexCache creation uses async polling to detect completion. If the user closes the browser during creation, the ONTAP-side operation continues. The created volume appears on the next list refresh — no data loss or inconsistent state results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Cluster and SVM Peering — the gap the console leaves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Peering is a two-sided operation, and the authentication passphrase has to travel between the two clusters. The panel drives one side at a time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8fskly3zr3rkiayssqhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8fskly3zr3rkiayssqhj.png" alt="The Peering panel showing the cluster peers tab. Two peers are listed with state badges — one available and authenticated, one pending with authentication absent — each with Accept and Delete actions" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The prerequisite that trips people up is the intercluster LIF, so it gets its own tab rather than being left as a footnote. Both clusters need at least one in &lt;code&gt;up&lt;/code&gt; state, and TCP 11104, 11105 plus ICMP have to be allowed between their addresses — the intercluster LIF addresses, not the management LIF.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1av49klx0fbdz3gvs82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1av49klx0fbdz3gvs82.png" alt="The intercluster LIF tab listing two LIFs in up state on separate nodes, with a Ready for peering badge and a note that cluster peering needs at least one such LIF on both sides" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flow is: check the LIFs, create the peer on one cluster with &lt;code&gt;Generate passphrase&lt;/code&gt;, then enter that passphrase under &lt;code&gt;Accept&lt;/code&gt; on the other. The generated value is shown &lt;strong&gt;once&lt;/strong&gt; — ONTAP returns it in the creation response only, so the panel surfaces it in a banner you have to dismiss deliberately. Lose it and the peer has to be deleted and recreated.&lt;/p&gt;

&lt;p&gt;SVM peers come after the cluster peer reaches &lt;code&gt;available&lt;/code&gt;, and are accepted on the remote side without a passphrase. An SVM-level SnapMirror additionally needs the source subtype &lt;code&gt;default&lt;/code&gt; and the destination &lt;code&gt;dp_destination&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cluster Information — nodes, licences, LIFs, protocols, DNS, jobs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F75kmu6rs32q243wsndxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F75kmu6rs32q243wsndxu.png" alt="The Cluster information panel overview tab, showing the cluster name and ONTAP version, with the node and licence lists empty and a note under each explaining that this is expected on FSx for ONTAP rather than an error" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four tabs: overview (cluster name and version, nodes, licences), interfaces (LIF list with enable/disable), services (NFS, SMB and S3 state with enable/disable, plus the SVM DNS domains and servers), and jobs.&lt;/p&gt;

&lt;p&gt;The overview tab is quieter than that list suggests. On the cluster I tested (ONTAP 9.17.1P7D1) both &lt;code&gt;/cluster/nodes&lt;/code&gt; and &lt;code&gt;/cluster/licensing/licenses&lt;/code&gt; returned zero records with no error, because AWS manages the cluster rather than the tenant. The first version of the panel rendered that as a bare "No nodes", which reads as a failure, so it now states that an empty list is expected here. The cluster name and ONTAP version come from &lt;code&gt;/cluster&lt;/code&gt; and are still populated.&lt;/p&gt;

&lt;p&gt;The jobs tab matters more than it looks. FlexCache creation, FlexClone split, SnapMirror transfers and peering all run as asynchronous ONTAP jobs, so this is where their progress and, more usefully, their failure reasons show up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtgaar5wk1z1o4e03eb3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtgaar5wk1z1o4e03eb3.png" alt="The Cluster information services tab. NFS, CIFS and S3 are listed as enabled with their detail column showing the AD domain for CIFS, each with a Disable action, above the DNS domains and servers form" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DNS note&lt;/strong&gt;: an AD-joined SVM resolves its domain controllers through the servers set here. A wrong value breaks SMB, and on an AD-joined SVM it also makes S3 Access Point data operations fail with &lt;code&gt;AccessDenied&lt;/code&gt; — while &lt;code&gt;HeadBucket&lt;/code&gt; keeps succeeding, which sends you looking at IAM instead of the file system layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Destructive operations are gated in both layers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SnapMirror break, resync and delete, Vscan and FPolicy policy deletion, peer deletion, and disabling a LIF or a protocol all show an inline confirmation row before anything is sent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fajjmcxj6wqx4x6qe2s3x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fajjmcxj6wqx4x6qe2s3x.png" alt="The Vscan panel with a delete confirmation row expanded under the policy, warning that deleting the policy stops its scope being scanned, with Execute and Cancel buttons" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The confirmation is not only in the UI. The Lambda refuses the same actions unless &lt;code&gt;confirm=true&lt;/code&gt; is present, so a direct call that bypasses the browser is rejected identically. That split matters: a UI-only guard is a suggestion, not a control.&lt;/p&gt;

&lt;p&gt;Getting this wrong is instructive. In the first cut, the Vscan and FPolicy delete buttons sent no &lt;code&gt;confirm&lt;/code&gt; flag and had no confirmation row, and the handler did not check for one either — while the documentation already claimed the operation was confirm-gated. The button appeared to work and the docs looked right. The fix was to make all three agree, and to pin the contract in tests: for every confirm-gated action, assert it refuses without &lt;code&gt;confirm&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; succeeds with exactly the parameters the UI sends. The second half of that assertion is the one that would have caught it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Model
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;Cognito User Pool + MFA (TOTP/SMS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization (API)&lt;/td&gt;
&lt;td&gt;Cognito Groups (&lt;code&gt;storage-admin&lt;/code&gt; / &lt;code&gt;authenticated&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization (Files)&lt;/td&gt;
&lt;td&gt;S3 AP + UNIX/Windows file system identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport encryption&lt;/td&gt;
&lt;td&gt;HTTPS (AppSync) + TLS 1.2 (ONTAP REST API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets management&lt;/td&gt;
&lt;td&gt;Secrets Manager (ONTAP credentials)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;CloudTrail S3 data events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WORM&lt;/td&gt;
&lt;td&gt;SnapLock (Compliance/Enterprise) + S3 Object Lock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ransomware protection&lt;/td&gt;
&lt;td&gt;ONTAP ARP/AI + portal containment actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHI protection&lt;/td&gt;
&lt;td&gt;Path-based guardrail (AI processing block)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only users in the &lt;code&gt;storage-admin&lt;/code&gt; group can execute admin operations (volume creation, SnapLock configuration, ARP containment, etc.). Regular users are limited to file browsing and AI processing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Enterprise SSO note&lt;/strong&gt;: Cognito User Pool supports SAML 2.0 and OIDC federation. To integrate with an existing IdP such as Okta, Azure AD, or Google Workspace, see Cognito's &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-saml-idp.html" rel="noopener noreferrer"&gt;Adding SAML identity providers&lt;/a&gt;. Group mapping lets you map IdP groups to the Cognito &lt;code&gt;storage-admin&lt;/code&gt; group.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure protection note&lt;/strong&gt;: Amplify Hosting is served via Amazon CloudFront, so AWS Shield Standard (DDoS protection) is automatically applied. If additional WAF rules are needed, attach AWS WAF to the CloudFront distribution.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Usage Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: Ransomware Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Storage Dashboard shows 🚨 ARP Threats: 1
2. Navigate to ARP/AI panel → view threat details
3. Click [Contain] → SMB user blocked + snapshot taken
4. State transitions to 🟠 Contained
5. After forensic analysis, [Investigation Complete] → [Resolve]
6. Unblock to resume normal operations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 2: Compliance Audit
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Lock panel → SnapLock tab to review Compliance volume list
2. Tamperproof tab to apply FISC 7-year lock to snapshots
3. S3 Object Lock tab to verify output bucket retention settings
4. Audit Trail to review operation history
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 3: Daily Monitoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Storage Dashboard — glance at 4 cards (30 seconds)
2. If any volume exceeds 85% capacity, drill into Volume Manager
3. Check EMS Events for recent alerts
4. No issues → done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Design Trade-offs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Design Decision&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;localStorage (Incident State)&lt;/td&gt;
&lt;td&gt;Simple deployment&lt;/td&gt;
&lt;td&gt;Not shared across browsers; incident state can be lost if the browser crashes. DynamoDB migration recommended for production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHI path regex&lt;/td&gt;
&lt;td&gt;Simple, immediate&lt;/td&gt;
&lt;td&gt;Requires folder naming convention compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generic Dispatch (10 endpoints)&lt;/td&gt;
&lt;td&gt;Avoids CFn 1MB limit&lt;/td&gt;
&lt;td&gt;IAM policy granularity is coarser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPC split&lt;/td&gt;
&lt;td&gt;Cold start optimization&lt;/td&gt;
&lt;td&gt;Two types of Lambda required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Promise.allSettled (Dashboard)&lt;/td&gt;
&lt;td&gt;Resilient to partial failures&lt;/td&gt;
&lt;td&gt;Failed cards show 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regulatory presets (hardcoded)&lt;/td&gt;
&lt;td&gt;Ready to use immediately&lt;/td&gt;
&lt;td&gt;Code change needed if regulations update&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Rollback Procedure
&lt;/h3&gt;

&lt;p&gt;Recovery paths if a portal update causes problems:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Rollback method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend UI issue&lt;/td&gt;
&lt;td&gt;One-click revert to the previous build from the Amplify Hosting console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda function issue&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git revert&lt;/code&gt; + &lt;code&gt;git push&lt;/code&gt; triggers automatic redeploy (Amplify Gen2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP configuration change issue&lt;/td&gt;
&lt;td&gt;Restore directly via ONTAP REST API (export-policy, name-mapping, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cognito configuration change&lt;/td&gt;
&lt;td&gt;CDK stack rollback is not available. Revert manually to the previous state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Because frontend and backend are both under Git management, &lt;code&gt;git revert&lt;/code&gt; + &lt;code&gt;git push&lt;/code&gt; rolls back immediately. Some ONTAP-side changes (such as enabling SnapLock) are irreversible, so verification before execution matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  8-Language Support (i18n)
&lt;/h2&gt;

&lt;p&gt;All admin features included, the entire portal supports 8 languages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ja&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;日本語&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;en&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;English&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ko&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;한국어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zh-CN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;简体中文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zh-TW&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;繁體中文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Français&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;de&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deutsch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;es&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Español&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Technical terms (ONTAP, SnapLock, FlexClone, S3 AP, ARP/AI, WORM, FISC, SOX, HIPAA) are not translated. Browser &lt;code&gt;navigator.language&lt;/code&gt; auto-detection with instant switching via the header language picker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Audit Log — Checking "Who Accessed What and When" in the UI
&lt;/h2&gt;

&lt;p&gt;The most frequent request from compliance officers was "I want to check the file access trail myself." Grepping CloudTrail logs from the CLI is not realistic for anyone outside the security team.&lt;/p&gt;

&lt;p&gt;The portal's Audit tab runs filtered queries:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Filter&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File path&lt;/td&gt;
&lt;td&gt;Show only accesses under &lt;code&gt;/contracts/&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event type&lt;/td&gt;
&lt;td&gt;READ / WRITE / ALL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time range&lt;/td&gt;
&lt;td&gt;2026-07-01 – 2026-07-28&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AppSync Query → Lambda → Athena SQL → CloudTrail S3 Data Event logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frh1kzeq277eyvyi0105g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frh1kzeq277eyvyi0105g.png" alt="The path for reviewing audit logs from the UI. The web browser calls an AWS Lambda function through AWS AppSync, and Amazon Athena runs the SQL. Athena reads the table definition from AWS Glue (Data Catalog) and scans the Amazon S3 logs where AWS CloudTrail recorded the S3 data events" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part2-audit-log-pipeline-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;CloudTrail S3 data events are registered as a Glue table and queried with Athena. Results display in table form, and access denials (AccessDenied) are highlighted in red.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Enable data events for the S3 AP ARN on a CloudTrail Trail&lt;/li&gt;
&lt;li&gt;Create the Athena table via Glue Crawler or a manual &lt;code&gt;CREATE TABLE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;ATHENA_AUDIT_DATABASE&lt;/code&gt;, &lt;code&gt;ATHENA_AUDIT_TABLE&lt;/code&gt;, and &lt;code&gt;ATHENA_AUDIT_OUTPUT&lt;/code&gt; as Lambda environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these are unconfigured, the UI displays "configuration required" guidance with the setup steps. The design treats this as onboarding rather than an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Retention
&lt;/h3&gt;

&lt;p&gt;Query results are stored in the Athena workgroup output location (S3). Retention of the original CloudTrail logs is controlled by the S3 bucket lifecycle policy on the Trail's bucket. Set retention periods such as FISC 7 years or HIPAA 6 years according to your audit requirements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: If you store audit trails in DynamoDB, storage costs grow in large environments. Set a retention policy (TTL) and archive old records to S3 Glacier. CloudTrail log retention is controlled separately via the Trail's lifecycle policy.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  FlexClone Restore — Instant Recovery from Snapshots
&lt;/h2&gt;

&lt;p&gt;When recovering from ransomware damage or accidental deletion, the requirement is "I want to go back to the snapshot from before the infection." Previously this meant creating a FlexClone from the CLI and attaching an S3 AP as a sequence of manual operations.&lt;/p&gt;

&lt;p&gt;In the portal, from the 📸 button on the Files tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Enter the snapshot name (e.g., daily.2026-07-18_0010)
2. Click [Clone &amp;amp; Attach]
3. Step Functions automatically runs FlexClone creation → S3 AP attach
4. FlexClone information appears on the Results tab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  FlexClone Status Display
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔄 FlexClone Volume
  Volume:  clone-uc6-20260718-abc123
  Parent:  vol_data
  Status:  🟢 online
  Created: 2026-07-18 15:00:00
  Size:    128 MB
  S3 AP:   clone-uc6-abc123-s3alias
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ransomware recovery&lt;/td&gt;
&lt;td&gt;Immediate access to a pre-infection snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forensics&lt;/td&gt;
&lt;td&gt;Isolate a point-in-time copy for investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Validate against a clone without touching production data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;FlexClone is a metadata-only copy, so it completes in seconds with near-zero additional capacity. Differential capacity is consumed only as writes occur.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Accessibility note&lt;/strong&gt;: Confirmation dialogs for FlexCache deletion and volume deletion are displayed inline. For screen reader users, confirmation messages are announced via &lt;code&gt;role="alertdialog"&lt;/code&gt; and &lt;code&gt;aria-describedby&lt;/code&gt;. Keyboard navigation (Tab/Enter/Escape) is fully supported.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput note&lt;/strong&gt;: A FlexClone volume shares the throughput budget with its parent volume. If clones are used actively in parallel in production, account for the performance impact on the parent volume. For read-oriented uses such as forensics this is typically not a concern.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Athena Query — SQL Analytics on NAS Data
&lt;/h2&gt;

&lt;p&gt;When files on FSx for ONTAP are cataloged via Glue Crawler, you can run SQL queries using Athena. The portal's "Analytics" tab lets you enter a database name and SQL, and execute directly.&lt;/p&gt;

&lt;p&gt;There is no need to open the AWS Athena console separately — everything completes inside the portal.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI Layout
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="err"&gt;┌──────────────────────────────────────────────────┐&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="k"&gt;SQL&lt;/span&gt; &lt;span class="n"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Athena&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;        &lt;span class="p"&gt;]&lt;/span&gt;        &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──────────────────────────────────────────────────┤&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;💡&lt;/span&gt; &lt;span class="n"&gt;How&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;catalog&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;FSx&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ONTAP&lt;/span&gt;    &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;Glue&lt;/span&gt; &lt;span class="n"&gt;Crawler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;analyze&lt;/span&gt; &lt;span class="n"&gt;them&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;   &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="k"&gt;SQL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;                                             &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;▸&lt;/span&gt; &lt;span class="err"&gt;📝&lt;/span&gt; &lt;span class="k"&gt;View&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collapsible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;├──────────────────────────────────────────────────┤&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;TABLES&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;                           &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                                                  &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;                                      &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└──────────────────────────────────────────────────┘&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First time&lt;/strong&gt;: run &lt;code&gt;SHOW TABLES IN default&lt;/code&gt; to discover available tables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Once you know table names&lt;/strong&gt;: execute specific SELECT queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Results&lt;/strong&gt;: displayed in table form&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Practical Query Examples
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Find large files (capacity planning)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;size&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s3_objects&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000000000&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;size&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;

&lt;span class="c1"&gt;-- Total size of a specific folder (project sizing)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;total_bytes&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s3_objects&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'engineering/%'&lt;/span&gt;

&lt;span class="c1"&gt;-- Files modified in last 7 days (change tracking)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_modified&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s3_objects&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;last_modified&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;current_date&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="s1"&gt;'7'&lt;/span&gt; &lt;span class="k"&gt;day&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The portal UI includes an expandable "View query examples" section, so even users unfamiliar with SQL can get started by copy-pasting.&lt;/p&gt;

&lt;p&gt;Not just "browse the files" but "ask questions of the data" — directly from the portal.&lt;/p&gt;

&lt;h3&gt;
  
  
  File Formats Glue Crawler Recognizes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Formats&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Structured data&lt;/td&gt;
&lt;td&gt;CSV, TSV, JSON, Parquet, ORC, Avro&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs&lt;/td&gt;
&lt;td&gt;Apache/NGINX logs, CloudTrail JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documents&lt;/td&gt;
&lt;td&gt;— (text extraction requires Textract or Bedrock)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;CAD/EDA binary files cannot be cataloged by Glue Crawler, but file metadata (size, last modified, path) is still retrievable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Athena Cost Optimization Tips
&lt;/h3&gt;

&lt;p&gt;Athena bills on the volume of data scanned ($5/TB). Ways to keep costs down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Date partitions (&lt;code&gt;year=/month=/day=&lt;/code&gt;) reduce scan volume when a WHERE clause narrows the time range&lt;/li&gt;
&lt;li&gt;With columnar formats such as Parquet/ORC, specifying only the columns you need instead of &lt;code&gt;SELECT *&lt;/code&gt; reduces cost&lt;/li&gt;
&lt;li&gt;Make it a habit to always add a &lt;code&gt;LIMIT&lt;/code&gt; clause to exploratory queries&lt;/li&gt;
&lt;li&gt;Setting a query limit on the Athena workgroup (for example 10 GB/day) caps unexpected scan volume&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cost Awareness
&lt;/h2&gt;

&lt;p&gt;Rough additional cost if every feature in this article is enabled:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Estimate&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPC Lambda (Admin)&lt;/td&gt;
&lt;td&gt;~$5/month&lt;/td&gt;
&lt;td&gt;Depends on invocation frequency. Negligible for daily checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudTrail S3 Data Events&lt;/td&gt;
&lt;td&gt;~$10–$50/month&lt;/td&gt;
&lt;td&gt;Proportional to file access volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Athena queries&lt;/td&gt;
&lt;td&gt;$5/TB scanned&lt;/td&gt;
&lt;td&gt;Audit queries scan little; partitions reduce it further&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets Manager&lt;/td&gt;
&lt;td&gt;$0.40/secret/month&lt;/td&gt;
&lt;td&gt;One ONTAP credential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DemoMode&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;No FSx for ONTAP needed. Runs on S3 alone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cost of FSx for ONTAP itself (~$194/month at 128 MBps) was covered in Part 1. The portal's incremental cost depends on usage frequency, but evaluating in DemoMode adds nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment Time Estimates
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Prerequisite&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DemoMode deploy&lt;/td&gt;
&lt;td&gt;~15 min&lt;/td&gt;
&lt;td&gt;Amplify CLI installed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add VPC + ONTAP connectivity&lt;/td&gt;
&lt;td&gt;~30 min&lt;/td&gt;
&lt;td&gt;FSx for ONTAP file system running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit Log configuration&lt;/td&gt;
&lt;td&gt;~20 min&lt;/td&gt;
&lt;td&gt;CloudTrail + Glue Crawler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full feature deploy&lt;/td&gt;
&lt;td&gt;~60 min&lt;/td&gt;
&lt;td&gt;All of the above&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What to Expect After Deployment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Once the DemoMode deploy completes, the portal is reachable at &lt;code&gt;https://&amp;lt;branch&amp;gt;.amplifyapp.com&lt;/code&gt;. Cognito sign-up → log in → the file list shows test data from the S3 bucket&lt;/li&gt;
&lt;li&gt;Once VPC connectivity is added, the Storage Dashboard shows actual volume counts and utilization, and protected volumes appear in the ARP panel&lt;/li&gt;
&lt;li&gt;Once all features are deployed, the Audit Log tab can run CloudTrail queries and the Lock panel shows SnapLock/Object Lock settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Environment Variables and Configuration Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DEMO_MODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run without FSx for ONTAP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;true&lt;/code&gt; (PoC) / &lt;code&gt;false&lt;/code&gt; (production)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ONTAP_SECRET_ARN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Secrets Manager ARN for ONTAP credentials&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:fsxn-admin-XXXXXX&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ATHENA_AUDIT_DATABASE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Glue database name for audit queries&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cloudtrail_logs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ATHENA_AUDIT_TABLE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Athena table name for audit queries&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s3_data_events&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ATHENA_AUDIT_OUTPUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;S3 location for Athena query results&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s3://my-audit-results/athena-output/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  PoC → Production Checklist
&lt;/h3&gt;

&lt;p&gt;After evaluating in DemoMode, use this checklist when moving to production connectivity:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Verification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;VPC subnet contains the FSx for ONTAP ENIs; Security Group allows TCP 443 (management LIF). Note: NFS (2049) / SMB (445) are for data access and are not needed for the portal's admin operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Cognito User Pool MFA enabled; &lt;code&gt;storage-admin&lt;/code&gt; group members confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets&lt;/td&gt;
&lt;td&gt;ONTAP credentials registered in Secrets Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;CloudTrail Trail with S3 data events enabled for the S3 AP ARN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backup&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;portal-config.ts&lt;/code&gt; values in Git (secrets excluded)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;CloudTrail data event estimate confirmed (proportional to access volume)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSO&lt;/td&gt;
&lt;td&gt;(Optional) SAML/OIDC federation configured if using an enterprise IdP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Role-Based Documentation (8 Languages × 3 Guides)
&lt;/h2&gt;

&lt;p&gt;Alongside the feature additions, role-specific documentation was built. Based on usability principles (visibility of system status, task-oriented structure, ease of error recovery), 3 guides are provided in 8 languages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Target Role&lt;/th&gt;
&lt;th&gt;Key Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Guide&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;End users&lt;/td&gt;
&lt;td&gt;Sign in, file operations, AI processing, FAQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance Guide&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Security/Compliance officers&lt;/td&gt;
&lt;td&gt;ARP verification, WORM checks, audit trail, PHI guardrail validation, regulatory mapping (FISC/HIPAA/SOX/NIST/ISO)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quick Reference&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All roles&lt;/td&gt;
&lt;td&gt;1-page cheat sheet (navigation, tasks by role, status indicators, troubleshooting)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Supported languages: 日本語, English, 한국어, 简体中文, 繁體中文, Français, Deutsch, Español&lt;/p&gt;

&lt;p&gt;Design choices for the compliance officer guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All tasks executable without &lt;code&gt;storage-admin&lt;/code&gt; privileges (read-only access is sufficient)&lt;/li&gt;
&lt;li&gt;Each task includes "Evidence for auditors" instructions&lt;/li&gt;
&lt;li&gt;Explicit "What you cannot do" escalation table showing who to contact&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  FlexCache / SnapMirror Management
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Direct ONTAP REST API Operations from the Browser
&lt;/h3&gt;

&lt;p&gt;FlexCache, FlexClone, SnapMirror, Vscan, FPolicy, cluster and SVM peering, and the cluster services are all managed through the browser UI — 110 actions in total. A VPC-deployed Lambda connects to the FSx for ONTAP management endpoint via HTTPS, calling ONTAP REST API with credentials from Secrets Manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser → AppSync (Cognito auth) → Lambda (in VPC) → ONTAP REST API
                                                       ↓
                                                Secrets Manager
                                                (fsxadmin credentials)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9n3edt7rht9yvk3rfcgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9n3edt7rht9yvk3rfcgn.png" alt="Reaching the ONTAP REST API from the browser. The web browser authenticates with Cognito and connects to AWS AppSync; an AWS Lambda function inside the VPC reads the fsxadmin credentials from AWS Secrets Manager and calls the ONTAP REST API on Amazon FSx for NetApp ONTAP. The Lambda sits in the VPC because the ONTAP management LIF is private" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part2-ontap-rest-api-path-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  FlexCache Create UI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzmkdko18hihx8h37791x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzmkdko18hihx8h37791x.png" alt="The FlexCache create screen in the portal. The origin volume is picked from a dropdown, then cache name, size and prepopulate paths are entered before creating. Existing caches and their state are listed on the same screen" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the origin volume from a dropdown (datalist), specify cache name, size, and prepopulate paths, then create. The experience mirrors ONTAP System Manager — accessible from any browser with Cognito authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  SnapMirror Lifecycle Management
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkha0ihymyj350i0y8sj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkha0ihymyj350i0y8sj8.png" alt="The SnapMirror list screen in the portal. The relationship shows source and destination paths, its policy, a Broken-off state badge, and the action buttons that apply in that state including Resync and Delete" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The replication relationship list shows state badges (✅ Snapmirrored / 🔴 Broken-off / 🔄 Transferring / ⏸️ Paused) with context-sensitive action buttons. DR failover (Break → Resync) is fully accessible from the browser. Lag times exceeding your RPO target display in red with a ⚠️ RPO warning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FPolicy — Event Definitions and Notification Policies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FPolicy is where file access notification is configured: an event definition&lt;br&gt;
names the protocol and the operations to watch, and a policy subscribes to those&lt;br&gt;
events and points at an engine. The panel exposes all of it — create, enable,&lt;br&gt;
disable, delete — across three tabs for policies, events and connections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjkjwchhkvf3dwv7xnt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjkjwchhkvf3dwv7xnt5.png" alt="The Policies tab of the FPolicy panel. One row shows the audit_all policy as enabled with priority 1, engine external and the file_ops_cifs event set, alongside Disable and Delete actions. Delete is not clickable because the policy is enabled" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the Delete button on the enabled policy. ONTAP refuses to delete a policy&lt;br&gt;
while it is enabled, so the panel disables the control rather than letting the&lt;br&gt;
call fail. Disable first, then delete. The same ordering applies through the&lt;br&gt;
REST API, and it is the kind of constraint that is easier to encode in the UI&lt;br&gt;
than to explain in a runbook.&lt;/p&gt;
&lt;h3&gt;
  
  
  Where the Portal Is Self-Contained, and Where It Needs Something Else
&lt;/h3&gt;

&lt;p&gt;The containment actions in this portal are a port of &lt;code&gt;ontap_response.py&lt;/code&gt; from a&lt;br&gt;
separate repository, &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;fsxn-observability-integrations&lt;/a&gt;&lt;br&gt;
— the module docstring records it. The ONTAP mechanisms are identical:&lt;br&gt;
name-mapping deny, export-policy deny rule, protective snapshot, CIFS session&lt;br&gt;
disconnect. What differs is the trigger, and the layers around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-contained in the portal&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Requires&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Review ARP/AI state, attack probability and suspect files&lt;/td&gt;
&lt;td&gt;The portal reaching the ONTAP REST API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block and unblock an SMB user or an NFS client IP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;storage-admin&lt;/code&gt; group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create a protective snapshot; lock a snapshot (WORM)&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disconnect CIFS sessions&lt;/td&gt;
&lt;td&gt;An AD-joined SVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List active blocks and lift them individually&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block expiry and automatic lifting (24 hours by default)&lt;/td&gt;
&lt;td&gt;The block ledger (DynamoDB) being reachable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply the same block across several SVMs (&lt;code&gt;svms&lt;/code&gt; or &lt;code&gt;allSvms&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit file access that went through the S3 Access Point&lt;/td&gt;
&lt;td&gt;CloudTrail data events + Athena&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlexClone a snapshot to browse it; diff two generations&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every one of these &lt;strong&gt;starts when a person clicks&lt;/strong&gt;. Nothing in the portal&lt;br&gt;
contains a threat unattended — expiry is the one exception, and it only ever&lt;br&gt;
works in the direction of ending a lockout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Needs something outside the portal&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;What it takes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Contain without waiting for a human&lt;/td&gt;
&lt;td&gt;An SNS topic plus a response Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Be told about a detection instead of finding it&lt;/td&gt;
&lt;td&gt;EMS → webhook → SIEM or an observability platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cut NFS off without the client cache window&lt;/td&gt;
&lt;td&gt;A VPC NACL deny rule (network layer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Judge a recovery point before restoring from it&lt;/td&gt;
&lt;td&gt;A verification workflow (FlexClone + isolated scan)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detect anomalies against a per-user ML baseline&lt;/td&gt;
&lt;td&gt;A SIEM with anomaly detection, or a dedicated storage security product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trace file access that arrived over NFS or SMB directly&lt;/td&gt;
&lt;td&gt;An ONTAP audit log / FPolicy delivery pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The audit boundary is the one most likely to be misread. The portal's audit trail&lt;br&gt;
reads CloudTrail S3 data events for the S3 Access Point. Access that arrived over&lt;br&gt;
NFS or SMB does not appear there at all — that needs ONTAP's own audit log or&lt;br&gt;
FPolicy events. The two are complementary, not substitutes.&lt;/p&gt;

&lt;p&gt;The delivery pipeline is still yours to build, but there is now somewhere for it&lt;br&gt;
to deliver to. Once FPolicy (or Transfer Family) publishes to EventBridge, a&lt;br&gt;
bridge Lambda writes what arrives into a notification table and a &lt;strong&gt;Folder&lt;br&gt;
Watch&lt;/strong&gt; section shows the events under the prefixes you are watching. It is&lt;br&gt;
enabled by an admin toggle and off by default: until an admin states that a&lt;br&gt;
publisher exists, turning it on would only ever show an inbox that cannot fill.&lt;br&gt;
Filtering applies the Cognito group path boundary first and each user’s own&lt;br&gt;
watches second. A watch is your own record, so you may register &lt;code&gt;/&lt;/code&gt;, but that&lt;br&gt;
cannot reveal anything outside the group boundary.&lt;/p&gt;

&lt;p&gt;So the portal is the &lt;strong&gt;hands&lt;/strong&gt; of incident response: it puts the ONTAP&lt;br&gt;
containment actions in a browser, behind Cognito groups, with confirmation and an&lt;br&gt;
audit trail. If you need something watching around the clock and moving those&lt;br&gt;
hands for you, detection and response belong in a pipeline. Conversely, if you&lt;br&gt;
already detect in a SIEM and only lack a way to stop it at the storage layer, an&lt;br&gt;
SNS-triggered response Lambda fits that shape better than a portal button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One click was too few&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Writing this section is what exposed the gap worth fixing. A block removes a&lt;br&gt;
principal's data access across the whole SVM. The first version executed on a&lt;br&gt;
single click, with no confirmation and no &lt;code&gt;confirm&lt;/code&gt; parameter in the payload —&lt;br&gt;
the only guards were the Cognito group and a protected-accounts list. At the time&lt;br&gt;
there was also no expiry, so a block stayed until a person lifted it.&lt;/p&gt;

&lt;p&gt;There are now two gates. The UI asks, with wording specific to the action,&lt;br&gt;
because the consequences differ: an NFS block is subject to client-side attribute&lt;br&gt;
caching for up to 60 seconds, an SMB block is not, and disconnecting sessions on&lt;br&gt;
its own does not stop the next login. The Lambda then refuses any call that&lt;br&gt;
arrives without &lt;code&gt;confirm: true&lt;/code&gt;, in front of the ONTAP client construction — a&lt;br&gt;
dialog in a browser is a suggestion, and anything calling AppSync directly skips&lt;br&gt;
it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa5fk4v9e8gk1vlcrmlit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa5fk4v9e8gk1vlcrmlit.png" alt="The containment form in the portal with domain, username, client IP and reason filled in. Below the four action buttons, a confirmation row explains that the action creates a snapshot, blocks the targets and disconnects their SMB sessions across the whole SVM, with Run and Cancel buttons" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Session disconnect became its own action in the same pass. It existed in the&lt;br&gt;
handler but only ever ran as step 4 of full containment, so an operator who had&lt;br&gt;
already blocked a user had no way to cut the sessions that survived the block.&lt;br&gt;
Order matters: block first, then disconnect. Disconnecting before the block is in&lt;br&gt;
place just invites a successful reconnect.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Async Operations with &lt;code&gt;return_timeout=0&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;FlexCache creation is an asynchronous ONTAP job taking 30-120 seconds. By specifying &lt;code&gt;return_timeout=0&lt;/code&gt;, ONTAP returns immediately with 202 Accepted + job UUID, preventing Lambda timeout. The UI auto-refreshes the list at 10s/30s/60s intervals.&lt;/p&gt;
&lt;h4&gt;
  
  
  One Wrong Field Name Empties the Whole List
&lt;/h4&gt;

&lt;p&gt;The SnapMirror list was requesting &lt;code&gt;fields=...,last_transfer_type,last_transfer_size&lt;/code&gt;. &lt;code&gt;last_transfer_size&lt;/code&gt; is not a field on &lt;code&gt;/snapmirror/relationships&lt;/code&gt;, and ONTAP rejects the &lt;em&gt;entire&lt;/em&gt; request when a single field name is unknown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The value "last_transfer_size" is invalid for field "fields" (&amp;lt;field,...&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So every relationship vanished — not with a visible error, but as an empty list. What made this survive the test suite is worth noting: the mock ONTAP in the unit tests returns records regardless of which &lt;code&gt;fields&lt;/code&gt; are requested, so a test that asserts on the mapped response passes either way. The fix was to assert on the outgoing query string instead. Per-transfer byte counts were already available from &lt;code&gt;/snapmirror/relationships/{uuid}/transfers&lt;/code&gt;, so nothing was lost by dropping the field.&lt;/p&gt;

&lt;h4&gt;
  
  
  Automated 3-Step FlexCache Deletion
&lt;/h4&gt;

&lt;p&gt;Mounted FlexCache volumes cannot be deleted directly. The portal automates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove junction path (unmount)&lt;/li&gt;
&lt;li&gt;Set volume offline&lt;/li&gt;
&lt;li&gt;Delete FlexCache (async)&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Credential Synchronization
&lt;/h4&gt;

&lt;p&gt;When changing the &lt;code&gt;fsxadmin&lt;/code&gt; password, update &lt;strong&gt;both&lt;/strong&gt; the FSx for ONTAP API and Secrets Manager simultaneously. Updating only one side causes authentication failures that can trigger ONTAP's account lockout mechanism. Recovery: &lt;code&gt;aws fsx update-file-system&lt;/code&gt; password reset → Secrets Manager sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  FSx for ONTAP Specifics
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;FSx for ONTAP&lt;/th&gt;
&lt;th&gt;On-prem ONTAP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate specification&lt;/td&gt;
&lt;td&gt;Not needed (auto-selected)&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SVM creation&lt;/td&gt;
&lt;td&gt;AWS API only&lt;/td&gt;
&lt;td&gt;CLI/REST available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intra-cluster FlexCache&lt;/td&gt;
&lt;td&gt;Supported (no peering needed)&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fsxadmin password reset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws fsx update-file-system&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;security login password&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Coexistence with Existing Tools
&lt;/h3&gt;

&lt;p&gt;This portal is not a replacement for the ONTAP CLI or REST API. It makes a subset of those operations accessible from a browser UI with Cognito authentication — an additional management layer, not a substitute.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Portal's Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Using cloud file-sharing SaaS&lt;/td&gt;
&lt;td&gt;AI processing and audit for large-scale NAS data only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Running self-hosted file sharing&lt;/td&gt;
&lt;td&gt;Add S3 AP as External Storage for management operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Using hybrid file services&lt;/td&gt;
&lt;td&gt;Add data protection and ARP/AI visibility layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating daily through the ONTAP CLI / REST API&lt;/td&gt;
&lt;td&gt;Provide visibility to non-storage-admin team members&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The portal provides a management layer for NAS-specific capabilities (Snapshot, FlexClone, FlexCache, SnapMirror, ARP/AI) accessible from the browser. Adoption can be incremental — management operations only, AI processing only, or the full suite — depending on existing workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  PoC → Production Migration Flow
&lt;/h3&gt;

&lt;p&gt;After evaluating in DemoMode (no FSx for ONTAP required), migrate to production connectivity in three phases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────┐     ┌────────────────┐     ┌────────────────┐
│ Phase 1: PoC   │     │ Phase 2: VPC   │     │ Phase 3: Prod  │
│ (~15 min)      │     │   Connectivity │     │   Hardening    │
│                │     │ (~30 min)      │     │ (~60 min)      │
│ DemoMode=true  │ ──→ │ ONTAP mgmt LIF │ ──→ │ Least-privilege│
│ S3 bucket      │     │ Secrets Mgr    │     │ MFA required   │
│ Auth: Cognito  │     │ VPC Endpoint   │     │ WAF added      │
│                │     │                │     │ Audit enabled  │
└────────────────┘     └────────────────┘     └────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ci2y0n59jy5pir4k0xb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ci2y0n59jy5pir4k0xb.png" alt="Three phases from PoC to production connectivity. Phase 1 runs with DemoMode=true against an S3 bucket only; Phase 2 adds the ONTAP management LIF connection, AWS Secrets Manager, and VPC endpoints; Phase 3 applies least-privilege IAM, required MFA, AWS WAF, and audit logging" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/part2-poc-to-production-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Added Cost&lt;/th&gt;
&lt;th&gt;What You Get&lt;/th&gt;
&lt;th&gt;What Changes&lt;/th&gt;
&lt;th&gt;What Stays the Same&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (PoC)&lt;/td&gt;
&lt;td&gt;~15 min&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;UI/UX evaluation, AI processing test&lt;/td&gt;
&lt;td&gt;Nothing (fresh deploy)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 (VPC)&lt;/td&gt;
&lt;td&gt;~30 min&lt;/td&gt;
&lt;td&gt;Lambda VPC ~$5/mo&lt;/td&gt;
&lt;td&gt;ONTAP admin operations, dashboard&lt;/td&gt;
&lt;td&gt;Lambda VPC config added, Secrets Manager registered&lt;/td&gt;
&lt;td&gt;Frontend UI, Cognito settings, S3 bucket config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 (Prod)&lt;/td&gt;
&lt;td&gt;~60 min&lt;/td&gt;
&lt;td&gt;CloudTrail ~$10–50/mo&lt;/td&gt;
&lt;td&gt;Audit, WAF, MFA, least-privilege IAM&lt;/td&gt;
&lt;td&gt;IAM policy tightening, WAF attachment, MFA enforcement&lt;/td&gt;
&lt;td&gt;Application code, ONTAP connection settings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Post-Deployment Verification
&lt;/h3&gt;

&lt;p&gt;Expected state after each phase completes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;After Phase 1&lt;/strong&gt;: you can log in to the portal, and DemoMode file listing and AI processing tests work. The Storage Dashboard still shows "not connected"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After Phase 2&lt;/strong&gt;: the Storage Dashboard shows actual volume information, and ONTAP data appears in the ARP panel and EMS Events&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After Phase 3&lt;/strong&gt;: login is impossible without MFA, CloudTrail records all operations, and WAF applies rate limiting&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Irreversible operations warning&lt;/strong&gt;: The following operations cannot be undone once executed. Verify your organization's policies before enabling them in Phase 2+:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SnapLock Compliance enablement&lt;/strong&gt;: Volume SnapLock type cannot be changed after creation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tamperproof Snapshot retention period&lt;/strong&gt;: Once set, the period cannot be shortened (only extended)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 Object Lock Compliance mode&lt;/strong&gt;: No one, including root, can delete objects until retention expires&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;For detailed migration steps, see the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorization Model (PoC → Production)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;PoC&lt;/th&gt;
&lt;th&gt;Production&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AppSync auth&lt;/td&gt;
&lt;td&gt;&lt;code&gt;allow.authenticated()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;allow.groups(["storage-admin"])&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IAM resource scope&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"*"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specific ARN patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;generateClient&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;authMode: "userPool"&lt;/code&gt; required&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In Amplify Gen2 with multiple auth providers, &lt;code&gt;generateClient()&lt;/code&gt; must explicitly specify &lt;code&gt;authMode: "userPool"&lt;/code&gt; to ensure the Cognito token is sent to AppSync. This is a recommended pattern per official documentation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/solutions/amplify-portal" rel="noopener noreferrer"&gt;GitHub: solutions/amplify-portal/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-user-guide.md" rel="noopener noreferrer"&gt;User Guide (8 languages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-compliance-guide.md" rel="noopener noreferrer"&gt;Compliance Guide (8 languages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-quick-reference.md" rel="noopener noreferrer"&gt;Quick Reference (8 languages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/IMPLEMENTATION.md" rel="noopener noreferrer"&gt;Implementation Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/GETTING-STARTED.md" rel="noopener noreferrer"&gt;Getting Started Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/admin-resource-management-demo.md" rel="noopener noreferrer"&gt;Admin Demo Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/ai-agent-demo-guide.en.md" rel="noopener noreferrer"&gt;AI Agent Demo Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/solutions/amplify-portal/docs/SECURITY-REVIEW.md" rel="noopener noreferrer"&gt;Security Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-scaling-guide.md" rel="noopener noreferrer"&gt;Scaling Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-accessibility.md" rel="noopener noreferrer"&gt;Accessibility Statement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/anti-ransomware-vol.html" rel="noopener noreferrer"&gt;AWS: ONTAP ARP/AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html" rel="noopener noreferrer"&gt;AWS: S3 Object Lock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-1-browser-access" rel="noopener noreferrer"&gt;Part 1: Adding a File Portal to FSx for ONTAP S3 AP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-3-ai-agent-mcp" rel="noopener noreferrer"&gt;Part 3: Embedding AI Agents into a File Portal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary and Next Steps
&lt;/h2&gt;

&lt;p&gt;Building on the file portal from Part 1, ONTAP management operations and data protection features were embedded:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What it enables&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Storage Dashboard&lt;/td&gt;
&lt;td&gt;Health at a glance immediately after login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident Lifecycle&lt;/td&gt;
&lt;td&gt;Ransomware response with state management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHI Guardrail&lt;/td&gt;
&lt;td&gt;Structurally prevents AI processing of regulated data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 Object Lock&lt;/td&gt;
&lt;td&gt;Tamper prevention for AI results, configurable from UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EMS Events&lt;/td&gt;
&lt;td&gt;ONTAP alerts without CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retention Presets&lt;/td&gt;
&lt;td&gt;Just pick the regulation, get the right retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit Log&lt;/td&gt;
&lt;td&gt;"Who accessed what and when" — self-service for compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlexClone Restore&lt;/td&gt;
&lt;td&gt;Recover from snapshot in seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlexCache CRUD&lt;/td&gt;
&lt;td&gt;Create/delete read cache volumes from browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SnapMirror Lifecycle&lt;/td&gt;
&lt;td&gt;Sync, break, resync, quiesce — DR from a browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Athena Query&lt;/td&gt;
&lt;td&gt;Ask SQL questions against NAS data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Welcome Modal&lt;/td&gt;
&lt;td&gt;First-time users productive in 10 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From a portal that "just browses files" to one that "completes storage operations from the web." Daily monitoring and incident first response now finish in the browser without opening an ONTAP CLI session.&lt;/p&gt;

&lt;p&gt;All code is available in the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/solutions/amplify-portal" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a next step, after running DemoMode using the instructions in Part 1, try adding the VPC configuration to enable ONTAP connectivity. That gets you to a state where every feature in this article is usable. Migration details are collected in the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Part 3, I'll write about embedding AI agents into this portal — completing file operations, analysis, and admin operations in natural language.&lt;/p&gt;

&lt;p&gt;I hope this post helps someone out there.&lt;/p&gt;

&lt;p&gt;See you next time.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>netapp</category>
      <category>security</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Adding a File Portal to FSx for ONTAP S3 Access Points — Choosing Between Amplify Gen2 and Nextcloud (Part 1)</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Mon, 03 Aug 2026 10:16:29 +0000</pubDate>
      <link>https://dev.to/aws-builders/adding-a-file-portal-to-fsx-for-ontap-s3-access-points-choosing-between-amplify-gen2-and-887</link>
      <guid>https://dev.to/aws-builders/adding-a-file-portal-to-fsx-for-ontap-s3-access-points-choosing-between-amplify-gen2-and-887</guid>
      <description>&lt;p&gt;&lt;strong&gt;Reach the NAS from a browser and from AI, without stopping existing mounts&lt;/strong&gt; — choosing between Amplify Gen2 and Nextcloud (part 1 of 3)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Japanese version of this article is available: &lt;a href="https://hakobiya.hatenablog.com/entry/fsxn-file-portal-1-browser-access" rel="noopener noreferrer"&gt;日本語版&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I've been asked more than a few times how to open files sitting on a NAS in a browser and run AI over them. The data lives on NFS/SMB volumes and runs to hundreds of terabytes — between the sheer volume, the latency, and data-residency rules, copying it out to an external service isn't realistic. Requiring an NFS mount instead puts the data out of reach for anyone who isn't an engineer. Closing that gap felt worth doing, so I built a verification environment for it.&lt;/p&gt;

&lt;p&gt;What I used is Amazon FSx for NetApp ONTAP S3 Access Points (hereafter FSx for ONTAP S3 AP, or S3 AP — an access point that exposes NAS volumes for read/write through the S3 API). Because it reaches the data in place, you can add a browser UI and AI processing while leaving existing NFS/SMB workflows exactly as they are. I implemented the portal with two approaches: Amplify Gen2 as an AI-processing dashboard, and Nextcloud as a file-sharing UI.&lt;/p&gt;

&lt;p&gt;Here's the conclusion up front:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 AP gives you browser access to NAS volumes with no data migration&lt;/li&gt;
&lt;li&gt;Amplify Gen2 and Nextcloud aren't mutually exclusive — both can attach to the same volume at the same time&lt;/li&gt;
&lt;li&gt;The deciding axis: Nextcloud when file sharing is the center of gravity, Amplify Gen2 when AI processing and ONTAP admin operations are&lt;/li&gt;
&lt;li&gt;With DemoMode you can bring the portal up in under 30 minutes without FSx for ONTAP, and try file browsing and AI processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, I'll walk through the design of the two approaches and how to choose between them, the DemoMode startup steps, and the places where I got stuck during implementation.&lt;/p&gt;

&lt;p&gt;Here's the overall picture first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0168qcel1pv3om6m1s2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0168qcel1pv3om6m1s2.png" alt="File portal architecture built on FSx for ONTAP S3 Access Points. Users reach two frontends from a web browser — Amplify Gen2 as an AI processing dashboard and Nextcloud as a file sharing UI — and both read and write the same FSx for ONTAP volume through one S3 Access Point. Existing NFS and SMB clients access the same volume concurrently" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/architecture-overview-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available, and every figure is listed in the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/architecture-diagrams.en.md" rel="noopener noreferrer"&gt;architecture diagram index&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: Overall architecture — two frontends reaching the same volume through one S3 Access Point&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The part worth noticing is that neither frontend moves any data. The S3 Access Point reads the existing NFS/SMB volume in place, so the same files stay available to existing clients at the same time.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Role it plays&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amplify Gen2&lt;/td&gt;
&lt;td&gt;AI processing dashboard (file selection → AI trigger → result display)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nextcloud&lt;/td&gt;
&lt;td&gt;File sharing UI (browsing, sync, sharing links)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pick based on what you want to do. Both can connect to the same volume simultaneously, so you can start incrementally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;License&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/LICENSE" rel="noopener noreferrer"&gt;MIT License&lt;/a&gt;. Commercial use, modification, and redistribution permitted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns" rel="noopener noreferrer"&gt;Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites and Positioning
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Audience&lt;/strong&gt;: Anyone with unstructured data on NAS who wants to protect and leverage that data. On-premises NAS, cloud NAS (FSx for ONTAP, EFS, Azure NetApp Files, etc.) — the platform doesn't matter.&lt;/p&gt;

&lt;p&gt;File data on NAS shares several common challenges:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Challenge&lt;/th&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data grows but stays underutilized&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Files accumulate year over year — ownership unclear, labels missing, search difficult (&lt;a href="https://cloudsecurityalliance.org/articles/unstructured-data-surges-as-enterprises-struggle-to-maintain-visibility-and-security-cloud-security-alliance-study-finds" rel="noopener noreferrer"&gt;CSA study&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ransomware target&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shared drives are primary targets for encryption attacks. Without detection/stop mechanisms, damage spreads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Want AI but can't move data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data volume, latency requirements, and data residency regulations make copying to external services impractical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Limited remote access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VPN + mount is required — browser-based access needs additional infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audit &amp;amp; compliance overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Access logs exist but answering "who accessed what when" in a UI requires a separate analytics layer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This project implements approaches to these challenges using &lt;strong&gt;FSx for ONTAP S3 Access Points&lt;/strong&gt;. FSx for ONTAP was chosen because it combines NFS/SMB/S3 multi-protocol access with integrated data protection: Snapshots, SnapLock (WORM), FlexClone, and ARP/AI (autonomous ransomware detection).&lt;/p&gt;

&lt;p&gt;How you use the portal depends on your environment:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your Environment&lt;/th&gt;
&lt;th&gt;How to Use This Portal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Considering migration from on-prem NAS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Build FSx for ONTAP + S3 AP for browser access, AI processing, and data protection in one step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Already using FSx for ONTAP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enable S3 AP on existing volumes — all portal features become available immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NAS + SaaS side by side&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keep SaaS as-is. Add AI processing, audit, and protection for NAS data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Using another cloud NAS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Connect via SnapMirror or DataSync to FSx for ONTAP, then add capabilities incrementally&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What this portal provides&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser access to NAS files (no VPN)&lt;/li&gt;
&lt;li&gt;AI analysis, classification, semantic search (Bedrock integration)&lt;/li&gt;
&lt;li&gt;ONTAP-specific data protection (Snapshot, SnapLock, FlexClone, ARP/AI)&lt;/li&gt;
&lt;li&gt;Audit trail visibility (CloudTrail + Athena)&lt;/li&gt;
&lt;li&gt;Sharing links (Presigned URLs), QR code access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How it differs from SaaS file sharing&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No real-time co-authoring (like Google Docs simultaneous editing)&lt;/li&gt;
&lt;li&gt;No desktop sync client (NFS/SMB mount serves this purpose)&lt;/li&gt;
&lt;li&gt;No native mobile app (responsive web UI as alternative)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Authentication is independent via Cognito (SAML/OIDC federation supported). No impact on existing SaaS contracts or licenses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Current Setup&lt;/th&gt;
&lt;th&gt;What this portal adds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Box for contracts&lt;/td&gt;
&lt;td&gt;Tamperproof Snapshot on NAS originals (FISC 7-year retention)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SharePoint for design docs &amp;amp; reports&lt;/td&gt;
&lt;td&gt;AI anomaly detection and classification on NAS files (one-click trigger)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Drive for team files&lt;/td&gt;
&lt;td&gt;"Who accessed what when" audit trail (CloudTrail + Athena)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dropbox for project file sync&lt;/td&gt;
&lt;td&gt;Ransomware detection + automated containment (ARP/AI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFS/SMB direct access only&lt;/td&gt;
&lt;td&gt;Browser-based file access for non-technical users + AI analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Industry-specific examples&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Financial services&lt;/strong&gt;: "Hundreds of TB of trading logs and risk calculation results on NFS. Daily documents in SharePoint, but we need anomaly detection on logs and 7-year audit trail retention"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manufacturing&lt;/strong&gt;: "500TB of CAD files on NFS, daily document sharing via SharePoint. Add only AI quality inspection on CAD files through the portal"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Healthcare&lt;/strong&gt;: "DICOM images stored on NAS, clinical data in a dedicated system. Need AI diagnostic support access to images with HIPAA-compliant retention management"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media &amp;amp; entertainment&lt;/strong&gt;: "Multiple PB of video assets (ProRes/MXF). Daily editing via NFS mount from Avid/Premiere, but need AI auto-tagging of content management metadata"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal&lt;/strong&gt;: "Tens of thousands of contract PDFs accumulated on NAS. Need AI-powered content search, automated classification, and deadline visibility"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Research&lt;/strong&gt;: "Hundreds of TB of genomics analysis and simulation results. Researchers want to search and preview results from a browser without using CLI"&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Adding Web Experiences to NFS/SMB File Servers
&lt;/h2&gt;

&lt;p&gt;NFS/SMB file servers have clear strengths: high throughput, low latency, multi-protocol support, and deep integration with workstation tools. These qualities make them the backbone of many organizations' workflows. Meanwhile, some of the web-based experiences that SaaS file sharing provides — browser access, AI integration, searchable audit trails — require additional tooling when working with file servers.&lt;/p&gt;

&lt;p&gt;This portal adds those web experiences to existing file server environments without changing anything about how the servers operate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Experience Added&lt;/th&gt;
&lt;th&gt;Traditional Approach&lt;/th&gt;
&lt;th&gt;How This Portal Delivers It&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Browser access&lt;/strong&gt; (no VPN)&lt;/td&gt;
&lt;td&gt;VPN + mount configuration&lt;/td&gt;
&lt;td&gt;S3 AP + Cognito auth (Internet-origin)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Natural language file search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;grep or find on file names/paths&lt;/td&gt;
&lt;td&gt;Bedrock Knowledge Base semantic search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Sharing links&lt;/strong&gt; (expiring, password-protected)&lt;/td&gt;
&lt;td&gt;Manual smbclient or email attachment&lt;/td&gt;
&lt;td&gt;Presigned URL time-limited links + QR codes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Version history visibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Snapshots exist but require CLI/API&lt;/td&gt;
&lt;td&gt;Snapshot list in UI + FlexClone one-click restore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audit trail in a UI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parse auditd or FPolicy logs&lt;/td&gt;
&lt;td&gt;CloudTrail + Athena self-service query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI analysis &amp;amp; classification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires building a separate pipeline&lt;/td&gt;
&lt;td&gt;Bedrock + Step Functions one-click trigger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ransomware visibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ONTAP ARP runs but checking needs the ONTAP CLI / REST API&lt;/td&gt;
&lt;td&gt;ARP/AI dashboard in browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mobile / tablet access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires dedicated apps or VPN&lt;/td&gt;
&lt;td&gt;Responsive web UI + QR code access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance reporting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run SnapLock CLI commands and compile manually&lt;/td&gt;
&lt;td&gt;Lock panel with FISC/SOX/HIPAA presets + status overview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;No data movement required.&lt;/strong&gt; S3 AP reads and writes data directly on the NAS volume. Edit via NFS/SMB → browse via S3 AP in browser → AI results written back to the same volume. All the same data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Existing NFS/SMB workflows are &lt;strong&gt;unaffected&lt;/strong&gt;. NFS mounts from CAD tools, SMB access from Avid, cron job file processing — all continue working exactly as before. S3 AP is an additional access path to the same volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Authentication is independent from existing SaaS (Cognito or LDAP/SAML). No impact on existing SaaS contracts or licenses.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How to Choose
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Selection Flow (Q1-Q3)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Q1. Do users need to operate files from a browser?
  → No: EventBridge Scheduler (scheduled batch) is sufficient
  → Yes: Go to Q2

Q2. Primary need: "file sharing &amp;amp; sync"? Or "AI/ML processing launch &amp;amp; result viewing"?
  → File sharing focused: Nextcloud (or Storage Browser for S3)
  → AI processing focused: Amplify Gen2 portal
  → Both: Use together (covered in this article)

Q3. Are users technical? Or non-engineers?
  → Technical: Any of the GUI portals above
  → Non-engineers: Add Amazon Quick (MCP, natural language operation)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you want to do&lt;/th&gt;
&lt;th&gt;Suited approach&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trigger AI/ML processing from UI, see results in real time&lt;/td&gt;
&lt;td&gt;Amplify Gen2&lt;/td&gt;
&lt;td&gt;Custom code required, React knowledge assumed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browse, upload, sync, and share files via web&lt;/td&gt;
&lt;td&gt;Nextcloud&lt;/td&gt;
&lt;td&gt;AI integration needs Webhook development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero-custom-code file operation UI&lt;/td&gt;
&lt;td&gt;Storage Browser for S3&lt;/td&gt;
&lt;td&gt;Limited features (browse/DL/UL only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Natural language file search &amp;amp; analysis&lt;/td&gt;
&lt;td&gt;Amazon Quick + AgentCore MCP&lt;/td&gt;
&lt;td&gt;Preview stage, region availability limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No frontend needed, batch is fine&lt;/td&gt;
&lt;td&gt;EventBridge Scheduler&lt;/td&gt;
&lt;td&gt;No interactive operation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How to choose&lt;/strong&gt;: Amplify Gen2, Nextcloud, Storage Browser for S3, and Amazon Quick each suit a different context. The trade-offs above are listed symmetrically, including the constraints of the option I reached for, and the article records what actually worked on technical grounds. Read it as material for choosing against your own requirements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Cost Estimates
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;th&gt;Includes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amplify Gen2 portal&lt;/td&gt;
&lt;td&gt;~$18-46&lt;/td&gt;
&lt;td&gt;Cognito/AppSync/Lambda (within Free Tier) + AI pay-per-use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nextcloud (EC2)&lt;/td&gt;
&lt;td&gt;~$70-110&lt;/td&gt;
&lt;td&gt;EC2 + RDS + ALB. Local Docker = $0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage Browser for S3&lt;/td&gt;
&lt;td&gt;~$5&lt;/td&gt;
&lt;td&gt;Amplify Hosting only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick + AgentCore MCP&lt;/td&gt;
&lt;td&gt;~$5-15&lt;/td&gt;
&lt;td&gt;Lambda execution only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventBridge direct&lt;/td&gt;
&lt;td&gt;~$1-5&lt;/td&gt;
&lt;td&gt;Lambda + Step Functions execution only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: FSx for ONTAP infrastructure (~$194/month, 128 MBps configuration) is common across all approaches. The portal itself adds only tens of dollars per month. At 100 users, Cognito/AppSync/Lambda costs remain within pay-per-use bounds (serverless). At 1000 users, FSx for ONTAP throughput scaling (128→256 MBps, +~$194/month) is the primary scaling cost.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Approach 1: Amplify Gen2 — AI Processing Dashboard
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Amplify Gen2 (Key Points for NAS Users)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.amplify.aws/" rel="noopener noreferrer"&gt;AWS Amplify Gen2&lt;/a&gt; is a full-stack development framework that lets you define both frontend (UI) and backend (auth, API, database, storage) in TypeScript and deploy to AWS.&lt;/p&gt;

&lt;p&gt;What this means for NAS/file server users:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;What Amplify Gen2 Handles&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No infrastructure management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No servers to provision, patch, or scale. Everything runs serverless (Lambda, AppSync, Cognito)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in authentication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cognito provides email login, MFA, and enterprise SSO (SAML/OIDC) out of the box. No custom auth system to build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Direct AWS service integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Connect to S3 Access Points, Bedrock (AI), Step Functions (workflows), Athena (analytics) with minimal code. No need to design IAM from scratch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Git-based deployment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git push&lt;/code&gt; triggers automatic build and deploy. No separate CI/CD pipeline required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Per-developer sandboxes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Isolated environments auto-created per developer. Team members work in parallel without conflicts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDK extensibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When standard features aren't enough, add any AWS resource (VPC Lambda, DynamoDB, etc.) via AWS CDK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In short: when you want "browser UI + AI processing + authentication on NAS data," Amplify Gen2 delivers this without building or maintaining web servers. You write UI in React; AWS managed services handle the backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────────────────────────┐
│  Amplify Gen2                                     │
│  ┌──────────┐  ┌───────────────────────────────┐  │
│  │ Cognito  │  │ AppSync (Generic Dispatch)    │  │
│  │ + MFA    │  │  fileQuery → ListFiles λ      │  │
│  │ + Groups │  │  adminQuery → ResourceMgmt λ  │  │
│  └──────────┘  │  arpQuery → ArpResponse λ     │  │
│                │  protectionQuery → Snapshot λ │  │
│                └──────────────┬────────────────┘  │
└───────────────────────────────┼───────────────────┘
                                │
          ┌─────────────────────┼────────────────────┐
          │                     │                    │
          ▼                     ▼                    ▼
┌──────────────────┐  ┌─────────────────┐  ┌────────────────┐
│ S3 Access Point  │  │ ONTAP REST API  │  │ Step Functions │
│ (Internet-origin)│  │ (inside VPC)    │  │ (AI/ML jobs)   │
└──────────────────┘  └─────────────────┘  └────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fug4u6ypi1jo4mdaq8wb6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fug4u6ypi1jo4mdaq8wb6.png" alt="Amplify Gen2 AI processing portal architecture. A web browser and Amazon Quick reach AWS Amplify, Amazon Cognito, and the Amazon Bedrock AgentCore; AppSync GraphQL API invokes Lambda functions running outside the VPC on ARM64. Those functions call Bedrock, Rekognition, Athena, Textract, and Comprehend, and read and write the FSx for ONTAP volume through the S3 Access Point. Audit logs are written to S3 Object Lock as WORM" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/amplify-vpc-split-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: Amplify Gen2 architecture — Lambda outside the VPC reads and writes the volume through the S3 Access Point&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Keeping Lambda outside the VPC and letting it call the S3 Access Point directly is the crux of this design. Here's why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Design Decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;VPC split architecture&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Non-VPC Lambda&lt;/strong&gt;: Reads/writes files via S3 AP (Internet-origin). Fast cold starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC Lambda&lt;/strong&gt;: Calls ONTAP REST API (management LIF). Must be inside VPC.&lt;/li&gt;
&lt;li&gt;Never combine both in one Lambda (Internet-origin S3 AP unreachable via S3 Gateway VPC Endpoint).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Network note&lt;/strong&gt;: VPC Lambda handles admin operations only. Required VPC Endpoints: Secrets Manager and CloudWatch Logs. S3 AP data access uses non-VPC Lambda, so NAT Gateway is not needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Generic Dispatch pattern&lt;/strong&gt;: 155 operations consolidated into 10 generic endpoints (&lt;code&gt;action&lt;/code&gt; + &lt;code&gt;params: AWSJSON&lt;/code&gt;) to avoid CloudFormation 1MB limit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extensibility note&lt;/strong&gt;: To add new operations, simply add an &lt;code&gt;action&lt;/code&gt; entry to the Lambda handler's dispatch map. No AppSync schema or CloudFormation changes needed. See the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/infrastructure/pstk-automation/docs/pstk-action-catalog.md" rel="noopener noreferrer"&gt;PSTK Action Catalog&lt;/a&gt; for the full action list.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  UI Layout (Sidebar)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────┬─────────────────────────────────────┐
│ Browse        │                                     │
│  📂 All Files │  [Main Content Area]                │
│  ⭐ Favorites │                                     │
│  🕐 Recent    │                                     │
│  🔔 Watch     │                                     │
│  📤 Upload    │                                     │
│               │                                     │
│ AI &amp;amp; Proc.    │                                     │
│  ⚡ AI Proc.  │                                     │
│  🤖 AI Chat   │                                     │
│  🔍 Search    │                                     │
│  📋 History   │                                     │
│  📊 Analytics │                                     │
│  🗂️ Agent Dir │                                     │
│               │                                     │
│ Data Prot.    │  + Right Panel: AI Assistant        │
│  📸 Snapshots │  (appears on file selection)        │
│  🔒 Lock      │                                     │
│  🛡️ ARP/AI    │                                     │
│               │                                     │
│ Admin         │                                     │
│  🔧 Resources │                                     │
│  🔄 Version   │                                     │
│  🔍 Audit     │                                     │
└───────────────┴─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4 groups × 17 sections. Same sidebar pattern as Google Drive and Box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;File selection → AI processing trigger → real-time result display (5s polling)&lt;/li&gt;
&lt;li&gt;Bedrock Q&amp;amp;A, Rekognition image analysis, Athena SQL, Textract OCR&lt;/li&gt;
&lt;li&gt;FlexClone snapshot restore (one-click from UI)&lt;/li&gt;
&lt;li&gt;Job execution history (DynamoDB, per-user tracking)&lt;/li&gt;
&lt;li&gt;8-language i18n (JA/EN/KO/ZH-CN/ZH-TW/FR/DE/ES)&lt;/li&gt;
&lt;li&gt;Keyboard navigation + ARIA labels + Dark/Light mode&lt;/li&gt;
&lt;li&gt;Responsive (hamburger menu at 768px, tablet-ready)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Audit note&lt;/strong&gt;: All operations are recorded in CloudTrail. Audit log retention is controlled via CloudTrail settings (default 90 days, extendable to 7 years for compliance). Self-service Athena queries available from the portal's Audit section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: Blast radius if a Cognito token is compromised — tokens are scoped by Cognito Groups via AppSync resolver authorization; access is limited to resources within the user's group. Default token expiry: 1 hour. MFA-required setting mitigates leakage risk.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Gotchas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AppSync APPSYNC_JS runtime: &lt;code&gt;new Date()&lt;/code&gt; not available → use &lt;code&gt;util.time.nowISO8601()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Data Source must be in the same CDK stack as AppSync API ("Data source not found" otherwise)&lt;/li&gt;
&lt;li&gt;Bedrock Nova Lite: requires &lt;code&gt;converse()&lt;/code&gt; API (&lt;code&gt;invoke_model&lt;/code&gt; + &lt;code&gt;inputText&lt;/code&gt; is Titan-only)&lt;/li&gt;
&lt;li&gt;Presigned URLs: need explicit SigV4 + regional endpoint&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Approach 2: Nextcloud — File Sharing UI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Nextcloud (Key Points for NAS Users)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://nextcloud.com/" rel="noopener noreferrer"&gt;Nextcloud&lt;/a&gt; is a self-hosted, open-source file sharing and collaboration platform. It provides Google Drive/Dropbox-like user experience on infrastructure you control.&lt;/p&gt;

&lt;p&gt;What this means for NAS/file server users:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;What Nextcloud Handles&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data sovereignty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File data stays on your servers. No need to entrust data to external SaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Direct NAS connection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;External Storage feature mounts S3 AP / NFS / SMB / WebDAV as additional folders. No data copy needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Familiar experience&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Desktop sync client (Windows/Mac/Linux), mobile apps, sharing links — SaaS-equivalent UX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No per-user licensing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGPL-3.0, free to use. No per-seat pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports LDAP, SAML, OIDC. Connects to existing Active Directory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When you configure FSx for ONTAP's S3 AP as Nextcloud's External Storage backend, ONTAP volume files appear in Nextcloud's folder listing. Files saved via NFS/SMB are immediately visible in the browser and syncable to desktop clients.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Nextcloud's External Storage App mounts S3 AP as S3-compatible storage&lt;/span&gt;
Nextcloud &lt;span class="o"&gt;(&lt;/span&gt;Docker&lt;span class="o"&gt;)&lt;/span&gt; → External Storage App &lt;span class="o"&gt;(&lt;/span&gt;S3 backend&lt;span class="o"&gt;)&lt;/span&gt; → S3 AP → FSx &lt;span class="k"&gt;for &lt;/span&gt;ONTAP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvswszusgdiba6irozbz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvswszusgdiba6irozbz.png" alt="Nextcloud file sharing UI architecture. A web browser reaches Nextcloud on EC2 with Docker through Elastic Load Balancing, with metadata in Amazon RDS for MariaDB. Nextcloud's External Storage App mounts the S3 Access Point over the S3 API to reach the FSx for ONTAP volume. EventBridge Scheduler and Step Functions trigger AI processing with Bedrock, Rekognition, Athena, and Comprehend" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/nextcloud-external-storage-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3: Nextcloud architecture — the External Storage App mounts the S3 Access Point as S3-compatible storage&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Pass the S3 AP alias as the bucket name, and ONTAP volume contents appear in Nextcloud's file listing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup (~5 minutes)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start Nextcloud container&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;solutions/nextcloud-test
make up

&lt;span class="c"&gt;# Set your S3 AP alias or bucket name (e.g., "my-volume-ap-s3alias")&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_S3AP_ALIAS&amp;gt;

&lt;span class="c"&gt;# Configure External Storage to mount ONTAP volume via S3 AP&lt;/span&gt;
make configure-s3

&lt;span class="c"&gt;# Verify connection (success = file listing returned)&lt;/span&gt;
make verify

&lt;span class="c"&gt;# Open in browser&lt;/span&gt;
open http://localhost:8080  &lt;span class="c"&gt;# admin / admin123&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What to expect&lt;/strong&gt;: Nextcloud file listing shows files from your ONTAP volume (or S3 bucket) via S3 AP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Desktop sync client (Windows/Mac/Linux)&lt;/li&gt;
&lt;li&gt;Sharing links (password-protected, time-limited)&lt;/li&gt;
&lt;li&gt;Comments &amp;amp; annotations&lt;/li&gt;
&lt;li&gt;WebDAV access&lt;/li&gt;
&lt;li&gt;LDAP/SAML authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trade-offs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strengths&lt;/th&gt;
&lt;th&gt;Considerations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mature NAS file sharing tool&lt;/td&gt;
&lt;td&gt;AI/ML integration needs Webhook development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop sync + mobile apps&lt;/td&gt;
&lt;td&gt;EC2/RDS operational cost (production config)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free under AGPL-3.0 (Docker as-is)&lt;/td&gt;
&lt;td&gt;Source disclosure obligation if server code is modified&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Gotchas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;use_path_style=true&lt;/code&gt; required (S3 AP alias only works with path-style addressing)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;occ files_external:config&lt;/code&gt; must be run once per parameter ("Too many arguments" otherwise)&lt;/li&gt;
&lt;li&gt;Empty credentials cause IMDS (169.254.169.254) fallback timeout in Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cost
&lt;/h3&gt;

&lt;p&gt;Local Docker: $0. Production (EC2 + RDS + ALB): ~$70-110/month.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coexistence Pattern: Amplify + Nextcloud
&lt;/h2&gt;

&lt;p&gt;They are not mutually exclusive — both can &lt;strong&gt;access the same FSx for ONTAP volume simultaneously&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Nextcloud&lt;/th&gt;
&lt;th&gt;Amplify Gen2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File browsing&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File DL/UL&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (Presigned URL, 50GB object limit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop sync&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;△ (Use NFS/SMB instead)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sharing links (time-limited)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (Presigned URL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI/ML processing workflows&lt;/td&gt;
&lt;td&gt;⚠️ Webhook needed&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File Q&amp;amp;A (Bedrock)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlexClone restore&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP admin operations&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Expected Usage Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Team uses Nextcloud daily for file browsing &amp;amp; sharing
   (same data visible as NFS/SMB users)

2. When AI processing is needed on a specific folder,
   launch it from the Amplify portal

3. Result files are written back to the same volume,
   instantly visible from Nextcloud and NFS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FYoshiki0705%2FFSx-for-ONTAP-S3AccessPoints-Serverless-Patterns%2Fmain%2Fdocs%2Fimages%2Fpng%2Fcoexistence-3path-en%402x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FYoshiki0705%2FFSx-for-ONTAP-S3AccessPoints-Serverless-Patterns%2Fmain%2Fdocs%2Fimages%2Fpng%2Fcoexistence-3path-en%402x.png" alt="Amplify Gen2 and Nextcloud running side by side. The left AI processing and analytics block holds AWS Amplify, Cognito, AppSync, and Lambda calling Bedrock, Rekognition, Athena, Textract, and Comprehend. The right file management and sync block holds Nextcloud behind Elastic Load Balancing with RDS. Both blocks reach the same FSx for ONTAP volume through one shared S3 Access Point, coexisting with NFS and SMB clients" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Light theme shown. A &lt;a href="https://raw.githubusercontent.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/main/docs/images/png/coexistence-3path-en-dark@2x.png" rel="noopener noreferrer"&gt;dark theme version&lt;/a&gt; is available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4: Running both — AI processing and file management share one S3 Access Point&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Authentication is independent (Nextcloud: LDAP/SAML, Amplify: Cognito). For gradual adoption, set up Nextcloud first, then add Amplify when processing needs arise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Consistency
&lt;/h3&gt;

&lt;p&gt;ONTAP guarantees &lt;strong&gt;strong consistency&lt;/strong&gt; across multi-protocol access. A PutObject via S3 AP is immediately visible from NFS/SMB after write completion. The reverse is also true. Whichever portal writes, all see consistent data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Storage operations note&lt;/strong&gt;: Your existing procedures (volume creation, snapshot management, and so on) remain unchanged. This portal is an end-user-facing AI processing and file access layer; administrators carry on with the AWS Management Console / FSx API and the ONTAP CLI / REST API. Those three are the management interfaces reachable for FSx for ONTAP — ONTAP System Manager is not among them (&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/fsx-ontap-management-interfaces.md" rel="noopener noreferrer"&gt;management interfaces&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Comparison with Alternatives
&lt;/h2&gt;

&lt;p&gt;Multiple approaches exist for "accessing NAS data from a browser." Each has trade-offs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Suited for&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;This portal (S3 AP + Amplify/Nextcloud)&lt;/td&gt;
&lt;td&gt;AI processing + admin ops without data movement&lt;/td&gt;
&lt;td&gt;Custom code required, hours of initial setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DataSync + S3 + any portal&lt;/td&gt;
&lt;td&gt;Leveraging S3-native ecosystem&lt;/td&gt;
&lt;td&gt;Data copy, sync lag, storage cost duplication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer Family SFTP&lt;/td&gt;
&lt;td&gt;Existing SFTP client compatibility&lt;/td&gt;
&lt;td&gt;No web UI, AI integration needs extra development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EFS + Lambda&lt;/td&gt;
&lt;td&gt;Serverless simplicity&lt;/td&gt;
&lt;td&gt;No ONTAP-specific features (SnapLock, FlexClone, ARP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full SaaS (Box/SharePoint etc.)&lt;/td&gt;
&lt;td&gt;Zero infrastructure, immediate availability&lt;/td&gt;
&lt;td&gt;NAS data copy required, limited data protection features&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The S3 AP characteristic is "access data via S3 API without moving it." No data copy means no consistency issues or double storage costs. However, it's not "sign up and use immediately" like SaaS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How to choose&lt;/strong&gt;: DataSync + S3, Transfer Family SFTP, EFS + Lambda, and SaaS file sharing each suit a different context. The table above also carries the constraints on the FSx for ONTAP S3 AP side (custom code required, a few hours to stand up). Read it as material for choosing against your own requirements.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Try It (~30 Minutes)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Check Command&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;20.x or later&lt;/td&gt;
&lt;td&gt;&lt;code&gt;node --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 min if installed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;10.x or later&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bundled with Node.js&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS CLI&lt;/td&gt;
&lt;td&gt;2.x&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~2 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Account&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws sts get-caller-identity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 min if authenticated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;24.x or later&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nextcloud only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;FSx for ONTAP is &lt;strong&gt;NOT required&lt;/strong&gt; for DemoMode. You can verify portal behavior with a regular S3 bucket.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Fastest Path (~5 min, copy-paste 4 lines)
&lt;/h3&gt;

&lt;p&gt;If Node.js and AWS credentials are ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone repository and navigate to portal directory&lt;/span&gt;
git clone https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns.git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/solutions/amplify-portal

&lt;span class="c"&gt;# Install dependencies (~2 min)&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy config (DemoMode default — no edits needed)&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;amplify/portal-config.example.ts amplify/portal-config.ts

&lt;span class="c"&gt;# Start sandbox (first run also creates Cognito users, ~3 min)&lt;/span&gt;
npx ampx sandbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What to expect&lt;/strong&gt;: Terminal shows &lt;code&gt;✅ Deployment complete&lt;/code&gt;, then &lt;code&gt;http://localhost:5173&lt;/code&gt; opens the portal. You can browse files and access AI processing screens from the sidebar.&lt;/p&gt;

&lt;h3&gt;
  
  
  portal-config.ts Key Parameters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// portal-config.ts — parameter explanations&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;portalConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// S3 AP alias (empty string = DemoMode, uses regular S3 bucket)&lt;/span&gt;
  &lt;span class="c1"&gt;// Production example: "my-ontap-vol-ap-s3alias"&lt;/span&gt;
  &lt;span class="na"&gt;s3ApAlias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;// VPC ID (empty = no VPC Lambda = DemoMode)&lt;/span&gt;
  &lt;span class="c1"&gt;// Production example: "vpc-0123456789abcdef0"&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;// Cognito group-to-S3AP mapping (different access per group)&lt;/span&gt;
  &lt;span class="c1"&gt;// Example: analysts group gets analysis AP only, admins get full access&lt;/span&gt;
  &lt;span class="na"&gt;groupApMapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// "analysts": "analysis-vol-ap-s3alias",&lt;/span&gt;
    &lt;span class="c1"&gt;// "admins": "admin-vol-ap-s3alias"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CI/CD note&lt;/strong&gt;: Amplify Gen2 auto-deploys on git push. &lt;code&gt;git push origin main&lt;/code&gt; triggers Amplify Hosting build/deploy. No separate CI/CD pipeline needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Nextcloud Setup (~5 min)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start Nextcloud container&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;solutions/nextcloud-test
make up

&lt;span class="c"&gt;# Set your S3 AP alias or S3 bucket name&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;S3_BUCKET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_BUCKET_OR_AP_ALIAS&amp;gt;

&lt;span class="c"&gt;# Configure External Storage&lt;/span&gt;
make configure-s3

&lt;span class="c"&gt;# Verify connection&lt;/span&gt;
make verify

&lt;span class="c"&gt;# Open in browser&lt;/span&gt;
open http://localhost:8080  &lt;span class="c"&gt;# admin / admin123&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What to expect&lt;/strong&gt;: Nextcloud file listing shows files from the ONTAP volume (or S3 bucket) via S3 AP.&lt;/p&gt;

&lt;h3&gt;
  
  
  About DemoMode
&lt;/h3&gt;

&lt;p&gt;Leave VPC settings empty in &lt;code&gt;portal-config.ts&lt;/code&gt; to experience the portal UI and AI processing flow without FSx for ONTAP.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;DemoMode&lt;/th&gt;
&lt;th&gt;Production&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sidebar UI / navigation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File browsing&lt;/td&gt;
&lt;td&gt;⚠️ (S3 bucket)&lt;/td&gt;
&lt;td&gt;✅ (S3 AP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI processing&lt;/td&gt;
&lt;td&gt;⚠️ (needs Step Functions)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP admin panels&lt;/td&gt;
&lt;td&gt;⚠️ (shows "connection required")&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For production connectivity, see &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Role-Based Documentation (8 Languages)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Audience&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-user-guide.md" rel="noopener noreferrer"&gt;User Guide&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;End users&lt;/td&gt;
&lt;td&gt;Sign in → file ops → AI → FAQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-compliance-guide.md" rel="noopener noreferrer"&gt;Compliance Guide&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Security/Compliance officers&lt;/td&gt;
&lt;td&gt;ARP verification → WORM checks → audit trail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-quick-reference.md" rel="noopener noreferrer"&gt;Quick Reference&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;All roles&lt;/td&gt;
&lt;td&gt;1-page operations cheat sheet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Demo note&lt;/strong&gt;: Minimum 30-minute demo setup is "4-line fastest path → DemoMode launch → file browsing → AI processing screen." No FSx for ONTAP pre-build required.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Operational Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  File-Level Access Control
&lt;/h3&gt;

&lt;p&gt;S3 AP access is governed by ONTAP's UNIX permissions (UID/GID) or Windows ACLs. The File System Identity specified when creating the S3 AP determines "who" the access runs as.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example: separate team access with multiple S3 APs&lt;/span&gt;
S3 AP &lt;span class="s2"&gt;"portal-readonly"&lt;/span&gt;  → UID 1001 &lt;span class="o"&gt;(&lt;/span&gt;read-only&lt;span class="o"&gt;)&lt;/span&gt;
S3 AP &lt;span class="s2"&gt;"portal-analyst"&lt;/span&gt;   → UID 1002 &lt;span class="o"&gt;(&lt;/span&gt;analysis team, specific &lt;span class="nb"&gt;dirs &lt;/span&gt;only&lt;span class="o"&gt;)&lt;/span&gt;
S3 AP &lt;span class="s2"&gt;"portal-admin"&lt;/span&gt;     → UID 0    &lt;span class="o"&gt;(&lt;/span&gt;admin, full access&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Throughput Sharing
&lt;/h3&gt;

&lt;p&gt;S3 AP access shares the same FSx for ONTAP throughput budget as NFS/SMB. Normal portal usage (directory listing + individual reads) is not an issue, but if heavy parallel reads coexist with NFS workloads, monitor CloudWatch &lt;code&gt;ThroughputUtilization&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Options if throughput is insufficient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scale up throughput capacity (128→256/512/1024/2048 MBps)&lt;/li&gt;
&lt;li&gt;Set QoS policy to cap portal volume throughput&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multi-Account Environments
&lt;/h3&gt;

&lt;p&gt;This portal is designed for single-account use. AWS Organizations considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 AP&lt;/strong&gt;: Cross-account access requires AP resource policy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cognito&lt;/strong&gt;: Multi-account user consolidation recommended via SAML federation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tenant isolation&lt;/strong&gt;: &lt;code&gt;groupApMapping&lt;/code&gt; assigns different S3 APs per group&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  About Presigned URLs
&lt;/h3&gt;

&lt;p&gt;AWS documentation lists Presign as "Not supported," but they work in practice (confirmed with AWS Support). Presigning is client-side SigV4 signature calculation, and since GetObject is Supported, there's no structural way to block it. However, production reliance is at your own risk since documentation says "Not supported." Set short expiry (5 minutes or less recommended).&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling Characteristics
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Scaling&lt;/th&gt;
&lt;th&gt;Downtime&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lambda / AppSync / Cognito / DynamoDB&lt;/td&gt;
&lt;td&gt;Automatic (serverless)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSx for ONTAP&lt;/td&gt;
&lt;td&gt;Manual throughput/storage expansion&lt;/td&gt;
&lt;td&gt;Minutes during throughput change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Portal components are all serverless — the only scaling bottleneck is FSx for ONTAP throughput.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Data engineering note&lt;/strong&gt;: File metadata is available via CloudTrail + S3 AP access logs. Queryable with Athena, but building a dedicated metadata catalog (Glue Data Catalog etc.) requires separate design.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Series Structure (3 Parts)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Theme&lt;/th&gt;
&lt;th&gt;Key Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Part 1 (this article)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Portal foundation&lt;/td&gt;
&lt;td&gt;Amplify Gen2 vs Nextcloud, coexistence patterns, DemoMode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Part 2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Storage operations&lt;/td&gt;
&lt;td&gt;ARP/AI incident response, Tamperproof Snapshot, regulatory retention, Audit Log, FlexClone Restore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Part 3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI agent integration&lt;/td&gt;
&lt;td&gt;AgentChat, semantic search, multi-agent teams, HITL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: I'm not using FSx for ONTAP yet. Can I try this?&lt;/strong&gt;&lt;br&gt;
Yes. DemoMode uses a regular S3 bucket to demonstrate the portal's UI and AI processing flow. FSx for ONTAP can be added later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Do I need to replace my existing Box/SharePoint?&lt;/strong&gt;&lt;br&gt;
No. This portal is an additional layer for AI processing, data protection, and audit on NAS data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How much does it cost?&lt;/strong&gt;&lt;br&gt;
DemoMode is free (within AWS Free Tier). Production portal add-on: ~$5–50/month. Main cost is FSx for ONTAP infrastructure (~$194/month minimum).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What about security?&lt;/strong&gt;&lt;br&gt;
Cognito MFA + Groups role separation, HTTPS, Secrets Manager. Enterprise SSO (SAML/OIDC) supported via Cognito federation. Part 2 covers the security model in detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can it handle large files (multiple GB)?&lt;/strong&gt;&lt;br&gt;
S3 AP upload has a 50GB object size limit (a single PutObject is capped at 5GB, so Storage Browser switches to multipart above that). For files larger than 50GB, place them on the volume via NFS/SMB and use the portal for browsing/processing only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does this affect my existing operational procedures?&lt;/strong&gt;&lt;br&gt;
No. This portal is an end-user-facing additional layer. Operating through the ONTAP CLI / REST API and the AWS Management Console continues exactly as before.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verified Environment
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;20.18.x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React&lt;/td&gt;
&lt;td&gt;18.3.x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amplify Gen2&lt;/td&gt;
&lt;td&gt;1.x (as of 2026-07)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python (Lambda)&lt;/td&gt;
&lt;td&gt;3.12 (ARM64)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSx for ONTAP&lt;/td&gt;
&lt;td&gt;ONTAP 9.17.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;ap-northeast-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verified&lt;/td&gt;
&lt;td&gt;2026-07&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns" rel="noopener noreferrer"&gt;GitHub: FSx for ONTAP S3 AP Serverless Patterns&lt;/a&gt; — This repository (MIT License)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-user-guide.md" rel="noopener noreferrer"&gt;User Guide (8 languages)&lt;/a&gt; — End-user daily operations guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-compliance-guide.md" rel="noopener noreferrer"&gt;Compliance Guide (8 languages)&lt;/a&gt; — ARP/WORM/audit trail verification procedures&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt; — DemoMode to production connectivity migration&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-scaling-guide.md" rel="noopener noreferrer"&gt;Scaling Guide&lt;/a&gt; — Capacity planning and throughput design&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/nextcloud-external-storage-s3ap.md" rel="noopener noreferrer"&gt;Nextcloud External Storage Setup&lt;/a&gt; — Nextcloud + S3 AP detailed configuration&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/s3ap-compatibility-notes.md" rel="noopener noreferrer"&gt;S3 AP Compatibility Notes&lt;/a&gt; — API support status and known constraints&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/demo-mode-guide.md" rel="noopener noreferrer"&gt;DemoMode Guide&lt;/a&gt; — Running without FSx for ONTAP&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/s3-access-points.html" rel="noopener noreferrer"&gt;AWS: FSx for ONTAP S3 Access Points&lt;/a&gt; — Official documentation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary and Next Steps
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Point&lt;/th&gt;
&lt;th&gt;Conclusion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data migration&lt;/td&gt;
&lt;td&gt;Not needed — S3 AP reads the same volume NFS/SMB already uses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portal choice&lt;/td&gt;
&lt;td&gt;Nextcloud when file sharing is the center of gravity, Amplify Gen2 when AI processing and ONTAP admin operations are&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Running both&lt;/td&gt;
&lt;td&gt;Both can attach to the same volume at once. Authentication stays independent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How to try it&lt;/td&gt;
&lt;td&gt;DemoMode takes about 30 minutes and needs no FSx for ONTAP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existing workflows&lt;/td&gt;
&lt;td&gt;NFS/SMB mounts and ONTAP CLI / REST API operations continue unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For next steps, start with the 4-line fastest path in DemoMode and spend a few minutes in the sidebar UI and the AI processing screen. Once you can see which approach fits, the &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/en/portal-poc-to-production.md" rel="noopener noreferrer"&gt;PoC → Production Guide&lt;/a&gt; covers moving to a production connection.&lt;/p&gt;

&lt;p&gt;Part 2 covers storage operations (ARP/AI incident response, Tamperproof Snapshot, regulatory retention, Audit Log, FlexClone Restore), and Part 3 covers AI agent integration (AgentChat, semantic search, multi-agent teams, HITL).&lt;/p&gt;

&lt;p&gt;I hope this post helps someone out there.&lt;/p&gt;

&lt;p&gt;See you next time.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>netapp</category>
      <category>serverless</category>
      <category>storage</category>
    </item>
    <item>
      <title>KNFSD File Cache FSx for ONTAP: NFS Read Speedup + S3 Access Points Dual-Path</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:59:50 +0000</pubDate>
      <link>https://dev.to/aws-builders/knfsd-file-cache-x-fsx-for-ontap-nfs-read-speedup-s3-access-points-dual-path-kn1</link>
      <guid>https://dev.to/aws-builders/knfsd-file-cache-x-fsx-for-ontap-nfs-read-speedup-s3-access-points-dual-path-kn1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In July 2026, AWS released &lt;a href="https://github.com/awslabs/knfsd-file-cache" rel="noopener noreferrer"&gt;KNFSD File Cache&lt;/a&gt; as Preview — an open-source (Apache 2.0) NFS caching proxy built on the Linux kernel's NFS re-export and FS-Cache subsystems.&lt;/p&gt;

&lt;p&gt;This is the first time an NFS read-acceleration layer has shipped as an official AWS solution. Working daily with FSx for ONTAP NFS performance for EDA and VFX workloads, my reaction was immediate: spin up a verification environment and see what happens.&lt;/p&gt;

&lt;p&gt;What I tested was a &lt;strong&gt;Dual-Path architecture&lt;/strong&gt;: KNFSD caching NFS reads from the same FSx for ONTAP volume that S3 Access Points expose to serverless Lambda processing. The question: can compute fleets read at local-NVMe speed while Lambda runs AI/ML workloads on the same data, without bandwidth contention?&lt;/p&gt;

&lt;p&gt;Here's what I found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dual-Path E2E test passed&lt;/strong&gt;: A file written via S3 AP was immediately readable through the KNFSD NFS cache&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache effect&lt;/strong&gt;: first read 55ms → subsequent reads 2ms (28x improvement), proxy cache serves 422-619 MB/s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NFSv4.1 is mandatory&lt;/strong&gt;: NFSv3 re-export causes Stale file handle on file creation (kernel-level filehandle size constraint)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FSID_MODE=local + SQLite on FSx for ONTAP&lt;/strong&gt;: FSID persistence at zero additional cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post covers every pitfall I hit during deployment, and why this architecture still makes sense despite those issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Consider This — and When Not To
&lt;/h2&gt;

&lt;h3&gt;
  
  
  This architecture suits workloads that:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Need NFS read bandwidth beyond FSx for ONTAP's provisioned throughput (EDA DRC/LVS, VFX rendering, genomics)&lt;/li&gt;
&lt;li&gt;Want both NFS (high-speed reads) and S3 API (Lambda AI/ML post-processing) on the same data&lt;/li&gt;
&lt;li&gt;Use Spot instances for burst compute and need the cache to stay warm through reclamation&lt;/li&gt;
&lt;li&gt;Unify multiple NFS sources (FSx for ONTAP + on-premises NAS + other clouds) into one cache layer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Consider alternatives when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;FSx for ONTAP throughput scaling alone covers your bandwidth needs (steady-state workloads)&lt;/li&gt;
&lt;li&gt;Write caching is needed (FlexCache offers configurable write-back/write-around)&lt;/li&gt;
&lt;li&gt;You want fully managed operations with no EC2 to run (FlexCache or Amazon File Cache)&lt;/li&gt;
&lt;li&gt;Production SLA is non-negotiable (KNFSD is Preview — wait for GA)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;On vendor neutrality&lt;/strong&gt;: This post evaluates KNFSD File Cache on technical merits only. FlexCache, Amazon File Cache, EFS, and other options each suit different contexts. The goal here is to document what actually works, not to rank solutions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is KNFSD File Cache?
&lt;/h2&gt;

&lt;p&gt;KNFSD File Cache is an open-source (Apache 2.0) NFS caching proxy built on the Linux kernel's NFS re-export and FS-Cache subsystems. NFS re-export means mounting a remote NFS share and publishing it as a new NFS export to downstream clients — the proxy sits transparently between source and consumers. Wētā FX (Avatar: The Way of Water) and ILM used the predecessor project in production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NFS Source (FSx for ONTAP)
     │ NFS mount (NFSv4.1, fsc)
     ▼
KNFSD Proxy (EC2, NVMe L2 cache)
     │ NFS re-export (NFSv4.1)
     ▼
Compute Fleet (Spot × hundreds)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;L1 cache: Linux Page Cache (RAM — 5-9 GB/s on 16 GB in this test)&lt;/li&gt;
&lt;li&gt;L2 cache: FS-Cache (local NVMe — survives reboot, 106 MB/s measured)&lt;/li&gt;
&lt;li&gt;Writes: write-through (immediately forwarded to source)&lt;/li&gt;
&lt;li&gt;Scaling: ASG + DNS round-robin or NLB&lt;/li&gt;
&lt;li&gt;Prerequisite: source must be an NFS v3/4.x server (parallel filesystems like Lustre/GPFS/WekaFS are not supported)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key difference from FlexCache: KNFSD is a protocol-level transparent proxy that doesn't require the source to be ONTAP. It can unify FSx for OpenZFS, on-premises NetApp/Pure/Dell/DDN (A3I), and other-cloud NFS servers (via Direct Connect / Cloud Interconnect) into a single cache layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test Environment
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;ap-northeast-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source&lt;/td&gt;
&lt;td&gt;FSx for ONTAP (128 MBps, Single-AZ, ONTAP 9.17.1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KNFSD Proxy&lt;/td&gt;
&lt;td&gt;m6gd.xlarge (arm64 Graviton, 16 GB RAM, 237 GB NVMe)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel&lt;/td&gt;
&lt;td&gt;7.1.3-knfsd (Packer custom build)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSID Mode&lt;/td&gt;
&lt;td&gt;local (SQLite on FSx for ONTAP NFS mount)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFS Version&lt;/td&gt;
&lt;td&gt;NFSv4.1 (source → proxy → client)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test Client&lt;/td&gt;
&lt;td&gt;t4g.micro (AL2023, 916 MB RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP&lt;/td&gt;
&lt;td&gt;Internet-origin, UNIX identity (root)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: KNFSD-specific incremental resources only (Packer Spot build ~$0.30 + m6gd.xlarge 1hr ~$0.29). Prerequisites: a running FSx for ONTAP (~$194/mo minimum) + VPC infrastructure. If you already operate FSx for ONTAP, the incremental evaluation cost is effectively &amp;lt; $1.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Dual-Path E2E Test Results (Verified)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Lambda / CLI]                    [Compute Fleet]
     │                                 │
     │ S3 PutObject                    │ NFS read (NFSv4.1)
     ▼                                 ▼
┌──────────────────┐         ┌──────────────────────┐
│ S3 Access Point  │         │ KNFSD File Cache     │
│ (Internet-origin)│         │ (m6gd.xlarge, NVMe)  │
└────────┬─────────┘         └──────────┬───────────┘
         │                              │
         │  ← same volume →             │ NFS mount (NFSv4.1)
         ▼                              ▼
┌──────────────────────────────────────────────────┐
│ FSx for ONTAP Volume (/vol1, UNIX security style)│
└──────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP write → KNFSD NFS read&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Immediate reflection, content match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFS write → S3 AP read (MD5)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;c092ef65...&lt;/code&gt; match both directions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP batch 50 files → NFS bulk read&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;50 files in 107ms (2.1ms/file)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP multipart 50MB → NFS read&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MD5 verified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFSv4.1 write via KNFSD&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Write-through reflects immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fsidd + SQLite persistence&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQLite created on FSx for ONTAP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proxy restart → client continues&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;✅&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NFSv4.1 grace period, no remount needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Actual test log&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;test.txt s3://arn:aws:s3:ap-northeast-1:XXXX:accesspoint/knfsd-dualpath-test/s3ap-e2e-1784803253.txt
&lt;span class="c"&gt;# → upload: success&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /mnt/knfsd/vol1/s3ap-e2e-1784803253.txt  &lt;span class="c"&gt;# NFSv4.1 via KNFSD&lt;/span&gt;
dual-path-e2e-test-1784803253
&lt;span class="c"&gt;# → read success ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Performance Numbers
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Test environment note&lt;/strong&gt;: These numbers are from m6gd.xlarge (237 GB NVMe, single drive). Production-recommended instances (im4gn.16xlarge: 30 TB NVMe RAID, i3en.24xlarge: 60 TB) are expected to deliver significantly higher L2 NVMe throughput (estimated 2-8 GB/s sequential).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3-Layer Cache Hierarchy
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;L1: Proxy RAM (page cache)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.0-9.1 GB/s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hot data, repeated reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L2: NVMe (FS-Cache)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;106 MB/s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Warm-up shortcut after proxy restart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source: FSx for ONTAP (NFS fetch)&lt;/td&gt;
&lt;td&gt;18-19 MB/s&lt;/td&gt;
&lt;td&gt;Cache miss, initial fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important note on source performance&lt;/strong&gt;: The 18-19 MB/s figure reflects test-time NFS mount constraints (NFSv3 single-stream, rsize=64K) — &lt;strong&gt;not&lt;/strong&gt; FSx for ONTAP's throughput limit (128 MBps). Switching the source mount to NFSv4.1 + rsize=1M is expected to significantly improve cache miss performance (proposed upstream in &lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/42" rel="noopener noreferrer"&gt;Issue #42&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;L2 NVMe is &lt;strong&gt;5.6x faster&lt;/strong&gt; than source fetch. After a proxy reboot with empty RAM, data is served from NVMe cache immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throughput
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sequential read (proxy L1 → client)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;422-619 MB/s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large write (write-through)&lt;/td&gt;
&lt;td&gt;157-218 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP multipart upload (50 MB)&lt;/td&gt;
&lt;td&gt;36.6 MiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Latency
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Cold&lt;/th&gt;
&lt;th&gt;Cached&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10 MB file read&lt;/td&gt;
&lt;td&gt;55 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;28x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 KB small file&lt;/td&gt;
&lt;td&gt;1.75 ms&lt;/td&gt;
&lt;td&gt;1.5 ms&lt;/td&gt;
&lt;td&gt;14%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP batch → NFS&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.1 ms/file&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Working Set &amp;gt; Client RAM
&lt;/h3&gt;

&lt;p&gt;With client RAM at 916 MB and a 500 MB dataset, reading after &lt;code&gt;drop_caches&lt;/code&gt; still achieves &lt;strong&gt;422-428 MB/s&lt;/strong&gt; — served from the KNFSD proxy's 16 GB RAM cache. This is the core value proposition: &lt;strong&gt;small compute nodes can access datasets larger than their local memory at proxy-cache speed&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  nconnect Caveat
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;nconnect&lt;/th&gt;
&lt;th&gt;100 MB cold read&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (default)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;619 MB/s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;184 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On t4g.micro (5 Gbps NIC), nconnect=16 is counterproductive. Only effective on 100 Gbps instances (c5n.18xlarge, hpc7g).&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Coherency
&lt;/h3&gt;

&lt;p&gt;S3 AP write visibility through KNFSD depends on NFS attribute cache timeouts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;acregmin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3s&lt;/td&gt;
&lt;td&gt;Minimum file attribute cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;acdirmax&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;60s&lt;/td&gt;
&lt;td&gt;Maximum directory attribute cache&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In our tests, S3 AP-written files were immediately visible through KNFSD (new files bypass directory attribute cache). For frequently-overwritten files, set &lt;code&gt;acregmax=5-10&lt;/code&gt; to reduce stale-data windows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Every Pitfall We Hit (Documenting All of Them)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NFSv3 Breaks Writes (Most Important Finding)
&lt;/h3&gt;

&lt;p&gt;This consumed the most debugging time. When mounting the KNFSD proxy via NFSv3, existing file reads succeed but new file creation returns &lt;code&gt;Stale file handle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The cause is documented in the &lt;a href="https://docs.kernel.org/next/filesystems/nfs/reexport.html" rel="noopener noreferrer"&gt;Linux Kernel NFS re-export documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;reexport server's filehandle for the reexported object will be X+22 bytes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;FSx for ONTAP filehandles are ~40+ bytes. After +22 bytes = ~62+ bytes. New file creation (which adds subdirectory inode information) pushes past NFSv3's &lt;strong&gt;64-byte limit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;NFSv4.1 supports 128 bytes — ample headroom. Our Terraform &lt;strong&gt;validates against nfs_version="3"&lt;/strong&gt; with a clear error message linking to the upstream issue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Filed upstream as &lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/40" rel="noopener noreferrer"&gt;Issue #40&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Other Pitfalls
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;proxy-startup.sh immediate failure&lt;/td&gt;
&lt;td&gt;No EC2 API access (no Public IP)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;assign_public_ip = true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSM &lt;code&gt;GetParametersByPath&lt;/code&gt; denied&lt;/td&gt;
&lt;td&gt;IAM missing path-level ARN&lt;/td&gt;
&lt;td&gt;Include both &lt;code&gt;.../*&lt;/code&gt; and &lt;code&gt;...&lt;/code&gt; (&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/41" rel="noopener noreferrer"&gt;Issue #41&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"No storage devices found"&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CACHEFILESD_DISK_TYPE=local_nvme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Correct value: &lt;code&gt;local-nvme&lt;/code&gt; (hyphen)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;FSID_MODE=static&lt;/code&gt; breaks all writes&lt;/td&gt;
&lt;td&gt;fsidd disabled, filehandle unresolvable&lt;/td&gt;
&lt;td&gt;Switch to &lt;code&gt;FSID_MODE=local&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP create BadRequest&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--type One_Zone&lt;/code&gt; is for OpenZFS&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;--type ONTAP&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;exportfs: No fsid found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fsidd first-time allocation warning&lt;/td&gt;
&lt;td&gt;No operational impact (ignore)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  FSID_MODE=local: SQLite on FSx for ONTAP
&lt;/h2&gt;

&lt;p&gt;KNFSD's NFS re-export requires stable FSID management. &lt;code&gt;FSID_MODE=static&lt;/code&gt; (fsidd disabled) is fundamentally broken — all write operations fail with Stale file handle.&lt;/p&gt;

&lt;p&gt;The fix: use the Linux kernel's fsidd daemon with SQLite backend, placing the database file on the FSx for ONTAP NFS mount:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/srv/nfs/vol1/.knfsd/fsids.sqlite  ← on FSx for ONTAP (persistent, 99.99% SLA)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;local (SQLite on FSx)&lt;/th&gt;
&lt;th&gt;external (RDS)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Additional cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$15-45/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistence&lt;/td&gt;
&lt;td&gt;✅ (FSx for ONTAP SLA)&lt;/td&gt;
&lt;td&gt;✅ (RDS SLA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-node&lt;/td&gt;
&lt;td&gt;△ (single-node only)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;PoC / single-node&lt;/td&gt;
&lt;td&gt;Production multi-node&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  FlexCache and KNFSD: Different Tools for Different Contexts
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;FlexCache&lt;/th&gt;
&lt;th&gt;KNFSD&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source must be ONTAP&lt;/td&gt;
&lt;td&gt;✅ Native integration&lt;/td&gt;
&lt;td&gt;○ Any NFS-compatible filer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple source unification&lt;/td&gt;
&lt;td&gt;Not possible&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write-back/write-around&lt;/td&gt;
&lt;td&gt;✅ (configurable)&lt;/td&gt;
&lt;td&gt;△ (write-through only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Burst read scaling&lt;/td&gt;
&lt;td&gt;△ (within FSx throughput)&lt;/td&gt;
&lt;td&gt;✅ (NVMe cache scales with ASG)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed operations&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;△ (EC2 operations)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;NFSv3/4.x&lt;/td&gt;
&lt;td&gt;NFSv4.1 (required for re-export)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data protection integration&lt;/td&gt;
&lt;td&gt;✅ (SnapMirror/SnapLock)&lt;/td&gt;
&lt;td&gt;None (pass-through)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node elasticity&lt;/td&gt;
&lt;td&gt;△ (manual)&lt;/td&gt;
&lt;td&gt;✅ (Auto Scaling)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FlexCache note&lt;/strong&gt;: FlexCache also doesn't consume origin bandwidth on cache hits (same structure as KNFSD). However, in FSx for ONTAP's managed environment, auto-scaling FlexCache node count is not possible. For burst read bandwidth exceeding FSx max throughput, KNFSD offers more flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon File Cache / FSx for Lustre&lt;/strong&gt;: Amazon File Cache is a managed Lustre-compatible cache requiring the Lustre kernel client module on every node. KNFSD uses standard NFS clients (built into Linux/macOS), requiring no additional modules. However, Lustre's parallel I/O bandwidth is inherently higher than NFS re-export — if raw bandwidth is the priority and you can deploy Lustre clients on all nodes, File Cache / FSx for Lustre is the better fit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost break-even guideline&lt;/strong&gt;: KNFSD becomes economical when you need burst bandwidth beyond FSx for ONTAP's maximum throughput tier (4,096 MBps at ~$2,000/mo). For steady workloads where FSx throughput scaling suffices, increasing FSx throughput is simpler.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Target Workloads
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Industry&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;KNFSD Role&lt;/th&gt;
&lt;th&gt;S3 AP Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Semiconductor EDA&lt;/td&gt;
&lt;td&gt;DRC/LVS burst&lt;/td&gt;
&lt;td&gt;Tech file repeated reads&lt;/td&gt;
&lt;td&gt;Verification result AI classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VFX&lt;/td&gt;
&lt;td&gt;Rendering&lt;/td&gt;
&lt;td&gt;Texture/asset Fanout&lt;/td&gt;
&lt;td&gt;Render quality AI check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Genomics&lt;/td&gt;
&lt;td&gt;Reference genome + dbSNP&lt;/td&gt;
&lt;td&gt;Hundreds of nodes on same reference&lt;/td&gt;
&lt;td&gt;Variant AI classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Financial Risk&lt;/td&gt;
&lt;td&gt;Monte Carlo VaR&lt;/td&gt;
&lt;td&gt;Market data sub-ms delivery&lt;/td&gt;
&lt;td&gt;Anomaly scenario AI detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automotive CAE&lt;/td&gt;
&lt;td&gt;Structural sim&lt;/td&gt;
&lt;td&gt;Shared mesh data reads&lt;/td&gt;
&lt;td&gt;Result comparison AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weather&lt;/td&gt;
&lt;td&gt;NWP ensemble&lt;/td&gt;
&lt;td&gt;GFS initial condition cache&lt;/td&gt;
&lt;td&gt;Extreme weather AI detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Step-by-Step Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Build AMI (~25 min)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find your subnet (same AZ as FSx for ONTAP recommended)&lt;/span&gt;
aws ec2 describe-subnets &lt;span class="nt"&gt;--filters&lt;/span&gt; &lt;span class="s2"&gt;"Name=vpc-id,Values=vpc-YOUR-VPC"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Subnets[].{Id:SubnetId,AZ:AvailabilityZone}'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; table

git clone https://github.com/awslabs/knfsd-file-cache.git /tmp/knfsd-file-cache
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp/knfsd-file-cache/image
packer build &lt;span class="nt"&gt;-var&lt;/span&gt; &lt;span class="s1"&gt;'REGION=ap-northeast-1'&lt;/span&gt; &lt;span class="nt"&gt;-var&lt;/span&gt; &lt;span class="s1"&gt;'ARCH=["arm64"]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-var&lt;/span&gt; &lt;span class="s1"&gt;'ASSOCIATE_PUBLIC_IP_ADDRESS=true'&lt;/span&gt; &lt;span class="nt"&gt;-var&lt;/span&gt; &lt;span class="s1"&gt;'SUBNET=subnet-YOUR-SUBNET'&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# → Note the AMI ID (ami-0xxxxxxxxxx)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The AMI is reusable across deploy/destroy cycles. Rebuilds are only needed for kernel updates (~monthly). Normal deploys just pass the existing AMI ID to Terraform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Terraform Deploy (~3 min)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;infrastructure/knfsd-file-cache/terraform
&lt;span class="nb"&gt;cp &lt;/span&gt;terraform.tfvars.example terraform.tfvars
&lt;span class="c"&gt;# Edit: vpc_id, subnet_ids, knfsd_ami_id, source_mounts&lt;/span&gt;

./scripts/preflight-check.sh   &lt;span class="c"&gt;# Validates environment before deploy&lt;/span&gt;
terraform init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Mount from Client
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/knfsd
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;-t&lt;/span&gt; nfs &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;vers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.1 &amp;lt;KNFSD_IP&amp;gt;:/vol1 /mnt/knfsd
&lt;span class="nb"&gt;echo test&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /mnt/knfsd/hello.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /mnt/knfsd/hello.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ Always specify &lt;code&gt;vers=4.1&lt;/code&gt;. Using &lt;code&gt;vers=3&lt;/code&gt; will cause Stale file handle on file creation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. Verify Cache Effect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/urandom &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/mnt/knfsd/bench.dat &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1M &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;sync
sync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo 3 &amp;gt; /proc/sys/vm/drop_caches'&lt;/span&gt;
&lt;span class="nb"&gt;time cat&lt;/span&gt; /mnt/knfsd/bench.dat &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null   &lt;span class="c"&gt;# ~55ms (first read — fetched from source)&lt;/span&gt;
&lt;span class="nb"&gt;time cat&lt;/span&gt; /mnt/knfsd/bench.dat &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null   &lt;span class="c"&gt;# ~2ms  (subsequent — served from cache, 28x)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Dual-Path Test (if you have an S3 AP)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Write via S3 AP&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;test.txt &lt;span class="s2"&gt;"s3://arn:aws:s3:REGION:ACCOUNT:accesspoint/AP-NAME/file.txt"&lt;/span&gt;

&lt;span class="c"&gt;# Read via KNFSD NFS (immediate reflection)&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /mnt/knfsd/file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: The above test uses &lt;code&gt;root&lt;/code&gt; (UID 0) as the S3 AP FileSystemIdentity. This is for testing only. In production, use a dedicated non-root user following least-privilege principles.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  6. Cleanup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform destroy
aws ec2 deregister-image &lt;span class="nt"&gt;--image-id&lt;/span&gt; ami-xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Upstream Feedback
&lt;/h2&gt;

&lt;p&gt;Five issues filed during this verification:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Summary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/38" rel="noopener noreferrer"&gt;#38&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Verification report + minimal example for existing source filers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/39" rel="noopener noreferrer"&gt;#39&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Private subnet support (graceful degradation without EC2 API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/40" rel="noopener noreferrer"&gt;#40&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;NFSv3 re-export filehandle overflow documentation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/41" rel="noopener noreferrer"&gt;#41&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;IAM policy missing path-level ARN (bug fix)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues/42" rel="noopener noreferrer"&gt;#42&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;NFSv4.1 source mount support (end-to-end v4.1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Filing upstream issues for things you find broken (or under-documented) is one of the most impactful things you can do with a Preview-stage OSS project. It ensures the maintainers have real-world data to prioritize GA fixes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary and Next Steps
&lt;/h2&gt;

&lt;p&gt;Dual-Path E2E test passed — S3 AP write → KNFSD NFS read works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three key findings:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;NFSv4.1 mandatory (NFSv3 filehandle size limit breaks writes)&lt;/li&gt;
&lt;li&gt;FSID_MODE=local + SQLite on FSx for ONTAP provides FSID persistence at $0&lt;/li&gt;
&lt;li&gt;S3 AP writes reflect immediately through KNFSD NFS&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What's next:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wait for GA (SLA terms, support scope confirmation)&lt;/li&gt;
&lt;li&gt;Multi-node (ASG + NLB) verification&lt;/li&gt;
&lt;li&gt;EDA/VFX-specific file access pattern benchmarks&lt;/li&gt;
&lt;li&gt;im4gn.16xlarge (30 TB NVMe) L2 bandwidth at production scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;KNFSD File Cache is Preview, but it clearly functions as a practical read-acceleration layer for burst compute workloads. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small-scale starting point&lt;/strong&gt;: m6gd.xlarge × 1 running 24/7 = ~$215/mo. Daytime-only (10h) = ~$65/mo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache" rel="noopener noreferrer"&gt;KNFSD File Cache GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/media/introducing-knfsd-file-cache-extending-your-nfs-storage-into-the-cloud/" rel="noopener noreferrer"&gt;AWS Launch Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/docs/knfsd-s3ap-dual-path-architecture.md" rel="noopener noreferrer"&gt;Dual-Path Architecture Guide (JA)&lt;/a&gt; — 7 industry deep dives + cost estimates + observability&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/tree/main/infrastructure/knfsd-file-cache" rel="noopener noreferrer"&gt;Terraform + Demo Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/blob/main/infrastructure/knfsd-file-cache/docs/fsid-backend-options.md" rel="noopener noreferrer"&gt;FSID Backend Options&lt;/a&gt; — SQLite/RDS/Aurora comparison&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/next/filesystems/nfs/reexport.html" rel="noopener noreferrer"&gt;Linux Kernel NFS Re-export Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/awslabs/knfsd-file-cache/issues?q=author%3AYoshiki0705" rel="noopener noreferrer"&gt;Verification Issues #38-#42&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Preview notice&lt;/strong&gt;: KNFSD File Cache is in Preview as of July 2026. The code is OSS (Apache 2.0) but AWS Preview Service Terms apply. Evaluate for non-production or supplementary use until GA. AWS Support coverage may not extend to KNFSD-specific issues — GitHub Issues is the primary channel. NVMe instance store cache data is protected by AES-256 hardware encryption and auto-erased on instance termination.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>nfs</category>
      <category>hpc</category>
      <category>storage</category>
    </item>
    <item>
      <title>Mackerel's Log Feature Just Opened in Beta — Here's What It Takes to Wire It Into an OTLP Pipeline</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Mon, 20 Jul 2026 08:05:24 +0000</pubDate>
      <link>https://dev.to/aws-builders/mackerels-log-feature-just-opened-in-beta-heres-what-it-takes-to-wire-it-into-an-otlp-pipeline-888</link>
      <guid>https://dev.to/aws-builders/mackerels-log-feature-just-opened-in-beta-heres-what-it-takes-to-wire-it-into-an-otlp-pipeline-888</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mackerel.io/" rel="noopener noreferrer"&gt;Mackerel&lt;/a&gt; — Hatena's Japan-origin observability platform — opened its log feature as &lt;a href="https://mackerel.io/ja/blog/entry/announcement/log-beta-release" rel="noopener noreferrer"&gt;public beta on July 16, 2026&lt;/a&gt;. In response, this repository added Mackerel integration for shipping FSx for ONTAP file access audit logs, EMS events, and FPolicy events via the existing Lambda/OTel Collector pipeline.&lt;/p&gt;

&lt;p&gt;The OTel Collector path worked immediately — just add an exporter config entry. But the direct-send path (Lambda → vendor OTLP endpoint, no Collector) exposed two compatibility gaps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mackerel requires a custom &lt;code&gt;Mackerel-Api-Key&lt;/code&gt; header, not &lt;code&gt;Bearer&lt;/code&gt;/&lt;code&gt;Basic&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mackerel's OTLP endpoint only accepts Protobuf, rejecting OTLP/JSON outright&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article covers the generic auth header primitive and limited Protobuf encoder added to close those gaps. Both delivery paths are confirmed E2E against a live Mackerel organization, but since the log feature is still in beta, production deployments should use the Collector path and should not treat Mackerel as the sole audit trail destination.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scope&lt;/strong&gt;: This article covers shipping FSx for ONTAP file access audit logs, EMS events, and FPolicy events to Mackerel via the existing Lambda/OTel Collector integration. It does not cover Collector high availability, Lambda retry/DLQ design, NAT Gateway routing, or log-loss recovery — see the &lt;a href="https://dev.to/aws-builders/escape-vendor-lock-in-multi-backend-log-delivery-with-otel-collector-for-fsx-for-ontap-2inb"&gt;base article (Part 5)&lt;/a&gt; and repository operations docs for those topics.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FSx for ONTAP
├─ File access audit (EVTX/XML)
├─ EMS events
└─ FPolicy events
         │
         ▼
Lambda: builds OTLP Logs Data Model
         │
         ├──▶ OTel Collector ──▶ Mackerel [recommended]
         │
         └──▶ Direct to Mackerel [verification path]
              - Mackerel-Api-Key header
              - Accept: */*
              - OTLP/Protobuf required
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;Yoshiki0705/fsxn-observability-integrations&lt;/a&gt;&lt;br&gt;
New files: &lt;code&gt;integrations/mackerel/&lt;/code&gt;, &lt;code&gt;integrations/otel-collector/otel-collector-config-mackerel.yaml&lt;/code&gt;&lt;br&gt;
Modified: &lt;code&gt;integrations/otel-collector/lambda/{handler,ems_handler,fpolicy_handler}.py&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a standalone entry in the &lt;a href="https://dev.to/aws-builders/why-your-fsx-for-ontap-audit-logs-deserve-better-than-ec2-kod"&gt;Serverless Observability for FSx for ONTAP&lt;/a&gt; series — it's not a continuation of the incident-response article, and doesn't assume you've read it. It builds on &lt;a href="https://dev.to/aws-builders/escape-vendor-lock-in-multi-backend-log-delivery-with-otel-collector-for-fsx-for-ontap-2inb"&gt;Part 5&lt;/a&gt; (the vendor-neutral OTel Collector pattern), since that's exactly the mechanism a new backend plugs into.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Mackerel, and Why Now
&lt;/h2&gt;

&lt;p&gt;This series has already shipped FSx for ONTAP audit logs to 9 observability platforms — Datadog, Splunk, Grafana Cloud, Honeycomb, and others — all confirmed E2E against real accounts. A few readers, mostly from Japan, have asked why Mackerel wasn't on that list. Fair question, and one I'd been wanting to answer for a while.&lt;/p&gt;

&lt;p&gt;The short answer: it wasn't this repository's gap to close. Mackerel simply didn't have a log-sending feature yet. It's offered OpenTelemetry-based tracing (APM) for a while, but logs were a gap in Mackerel's own product.&lt;/p&gt;

&lt;p&gt;There's another direct trigger behind this article. At &lt;a href="https://sre-next.dev/2026/" rel="noopener noreferrer"&gt;SRE NEXT 2026&lt;/a&gt;, I had a chance to casually catch up with some longtime acquaintances on the Mackerel team and trade notes on Observability for Amazon FSx for NetApp ONTAP. That particular conversation didn't lead anywhere specific on its own, but the conference as a whole gave me useful ideas and motivation for infrastructure-focused development, which fed directly into picking this integration up.&lt;/p&gt;

&lt;p&gt;That changed on &lt;strong&gt;July 16, 2026&lt;/strong&gt;, when Mackerel &lt;a href="https://mackerel.io/ja/blog/entry/announcement/log-beta-release" rel="noopener noreferrer"&gt;opened its log feature as a public beta&lt;/a&gt;. A feature I'd been waiting on finally showed up, which is the actual reason this article exists.&lt;/p&gt;

&lt;p&gt;That said, "just opened in beta" is worth taking seriously. The feature itself is new and explicitly non-GA — a genuinely different situation from adding an eighth or ninth already-mature vendor without much thought. This article walks through what actually broke while wiring it up, and why it still sits in a separate section instead of being quietly folded into the main vendor table.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Vendor-neutral note&lt;/strong&gt;: this article evaluates Mackerel's OTLP log ingestion on its technical merits — the same way this repository's &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/vendor-comparison.md" rel="noopener noreferrer"&gt;vendor-comparison.md&lt;/a&gt; treats Datadog, Grafana, Splunk, and the other 9. No platform in this comparison is framed as superior to another; each fits a different context, and the goal here is documenting what's actually supported, not ranking who's "better."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;When this integration is a good fit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already use Mackerel for monitoring/APM&lt;/li&gt;
&lt;li&gt;You want to integrate FSx for ONTAP events into your existing incident investigation workflow&lt;/li&gt;
&lt;li&gt;You use an OTel Collector as a shared telemetry router&lt;/li&gt;
&lt;li&gt;You can evaluate a beta feature in a non-production or supplementary capacity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to consider other options for now:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regulatory/audit requirements demand guaranteed data retention&lt;/li&gt;
&lt;li&gt;This would be your sole security log destination&lt;/li&gt;
&lt;li&gt;Log loss is unacceptable and formal support terms are required&lt;/li&gt;
&lt;li&gt;Strict data residency or contract-path conditions apply&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Mackerel's Beta Actually Supports
&lt;/h2&gt;

&lt;p&gt;Before writing any integration code, the first step was reading Mackerel's own documentation rather than assuming logs would work like traces. As of July 2026, the log-sending method documented by Mackerel's official help is OpenTelemetry-based. This article uses OTLP/HTTP accordingly. Some things turned out to be shared, some didn't:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Mackerel Tracing (APM)&lt;/th&gt;
&lt;th&gt;Mackerel Logs (beta, 2026-07-16)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;OTLP/HTTP&lt;/td&gt;
&lt;td&gt;OTLP/HTTP (same)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endpoint&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://otlp-vaxila.mackerelio.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Mackerel-Api-Key&lt;/code&gt; header (Write scope)&lt;/td&gt;
&lt;td&gt;Same header, same scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required extra header&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Accept: */*&lt;/code&gt; (documented as required by Mackerel; the reason isn't publicly documented)&lt;/td&gt;
&lt;td&gt;Same requirement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grouping key&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;service.namespace&lt;/code&gt; + &lt;code&gt;service.name&lt;/code&gt; resource attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retention&lt;/td&gt;
&lt;td&gt;(APM's own terms)&lt;/td&gt;
&lt;td&gt;30 days planned at GA; beta operates under the same window but &lt;strong&gt;with no guarantee&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collector batch config&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;~3.5MB (&lt;code&gt;sending_queue.batch.max_size: 3500000&lt;/code&gt; bytes). This is a Collector-side setting matching Mackerel's official config example, not an absolute API max request size&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical upshot: if you already have an OTel Collector sending traces to Mackerel, adding logs is a second exporter pipeline entry, not a new integration pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwotmejtys8w2tj8s16gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwotmejtys8w2tj8s16gb.png" alt="Mackerel Logs UI — beta notice and search history" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Mackerel's Logs feature top page. The beta notice (no data retention guarantee, unscheduled maintenance possible) is explicitly displayed.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Architecture Question: Collector or Direct-Send?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Collector path is recommended for most deployments.&lt;/strong&gt; Direct-send is an option for minimal setups without a Collector, or for verifying protocol compatibility. Mackerel's own documentation also &lt;a href="https://mackerel.io/ja/docs/entry/log/sending" rel="noopener noreferrer"&gt;recommends placing a Collector in between&lt;/a&gt; for filtering and masking.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Recommended Path&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Production use, masking, multiple destinations, retry control&lt;/td&gt;
&lt;td&gt;Collector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimize components in a small environment&lt;/td&gt;
&lt;td&gt;Direct-send&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Just want to try Mackerel integration first&lt;/td&gt;
&lt;td&gt;Local Collector test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handling security audit logs&lt;/td&gt;
&lt;td&gt;Collector (filter sensitive attributes)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This repository's &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/tree/main/integrations/otel-collector" rel="noopener noreferrer"&gt;OTel Collector integration&lt;/a&gt; already ships FSx for ONTAP audit/EMS/FPolicy logs to Datadog, Grafana Cloud, and Honeycomb simultaneously from one Lambda codebase — the Lambda builds a backend-neutral OTLP payload, and the Collector's &lt;code&gt;exporters&lt;/code&gt; config decides where it goes. Adding Mackerel as a fourth backend to that pattern needed &lt;strong&gt;zero Lambda changes&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# otel-collector-config-mackerel.yaml&lt;/span&gt;
&lt;span class="c1"&gt;# NOTE: This repo's verified Collector version (0.152.0) uses otlp_http. Older&lt;/span&gt;
&lt;span class="c1"&gt;# versions may require otlphttp (no underscore). Check your version's docs.&lt;/span&gt;
&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;otlp_http/mackerel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://otlp-vaxila.mackerelio.com&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*/*"&lt;/span&gt;
      &lt;span class="na"&gt;Mackerel-Api-Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${env:MACKEREL_APIKEY}&lt;/span&gt;
    &lt;span class="na"&gt;sending_queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;max_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3500000&lt;/span&gt;
        &lt;span class="na"&gt;sizer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bytes&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp_http/mackerel&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole integration for the Collector-mediated path. But this repository also supports a &lt;strong&gt;direct-send&lt;/strong&gt; path — Lambda posts straight to a vendor's OTLP endpoint, skipping the Collector entirely — used today for Grafana Cloud via &lt;code&gt;AUTH_MODE=basic&lt;/code&gt;. Checking whether that path also worked for Mackerel is where things got more interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Gap: A Header Mackerel Needs That the Direct-Send Path Couldn't Send
&lt;/h2&gt;

&lt;p&gt;"Add an exporter and you're done" turned out not to cover every path. The direct-send auth logic in &lt;code&gt;handler.py&lt;/code&gt;, &lt;code&gt;ems_handler.py&lt;/code&gt;, and &lt;code&gt;fpolicy_handler.py&lt;/code&gt; only supported two modes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;AUTH_MODE&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;basic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;auth_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Basic &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;auth_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mackerel's auth is neither. It's a bare custom header, &lt;code&gt;Mackerel-Api-Key: &amp;lt;token&amp;gt;&lt;/code&gt;, with no &lt;code&gt;Bearer&lt;/code&gt; or &lt;code&gt;Basic&lt;/code&gt; wrapping. At that point, direct-send to Mackerel without a Collector simply wasn't possible.&lt;/p&gt;

&lt;p&gt;The fix is a generic primitive rather than a Mackerel-specific branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTH_MODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AUTH_MODE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bearer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# "bearer", "basic", or "header"
&lt;/span&gt;&lt;span class="n"&gt;AUTH_HEADER_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AUTH_HEADER_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;EXTRA_HEADERS_JSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EXTRA_HEADERS_JSON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;AUTH_MODE&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;header&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;auth_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;AUTH_HEADER_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;EXTRA_HEADERS_JSON&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;extra_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EXTRA_HEADERS_JSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;auth_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_headers&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;extra_headers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;AUTH_MODE=header&lt;/code&gt; sends the secret verbatim under any header name you specify. Mackerel happens to be the first consumer, but nothing about the option itself references Mackerel. &lt;code&gt;EXTRA_HEADERS_JSON&lt;/code&gt; covers Mackerel's required &lt;code&gt;Accept: */*&lt;/code&gt;, which isn't authentication at all — just a static header their backend depends on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;EXTRA_HEADERS_JSON&lt;/code&gt; constraint&lt;/strong&gt;: This is for static, non-secret headers like &lt;code&gt;Accept&lt;/code&gt; only. Do not specify auth headers (&lt;code&gt;Authorization&lt;/code&gt;, &lt;code&gt;Mackerel-Api-Key&lt;/code&gt;, etc.), &lt;code&gt;Content-Type&lt;/code&gt;, &lt;code&gt;Content-Length&lt;/code&gt;, or &lt;code&gt;Host&lt;/code&gt; — these are controlled by &lt;code&gt;AUTH_MODE&lt;/code&gt;/&lt;code&gt;OTLP_CONTENT_TYPE&lt;/code&gt; settings or set automatically by the HTTP library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same fix went into &lt;code&gt;ems_handler.py&lt;/code&gt; and &lt;code&gt;fpolicy_handler.py&lt;/code&gt; too. The CloudFormation template passes these env vars to all three Lambda functions, so patching only one would have left the other two silently ignoring &lt;code&gt;AUTH_MODE=header&lt;/code&gt; if someone set it.&lt;/p&gt;

&lt;p&gt;12 new unit tests cover this across the three handlers (4 each in &lt;code&gt;handler.py&lt;/code&gt;, &lt;code&gt;ems_handler.py&lt;/code&gt;, and &lt;code&gt;fpolicy_handler.py&lt;/code&gt;): custom-header auth, &lt;code&gt;EXTRA_HEADERS_JSON&lt;/code&gt; merging, the case where no API key secret is configured but extra headers still apply, and invalid &lt;code&gt;EXTRA_HEADERS_JSON&lt;/code&gt; producing a startup warning with extra headers disabled. &lt;code&gt;cfn-lint&lt;/code&gt; and &lt;code&gt;gitleaks&lt;/code&gt; run clean on the modified template and new files.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Second Gap: Auth Was Fixed, But the Payload Format Wasn't
&lt;/h2&gt;

&lt;p&gt;Fixing auth wasn't the finish line, though. The unit tests mock the HTTP layer entirely, so they passed without catching what a real API key call turned up next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;OTLP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;endpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"json is not supported yet"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;_send_otlp_payload&lt;/code&gt; always sends OTLP/JSON with &lt;code&gt;Content-Type: application/json&lt;/code&gt;, but Mackerel's OTLP endpoint accepts Protobuf only and rejects JSON outright. The Collector-mediated path never surfaced this: the Collector decodes received OTLP data into its internal data model, then re-serializes via the &lt;code&gt;otlphttp&lt;/code&gt; exporter whose default encoding is Protobuf (&lt;code&gt;proto&lt;/code&gt;). So even though the Lambda sends OTLP/JSON to the Collector, the Collector sends OTLP/Protobuf to Mackerel. The direct-send Lambda code simply never had a Protobuf encoder.&lt;/p&gt;

&lt;p&gt;This project's policy is to include no additional Python dependency packages in the Lambda deployment package. Only &lt;code&gt;boto3&lt;/code&gt; and &lt;code&gt;urllib3&lt;/code&gt; — both available in the Lambda Python runtime environment — are used; &lt;code&gt;protobuf&lt;/code&gt;/&lt;code&gt;opentelemetry-proto&lt;/code&gt; are not bundled. Adding those packages for one vendor felt disproportionate, so the fix is a small hand-rolled encoder (&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/integrations/otel-collector/lambda/otlp_protobuf.py" rel="noopener noreferrer"&gt;&lt;code&gt;otlp_protobuf.py&lt;/code&gt;&lt;/a&gt;). This encoder is not a general-purpose OTLP implementation. It covers only the limited data structures this repository's FSx for ONTAP log builders produce: &lt;code&gt;timeUnixNano&lt;/code&gt;, &lt;code&gt;severityNumber&lt;/code&gt;, &lt;code&gt;severityText&lt;/code&gt;, &lt;code&gt;body.stringValue&lt;/code&gt;, &lt;code&gt;attributes&lt;/code&gt; (stringValue only), resource attributes (stringValue only), and &lt;code&gt;InstrumentationScope&lt;/code&gt;. It does not support the full OTLP Logs field set or all &lt;code&gt;AnyValue&lt;/code&gt; types, and is not intended for reuse outside this project. Field numbers came straight from the &lt;a href="https://github.com/open-telemetry/opentelemetry-proto" rel="noopener noreferrer"&gt;official OTLP proto definitions&lt;/a&gt; (Apache License 2.0); the encoder's byte output was cross-checked against the official &lt;code&gt;opentelemetry-proto&lt;/code&gt; generated Python classes in a throwaway virtualenv before it touched a real account. We monitor official proto definition updates and maintain compatibility tests against the generated classes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;OTLP_CONTENT_TYPE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OTLP_CONTENT_TYPE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# "json" or "protobuf"
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;protobuf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/x-protobuf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encode_logs_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding &lt;code&gt;OTLP_CONTENT_TYPE=protobuf&lt;/code&gt;, calling &lt;code&gt;handler.py&lt;/code&gt;'s actual &lt;code&gt;build_otlp_payload&lt;/code&gt; and &lt;code&gt;_send_otlp_payload&lt;/code&gt; functions — the same code the Lambda runs, not a reimplementation — against the real Mackerel API key succeeded. For the two sample records sent (&lt;code&gt;ReadData&lt;/code&gt;/&lt;code&gt;Success&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt;/&lt;code&gt;Access Denied&lt;/code&gt;), this repository's generated audit attributes — operation type, result, file path, SVM name, user information, event timestamp — were confirmed searchable on Mackerel's log search UI.&lt;/p&gt;

&lt;p&gt;Unit tests verify auth headers, Content-Type branching, and encoding output. However, they cannot detect vendor-side acceptance behavior, rate limits, network path issues, or search-indexing delays — those require E2E tests against the real endpoint, which we run separately. 20 more unit tests were added: 3 per handler for the new content-type path, plus 11 in a dedicated &lt;code&gt;test_otlp_protobuf.py&lt;/code&gt;, bringing the OTel Collector integration's test suite to 110 passing tests.&lt;/p&gt;

&lt;p&gt;Verifying one delivery path for a vendor doesn't verify another. Auth headers, payload wire format, and network reachability can each fail independently, and a unit-test suite that mocks the HTTP layer won't catch a payload-format mismatch that only a real vendor endpoint enforces.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Still Isn't in the "9 Vendors, All Verified" List
&lt;/h2&gt;

&lt;p&gt;Every other vendor in this repository has a checkmark for a reason: an actual payload was sent to a live account and confirmed to arrive. Mackerel now has that checkmark too. Sample FSx audit log payloads showed up in Mackerel's log search UI with this repository's generated audit attributes confirmed searchable, through both the Collector-mediated path and the direct-send path once &lt;code&gt;OTLP_CONTENT_TYPE=protobuf&lt;/code&gt; was in place. This repo's &lt;code&gt;README.md&lt;/code&gt; reflects that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;E2E verified (open beta)&lt;/strong&gt; — Confirmed end-to-end against a live account, but the backend platform's own feature is itself in open beta (no data retention guarantee, unscheduled maintenance possible) — see the linked integration README for beta constraints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verification Detail&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;E2E verified&lt;/td&gt;
&lt;td&gt;2026-07-18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collector version&lt;/td&gt;
&lt;td&gt;0.152.0 (OpenTelemetry Collector Contrib)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;ap-northeast-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository commit&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;main&lt;/code&gt; branch HEAD at time of publication&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc58hebgq6qmunv99tauw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc58hebgq6qmunv99tauw.png" alt="Mackerel Log Search Results — FSx for ONTAP audit logs" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;E2E evidence: Searching by the fsxn-audit service shows 4 records — ReadData/Success, WriteData/Success, Open/Failure, Delete/Access Denied at WARN/INFO severity levels.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpym74aase3lrwmateeee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpym74aase3lrwmateeee.png" alt="Mackerel Log Detail — Delete/Access Denied audit attributes" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Log detail: Operation type, result, SVM name, file path, user info, client IP, and timestamp are all retained as searchable attributes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So the code-side gate is cleared. There's a second reason the integration still doesn't sit in the main table, though, and it's not about this repository's code at all — it's about what Mackerel itself has published about its own feature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No data-retention guarantee during the beta period&lt;/li&gt;
&lt;li&gt;Unscheduled maintenance is possible&lt;/li&gt;
&lt;li&gt;GA is planned for fall 2026, but the exact date isn't fixed yet&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: As of July 2026, the beta period is free. GA pricing is planned as ingest-volume-based billing. Pricing details, measurement units, and free-tier terms may change after this article's publication — check &lt;a href="https://mackerel.io/ja/pricing/" rel="noopener noreferrer"&gt;Mackerel's official pricing page&lt;/a&gt; for current terms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Folding this integration quietly into the "supported vendors" table with the same checkmark as the other 9 would let someone deploying it for security alerting (this repository's automated incident-response module, for instance) reasonably assume the same confidence level as Datadog or Splunk. That assumption would be wrong, not because of anything this repo's code does, but because the platform underneath it is explicitly pre-GA. So the integration stays in a separate "Emerging / Beta Vendors Under Evaluation" section of &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/vendor-comparison.md" rel="noopener noreferrer"&gt;vendor-comparison.md&lt;/a&gt;, marked as E2E-verified-but-beta, until Mackerel's own log feature reaches GA.&lt;/p&gt;

&lt;p&gt;One thing worth flagging for anyone reproducing this kind of verification: during investigation we also inspected GraphQL requests used internally by the browser UI, but we have not confirmed these are public/stable APIs. This repository's permanent E2E verification does not depend on them — final confirmation uses the official UI's log search screen combined with the Collector's own send metrics (&lt;code&gt;otelcol_exporter_sent_log_records&lt;/code&gt;). Internal implementation details on Mackerel's side may change without notice.&lt;/p&gt;


&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;FSx for ONTAP audit logs may contain usernames, file paths, share names, and client IP addresses — content that may constitute sensitive or personally-identifiable information depending on your organization's policies. Before sending production data to any external observability service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm your organization's data classification, storage location, access control, and retention requirements&lt;/li&gt;
&lt;li&gt;Use OTel Collector &lt;code&gt;filter&lt;/code&gt;/&lt;code&gt;transform&lt;/code&gt; processors to remove or mask sensitive attributes as needed (see this repository's &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/integrations/otel-collector/docs/en/pii-redaction-cookbook.md" rel="noopener noreferrer"&gt;PII redaction cookbook&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Do not use beta-period Mackerel as the sole storage destination for audit trails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On &lt;code&gt;EXTRA_HEADERS_JSON&lt;/code&gt; specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never put secret values in it — API keys belong in Secrets Manager&lt;/li&gt;
&lt;li&gt;Never put API keys directly in CloudFormation parameters or Lambda environment variables&lt;/li&gt;
&lt;li&gt;Never log full header contents at runtime&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Troubleshooting: 4-Layer Isolation
&lt;/h2&gt;

&lt;p&gt;When issues occur, isolate across these four layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;What to Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Generation&lt;/td&gt;
&lt;td&gt;Lambda&lt;/td&gt;
&lt;td&gt;OTLP record count, required attributes, timestamp, severity, resource attributes. If enabling debug logging, avoid outputting sensitive info like file paths or usernames&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Transmission&lt;/td&gt;
&lt;td&gt;Lambda / Collector exporter&lt;/td&gt;
&lt;td&gt;HTTP response code, timeouts, retry results (400, 401, 403, 429, 5xx)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Acceptance&lt;/td&gt;
&lt;td&gt;Collector metrics / OTLP response&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sent&lt;/code&gt;/&lt;code&gt;failed&lt;/code&gt; log records, partial success, drops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Consumption&lt;/td&gt;
&lt;td&gt;Mackerel UI&lt;/td&gt;
&lt;td&gt;service attribute match, search time range, filter conditions, indexing delay&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Distinguishing Collector/HTTP transmission failures (layers 2-3) from post-acceptance search/display issues (layer 4) is critical. If Mackerel rejects with HTTP 400, that's a layer 2-3 problem, not layer 4. See the troubleshooting table in &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/tree/main/integrations/mackerel/docs" rel="noopener noreferrer"&gt;&lt;code&gt;integrations/mackerel/docs/&lt;/code&gt;&lt;/a&gt; for detailed guidance.&lt;/p&gt;


&lt;h2&gt;
  
  
  Recommended Adoption Steps
&lt;/h2&gt;

&lt;p&gt;For evaluating this beta integration in stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;E2E verification with sample logs using a local Collector (&lt;code&gt;test-local-mackerel.sh&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Send non-production FSx for ONTAP audit logs in limited scope&lt;/li&gt;
&lt;li&gt;Evaluate send volume, data loss, searchability, and sensitive-information handling&lt;/li&gt;
&lt;li&gt;In production, implement dual-send to your existing log platform (CloudWatch Logs, S3, existing vendor)&lt;/li&gt;
&lt;li&gt;During the beta period, do not use Mackerel as your sole audit trail destination&lt;/li&gt;
&lt;li&gt;Re-evaluate for primary-path promotion once data retention terms, support conditions, and pricing are finalized at GA&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  What's Actually Usable Today
&lt;/h2&gt;

&lt;p&gt;Both paths below are now confirmed working end-to-end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Collector-mediated (recommended, zero Lambda changes)&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;integrations/otel-collector/.env.mackerel.example .env.mackerel
&lt;span class="c"&gt;# edit .env.mackerel with a Write-scoped Mackerel API key&lt;/span&gt;
bash integrations/otel-collector/scripts/test-local-mackerel.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Direct-send (skips the Collector; needs AUTH_MODE=header AND OtlpContentType=protobuf)&lt;/span&gt;
aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; integrations/otel-collector/template.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-otel-integration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;OtlpEndpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://otlp-vaxila.mackerelio.com &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;AuthMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;header &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;AuthHeaderName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Mackerel-Api-Key &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;ExtraHeadersJson&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"Accept":"*/*"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;OtlpContentType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;protobuf &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;ApiKeySecretArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;secret-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    ... &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;OtlpContentType=protobuf&lt;/code&gt; is not optional for Mackerel — without it, the send fails with the JSON-rejection error described above, even with correct auth.&lt;/p&gt;

&lt;p&gt;Full setup guides (bilingual) are in &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/tree/main/integrations/mackerel/docs" rel="noopener noreferrer"&gt;&lt;code&gt;integrations/mackerel/docs/&lt;/code&gt;&lt;/a&gt;, including a troubleshooting table that specifically tells you to isolate Collector-side failures from Mackerel-side rejections before debugging the wrong layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up, and What's Next
&lt;/h2&gt;

&lt;p&gt;So that's where Mackerel's log beta stands today. Getting there took two fixes that aren't visible when only the Collector-mediated path is tested — a custom auth header format, and a JSON-vs-Protobuf mismatch — and neither one surfaced until real credentials hit the direct-send path. A green unit-test suite doesn't tell you that.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AUTH_MODE=header&lt;/code&gt;, &lt;code&gt;EXTRA_HEADERS_JSON&lt;/code&gt;, and &lt;code&gt;OTLP_CONTENT_TYPE=protobuf&lt;/code&gt; options added here are not Mackerel-specific code — they're reusable primitives for any future OTLP/HTTP backend that requires a custom auth header or Protobuf-only ingestion.&lt;/p&gt;

&lt;p&gt;A few things to watch going forward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Watch for Mackerel's GA announcement for its log feature (data retention terms, pricing) — this article and the linked docs will be updated, not silently left stale, once that happens.&lt;/li&gt;
&lt;li&gt;Once GA lands with confirmed data retention conditions, support terms, and pricing, move Mackerel from "Emerging / Beta Vendors" into the main "Supported Vendors" comparison table.&lt;/li&gt;
&lt;li&gt;If you're running Mackerel already, the setup guide's sample OTLP payload is a good starting point to validate your own organization's setup independently.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mackerel's log feature still has some growing to do before GA, and I'm looking forward to seeing where it lands. Hope this was useful to someone wiring up the same thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/tree/main/integrations/mackerel" rel="noopener noreferrer"&gt;GitHub: &lt;code&gt;integrations/mackerel/&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/tree/main/integrations/otel-collector" rel="noopener noreferrer"&gt;GitHub: OTel Collector integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mackerel.io/ja/blog/entry/announcement/log-beta-release" rel="noopener noreferrer"&gt;Mackerel: Log feature open beta announcement (JA)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mackerel.io/ja/docs/entry/log/sending" rel="noopener noreferrer"&gt;Mackerel: Sending logs to Mackerel (JA help docs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mackerel.io/ja/pricing/" rel="noopener noreferrer"&gt;Mackerel: Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/vendor-comparison.md" rel="noopener noreferrer"&gt;GitHub: Vendor Comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/otlphttpexporter" rel="noopener noreferrer"&gt;OpenTelemetry Collector: OTLP HTTP Exporter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Automated Access Blocking for FSx for ONTAP — From Ransomware Detection to Storage-Layer Deny</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Sun, 12 Jul 2026 12:11:54 +0000</pubDate>
      <link>https://dev.to/aws-builders/automated-access-blocking-for-fsx-for-ontap-from-ransomware-detection-to-storage-layer-deny-4l2g</link>
      <guid>https://dev.to/aws-builders/automated-access-blocking-for-fsx-for-ontap-from-ransomware-detection-to-storage-layer-deny-4l2g</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem&lt;/strong&gt;: On Amazon FSx for NetApp ONTAP — a file system running on AWS — how do you &lt;em&gt;automatically stop ransomware from spreading&lt;/em&gt; after detection (via ARP/AI, SIEM, or CloudWatch alarm)?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt;: 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mechanism&lt;/strong&gt;: 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger&lt;/strong&gt;: Any source that can publish to SNS (CloudWatch Alarm, Datadog Monitor, Elastic SIEM, manual CLI).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt;: One CloudFormation stack. Tested with 52 unit tests (36 core + 16 network-layer). CLI helper for manual operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt;: ~$0.51/month (Lambda + SNS + Secrets Manager). Add ~$14/month if VPC Endpoints are needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timing&lt;/strong&gt;: Under 2 minutes end-to-end (verified). Worst-case with Lambda cold start + VPC ENI attach: under 3 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where this fits&lt;/strong&gt;: 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.)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;Yoshiki0705/fsxn-observability-integrations&lt;/a&gt;&lt;br&gt;
Template: &lt;code&gt;shared/templates/automated-response.yaml&lt;/code&gt;&lt;br&gt;
Module: &lt;code&gt;shared/python/ontap_response.py&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is Part 18 of the &lt;a href="https://dev.to/aws-builders/why-your-fsx-for-ontap-audit-logs-deserve-better-than-ec2-kod"&gt;Serverless Observability for FSx for ONTAP&lt;/a&gt; series. It builds on the detection capabilities from &lt;a href="https://dev.to/aws-builders/alerting-on-fsx-for-ontap-audit-logs-no-metric-filter-required-with-cloudwatch-log-alarms-15eg"&gt;Part 17&lt;/a&gt; (CloudWatch Log Alarm) and &lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Part 3&lt;/a&gt; (ARP + Datadog).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Gap Between Detection and Response
&lt;/h2&gt;

&lt;p&gt;The previous articles in this series covered &lt;em&gt;detection&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 3: ARP detects ransomware → EMS event → alert in ~30 seconds&lt;/li&gt;
&lt;li&gt;Part 17: CloudWatch Log Alarm detects suspicious admin operations → alert in ~90 seconds&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Idea Came From
&lt;/h2&gt;

&lt;p&gt;We have previously recommended dedicated storage security products — such as &lt;a href="https://docs.netapp.com/us-en/cloudinsights/cs_restrict_user_access.html" rel="noopener noreferrer"&gt;NetApp DII (Data Infrastructure Insights, formerly Cloud Insights) Storage Workload Security&lt;/a&gt; — 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.&lt;/p&gt;

&lt;p&gt;The friction shows up in a specific situation this series keeps running into: &lt;strong&gt;detection that originates outside DII&lt;/strong&gt;. 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."&lt;/p&gt;

&lt;p&gt;So the question became: "Can the same &lt;em&gt;containment-phase&lt;/em&gt; 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 &lt;code&gt;shared/python/ontap_response.py&lt;/code&gt; 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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/automated-response-guide.md#faq" rel="noopener noreferrer"&gt;Automated Response Guide on GitHub&lt;/a&gt; — it's a way to get the same storage-layer response when your detection already lives somewhere else.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------------------------------------------+
| Detection (existing - any source)                            |
|                                                              |
|  CloudWatch Log Alarm --+                                    |
|  ARP EMS -&amp;gt; Monitor ----+                                    |
|  FPolicy -&amp;gt; SIEM -------+-- SNS Trigger Topic                |
|  Manual CLI ------------+                                    |
|                                                              |
+--------------------------------------------------------------+
| Response (NEW - this article)                                |
|                                                              |
|  SNS -&amp;gt; Lambda (VPC) -&amp;gt; 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 -&amp;gt; email/PagerDuty) |
|                                                              |
+--------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key design choice: &lt;strong&gt;detection and response are decoupled via SNS&lt;/strong&gt;. 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.&lt;/p&gt;




&lt;h2&gt;
  
  
  How ONTAP User Blocking Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SMB: Name-Mapping Deny
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before: CORP\jdoe → maps to → jdoe (UNIX) → access granted
After:  CORP\jdoe → maps to → " " (empty)  → access DENIED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an SVM-wide block — it affects every volume and share within the SVM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Operational safety note&lt;/strong&gt;: The deny mapping is inserted at position 1 by default, meaning it's evaluated &lt;em&gt;before&lt;/em&gt; 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 &lt;code&gt;ontap_response.py&lt;/code&gt; if needed). Always test with &lt;code&gt;health_check&lt;/code&gt; and a non-production user first. To immediately undo an accidental block: &lt;code&gt;./automated-response-cli.sh unblock-smb --domain CORP --user jdoe&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;ONTAP REST API call:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/api/name-services/name-mappings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"win_unix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CORP&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;jdoe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"replacement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"svm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"svm-prod-01"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  NFS: Export-Policy Deny Rule
&lt;/h3&gt;

&lt;p&gt;For NFS clients, blocking is done via export-policy rules with &lt;code&gt;ro_rule: never&lt;/code&gt; and &lt;code&gt;rw_rule: never&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/api/protocols/nfs/export-policies/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;policy_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;/rules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"clients"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fsxn_auto_response,10.0.5.99"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ro_rule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"never"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rw_rule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"never"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"superuser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"never"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocols"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"any"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;fsxn_auto_response&lt;/code&gt; 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scope note&lt;/strong&gt;: Both SMB and NFS blocks are &lt;strong&gt;SVM-wide&lt;/strong&gt; — they affect ALL volumes and shares within the target SVM, not just the volume specified in the &lt;code&gt;contain_*&lt;/code&gt; 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 &lt;code&gt;create_snapshot&lt;/code&gt; (per-volume) and coordinate with your network team for host-level isolation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  NFS: Why Export-Policy Alone Isn't Instant (and How We Fixed It)
&lt;/h3&gt;

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

&lt;p&gt;Unlike SMB (where &lt;code&gt;disconnect_smb_sessions&lt;/code&gt; 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.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution: Network-layer blocking via VPC NACL deny rules.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;FsxSubnetId&lt;/code&gt; is configured, &lt;code&gt;contain_nfs_threat&lt;/code&gt; automatically applies &lt;em&gt;both&lt;/em&gt; layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;th&gt;Bypass?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ONTAP&lt;/td&gt;
&lt;td&gt;Export-policy deny rule&lt;/td&gt;
&lt;td&gt;Persistent, survives NACL removal&lt;/td&gt;
&lt;td&gt;Client cache (up to 60s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;NACL deny rule (rule 50-99)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Immediate&lt;/strong&gt; (packet-level)&lt;/td&gt;
&lt;td&gt;Cannot be bypassed by client&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy with network-layer NFS blocking enabled:&lt;/span&gt;
aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; shared/templates/automated-response.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-automated-response &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    ... &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;FsxSubnetId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;subnet-where-fsx-enis-reside&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Blast radius note&lt;/strong&gt;: 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 &lt;code&gt;"block_all_ports": false&lt;/code&gt; in the SNS message to block only NFS port 2049.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why NACL and not Security Group?&lt;/strong&gt; 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.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Session Disconnect
&lt;/h3&gt;

&lt;p&gt;Blocking prevents &lt;em&gt;new&lt;/em&gt; operations, but existing CIFS sessions can continue. The composite action also disconnects active sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/api/protocols/cifs/sessions/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;svm_uuid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;connection_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Safety Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Input Validation
&lt;/h3&gt;

&lt;p&gt;The module validates all inputs before calling ONTAP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username injection prevention (blocks &lt;code&gt;;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;`&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, newlines)&lt;/li&gt;
&lt;li&gt;Protected account denylist (&lt;code&gt;fsxadmin&lt;/code&gt;, &lt;code&gt;administrator&lt;/code&gt;, &lt;code&gt;vsadmin&lt;/code&gt;, &lt;code&gt;system&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;IP address format validation (valid IPv4 octets 0-255)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Snapshot Storm Prevention
&lt;/h3&gt;

&lt;p&gt;A configurable cooldown (default: 15 minutes) prevents creating multiple snapshots during a sustained attack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# If a snapshot with our prefix was created &amp;lt;15 min ago → skip
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_snapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;svm_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;svm-prod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volume_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vol_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cooldown_minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Prevents storm
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# result["status"] == "skipped" if cooldown active
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Marker-Based Cleanup
&lt;/h3&gt;

&lt;p&gt;All response rules include a consistent marker (&lt;code&gt;fsxn_auto_response&lt;/code&gt;), making it straightforward to find and remove all automated blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find all our rules&lt;/span&gt;
export-policy rule show &lt;span class="nt"&gt;-clientmatch&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;fsxn_auto_response&lt;span class="k"&gt;*&lt;/span&gt;
vserver name-mapping show &lt;span class="nt"&gt;-direction&lt;/span&gt; win-unix &lt;span class="nt"&gt;-replacement&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Evidence-handling note&lt;/strong&gt;: 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 &lt;em&gt;before&lt;/em&gt; 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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/automated-response-security-addendum.md#chain-of-custody-requirements-dfir" rel="noopener noreferrer"&gt;chain-of-custody gap table&lt;/a&gt; in the Security Addendum before treating "snapshot created" as "evidence preserved."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Time-Limited Blocks
&lt;/h3&gt;

&lt;p&gt;Persistent blocks are a real operational risk — a false positive can lock out a legitimate user indefinitely if nobody notices. The companion &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/templates/automated-response-ttl.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;automated-response-ttl.yaml&lt;/code&gt;&lt;/a&gt; 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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One Stack Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; shared/templates/automated-response.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-automated-response &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;OntapMgmtIp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;management-ip&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;OntapCredentialsSecretArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;secret-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;VpcId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;vpc-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;SubnetIds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;subnet-1&amp;gt;,&amp;lt;subnet-2&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;SecurityGroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;sg-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;DefaultSvmName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;svm-prod-01 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;SharedPythonLayerArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;layer-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;NotificationEmail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;security-team@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;New parameter (from verification)&lt;/strong&gt;: &lt;code&gt;SharedPythonLayerArn&lt;/code&gt; — provide the ARN of the &lt;code&gt;fsxn-shared-python&lt;/code&gt; Lambda Layer containing &lt;code&gt;ontap_response.py&lt;/code&gt;. Without this, the handler fails with &lt;code&gt;ModuleNotFoundError&lt;/code&gt;. Build and publish the layer first:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;bash shared/python/build-layer.sh
aws lambda publish-layer-version &lt;span class="nt"&gt;--layer-name&lt;/span&gt; fsxn-shared-python &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://shared/python/dist/fsxn-shared-python-layer.zip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compatible-runtimes&lt;/span&gt; python3.12 &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'LayerVersionArn'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;The stack creates:&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DLQ alarm = urgent&lt;/strong&gt;: A message in the DLQ means a containment action &lt;em&gt;failed&lt;/em&gt;. Unlike most DLQs where retry-later is fine, here it means &lt;strong&gt;the attacker may still have access&lt;/strong&gt;. Treat DLQ depth &amp;gt; 0 as a P1 incident requiring immediate human investigation. See the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/runbooks/dlq-replay.md" rel="noopener noreferrer"&gt;DLQ Replay Runbook&lt;/a&gt; for recovery steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critical: VPC Endpoints Required.&lt;/strong&gt; 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 (&lt;code&gt;CreateVpcEndpoints=true&lt;/code&gt;). If your VPC already has them, set it to &lt;code&gt;false&lt;/code&gt;. Without this, Lambda will timeout on every invocation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost note&lt;/strong&gt;: If your VPC already has a NAT Gateway, set &lt;code&gt;CreateVpcEndpoints=false&lt;/code&gt; — 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The CloudFormation template embeds the Lambda code inline for a quick first deployment. For a GitOps-friendly setup, package &lt;code&gt;ontap_response.py&lt;/code&gt; as a Lambda Layer instead using &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/python/build-layer.sh" rel="noopener noreferrer"&gt;&lt;code&gt;build-layer.sh&lt;/code&gt;&lt;/a&gt; and version it independently of the stack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Comprehensive deployment guidance&lt;/strong&gt;: For VPC Endpoint conflict avoidance, parameter file templates, and pre-deployment environment validation, see the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/deployment-guide.md" rel="noopener noreferrer"&gt;Deployment Guide&lt;/a&gt;. 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Connect Detection Sources
&lt;/h3&gt;

&lt;p&gt;Subscribe the trigger topic to your detection:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;How to Connect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CloudWatch Log Alarm&lt;/td&gt;
&lt;td&gt;Set alarm action to trigger topic ARN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datadog Monitor&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;@sns-&amp;lt;topic&amp;gt;&lt;/code&gt; in notification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Elastic SIEM&lt;/td&gt;
&lt;td&gt;Use SNS action in Kibana alert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws sns publish --topic-arn &amp;lt;arn&amp;gt; --message '&amp;lt;json&amp;gt;'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Alert-tuning note&lt;/strong&gt;: 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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/automated-response-guide.md" rel="noopener noreferrer"&gt;Reliability note in the Automated Response Guide&lt;/a&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  CLI Helper
&lt;/h2&gt;

&lt;p&gt;For manual operations and testing, use the included CLI wrapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESPONSE_TOPIC_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:sns:ap-northeast-1:123456789012:fsxn-automated-response-trigger"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DEFAULT_SVM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"svm-prod-01"&lt;/span&gt;

&lt;span class="c"&gt;# Full containment (snapshot + block + disconnect)&lt;/span&gt;
./shared/scripts/automated-response-cli.sh contain-smb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--domain&lt;/span&gt; CORP &lt;span class="nt"&gt;--user&lt;/span&gt; jdoe &lt;span class="nt"&gt;--volume&lt;/span&gt; vol_data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--reason&lt;/span&gt; &lt;span class="s2"&gt;"ARP detection - arw.volume.state alert"&lt;/span&gt;

&lt;span class="c"&gt;# Block a single IP&lt;/span&gt;
./shared/scripts/automated-response-cli.sh block-nfs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ip&lt;/span&gt; 10.0.5.99 &lt;span class="nt"&gt;--reason&lt;/span&gt; &lt;span class="s2"&gt;"Mass deletion from FPolicy"&lt;/span&gt;

&lt;span class="c"&gt;# Unblock after investigation&lt;/span&gt;
./shared/scripts/automated-response-cli.sh unblock-smb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--domain&lt;/span&gt; CORP &lt;span class="nt"&gt;--user&lt;/span&gt; jdoe

&lt;span class="c"&gt;# Dry-run test (no publish)&lt;/span&gt;
./shared/scripts/automated-response-cli.sh &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/scripts/automated-response-multi-svm-cli.sh" rel="noopener noreferrer"&gt;&lt;code&gt;automated-response-multi-svm-cli.sh&lt;/code&gt;&lt;/a&gt; instead — it wraps the single-SVM CLI, fans out the same action across a comma-separated SVM list, and reports per-SVM success/failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./shared/scripts/automated-response-multi-svm-cli.sh contain-smb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--svms&lt;/span&gt; &lt;span class="s2"&gt;"svm-prod-01,svm-prod-02,svm-dr-01"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--domain&lt;/span&gt; CORP &lt;span class="nt"&gt;--user&lt;/span&gt; jdoe &lt;span class="nt"&gt;--volume&lt;/span&gt; vol_data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--reason&lt;/span&gt; &lt;span class="s2"&gt;"ARP detection - multi-SVM block"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Composite Actions
&lt;/h2&gt;

&lt;p&gt;Individual actions (&lt;code&gt;block_smb_user&lt;/code&gt;, &lt;code&gt;block_nfs_ip&lt;/code&gt;, &lt;code&gt;create_snapshot&lt;/code&gt;, disconnect) can be combined into a single message:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Steps&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contain_smb_threat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Snapshot → Block SMB user → Disconnect sessions&lt;/td&gt;
&lt;td&gt;Compromised AD user detected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contain_nfs_threat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Snapshot → Block NFS IP&lt;/td&gt;
&lt;td&gt;Suspicious NFS client activity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contain_multiprotocol_threat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Snapshot → Block SMB user → Block NFS IP → Disconnect sessions&lt;/td&gt;
&lt;td&gt;Volume accessed via both SMB and NFS — a single-protocol block lets the attacker switch protocols and continue&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;contain_*&lt;/code&gt; 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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparison with DII Storage Workload Security
&lt;/h2&gt;

&lt;p&gt;Both approaches use the same underlying ONTAP mechanisms. The difference is where detection intelligence lives:&lt;/p&gt;

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

&lt;p&gt;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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/automated-response-guide.md#faq" rel="noopener noreferrer"&gt;Automated Response Guide&lt;/a&gt; for the fuller writeup.&lt;/p&gt;

&lt;p&gt;The table above compares &lt;em&gt;mechanisms&lt;/em&gt;. 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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Fits in Cyber Resilience: NIST CSF 2.0
&lt;/h2&gt;

&lt;p&gt;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. &lt;a href="https://www.nist.gov/cyberframework" rel="noopener noreferrer"&gt;NIST CSF 2.0&lt;/a&gt; organizes an organization's &lt;em&gt;entire&lt;/em&gt; cybersecurity risk-management program into &lt;strong&gt;Govern, Identify, Protect, Detect, Respond, Recover&lt;/strong&gt;, and NIST's dedicated ransomware profile (&lt;a href="https://csrc.nist.gov/pubs/ir/8374/r1/final" rel="noopener noreferrer"&gt;NIST IR 8374r1&lt;/a&gt;) maps ransomware-specific outcomes onto those six functions. Both AWS (&lt;a href="https://docs.aws.amazon.com/whitepapers/latest/ransomware-risk-management-on-aws-using-nist-csf/technical-capabilities.html" rel="noopener noreferrer"&gt;Ransomware Risk Management on AWS Using the NIST CSF&lt;/a&gt;) and NetApp (&lt;a href="https://www.netapp.com/it/blog/fortify-cybersecurity-nist-framework/" rel="noopener noreferrer"&gt;Fortify your cybersecurity defenses with NIST framework&lt;/a&gt;) 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.&lt;/p&gt;

&lt;p&gt;Placed on that map, this module and DII Storage Workload Security occupy the same narrow slice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CSF 2.0 Function&lt;/th&gt;
&lt;th&gt;What It Covers&lt;/th&gt;
&lt;th&gt;Where This Module (or DII) Sits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Govern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Risk strategy, roles, policy, board oversight&lt;/td&gt;
&lt;td&gt;Out of scope for both — this is an organizational responsibility no storage-layer tool automates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Identify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Asset/data inventory, classification&lt;/td&gt;
&lt;td&gt;Out of scope for &lt;em&gt;this&lt;/em&gt; module, but a companion module in the same repo — a &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/content-classification-scanner.md" rel="noopener noreferrer"&gt;Content-Level PII Classification Scanner&lt;/a&gt; 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&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Safeguards that reduce likelihood/impact&lt;/td&gt;
&lt;td&gt;Partially covered — ONTAP Snapshot/SnapLock, export-policy, name-mapping are the underlying safeguards both approaches call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Detect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Finding anomalies via monitoring&lt;/td&gt;
&lt;td&gt;Not this module's job — it &lt;em&gt;responds&lt;/em&gt; to a detection, it doesn't produce one (see &lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Part 3&lt;/a&gt; and &lt;a href="https://dev.to/aws-builders/alerting-on-fsx-for-ontap-audit-logs-no-metric-filter-required-with-cloudwatch-log-alarms-15eg"&gt;Part 17&lt;/a&gt; for the Detect side)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Respond&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mitigation, analysis, reporting on a detected incident&lt;/td&gt;
&lt;td&gt;✅ This is what this module does — block, snapshot, disconnect, notify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Restoring systems and coordinating with stakeholders&lt;/td&gt;
&lt;td&gt;The snapshot this module creates is Respond-phase evidence, not a verified recovery point on its own. A companion &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/verified-recovery-point-guide.md" rel="noopener noreferrer"&gt;Verified-Clean Recovery Point Guide&lt;/a&gt; closes part of that gap — see below — though the restore itself and stakeholder-level coordination remain manual&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Governance-reporting note&lt;/strong&gt;: 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy note&lt;/strong&gt;: 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 &lt;em&gt;type&lt;/em&gt;, count, and confidence per file (&lt;code&gt;EMAIL&lt;/code&gt;, &lt;code&gt;SSN&lt;/code&gt;, &lt;code&gt;CREDIT_DEBIT_NUMBER&lt;/code&gt;, 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.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Recovery-sufficiency note&lt;/strong&gt;: "We took a snapshot" and "we have a verified-clean recovery point" are two different maturity levels. &lt;a href="https://elastio.com/blog/mapping-ransomware-recovery-to-nist-csf-20" rel="noopener noreferrer"&gt;Elastio's mapping of ransomware recovery to CSF 2.0&lt;/a&gt; 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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/verified-recovery-point-guide.md" rel="noopener noreferrer"&gt;Verified-Clean Recovery Point Guide&lt;/a&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What "Verified Recovery" Looks Like in Practice
&lt;/h3&gt;

&lt;p&gt;After the containment above creates its protective snapshot, you can verify it before restoring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a single Step Functions workflow (5 Lambda functions). Deploy it and run a verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy the verification workflow&lt;/span&gt;
aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; shared/templates/restore-verification.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-restore-verification &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;VpcId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;vpc-id&amp;gt; &lt;span class="nv"&gt;SubnetIds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;subnet-1&amp;gt;,&amp;lt;subnet-2&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;SecurityGroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;sg-id&amp;gt; &lt;span class="nv"&gt;OntapMgmtIp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;mgmt-ip&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;OntapCredentialsSecretArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;secret-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM

&lt;span class="c"&gt;# Verify a specific snapshot before restoring&lt;/span&gt;
aws stepfunctions start-execution &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--state-machine-arn&lt;/span&gt; &amp;lt;from stack outputs&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="s1"&gt;'{"svm_name":"svm-prod","volume_name":"vol_data","snapshot_name":"incident_response_20260712_005307"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What it doesn't do&lt;/strong&gt;: 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Restore-testing note&lt;/strong&gt;: 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 &lt;code&gt;.encrypted&lt;/code&gt;/&lt;code&gt;.locked&lt;/code&gt;-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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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 &lt;em&gt;other&lt;/em&gt; components (ARP, EMS detection, Forensics dashboards, the recovery verification and PII scanning modules) land on Identify/Protect/Detect/Recover — lives in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cyber-resilience-capability-map.md" rel="noopener noreferrer"&gt;Cyber Resilience Capability Map&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  End-to-End Flow: ARP Detection → Auto-Block
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;ARP/AI detection: triggered within minutes of ransomware-like file operations (no learning period — ARP/AI in ONTAP 9.16.1+ is immediately active)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contain_smb_threat&lt;/code&gt; Lambda execution: &lt;strong&gt;1.8 seconds&lt;/strong&gt; (snapshot + block + session disconnect in a single invocation)&lt;/li&gt;
&lt;li&gt;SMB access denial confirmed after re-authentication
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SOC correlation tip&lt;/strong&gt;: Always include &lt;code&gt;incident_id&lt;/code&gt; and &lt;code&gt;detection_source&lt;/code&gt; in your SNS message so that the storage-layer block can be correlated with the upstream detection in your SIEM timeline:&lt;/p&gt;


&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"contain_smb_threat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"svm_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"svm-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"CORP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"jdoe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"volume_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"vol_data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ARP alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"incident_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"INC-2026-0712-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"detection_source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"datadog-monitor-arp"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;How immediate blocking actually works&lt;/strong&gt;: The &lt;code&gt;contain_smb_threat&lt;/code&gt; composite action achieves &lt;strong&gt;effective immediate cutoff&lt;/strong&gt; through a two-step mechanism:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;name-mapping deny&lt;/strong&gt; — blocks all &lt;em&gt;future&lt;/em&gt; authentication attempts (evaluated at session setup time, not per-I/O)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;disconnect_smb_sessions&lt;/code&gt;&lt;/strong&gt; — forcefully terminates the user's &lt;em&gt;existing&lt;/em&gt; active sessions via &lt;code&gt;DELETE /protocols/cifs/sessions/{svm}/{id}/{conn}&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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: &lt;strong&gt;the user is cut off within seconds of the Lambda executing&lt;/strong&gt;, not at the next natural session expiry.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ARP/AI verification note (ONTAP 9.16.1+)&lt;/strong&gt;: The CLI command &lt;code&gt;security anti-ransomware volume attack simulate&lt;/code&gt; referenced in some ONTAP documentation does &lt;strong&gt;NOT exist&lt;/strong&gt; 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 &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/ontap-rest-api-reference.md" rel="noopener noreferrer"&gt;ONTAP REST API Quick Reference&lt;/a&gt; for details.&lt;/p&gt;
&lt;/blockquote&gt;







&lt;h2&gt;
  
  
  What Blocking Looks Like: Visual Evidence
&lt;/h2&gt;

&lt;p&gt;The following was captured during E2E verification on ONTAP 9.17.1P7D1 (July 2026).&lt;/p&gt;

&lt;h3&gt;
  
  
  NFS: Before and After
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt; — user can list and read files normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /mnt/fsxn/
&lt;span class="go"&gt;hr-salary.txt  project-spec.txt  reports/

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /mnt/fsxn/hr-salary.txt
&lt;span class="go"&gt;Confidential HR Record - Employee Salary Data
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt; — export-policy deny rule applied (immediate, same-subnet):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /mnt/fsxn/
&lt;span class="go"&gt;ls: cannot access '/mnt/fsxn/': Permission denied

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /mnt/fsxn/hr-salary.txt
&lt;span class="go"&gt;cat: /mnt/fsxn/hr-salary.txt: Permission denied
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SMB: Before and After (AD-joined SVM)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt; — domain user DEMO\testuser can access CIFS share:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;X:\&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Mode&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;d-----&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;reports&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;hr-salary.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="o"&gt;----&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;43&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nx"&gt;project-spec.txt&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;X:\hr-salary.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Confidential&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;HR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Employee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Salary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt; — block_smb_user executed (name-mapping → nobody, volume perms 750):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;X:\&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# ACCESS DENIED — drive not accessible after block&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step Functions: Recovery Point Verification Workflow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fylt6hf8alz7c8h1132c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fylt6hf8alz7c8h1132c9.png" alt="Step Functions Graph View — execution in progress" width="800" height="828"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Step Functions console: All states succeeded (green). Verified-clean recovery point workflow completed end-to-end — waiting for FSx API to discover the ONTAP-created FlexClone. This is the ONTAP→FSx sync delay documented by AWS ("may take up to several minutes").&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Detection &amp;amp; Forensics: Datadog Dashboard
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63j7mjuqcmlig8vph1yl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63j7mjuqcmlig8vph1yl.png" alt="Datadog Forensics Dashboard" width="800" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Datadog Forensics Dashboard: Incident timeline (Detection → Response → Verification), user activity tracking, affected volumes, automated response actions log, ARP alert feed, and recovery verification results — all from a single pane.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffgzniwak3r55kpel3hot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffgzniwak3r55kpel3hot.png" alt="Datadog Log Explorer — Live ARP Detection" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Datadog Log Explorer: Real-time ARP detection events (&lt;code&gt;callhome.arw.activity.seen&lt;/code&gt;, &lt;code&gt;callhome.arw.volume.state&lt;/code&gt;) with structured attributes — entropy score, affected file count, new extensions detected.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb0946ot0sdf2l0p2gmvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb0946ot0sdf2l0p2gmvj.png" alt="Datadog Audit Trail — User + File Path" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;File Access Audit Trail: Who (CORP\jdoe) accessed what (/vol_data/finance/budget-2026.docx) with what operation (WriteData|Delete) — the same forensic visibility DII Storage Workload Security provides.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzlkgb1zumpusunw8q5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzlkgb1zumpusunw8q5o.png" alt="Datadog Audit Trail — Client IP" width="799" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scrolled right: Client IP (198.51.100.99) visible alongside the structured JSON content — enabling "who accessed what from where" forensic queries.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Vendor-neutral note&lt;/strong&gt;: The screenshots above use Datadog as a representative example, but this repository delivers the same logs to all 9 supported observability vendors (Datadog, Grafana, Splunk, Elastic, New Relic, Dynatrace, Sumo Logic, Honeycomb, OTel Collector). Deployable forensics dashboard definitions (user timeline, file access audit trail, affected volumes, client IP analysis) are provided for Datadog (JSON), Grafana (JSON), Splunk (SPL), and Elastic (KQL Saved Searches). See the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/native-alternative-matrix.md#forensics-dashboard--per-vendor-reference" rel="noopener noreferrer"&gt;per-vendor reference&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;The module has 52 unit tests covering:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Tests&lt;/th&gt;
&lt;th&gt;What's Verified&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SMB blocking&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Success, SVM not found, API error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SMB unblocking&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Success, not found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFS blocking&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Success, policy not found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFS unblocking&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Success, not found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snapshots&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Success, cooldown active/expired/disabled, volume not found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session disconnect&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;By user, no sessions, missing params&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composite actions&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Full sequence, partial failure, NFS containment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input validation&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Protected accounts, injection prevention, IP validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurable protected accounts&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PROTECTED_ACCOUNTS_EXTRA&lt;/code&gt; env var&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List blocks&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;With results, empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health check&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Success, SVM not found, unreachable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error handling&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Error attributes, timeout, malformed response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NACL blocking&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;Block IP, unblock, list active, find NACL, rule number allocation, marker validation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pytest shared/python/tests/test_ontap_response.py shared/python/tests/test_network_block.py &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;span class="c"&gt;# 52 passed in 0.06s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Your Deployment
&lt;/h3&gt;

&lt;p&gt;After deploying to your environment, run these checks within the first 30 days:&lt;/p&gt;

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

&lt;p&gt;If any of these fail, check the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/prerequisites.md#troubleshooting" rel="noopener noreferrer"&gt;Troubleshooting section in Prerequisites&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related Posts in This Series
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/aws-builders/why-your-fsx-for-ontap-audit-logs-deserve-better-than-ec2-kod"&gt;Part 1: Why Your FSx for ONTAP Audit Logs Deserve Better Than EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Part 3: Event-Driven Ransomware Detection with ONTAP ARP + Datadog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aws-builders/alerting-on-fsx-for-ontap-audit-logs-no-metric-filter-required-with-cloudwatch-log-alarms-15eg"&gt;Part 17: CloudWatch Log Alarms — No Metric Filter Required&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  EMS Webhook Integration: Payload Format
&lt;/h2&gt;

&lt;p&gt;When connecting ARP EMS events to your detection pipeline, note the &lt;strong&gt;actual&lt;/strong&gt; ONTAP EMS webhook payload format (verified on ONTAP 9.17.1P7D1):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message-name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"callhome.arw.activity.seen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message-severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message-timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-12T00:42:06+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vserver-name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"svm-prod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"volume-name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vol_data"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution&lt;/strong&gt;: Field names use &lt;strong&gt;hyphens&lt;/strong&gt; (&lt;code&gt;message-name&lt;/code&gt;), not camelCase (&lt;code&gt;messageName&lt;/code&gt;) or snake_case (&lt;code&gt;message_name&lt;/code&gt;). This matters for SIEM parsing rules and Lambda handler field validation.&lt;/p&gt;
&lt;/blockquote&gt;

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




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/python/ontap_response.py" rel="noopener noreferrer"&gt;GitHub: ontap_response.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/templates/automated-response.yaml" rel="noopener noreferrer"&gt;GitHub: automated-response.yaml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/automated-response-guide.md" rel="noopener noreferrer"&gt;GitHub: Automated Response Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/ontap-rest-api-reference.md" rel="noopener noreferrer"&gt;GitHub: ONTAP REST API Quick Reference&lt;/a&gt; — Common pitfalls (svm.uuid duplicate, allow_privileged_access, ARP/AI behaviors), verified on ONTAP 9.17.1P7D1&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/ems-detection-capabilities.md" rel="noopener noreferrer"&gt;GitHub: EMS Detection Capabilities&lt;/a&gt; — 30+ events, Push vs Pull delivery, latency comparison&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cyber-resilience-capability-map.md" rel="noopener noreferrer"&gt;GitHub: Cyber Resilience Capability Map&lt;/a&gt; — full NIST CSF 2.0 function mapping with FSx for ONTAP implementation and alternative implementation paths&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/verified-recovery-point-guide.md" rel="noopener noreferrer"&gt;GitHub: Verified-Clean Recovery Point Guide&lt;/a&gt; — FlexClone + isolated scan to verify a snapshot before restoring (CSF 2.0 RC.RP)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/content-classification-scanner.md" rel="noopener noreferrer"&gt;GitHub: Content-Level PII Classification Scanner&lt;/a&gt; — Amazon Comprehend-based PII discovery for file contents (CSF 2.0 Identify)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netapp.com/us-en/ontap-restapi/" rel="noopener noreferrer"&gt;NetApp: ONTAP REST API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/fsx/latest/ONTAPGuide/ARP.html" rel="noopener noreferrer"&gt;AWS: FSx for ONTAP ARP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nist.gov/cyberframework" rel="noopener noreferrer"&gt;NIST Cybersecurity Framework (CSF) 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://csrc.nist.gov/pubs/ir/8374/r1/final" rel="noopener noreferrer"&gt;NIST IR 8374r1 — Ransomware Risk Management: A CSF 2.0 Community Profile&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>observability</category>
      <category>aws</category>
      <category>serverless</category>
      <category>security</category>
    </item>
    <item>
      <title>Alerting on FSx for ONTAP Audit Logs — No Metric Filter Required, with CloudWatch Log Alarms</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Fri, 03 Jul 2026 16:15:43 +0000</pubDate>
      <link>https://dev.to/aws-builders/alerting-on-fsx-for-ontap-audit-logs-no-metric-filter-required-with-cloudwatch-log-alarms-15eg</link>
      <guid>https://dev.to/aws-builders/alerting-on-fsx-for-ontap-audit-logs-no-metric-filter-required-with-cloudwatch-log-alarms-15eg</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Once FSx for ONTAP audit logs land in CloudWatch Logs, a common next question is: &lt;em&gt;"How do I get alerted when someone touches a specific file?"&lt;/em&gt; Until recently you had to build a metric filter first. As of &lt;strong&gt;July 1, 2026&lt;/strong&gt;, &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/07/amazon-cloudwatch-log-alarms/" rel="noopener noreferrer"&gt;CloudWatch Log Alarms&lt;/a&gt; let you create an alarm &lt;strong&gt;directly from a Logs Insights query&lt;/strong&gt; — no metric filter step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch Log Alarm&lt;/strong&gt; (GA 2026-07-01): alarm straight from a log query. No metric filter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it works&lt;/strong&gt;: a Logs Insights query matches events, &lt;code&gt;count(*)&lt;/code&gt; turns them into a number, and the alarm fires when the count crosses a threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 detection presets&lt;/strong&gt;: sensitive-path access / failed access / bulk delete / privileged-user activity / custom.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-command deploy&lt;/strong&gt;: &lt;code&gt;bash shared/scripts/deploy-log-alarm.sh&lt;/code&gt; (working in ~15 minutes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt;: ~$6.6/month (100 MB/day). Slightly higher than the metric-filter approach, but you get log lines in the notification and retroactive queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E2E verified&lt;/strong&gt;: CloudFormation deploy through state transition, in the Tokyo region.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;Yoshiki0705/fsxn-observability-integrations&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is Part 17 of the &lt;a href="https://dev.to/aws-builders/why-your-fsx-for-ontap-audit-logs-deserve-better-than-ec2-kod"&gt;Serverless Observability for FSx for ONTAP&lt;/a&gt; series. It builds directly on the admin-audit pipeline from &lt;a href="https://dev.to/aws-builders/can-you-use-system-manager-with-fsx-for-ontap-a-reality-check-with-screenshots"&gt;Part 14&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two AWS Launches That Make This Work
&lt;/h2&gt;

&lt;p&gt;This article sits on top of &lt;strong&gt;two recent CloudWatch launches&lt;/strong&gt;. If you're arriving from outside this series, read these first — together they remove the EC2 syslog server &lt;em&gt;and&lt;/em&gt; the metric-filter step that used to stand between ONTAP logs and an alert.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Managed syslog ingestion (June 2026) — how the logs get in
&lt;/h3&gt;

&lt;p&gt;ONTAP emits its admin audit trail (and EMS events) as &lt;strong&gt;syslog&lt;/strong&gt;. Historically, capturing that meant running an EC2 syslog server. In June 2026, CloudWatch Logs added &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-cloudwatch-syslog-ingestion/" rel="noopener noreferrer"&gt;managed syslog ingestion&lt;/a&gt;: you send syslog (RFC 5424 / RFC 3164 / Cisco FTD/ASA) over a &lt;strong&gt;VPC endpoint&lt;/strong&gt; straight into a log group — no agent, no EC2.&lt;/p&gt;

&lt;p&gt;For FSx for ONTAP, that means pointing ONTAP &lt;code&gt;log-forwarding&lt;/code&gt; at the syslog VPC endpoint and having the admin audit log arrive in CloudWatch Logs directly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's New: &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-cloudwatch-syslog-ingestion/" rel="noopener noreferrer"&gt;Amazon CloudWatch Logs supports managed syslog ingestion&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Setup guide: &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_Syslog_Setup.html" rel="noopener noreferrer"&gt;Setting up syslog ingestion&lt;/a&gt; — VPC endpoint, log group, resource policy, and the three transport options (TCP+TLS 6514 encrypted, TCP 1514 plaintext, UDP 514 best-effort)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the piece the previous article (&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/syslog-vpce-setup-guide.md" rel="noopener noreferrer"&gt;Part 14 / Syslog VPCE setup&lt;/a&gt;) already wired up. If you followed it, your admin audit log is in CloudWatch Logs and this article's alarm has something to query.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. CloudWatch Log Alarms (July 2026) — how you alert on them
&lt;/h3&gt;

&lt;p&gt;The second launch is the subject of this article: alarms defined by a Logs Insights query rather than a metric.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's New: &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/07/amazon-cloudwatch-log-alarms/" rel="noopener noreferrer"&gt;Amazon CloudWatch supports creating alarms from log queries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Alarm-On-Logs.html" rel="noopener noreferrer"&gt;Alarming on logs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put together: &lt;strong&gt;ONTAP → managed syslog ingestion → CloudWatch Logs → Log Alarm → SNS&lt;/strong&gt;. No EC2, no metric filter, no forwarding Lambda.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;Alerting on log &lt;em&gt;content&lt;/em&gt; is a basic monitoring need. On CloudWatch it used to take a detour: create a metric filter, generate a custom metric from it, then attach an alarm to that metric — three steps. From "I want to detect this" to an alert actually firing was 15–30 minutes of setup.&lt;/p&gt;

&lt;p&gt;Log Alarms collapse the middle steps. You give a Logs Insights query a threshold, and the alarm reads straight from the logs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Before (metric filter)&lt;/th&gt;
&lt;th&gt;Log Alarm (NEW)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup steps&lt;/td&gt;
&lt;td&gt;3 (filter → metric → alarm)&lt;/td&gt;
&lt;td&gt;1 (Log Alarm only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query flexibility&lt;/td&gt;
&lt;td&gt;Filter pattern syntax only&lt;/td&gt;
&lt;td&gt;Full Logs Insights syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log lines in notification&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (up to 50)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retroactive to existing logs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IaC&lt;/td&gt;
&lt;td&gt;2 resources&lt;/td&gt;
&lt;td&gt;1 resource (&lt;code&gt;AWS::CloudWatch::LogAlarm&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The part I appreciate most: the notification can include the matched log lines. When the alert lands, you already see &lt;em&gt;who&lt;/em&gt; touched &lt;em&gt;which&lt;/em&gt; file and &lt;em&gt;what&lt;/em&gt; they did — you can form a first read before opening the console.&lt;/p&gt;




&lt;h2&gt;
  
  
  FSx for ONTAP Logs × Log Alarm
&lt;/h2&gt;

&lt;p&gt;There are three FSx for ONTAP log/event families, and it's worth separating them because only some are a natural fit for Log Alarms.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Log type&lt;/th&gt;
&lt;th&gt;What it records&lt;/th&gt;
&lt;th&gt;Delivery path&lt;/th&gt;
&lt;th&gt;Log Alarm target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Admin audit log&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ONTAP management ops (CLI / REST API)&lt;/td&gt;
&lt;td&gt;Managed syslog ingestion → CloudWatch Logs&lt;/td&gt;
&lt;td&gt;✅ this article&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File access audit log&lt;/td&gt;
&lt;td&gt;NAS file/folder ops (NFS / SMB)&lt;/td&gt;
&lt;td&gt;FSx for ONTAP S3 AP → Lambda&lt;/td&gt;
&lt;td&gt;Separate pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EMS events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ONTAP system events (capacity / HA / ARP)&lt;/td&gt;
&lt;td&gt;Managed syslog ingestion → CloudWatch Logs, or EMS Webhook → Lambda&lt;/td&gt;
&lt;td&gt;✅ when syslog-delivered&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Admin audit log&lt;/strong&gt; is the "who did what as an administrator" record — logins (success/failure), &lt;code&gt;security login&lt;/code&gt; account and role changes, &lt;code&gt;volume create/offline/delete&lt;/code&gt;, &lt;code&gt;vserver&lt;/code&gt; config changes, and privileged operations like &lt;code&gt;system node systemshell&lt;/code&gt; or &lt;code&gt;set -privilege diagnostic&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Two ONTAP settings, don't conflate them&lt;/strong&gt;: &lt;code&gt;security audit&lt;/code&gt; decides &lt;em&gt;what&lt;/em&gt; gets recorded (e.g., &lt;code&gt;security audit modify -cliget on -httpget on -ontapiget on&lt;/code&gt; to capture read/GET operations — off by default, so without it your &lt;code&gt;sensitive-file-access&lt;/code&gt; query on admin ops comes up empty), while &lt;code&gt;cluster log-forwarding&lt;/code&gt; decides &lt;em&gt;where&lt;/em&gt; it's sent. The exact commands are in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/syslog-vpce-setup-guide.md" rel="noopener noreferrer"&gt;Syslog VPCE setup guide&lt;/a&gt;. Note &lt;code&gt;cluster log-forwarding&lt;/code&gt; supports &lt;strong&gt;multiple destinations&lt;/strong&gt;, so you can add CloudWatch alongside an existing on-prem SIEM without cutting over.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;File access audit log&lt;/strong&gt; is the "which user did what to which file" record, enabled via &lt;code&gt;vserver audit create&lt;/code&gt; and emitted in Windows Security Event format (EVTX / XML). It's the right source for sensitive-folder access and mass-delete detection — but to use it with a Log Alarm you'd need a separate pipeline to land EVTX/XML into CloudWatch Logs. In this project, that content flows via the FSx for ONTAP S3 Access Point → Lambda path to each vendor instead.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Critical scoping (read before you trust a preset name)&lt;/strong&gt;: the presets in this article run against the &lt;strong&gt;admin audit log&lt;/strong&gt; (&lt;code&gt;/syslog/fsxn-admin-audit&lt;/code&gt;). That log contains &lt;strong&gt;management-plane&lt;/strong&gt; operations — it does &lt;strong&gt;not&lt;/strong&gt; see end-user file I/O over NFS/SMB. So on this log group:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bulk-delete-operations&lt;/code&gt; detects &lt;strong&gt;admin-plane&lt;/strong&gt; destructive ops (Snapshot delete, &lt;code&gt;volume offline/delete&lt;/code&gt;) — &lt;strong&gt;not&lt;/strong&gt; ransomware encrypting user files over SMB.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sensitive-file-access&lt;/code&gt; matches a path only when an &lt;strong&gt;admin command&lt;/strong&gt; references it — &lt;strong&gt;not&lt;/strong&gt; when a user opens that file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For &lt;strong&gt;user-file&lt;/strong&gt; ransomware/mass-delete/sensitive-access detection, use ONTAP &lt;strong&gt;ARP&lt;/strong&gt; (&lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Part 3&lt;/a&gt;) and &lt;strong&gt;FPolicy / file-access audit&lt;/strong&gt; (&lt;a href="https://dev.to/aws-builders/fpolicy-file-activity-pipeline-ontap-to-datadog-via-ecs-fargate-2ing"&gt;Part 4&lt;/a&gt;). The same preset works against a file-access-audit log group &lt;em&gt;if&lt;/em&gt; you land that data in CloudWatch Logs — but on &lt;code&gt;/syslog/fsxn-admin-audit&lt;/code&gt; it only sees the admin plane.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  EMS events (system events)
&lt;/h3&gt;

&lt;p&gt;The third source is &lt;strong&gt;EMS (Event Management System)&lt;/strong&gt; — ONTAP's internal system-event notifications. Where audit logs say "who did it", EMS says "what happened to the system", across seven severities (emergency → debug). Representative events this project normalizes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;arw.volume.state&lt;/code&gt; / &lt;code&gt;arw.vserver.state&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;alert&lt;/td&gt;
&lt;td&gt;ARP (Autonomous Ransomware Protection) state transition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;monitor.volume.full&lt;/code&gt; / &lt;code&gt;wafl.vol.full&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;alert&lt;/td&gt;
&lt;td&gt;Volume space exhaustion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wafl.quota.hardlimit.exceeded&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;Quota hard-limit exceeded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cf.fsm.takeoverStarted&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;alert&lt;/td&gt;
&lt;td&gt;HA takeover started&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;net.linkDown&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;alert&lt;/td&gt;
&lt;td&gt;Network link down&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;EMS has two routes. This project's EMS Webhook path (HTTPS → API Gateway → Lambda) normalizes and ships events to any vendor/OTLP. Alternatively, ONTAP 9.x can forward EMS over syslog (&lt;code&gt;event notification destination create -syslog ...&lt;/code&gt;) to the &lt;strong&gt;same&lt;/strong&gt; CloudWatch Logs syslog VPC endpoint you built for the admin audit log — no separate EC2 syslog server — and then EMS becomes a &lt;strong&gt;Log Alarm target&lt;/strong&gt; directly. If your need is "alert immediately on volume-full or an ARP state change", syslog-to-CloudWatch + a Log Alarm is the shortest path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FSx for ONTAP (ONTAP log-forwarding)
    │ Syslog TCP (TLS 6514)
    ▼
CloudWatch Logs managed syslog ingestion (VPC endpoint)
    │  → /syslog/fsxn-admin-audit
    │ Scheduled Query (5 min)
    ▼
CloudWatch Log Alarm
    │ count(*) &amp;gt; threshold → ALARM
    ▼
SNS → Email / Slack / PagerDuty (with log lines)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The actual log format
&lt;/h3&gt;

&lt;p&gt;Writing a Log Alarm query is easier if you know what the line looks like. A real admin-audit line in CloudWatch Logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;190&amp;gt;Jul  2 03:17:37 FsxId...-02: [kern_audit:info:6392]
...:: FsxId...:ssh :: &amp;lt;source-ip&amp;gt;:unknown ::
FsxId...:fsx-control-plane:admin ::
system node systemshell -node * -command "top -d 1 -s 1"
:: Success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads like an incantation, but everything is there: when, which protocol (ssh/http), from where (source IP), who (user), what (command), and the outcome (Success/Failure). A query usually just needs one of those.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why "Alert on a String" Actually Means "Count Then Compare"
&lt;/h2&gt;

&lt;p&gt;Worth recalling: a CloudWatch alarm compares a &lt;strong&gt;number&lt;/strong&gt; against a threshold. It is not natively a "fire when this string appears" trigger.&lt;/p&gt;

&lt;p&gt;So how does a Log Alarm alert on content? It turns the string into a number first. A Logs Insights query narrows to matching events, &lt;code&gt;count(*)&lt;/code&gt; converts them to a count, and the alarm fires when that count crosses the threshold. Read it as &lt;strong&gt;string → count → threshold&lt;/strong&gt; and it clicks.&lt;/p&gt;

&lt;p&gt;For example, to detect access to a confidential folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;like&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vol&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;confidential&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the aggregation to &lt;code&gt;count(*)&lt;/code&gt; and the threshold to &lt;code&gt;&amp;gt; 0&lt;/code&gt;, and a single access within the 5-minute window flips the alarm to ALARM. "Tell me the moment anyone touches the confidential folder" — done, with just that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;

&lt;p&gt;The repo ships a deploy script, so a few environment variables bring up the whole set of resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy script (recommended)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Sensitive-file access detection (auto-creates the SNS topic)&lt;/span&gt;
&lt;span class="nv"&gt;DETECTION_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sensitive-file-access &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;TARGET_PATTERN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/vol/data/confidential"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;CREATE_SNS_TOPIC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;SNS_TOPIC_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fsxn-security-alerts &lt;span class="se"&gt;\&lt;/span&gt;
  bash shared/scripts/deploy-log-alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script creates the SNS topic, deploys the CloudFormation stack, and prints the alarm name and console URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudFormation template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# shared/templates/cloudwatch-log-alarm.yaml (excerpt)&lt;/span&gt;
&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SensitiveFileAccessAlarm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::CloudWatch::LogAlarm&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AlarmName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fsxn-sensitive-file-access&lt;/span&gt;
      &lt;span class="na"&gt;ComparisonOperator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GreaterThanThreshold&lt;/span&gt;
      &lt;span class="na"&gt;Threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="na"&gt;QueryResultsToEvaluate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
      &lt;span class="na"&gt;QueryResultsToAlarm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;TreatMissingData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;notBreaching&lt;/span&gt;
      &lt;span class="na"&gt;ScheduledQueryConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;QueryString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;fields @timestamp, @message&lt;/span&gt;
          &lt;span class="s"&gt;| filter @message like /\/vol\/data\/confidential/&lt;/span&gt;
        &lt;span class="na"&gt;LogGroupIdentifiers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/syslog/fsxn-admin-audit&lt;/span&gt;
        &lt;span class="na"&gt;ScheduledQueryRoleARN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;ScheduledQueryRole.Arn&lt;/span&gt;
        &lt;span class="na"&gt;AggregationExpression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count(*)"&lt;/span&gt;
        &lt;span class="na"&gt;ScheduleConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ScheduleExpression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate(5&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;minutes)"&lt;/span&gt;
          &lt;span class="na"&gt;StartTimeOffset&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
      &lt;span class="na"&gt;AlarmActions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;AlarmSNSTopic&lt;/span&gt;
      &lt;span class="na"&gt;ActionLogLineCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;ActionLogLineRoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;LogLineRole.Arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;On &lt;code&gt;QueryResultsToEvaluate&lt;/code&gt; / &lt;code&gt;QueryResultsToAlarm&lt;/code&gt; (M-of-N)&lt;/strong&gt;: this is the flapping control — &lt;code&gt;3 / 1&lt;/code&gt; fires fast but can flap on a single spike; &lt;code&gt;3 / 2&lt;/code&gt; smooths transient blips at ~one extra interval of latency. Tune this &lt;em&gt;before&lt;/em&gt; the threshold. Per-use-case recommendations are in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#m-out-of-n-evaluation" rel="noopener noreferrer"&gt;setup guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detection presets
&lt;/h3&gt;

&lt;p&gt;The template ships five presets for common patterns. Switch &lt;code&gt;DetectionType&lt;/code&gt; and each gets an appropriate query and threshold.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DetectionType&lt;/th&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;Default threshold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sensitive-file-access&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Access to a specific path&lt;/td&gt;
&lt;td&gt;&amp;gt; 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;failed-access-attempts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authentication/authorization failures&lt;/td&gt;
&lt;td&gt;&amp;gt; 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bulk-delete-operations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mass deletion (ransomware signal)&lt;/td&gt;
&lt;td&gt;&amp;gt; 50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;specific-user-activity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Privileged-user monitoring&lt;/td&gt;
&lt;td&gt;&amp;gt; 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any Logs Insights query&lt;/td&gt;
&lt;td&gt;your choice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Regulated environments — one thing to get right first&lt;/strong&gt;: &lt;code&gt;ActionLogLineCount&lt;/code&gt; puts the matched log lines (usernames, file paths, client IPs — potentially &lt;strong&gt;PHI&lt;/strong&gt;) into the SNS notification, which leaves the CloudWatch boundary. For healthcare/finance/public-sector data, default to &lt;code&gt;ActionLogLineCount: 0&lt;/code&gt; and let responders pivot into Logs Insights for the detail. This is a detection &lt;em&gt;mechanism&lt;/em&gt;, not a compliance attestation — classify your fields and confirm APPI/FISC/ISMAP/HIPAA scope with your compliance team first. Full guidance, the regulated default, the alert-audit-trail requirements, and multi-account (StackSets) rollout are in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#regulated-environments-healthcare--finance--public-sector-default-to-actionloglinecount0" rel="noopener noreferrer"&gt;setup guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Admin-plane destructive-op detection (defense in depth)
&lt;/h3&gt;

&lt;p&gt;To be precise about scope: on the admin audit log this preset catches &lt;strong&gt;management-plane&lt;/strong&gt; destructive operations — a burst of Snapshot deletes, &lt;code&gt;volume offline&lt;/code&gt;, &lt;code&gt;volume delete&lt;/code&gt; — the kind of action an attacker with stolen admin credentials (or a mistaken operator) would take to remove recovery points. It does &lt;strong&gt;not&lt;/strong&gt; see user-file encryption over SMB; that's ONTAP ARP's job at the storage layer (&lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Part 3&lt;/a&gt;), with FPolicy (&lt;a href="https://dev.to/aws-builders/fpolicy-file-activity-pipeline-ontap-to-datadog-via-ecs-fargate-2ing"&gt;Part 4&lt;/a&gt;) for per-file operations. Layer all three: ARP for encryption, FPolicy for file ops, and this Log Alarm for admin-plane tampering (e.g., someone deleting the Snapshots you'd restore from).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DETECTION_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bulk-delete-operations &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;ALARM_THRESHOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;QUERY_RESULTS_TO_ALARM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;SNS_TOPIC_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_SNS_ARN&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  bash shared/scripts/deploy-log-alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Detection layer&lt;/th&gt;
&lt;th&gt;Catches&lt;/th&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Storage layer (ARP)&lt;/td&gt;
&lt;td&gt;User-file encryption&lt;/td&gt;
&lt;td&gt;ML-based entropy analysis&lt;/td&gt;
&lt;td&gt;Real-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File ops (FPolicy)&lt;/td&gt;
&lt;td&gt;Per-file create/write/delete/rename over NFS/SMB&lt;/td&gt;
&lt;td&gt;Protocol-level intercept&lt;/td&gt;
&lt;td&gt;~6 s (validated, Part 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin plane (Log Alarm)&lt;/td&gt;
&lt;td&gt;Snapshot/volume destructive ops by admins&lt;/td&gt;
&lt;td&gt;Count-based threshold on admin audit log&lt;/td&gt;
&lt;td&gt;~5 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three different vantage points on the same attack: ARP sees the encryption, FPolicy sees the file operations, and this Log Alarm sees an admin deleting the Snapshots you'd recover from. Layering them means whatever slips past one is more likely caught by another.&lt;/p&gt;

&lt;p&gt;In ATT&amp;amp;CK terms, that admin-plane view is &lt;strong&gt;T1490 Inhibit System Recovery&lt;/strong&gt; — an attacker deleting your restore points so you &lt;em&gt;can't&lt;/em&gt; roll back the encryption ARP detects (T1486). Two techniques, two controls: detect the Snapshot deletion here, and &lt;strong&gt;prevent&lt;/strong&gt; it with &lt;strong&gt;SnapLock&lt;/strong&gt; (WORM Snapshots that can't be deleted before expiry) so your recovery points survive the attempt. The full ATT&amp;amp;CK mapping, tamper-resistance guidance (who can delete the alarm and how to guard it), and a one-slide coverage map are in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#mitre-attck-mapping" rel="noopener noreferrer"&gt;setup guide&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ops note (baseline first)&lt;/strong&gt;: Scheduled bulk operations — nightly backups, batch ETL, archive cleanups — can legitimately exceed a "50 deletes / 5 min" threshold and page on-call for nothing. Baseline your normal delete volume for a few days &lt;em&gt;without&lt;/em&gt; an alarm action, then set the threshold above your routine peak (the exact baseline query is in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#baselining-a-threshold-before-enabling-bulk-delete-etc" rel="noopener noreferrer"&gt;setup guide&lt;/a&gt;). This mirrors the ARP learning-period caveat from &lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Part 3&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Compliance: notify on regulated-data access
&lt;/h3&gt;

&lt;p&gt;For finance or healthcare, where "any touch of this data must be recorded and notified", a simple per-path detection works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DETECTION_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sensitive-file-access &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;TARGET_PATTERN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/vol/finance/"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;ALARM_THRESHOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;SNS_TOPIC_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_SNS_ARN&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  bash shared/scripts/deploy-log-alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Alert-fatigue note&lt;/strong&gt;: A &lt;code&gt;&amp;gt; 0&lt;/code&gt; threshold on an actively-used path pages on every access and quickly becomes noise. Reserve &lt;code&gt;&amp;gt; 0&lt;/code&gt; for genuinely restricted paths (break-glass directories, quarantined data). For paths with legitimate regular access, prefer a rate threshold (e.g., access from an unexpected principal, or volume above a baseline) and route to a ticket/Slack channel rather than a pager.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Privileged-user monitoring
&lt;/h3&gt;

&lt;p&gt;Keeping a record of every admin-account action uses the same mechanism.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DETECTION_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;specific-user-activity &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;TARGET_PATTERN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"fsxadmin"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;ALARM_THRESHOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;SNS_TOPIC_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_SNS_ARN&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  bash shared/scripts/deploy-log-alarm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  E2E Validation (Tokyo Region)
&lt;/h2&gt;

&lt;p&gt;Because it's a brand-new feature, I was skeptical it would behave as documented. So I deployed the template in a real Tokyo-region environment and drove the alarm through a state transition.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CloudFormation deploy&lt;/td&gt;
&lt;td&gt;✅ Success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IAM role auto-creation&lt;/td&gt;
&lt;td&gt;✅ ScheduledQueryRole + LogLineRole&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduled Query execution&lt;/td&gt;
&lt;td&gt;✅ INSUFFICIENT_DATA → OK transition confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console display&lt;/td&gt;
&lt;td&gt;✅ Shown as "Log alarm" type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs Insights query&lt;/td&gt;
&lt;td&gt;✅ Matched (12 hits / 3,482 records scanned for &lt;code&gt;/volume/&lt;/code&gt;; 472 hits for &lt;code&gt;ssh&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In the console it shows up as a new &lt;strong&gt;"Log alarm"&lt;/strong&gt; type, distinct from the metric alarms you already have. In the screenshot below, look at the &lt;strong&gt;Type&lt;/strong&gt; column — the new alarm is labeled "Log alarm" rather than "Metric alarm".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2m5jq72v62fr1esptgbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2m5jq72v62fr1esptgbk.png" alt="CloudWatch Alarms list showing the new "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Opening the alarm shows the Log Alarm detail page. Note the &lt;strong&gt;query configuration&lt;/strong&gt; (the Logs Insights query string, the target log group &lt;code&gt;/syslog/fsxn-admin-audit&lt;/code&gt;, and the 5-minute schedule) and the &lt;strong&gt;two IAM roles&lt;/strong&gt; CloudFormation created automatically — &lt;code&gt;ScheduledQueryRole&lt;/code&gt; (runs the query) and &lt;code&gt;LogLineRole&lt;/code&gt; (attaches matched log lines to the notification).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nigc4xt75up2s6n7ci2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nigc4xt75up2s6n7ci2.png" alt="Log alarm detail page showing the Logs Insights query configuration, target log group, 5-minute schedule, and the auto-created ScheduledQueryRole and LogLineRole"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running the query in Logs Insights hits real audit data. The bar chart at the top shows the match count per interval, and the results table below lists the matched log lines — here the &lt;code&gt;/volume/&lt;/code&gt; filter returned &lt;strong&gt;12 matches across 3,482 records scanned&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fycyh5ms6ic4gxm4ffm9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fycyh5ms6ic4gxm4ffm9i.png" alt="Logs Insights query result for the /volume/ filter — 12 matches over 3,482 records scanned, with the match-count bar chart above the results table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The alarm itself stays &lt;strong&gt;OK&lt;/strong&gt; while there's no matching access — the screenshot shows the state after the initial &lt;code&gt;INSUFFICIENT_DATA → OK&lt;/code&gt; transition, with an empty history graph because nothing has crossed the threshold yet. With threshold &lt;code&gt;&amp;gt; 0&lt;/code&gt;, it flips to &lt;strong&gt;ALARM&lt;/strong&gt; the moment a single access to the sensitive path appears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0qt1ccmb072yhteghkbj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0qt1ccmb072yhteghkbj.png" alt="Log alarm detail page in state OK, showing the INSUFFICIENT_DATA to OK transition and a flat history graph below the threshold"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Audit trail of the alert itself&lt;/strong&gt;: for compliance you also need evidence that the alarm fired and who was notified. Alarm state history is retained &lt;strong&gt;90 days&lt;/strong&gt; (fixed); for multi-year evidence, route CloudWatch Alarm state-change events (EventBridge) to S3, and rely on CloudTrail for the "who configured this detection" record. Details and retention table: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#audit-trail-of-the-alert-itself" rel="noopener noreferrer"&gt;setup guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Gotchas
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gotcha&lt;/th&gt;
&lt;th&gt;Workaround&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS CLI not yet supported (no &lt;code&gt;put-log-alarm&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Use CloudFormation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cfn-lint E3006 (resource type not yet in the spec)&lt;/td&gt;
&lt;td&gt;Suppress per-resource (not a blanket disable); &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#caveats-discovered-during-validation" rel="noopener noreferrer"&gt;exact &lt;code&gt;Metadata&lt;/code&gt; snippet in the setup guide&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First evaluation takes 5–10 min&lt;/td&gt;
&lt;td&gt;Just wait&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notification includes log lines (PII/PHI risk)&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;ActionLogLineCount=0&lt;/code&gt; in regulated environments (see the callout above)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-node log streams (&lt;code&gt;FsxId...-01/-02&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Query the whole &lt;strong&gt;log group&lt;/strong&gt;, don't pin &lt;code&gt;@logStream&lt;/code&gt;, or you miss half the traffic on HA takeover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The "AWS CLI doesn't have &lt;code&gt;put-log-alarm&lt;/code&gt; yet" is a just-after-GA reality — for now CloudFormation or the console are the only creation paths. Platform/CoE note: drift detection won't cover a resource type the CLI can't yet describe, so treat CloudFormation as the single source of truth until the API surface completes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Rough estimate for &lt;strong&gt;one&lt;/strong&gt; alarm at a 5-minute cadence.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Logs/day&lt;/th&gt;
&lt;th&gt;Log Alarm&lt;/th&gt;
&lt;th&gt;Metric filter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;td&gt;~$6.6/month&lt;/td&gt;
&lt;td&gt;~$3/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500 MB&lt;/td&gt;
&lt;td&gt;~$33/month&lt;/td&gt;
&lt;td&gt;~$3/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;~$66/month&lt;/td&gt;
&lt;td&gt;~$3/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How the cost scales&lt;/strong&gt;: the table above is &lt;strong&gt;per alarm&lt;/strong&gt;. Each alarm runs its own Scheduled Query over the same log group, so cost is &lt;em&gt;alarms × cadence × scan size&lt;/em&gt; — ten alarms on one log group is ~10×, not a flat add-on. Narrow queries with &lt;code&gt;filter&lt;/code&gt;/&lt;code&gt;limit&lt;/code&gt; and consolidate related detections to keep it bounded. Full breakdown in the &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#how-cost-scales-read-before-fanning-out" rel="noopener noreferrer"&gt;setup guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Honestly, Log Alarms cost more than the metric-filter approach — the Scheduled Query scans logs on each run. But the difference is recoverable elsewhere: log lines in the notification cut investigation time, it applies retroactively to existing logs, and setup is a single step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When the premium is worth it&lt;/strong&gt; (a line you can put in a proposal): choose Log Alarms when the alert &lt;em&gt;content&lt;/em&gt; matters for triage (you want the matched lines in the page), when the detection query needs full Logs Insights syntax a metric filter can't express, or when you need to apply it retroactively to existing logs. Stick with metric filters for high-volume, well-understood, purely numeric signals where a few dollars × many alarms adds up. For most teams the crossover is engineer time: if the log-line context saves even one 15-minute console dig per incident, the premium pays for itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If volume makes cost a concern, dropping the cadence to 15 minutes cuts it to a third, and adding &lt;code&gt;limit&lt;/code&gt; to the query bounds the scan.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  When to Use Which
&lt;/h2&gt;

&lt;p&gt;Log Alarms aren't meant to replace every kind of monitoring. Depending on the need, metric filters or the OTel Collector fit better. Among this project's three delivery paths, the Log Alarm is the simplest entry point.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;th&gt;Extra infra&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Log Alarm&lt;/strong&gt; (this article)&lt;/td&gt;
&lt;td&gt;Simple threshold alerts&lt;/td&gt;
&lt;td&gt;None (self-contained in CloudWatch)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda → vendor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dashboards, SIEM&lt;/td&gt;
&lt;td&gt;Forwarding Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OTel Collector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-backend, PII redaction&lt;/td&gt;
&lt;td&gt;Forwarding Lambda + Collector (ECS Fargate)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Concretely, the OTel Collector path's "extra infra" is two layers: three forwarding Lambdas (audit-log shipper, EMS handler, FPolicy handler) sending OTLP/HTTP, plus a resident &lt;code&gt;otel/opentelemetry-collector-contrib&lt;/code&gt; task on ECS Fargate (with NAT Gateway for egress, Cloud Map for task IP resolution, ALB/autoscaling under load). Fan-out to Grafana/Honeycomb/Datadog and PII redaction are then a single change in the Collector's config YAML. The Log Alarm, by contrast, is the "everything stays inside CloudWatch" minimal option.&lt;/p&gt;

&lt;p&gt;A Log Alarm is a first alert, not a full investigation tool. Let it handle "notice it first", and hand off the deep dive to vendor tooling like Datadog or Splunk. That division of labor is the realistic one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For ONTAP operators&lt;/strong&gt;, the setup guide covers the storage-side specifics: what &lt;code&gt;security audit&lt;/code&gt; captures vs what &lt;code&gt;log-forwarding&lt;/code&gt; sends, keeping an existing SIEM alongside CloudWatch (multiple destinations), ONTAP EMS &lt;em&gt;native&lt;/em&gt; email/SNMP as an alternative to pushing to AWS, a dead-man's-switch heartbeat alarm for when syslog delivery stops, and DR-region deployment — &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md#security-audit--what-gets-captured" rel="noopener noreferrer"&gt;ONTAP operational notes&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Delete all Log Alarm stacks&lt;/span&gt;
bash shared/scripts/cleanup-log-alarm.sh &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;CloudWatch Log Alarms aren't a flashy feature. But "turn what you noticed in the logs straight into an alert" lowers the bar for setting up monitoring — you're done with one query before you'd have finished building a metric filter, staring at a metric, and wiring an alarm. It pairs well with FSx for ONTAP audit logs, answering the "I just want to notice it first" needs of storage security without extra infrastructure. There's some just-after-GA roughness (the AWS CLI hasn't caught up), but CloudFormation works today, verified in a real environment.&lt;/p&gt;

&lt;p&gt;Upcoming in the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phase 4&lt;/strong&gt;: Terraform module equivalents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phase 4&lt;/strong&gt;: CDK construct library&lt;/li&gt;
&lt;li&gt;PagerDuty escalation for CloudWatch alarms — see &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/pagerduty-escalation-guide.md" rel="noopener noreferrer"&gt;pagerduty-escalation-guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/ROADMAP.md" rel="noopener noreferrer"&gt;ROADMAP&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;github.com/Yoshiki0705/fsxn-observability-integrations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Template&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/templates/cloudwatch-log-alarm.yaml" rel="noopener noreferrer"&gt;cloudwatch-log-alarm.yaml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy script&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/shared/scripts/deploy-log-alarm.sh" rel="noopener noreferrer"&gt;deploy-log-alarm.sh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup guide (EN)&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/cloudwatch-log-alarm.md" rel="noopener noreferrer"&gt;cloudwatch-log-alarm.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runbook&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/runbooks/log-alarm-triggered.md" rel="noopener noreferrer"&gt;log-alarm-triggered.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Syslog VPCE setup&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations/blob/main/docs/en/syslog-vpce-setup-guide.md" rel="noopener noreferrer"&gt;syslog-vpce-setup-guide.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AWS references
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What's New — &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/07/amazon-cloudwatch-log-alarms/" rel="noopener noreferrer"&gt;CloudWatch supports creating alarms from log queries&lt;/a&gt; (2026-07)&lt;/li&gt;
&lt;li&gt;What's New — &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-cloudwatch-syslog-ingestion/" rel="noopener noreferrer"&gt;CloudWatch Logs supports managed syslog ingestion&lt;/a&gt; (2026-06)&lt;/li&gt;
&lt;li&gt;Docs — &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Alarm-On-Logs.html" rel="noopener noreferrer"&gt;Alarming on logs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs — &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_Syslog_Setup.html" rel="noopener noreferrer"&gt;Setting up syslog ingestion&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Series Navigation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 1&lt;/strong&gt;: &lt;a href="https://dev.to/aws-builders/why-your-fsx-for-ontap-audit-logs-deserve-better-than-ec2-kod"&gt;Why Your FSx for ONTAP Logs Deserve Better&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 3&lt;/strong&gt;: &lt;a href="https://dev.to/aws-builders/event-driven-ransomware-detection-with-ontap-arp-datadog-4cda"&gt;Event-Driven Ransomware Detection with ONTAP ARP + Datadog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 5&lt;/strong&gt;: &lt;a href="https://dev.to/aws-builders/escape-vendor-lock-in-multi-backend-log-delivery-with-otel-collector-for-fsx-for-ontap-2inb"&gt;Escape Vendor Lock-in with OTel Collector&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 13&lt;/strong&gt;: &lt;a href="https://dev.to/aws-builders/9-services-one-architecture-what-we-learned-shipping-fsx-for-ontap-logs-to-every-major-19ig"&gt;9 Vendors, One Architecture&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 14&lt;/strong&gt;: &lt;a href="https://dev.to/aws-builders/can-you-use-system-manager-with-fsx-for-ontap-a-reality-check-with-screenshots"&gt;Can You Use System Manager with FSx for ONTAP?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 17&lt;/strong&gt;: Alerting on Audit Logs with CloudWatch Log Alarms (this post)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;If you deploy this, I'd love to hear how it went — drop a comment or open a GitHub issue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;github.com/Yoshiki0705/fsxn-observability-integrations&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>security</category>
      <category>observability</category>
    </item>
    <item>
      <title>42 Patterns, Category Architecture, and HA LifeKeeper Monitoring — FSx for ONTAP S3 Access Points, Phase 18</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Sun, 21 Jun 2026 16:54:22 +0000</pubDate>
      <link>https://dev.to/aws-builders/42-patterns-category-architecture-and-ha-lifekeeper-monitoring-fsx-for-ontap-s3-access-points-4fh</link>
      <guid>https://dev.to/aws-builders/42-patterns-category-architecture-and-ha-lifekeeper-monitoring-fsx-for-ontap-s3-access-points-4fh</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Phase 18 restructures the entire repository from 41 flat directories into a categorized &lt;code&gt;solutions/&lt;/code&gt; hierarchy, adds &lt;strong&gt;HA LifeKeeper Monitoring&lt;/strong&gt; as a new pattern category, introduces &lt;strong&gt;5 category-specific architecture diagrams&lt;/strong&gt;, and establishes modern Python project infrastructure. The repository now contains &lt;strong&gt;42 deployable patterns&lt;/strong&gt; organized for discoverability at scale.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns" rel="noopener noreferrer"&gt;github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Restructure?
&lt;/h2&gt;

&lt;p&gt;With 41 pattern directories at the repository root, navigating the project had become unwieldy. New contributors could not quickly find patterns by domain, the README required extensive scrolling, and adding new categories (HA, GenAI) had no clear placement convention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (flat)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;legal-compliance/  financial-idp/  semiconductor-eda/  sap-erp-adjacent/
flexcache-anycast-dr/  genai-kb-selfservice-curation/  event-driven-fpolicy/
... (41 directories at root)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (categorized)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;solutions/
├── industry/           # 28 UC patterns (UC1-UC28)
├── flexcache/          # 7 FlexCache/FlexClone patterns
├── genai/              # 2 GenAI patterns (UC29-UC30)
├── sap/                # SAP/ERP pattern
├── ha/                 # HA monitoring (new)
├── event-driven/       # 2 FPolicy event-driven patterns
└── edge/               # CDN/edge delivery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Move: git mv with History Preservation
&lt;/h2&gt;

&lt;p&gt;All 41 directories were moved using &lt;code&gt;git mv&lt;/code&gt;, preserving full commit history. Key renames include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Old Path&lt;/th&gt;
&lt;th&gt;New Path&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sap-erp-adjacent/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solutions/sap/erp-adjacent/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Category grouping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dynamic-flexcache-render-workflow/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solutions/flexcache/dynamic-render-workflow/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shorter name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;genai-kb-selfservice-curation/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solutions/genai/kb-selfservice-curation/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strip prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;devops-flexclone-cicd/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solutions/flexcache/devops-cicd/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strip prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;content-edge-delivery/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solutions/edge/content-delivery/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Category grouping&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use &lt;code&gt;git log --follow &amp;lt;file&amp;gt;&lt;/code&gt; to trace history across the move.&lt;/p&gt;




&lt;h2&gt;
  
  
  HA LifeKeeper Monitoring — New Pattern
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SIOS LifeKeeper&lt;/strong&gt; is a Linux/Windows HA clustering solution that can be used on Amazon EC2 for application-aware failover scenarios. With FSx for ONTAP Multi-AZ as shared storage (NFS/iSCSI, depending on OS and configuration), this pattern focuses on observing LifeKeeper logs without putting monitoring agents on the HA nodes.&lt;/p&gt;

&lt;p&gt;The new HA pattern (&lt;code&gt;solutions/ha/lifekeeper-monitoring/&lt;/code&gt;) provides &lt;strong&gt;non-intrusive&lt;/strong&gt; log analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TB
    subgraph "HA Cluster"
        LK1[LifeKeeper Node 1&amp;lt;br/&amp;gt;Active]
        LK2[LifeKeeper Node 2&amp;lt;br/&amp;gt;Standby]
    end

    subgraph "Shared Storage"
        FSXN[FSx for ONTAP Multi-AZ]
        S3AP[S3 Access Point&amp;lt;br/&amp;gt;Read-only log access]
    end

    subgraph "Analysis Pipeline"
        SFN[Step Functions]
        DISC[Discovery Lambda&amp;lt;br/&amp;gt;Log classification]
        PROC[Processing Lambda&amp;lt;br/&amp;gt;Bedrock Root Cause Analysis]
        RPT[Report Lambda&amp;lt;br/&amp;gt;Health score + alerts]
    end

    LK1 --&amp;gt;|Log write| FSXN
    FSXN --&amp;gt; S3AP --&amp;gt;|Non-intrusive read| DISC
    SFN --&amp;gt; DISC --&amp;gt; PROC --&amp;gt; RPT
    PROC --&amp;gt;|Nova Pro| BEDROCK[Amazon Bedrock]
    RPT --&amp;gt; SNS[SNS Alert]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Design Decisions
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Non-intrusive to HA nodes&lt;/strong&gt;: No monitoring agent is installed on HA nodes. The S3 AP read path avoids host-level changes, while still consuming FSx/S3 API throughput like any other read workload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop&lt;/strong&gt;: AI analysis is advisory only. LifeKeeper's own health checks handle failover decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Scoring&lt;/strong&gt;: 0-100 score with deductions for failover events, comm path latency, and resource state anomalies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root Cause Analysis&lt;/strong&gt;: Bedrock Nova Pro analyzes state transitions (ISP→OSF, ISS→ISP) to identify likely causes.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Implementation note&lt;/strong&gt;: This pattern observes LifeKeeper logs and produces advisory analysis. It does not replace LifeKeeper cluster design, quorum/witness configuration, split-brain prevention, protocol-specific recovery kit setup, or application-level failover testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example Operational Metrics
&lt;/h3&gt;

&lt;p&gt;These are suggested evaluation metrics for future validation. Phase 18 verifies the DemoMode pipeline, not real-cluster failover triage time.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Demo Target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operations&lt;/td&gt;
&lt;td&gt;Time from workflow start to structured triage report&lt;/td&gt;
&lt;td&gt;&amp;lt; 10 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technical&lt;/td&gt;
&lt;td&gt;Log discovery completeness&lt;/td&gt;
&lt;td&gt;All configured LifeKeeper log paths in scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quality&lt;/td&gt;
&lt;td&gt;False positive alert rate&lt;/td&gt;
&lt;td&gt;&amp;lt; 5% (requires real-cluster validation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Monthly monitoring cost&lt;/td&gt;
&lt;td&gt;&amp;lt; $15 (5-min polling, 1 cluster)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Deploy (DemoMode)
&lt;/h3&gt;

&lt;p&gt;DemoMode=true deploys without FSx for ONTAP — uses a regular S3 bucket with sample LifeKeeper logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;solutions/ha/lifekeeper-monitoring
sam build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sam deploy &lt;span class="nt"&gt;--guided&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="nv"&gt;DemoMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;S3AccessPointAlias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-demo-bucket &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;OutputBucketName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-output-bucket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DemoMode verification confirms: SAM template deploys successfully, Step Functions workflow executes all states, Discovery Lambda classifies sample logs correctly, and Processing Lambda generates a health score report. Bedrock analysis produces structured, advisory observations based on log patterns; failover decisions remain outside the AI workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn9j5gotqqo5ddnaasfyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn9j5gotqqo5ddnaasfyn.png" alt="Step Functions graph view — HA LifeKeeper Monitoring workflow completed successfully" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verified in ap-northeast-1 on 2026-06-21. The sample log set intentionally contains failure-like events, resulting in a demo health score of 40/100. The score is not a benchmark for LifeKeeper or FSx for ONTAP; it demonstrates that the scoring pipeline detects and reports anomalies from sample logs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Coming in Phase 19&lt;/strong&gt;: Full E2E verification with a real SIOS LifeKeeper HA cluster (AWS Marketplace + FSx for ONTAP Multi-AZ) including live failover testing, actual state transition detection, and Bedrock RCA quality assessment against real-world failure scenarios.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Category Architecture Diagrams
&lt;/h2&gt;

&lt;p&gt;Phase 18 adds &lt;strong&gt;5 mermaid architecture diagrams&lt;/strong&gt; to README.md (both JA and EN), each in a collapsible &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; block:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Key Components&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🏭 FlexCache&lt;/td&gt;
&lt;td&gt;ONTAP REST API → HealthCheck → RouteDecision → DynamoDB routing → Create/Cleanup lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🤖 GenAI&lt;/td&gt;
&lt;td&gt;FPolicy → SQS → EventBridge → Bedrock KB → RetrieveAndGenerate / Agentic tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛡️ HA&lt;/td&gt;
&lt;td&gt;S3 AP non-intrusive read → Bedrock RCA → Health score → SNS alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ Event-Driven&lt;/td&gt;
&lt;td&gt;FPolicy Engine → ECS Fargate TCP → SQS → EventBridge rule routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌐 Edge/CDN&lt;/td&gt;
&lt;td&gt;3 delivery modes (ORIGIN_PULL, OAC, PUBLISH_PUSH) → vendor-neutral CDN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All diagrams include &lt;code&gt;accTitle&lt;/code&gt; and &lt;code&gt;accDescr&lt;/code&gt; for screen reader accessibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Infrastructure Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pyproject.toml (PEP 621)
&lt;/h3&gt;

&lt;p&gt;Modern Python project metadata with unified tool configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[tool.ruff]&lt;/span&gt;
&lt;span class="py"&gt;target-version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"py312"&lt;/span&gt;
&lt;span class="py"&gt;line-length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;

&lt;span class="nn"&gt;[tool.pytest.ini_options]&lt;/span&gt;
&lt;span class="py"&gt;addopts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"-v --tb=short --import-mode=importlib"&lt;/span&gt;

&lt;span class="nn"&gt;[tool.coverage.report]&lt;/span&gt;
&lt;span class="py"&gt;fail_under&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dependency Pinning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# requirements.txt — exact versions for reproducibility
&lt;/span&gt;&lt;span class="py"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=1.43.29&lt;/span&gt;
&lt;span class="py"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=2.7.0&lt;/span&gt;
&lt;span class="py"&gt;jsonschema&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=4.17.3&lt;/span&gt;

&lt;span class="c"&gt;# requirements-dev.txt
&lt;/span&gt;&lt;span class="py"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=9.1.0&lt;/span&gt;
&lt;span class="py"&gt;hypothesis&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=6.155.2&lt;/span&gt;
&lt;span class="py"&gt;moto&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=5.2.2&lt;/span&gt;
&lt;span class="py"&gt;ruff&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=0.15.17&lt;/span&gt;
&lt;span class="py"&gt;cfn-lint&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;=1.51.4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .cfnlintrc
&lt;/h3&gt;

&lt;p&gt;Project-wide cfn-lint configuration that discovers all templates under &lt;code&gt;solutions/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;templates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;solutions/**/template.yaml"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;solutions/**/template-deploy.yaml"&lt;/span&gt;
&lt;span class="na"&gt;ignore_checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;W3002&lt;/span&gt;  &lt;span class="c1"&gt;# Local CodeUri (sam build handles upload)&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;W1031&lt;/span&gt;  &lt;span class="c1"&gt;# Fn::Sub false positive with Secrets Manager ARNs&lt;/span&gt;
&lt;span class="na"&gt;regions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ap-northeast-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Additional Tooling
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.gitattributes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Consistent line endings, language-specific diff drivers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.github/PULL_REQUEST_TEMPLATE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Project-specific PR checklist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;solutions/README.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Category navigation index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep a Changelog format, all releases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CONTRIBUTING.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Adding a New Pattern" section with category guide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  CI/CD Changes
&lt;/h2&gt;

&lt;p&gt;The CI pipeline was split to avoid pytest &lt;code&gt;importlib&lt;/code&gt; mode namespace collisions when multiple patterns with identically-named &lt;code&gt;handler.py&lt;/code&gt; files are collected together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before: single pytest invocation (collision risk)&lt;/span&gt;
&lt;span class="s"&gt;pytest shared/tests/ solutions/**/tests/ --cov=shared&lt;/span&gt;

&lt;span class="c1"&gt;# After: isolated invocations&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run shared tests with coverage&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest shared/tests/ --cov=shared&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run pattern tests&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest solutions/industry/*/tests/ solutions/flexcache/*/tests/ ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also added &lt;code&gt;persist-credentials: false&lt;/code&gt; to all &lt;code&gt;actions/checkout&lt;/code&gt; steps (zizmor security hardening).&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-Perspective Review
&lt;/h2&gt;

&lt;p&gt;The restructuring and HA monitoring pattern were reviewed from partner delivery, storage architecture, HA operations, security, CI/CD, accessibility, and contributor onboarding perspectives. The review resulted in wording changes around neutrality, operational caveats, connector validation, HA safety boundaries, and repository discoverability.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Means for You
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Partner / SI / delivery team&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pattern selection is now intuitive by category — pick &lt;code&gt;solutions/industry/&lt;/code&gt; for industry PoCs, &lt;code&gt;solutions/flexcache/&lt;/code&gt; for distributed workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;New contributor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CONTRIBUTING.md&lt;/code&gt; now includes "Adding a New Pattern" with required checklist and category selection guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Existing repository users&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git log --follow &amp;lt;file&amp;gt;&lt;/code&gt; still works. &lt;code&gt;sam build&lt;/code&gt; and &lt;code&gt;sam deploy&lt;/code&gt; are unchanged (run from the pattern directory)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero changes needed in your &lt;code&gt;samconfig.toml&lt;/code&gt; or deployment scripts — CodeUri is relative to template.yaml&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure cost&lt;/strong&gt;: Zero. This is a repository organization change; it does not deploy AWS resources by itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Phase 16-17 blog articles (GenAI patterns) — ready to publish&lt;/li&gt;
&lt;li&gt;dev.to series updated for directory restructuring (Phase 13 link fixed)&lt;/li&gt;
&lt;li&gt;Next pattern candidates under evaluation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns.git
&lt;span class="nb"&gt;cd &lt;/span&gt;FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns

&lt;span class="c"&gt;# Browse patterns by category&lt;/span&gt;
&lt;span class="nb"&gt;ls &lt;/span&gt;solutions/

&lt;span class="c"&gt;# Deploy HA LifeKeeper monitoring (DemoMode)&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;solutions/ha/lifekeeper-monitoring
sam build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sam deploy &lt;span class="nt"&gt;--guided&lt;/span&gt; &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="nv"&gt;DemoMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Run tests&lt;/span&gt;
make test-quick &lt;span class="nv"&gt;PYTHON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.venv/bin/python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Yoshiki Fujiwara&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lifekeeper</category>
      <category>amazonfsxfornetappontap</category>
      <category>s3accesspoints</category>
    </item>
    <item>
      <title>Amazon Quick Agentic Workspace Powered by FSx for ONTAP S3 Access Points — Phase 17</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Sun, 21 Jun 2026 15:54:23 +0000</pubDate>
      <link>https://dev.to/aws-builders/amazon-quick-agentic-workspace-powered-by-fsx-for-ontap-s3-access-points-phase-17-1cf2</link>
      <guid>https://dev.to/aws-builders/amazon-quick-agentic-workspace-powered-by-fsx-for-ontap-s3-access-points-phase-17-1cf2</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;UC30 bridges the gap between file-based business data and AI-powered actions. Business users maintain structured and unstructured data on an FSx for ONTAP SMB share, while &lt;strong&gt;Amazon Quick&lt;/strong&gt; (Index / Sight / Flows) consumes it through S3 Access Points and a serverless Action API — providing search, BI, and governed action workflows from a single workspace.&lt;/p&gt;

&lt;p&gt;Where UC29 focuses on "self-service knowledge ingestion into Bedrock KB," UC30 focuses on &lt;strong&gt;unifying search, analytics, and action execution&lt;/strong&gt; behind Quick Suite's agentic interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New in this release&lt;/strong&gt;: &lt;code&gt;generate_brief_with_web&lt;/code&gt; action augments internal context with real-time web search results via AgentCore Web Search Tool (GA June 2026), enabling briefs that combine primary internal data with current public context.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns" rel="noopener noreferrer"&gt;github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns&lt;/a&gt; (see &lt;code&gt;solutions/genai/quick-agentic-workspace/&lt;/code&gt; and &lt;code&gt;samconfig.toml.example&lt;/code&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Amazon Quick × S3 AP Data Mapping
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quick Feature&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;S3 AP Data&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Quick Index / Research&lt;/td&gt;
&lt;td&gt;Unstructured file search&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;index/&amp;lt;role&amp;gt;/&lt;/code&gt; (md/pdf)&lt;/td&gt;
&lt;td&gt;S3 AP as data source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick Sight&lt;/td&gt;
&lt;td&gt;Structured BI &amp;amp; visualization&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;analytics/&amp;lt;role&amp;gt;/&lt;/code&gt; (csv)&lt;/td&gt;
&lt;td&gt;Glue/Athena (Athena Query Lambda)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick Flows&lt;/td&gt;
&lt;td&gt;Action automation&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;flows/&amp;lt;role&amp;gt;/&lt;/code&gt; (json)&lt;/td&gt;
&lt;td&gt;Action API (API Gateway + Lambda + Bedrock)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick Flows + Web&lt;/td&gt;
&lt;td&gt;Web-augmented briefs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;flows/&amp;lt;role&amp;gt;/&lt;/code&gt; + web&lt;/td&gt;
&lt;td&gt;Action API + AgentCore Web Search (opt-in)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Seven roles (sales / marketing / finance / IT / operations / legal / developers) share the same AI-dedicated volume — reusable from UC29.&lt;/p&gt;

&lt;p&gt;Design note: FSx for ONTAP S3 Access Points are useful as an integration boundary, but they do not remove the need to validate each consuming service connector. The access path combines S3/IAM policy evaluation with file-system-level identity authorization.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc9f2071r5vmlyf5xjobl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc9f2071r5vmlyf5xjobl.png" alt="Amazon Quick home screen showing Index, Sight, and Flows" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Amazon Quick provides a unified workspace — search (Index), BI (Sight), and action automation (Flows) — powered by FSx for ONTAP data via S3 Access Points.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows Explorer (drag &amp;amp; drop into quick-workspace/ SMB share)
  ├── index/&amp;lt;role&amp;gt;/ → Quick Index (unstructured search)
  ├── analytics/&amp;lt;role&amp;gt;/ → Glue/Athena → Quick Sight (BI)
  └── flows/&amp;lt;role&amp;gt;/ → Action API → Quick Flows (actions)

Action API (6 actions):
  API Gateway (IAM auth / SigV4)
  → Lambda (per-action authorization + HITL gate)
  → generate_brief           → Bedrock Converse (internal context only)
  → generate_brief_with_web  → Bedrock Converse + AgentCore Web Search (hybrid)
  → create_action_item       → SNS notification
  → request_approval         → DynamoDB (HITL entry)
  → approve                  → DynamoDB (admin only)
  → execute_approved         → DynamoDB check + execution (enforced HITL)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hybrid RAG Flow (generate_brief_with_web)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Quick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Flows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;request:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate_brief_with_web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;├─→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Internal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;params.context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;FSx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ONTAP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;content)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;├─→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AgentCore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Web&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(us-east&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;MCP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;protocol)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;params.web_query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;params.title&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Amazon&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;web&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;snippets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;URLs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;titles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dates&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;└─→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bedrock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Converse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(ap-northeast&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="err"&gt;system&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;prompt:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;internal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;primary,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;web&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;supplementary,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;untrusted&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Unified&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brief&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;Internal:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;Web:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;title&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;(URL)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;citations&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Security Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication + Per-Action Authorization
&lt;/h3&gt;

&lt;p&gt;The Action API uses IAM authentication (SigV4). The handler extracts the &lt;strong&gt;authenticated caller identity&lt;/strong&gt; (&lt;code&gt;requestContext.identity&lt;/code&gt;) — not self-declared body fields — and performs per-action authorization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ACTION_AUTH_MODE=open&lt;/code&gt; (default/demo): No enforcement; audit fields still bound to authenticated caller&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For production, use &lt;code&gt;ACTION_AUTH_MODE=enforce&lt;/code&gt; and explicitly define &lt;code&gt;AUTHORIZED_PRINCIPALS&lt;/code&gt; and &lt;code&gt;ADMIN_PRINCIPALS&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ACTION_AUTH_MODE=enforce&lt;/code&gt; (production):

&lt;ul&gt;
&lt;li&gt;Read-only actions (&lt;code&gt;generate_brief&lt;/code&gt;, &lt;code&gt;generate_brief_with_web&lt;/code&gt;): always allowed&lt;/li&gt;
&lt;li&gt;Mutating actions: caller must match &lt;code&gt;AUTHORIZED_PRINCIPALS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Admin actions (&lt;code&gt;approve&lt;/code&gt;): caller must match &lt;code&gt;ADMIN_PRINCIPALS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mismatch → &lt;strong&gt;403 Forbidden&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Enforced Human-in-the-Loop (HITL)
&lt;/h3&gt;

&lt;p&gt;High-risk operations are gated by a DynamoDB approval store:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;request_approval&lt;/code&gt; → persists record as &lt;code&gt;pending_approval&lt;/code&gt; (enforced=true)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;approve&lt;/code&gt; → admin transitions to &lt;code&gt;approved&lt;/code&gt; (ConditionExpression prevents race)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;execute_approved&lt;/code&gt; → &lt;strong&gt;only executes if record is &lt;code&gt;approved&lt;/code&gt;&lt;/strong&gt;; otherwise 409&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verified live: execute pre-approval → 409, post-approval → 200, re-execute → 409 (no replay).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: Approval records have a &lt;strong&gt;7-day TTL&lt;/strong&gt; (DynamoDB Time-to-Live). Stale pending approvals auto-expire, preventing indefinite accumulation of unreviewed requests. Expired records cannot be approved or executed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Additional Controls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt injection defense&lt;/strong&gt;: Both &lt;code&gt;generate_brief&lt;/code&gt; and &lt;code&gt;generate_brief_with_web&lt;/code&gt; treat context as untrusted data with explicit delimiter boundaries (&lt;code&gt;&amp;lt;internal_context&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;web_search_results&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web query safety&lt;/strong&gt;: Only &lt;code&gt;params.web_query&lt;/code&gt; or &lt;code&gt;params.title&lt;/code&gt; is sent to Web Search — never internal document content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raw SQL disabled by default&lt;/strong&gt;: &lt;code&gt;ALLOW_RAW_SQL=false&lt;/code&gt;; role-level data boundaries enforced via Lake Formation (LF-TBAC) in production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Results bucket hardening&lt;/strong&gt;: PublicAccessBlock + TLS-only + 30-day lifecycle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API throttling&lt;/strong&gt;: Rate/burst limits against denial-of-wallet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Search citation obligation&lt;/strong&gt;: Source URLs + titles are always included in responses (Acceptable Use Policy compliance)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Web-Augmented Brief Generation (opt-in)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;GA at AWS Summit NYC 2026 (June 17, 2026). Powered by AgentCore Web Search Tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Business briefs based solely on internal documents lack current market context. A sales brief about a product launch needs both the internal product spec &lt;em&gt;and&lt;/em&gt; awareness of relevant public announcements published recently. A legal compliance brief needs both the internal policy document &lt;em&gt;and&lt;/em&gt; the latest regulatory guidance.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;A new action &lt;code&gt;generate_brief_with_web&lt;/code&gt; combines internal context with real-time web search results. The internal context remains the primary source; web results are supplemental, cited, and treated as untrusted input.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate_brief_with_web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q3 Data Protection Regulatory Update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Internal operations follow FISC safety standards..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"web_query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data protection regulation 2026 Japan financial services"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate_brief_with_web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Q3 Data Protection Regulatory Update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"brief"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Based on internal FISC compliance documentation... Additionally, [Web: FISC 2026 Revision Summary](https://example.com/fisc) published on 2026-06-10 introduces..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"web_citations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/fisc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FISC 2026 Revision Summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"publishedDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-06-10"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"web_search_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"guardrail_applied"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Design Properties
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Internal context priority&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internal documents are the primary source; web supplements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graceful degradation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web Search failure → behaves like &lt;code&gt;generate_brief&lt;/code&gt; (internal only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Citation separation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internal sources and web sources are visually distinct in the brief&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Query safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only the &lt;code&gt;web_query&lt;/code&gt; (or &lt;code&gt;title&lt;/code&gt;) is sent externally — never internal content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cross-region&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gateway in us-east-1 (Web Search Tool constraint); adds ~100-200ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Authorization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read-only action (same tier as &lt;code&gt;generate_brief&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompt injection defense&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web results wrapped in &lt;code&gt;&amp;lt;web_search_results&amp;gt;&lt;/code&gt; as untrusted data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Activation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam deploy &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;EnableWebSearch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;gateway-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayRegion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Without these parameters, &lt;code&gt;generate_brief_with_web&lt;/code&gt; still works but produces internal-only briefs (graceful degradation).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Verification Findings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lake Formation + Athena
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9oksuqa5wmygv9o6ny04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9oksuqa5wmygv9o6ny04.png" alt="Athena recent queries showing UC30 quick-workspace queries" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Athena queries running against Glue tables backed by S3 AP data — the foundation for Quick Sight analytics.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgha9svhpx9xrhjg3ikgv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgha9svhpx9xrhjg3ikgv.png" alt="CloudFormation stack deployed for UC30" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The UC30 CloudFormation stack with all resources (API Gateway, Lambda, DynamoDB ApprovalsTable, Athena WorkGroup) deployed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The test account had Lake Formation governing the Data Catalog. The Athena Query Lambda's execution role required &lt;strong&gt;Lake Formation permission grants&lt;/strong&gt; (DESCRIBE on DB, SELECT/DESCRIBE on tables) in addition to IAM. Production deployments should design LF-TBAC for role-based data visibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon Quick × FSx for ONTAP S3 AP Integration Boundary
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpnv0byog65u1pkl7wr0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpnv0byog65u1pkl7wr0v.png" alt="Quick S3 Knowledge Base connection attempt with FSx for ONTAP S3 AP alias" width="799" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Amazon Quick's S3 KB connector accepts the S3 AP alias but authorization fails due to FSx for ONTAP's dual-layer auth — leading to the recommendation below.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fahj08qvya1cxlg6bs68v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fahj08qvya1cxlg6bs68v.png" alt="Quick Knowledge integrations panel" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Quick provides multiple data integration paths — for FSx for ONTAP data, Bedrock KB (UC29) or Athena-mediated access is the validated route in this repository.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Amazon Quick's S3 knowledge base connector accepts an FSx for ONTAP S3 AP alias as a "valid URL," but connection verification fails with &lt;em&gt;"You do not have permissions to access the S3 bucket."&lt;/em&gt; This is &lt;strong&gt;not&lt;/strong&gt; a missing IAM permission that can be simply added — it is a structural authorization path mismatch. Three factors block the standard connector path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ARN format mismatch&lt;/strong&gt; — FSx for ONTAP S3 APs use &lt;code&gt;arn:aws:s3:{region}:{account}:accesspoint/{name}&lt;/code&gt; (not the &lt;code&gt;arn:aws:s3:::{bucket}&lt;/code&gt; format). The connector's internal IAM evaluation likely targets the alias as a bucket name, which does not match IAM policy evaluation for the AP ARN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AP resource policy rejects the principal&lt;/strong&gt; — Adding Quick's data access role to the S3 AP resource policy returns &lt;code&gt;MalformedPolicy: Invalid principal in policy&lt;/code&gt;, indicating a principal constraint on FSx for ONTAP S3 AP policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer 2: filesystem identity&lt;/strong&gt; — Even if IAM layers were resolved, the ONTAP file-system identity (UNIX UID or AD user) associated with the S3 AP must independently permit read access to the target files.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For readers attempting this path&lt;/strong&gt;: Use CloudTrail to capture the exact &lt;code&gt;AccessDenied&lt;/code&gt; event and identify Quick's calling principal ARN. If the &lt;code&gt;MalformedPolicy&lt;/code&gt; constraint can be resolved (potentially by configuring the S3 AP with an AD-based identity rather than UNIX root), the direct path may become viable. As of June 2026, &lt;strong&gt;Bedrock Knowledge Base → FSx for ONTAP S3 AP&lt;/strong&gt; is the confirmed working route for RAG ingestion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Evidence-based implementation guidance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FSx for ONTAP → RAG&lt;/strong&gt;: Bedrock KB (UC29) is the validated path in this repository&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick Index&lt;/strong&gt;: Stage to a standard S3 bucket for predictable connector behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick Sight (BI)&lt;/strong&gt;: Athena-mediated access works (QuickSight role needs Athena/Glue/LF/results-bucket permissions)&lt;/li&gt;
&lt;li&gt;Direct Quick → FSx for ONTAP S3 AP (standard connector path): &lt;strong&gt;validated — does not work&lt;/strong&gt; (tested with UNIX root identity; &lt;code&gt;MalformedPolicy&lt;/code&gt; on AP resource policy). AD-based S3 AP identity configuration is tracked as a future hypothesis&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Glue Tables
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;analytics/&amp;lt;role&amp;gt;/&lt;/code&gt; CSVs are pointed to by Glue tables (&lt;code&gt;sales_pipeline&lt;/code&gt; / &lt;code&gt;it_incidents&lt;/code&gt;) created via Athena DDL. LOCATION uses S3 AP alias format: &lt;code&gt;s3://&amp;lt;alias&amp;gt;/quick-workspace/analytics/&amp;lt;role&amp;gt;/&lt;/code&gt;. For scale, migrate to Parquet + partitioning to reduce Athena scanned costs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Classification
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Classification&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action API response (generate_brief)&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Source-derived summary; no external disclosure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action API response (generate_brief_with_web)&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Contains internal citations; web portion is PUBLIC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Action API response (create/approve/execute)&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Business operation records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Athena query results (results bucket)&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Encrypted + 30-day lifecycle + TLS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB ApprovalsTable&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Approval state metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNS notifications&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Action summaries only; no file content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Search results (raw)&lt;/td&gt;
&lt;td&gt;PUBLIC&lt;/td&gt;
&lt;td&gt;External public information&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Extend &lt;code&gt;shared/data_classification.py&lt;/code&gt; for regulated workloads (CUI / FISC / HIPAA).&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Monthly estimate&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Quick&lt;/td&gt;
&lt;td&gt;Per-user/plan billing&lt;/td&gt;
&lt;td&gt;Separate; unsubscribe when done&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Athena&lt;/td&gt;
&lt;td&gt;Scanned-data pricing&lt;/td&gt;
&lt;td&gt;Reduce with Parquet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda / API Gateway&lt;/td&gt;
&lt;td&gt;Serverless pay-per-use&lt;/td&gt;
&lt;td&gt;&amp;lt; $10 for moderate usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock LLM (briefs)&lt;/td&gt;
&lt;td&gt;Usage-based&lt;/td&gt;
&lt;td&gt;Usage-based; verify the current model price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB (approvals)&lt;/td&gt;
&lt;td&gt;Pay-per-request&lt;/td&gt;
&lt;td&gt;Minimal for approval records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Budgets alarm&lt;/td&gt;
&lt;td&gt;Free (SNS delivery cost only)&lt;/td&gt;
&lt;td&gt;Created when &lt;code&gt;NotificationEmail&lt;/code&gt; set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AgentCore Web Search (opt-in)&lt;/td&gt;
&lt;td&gt;Per-query pricing (see &lt;a href="https://aws.amazon.com/bedrock/agentcore/pricing/" rel="noopener noreferrer"&gt;AgentCore pricing&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Gateway invocation pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-region transfer (opt-in)&lt;/td&gt;
&lt;td&gt;&amp;lt; $0.02&lt;/td&gt;
&lt;td&gt;us-east-1 ↔ ap-northeast-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Teardown / rebuild: one-command idempotent scripts (&lt;code&gt;scripts/teardown-uc29-uc30.sh&lt;/code&gt; / &lt;code&gt;scripts/rebuild-uc29-kb.py&lt;/code&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns.git
&lt;span class="nb"&gt;cd &lt;/span&gt;FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/solutions/genai/quick-agentic-workspace

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt        &lt;span class="c"&gt;# or: uv pip install -r requirements.txt&lt;/span&gt;

&lt;span class="nb"&gt;cat &lt;/span&gt;samconfig.toml.example  &lt;span class="c"&gt;# Review parameters&lt;/span&gt;

sam build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sam deploy &lt;span class="nt"&gt;--guided&lt;/span&gt;

&lt;span class="c"&gt;# DemoMode=true runs without FSx for ONTAP (regular S3 bucket)&lt;/span&gt;

&lt;span class="c"&gt;# Optional: Enable Web Search hybrid RAG&lt;/span&gt;
sam deploy &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;EnableWebSearch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;gateway-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayRegion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Governance Note
&lt;/h2&gt;

&lt;p&gt;This article is technical architecture guidance, not legal, compliance, or regulatory advice. Amazon Quick features, pricing, regional availability, and connector behavior are subject to change — verify with official documentation and your own account settings. S3 AP data source boundaries are at volume/prefix granularity. For per-user visibility control, use Quick's document-level ACL or Custom Permission-Aware RAG. Web Search Tool usage requires compliance with the Acceptable Use Policy (source citations must be retained and displayed in end-user output).&lt;/p&gt;




&lt;p&gt;Yoshiki Fujiwara&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonquick</category>
      <category>amazonfsxfornetappontap</category>
      <category>s3accesspoints</category>
    </item>
    <item>
      <title>Amazon Bedrock Knowledge Bases + FSx for ONTAP S3 Access Points: Self-Service AI Curation via Windows Drag &amp; Drop — Phase 16</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Sun, 21 Jun 2026 15:19:58 +0000</pubDate>
      <link>https://dev.to/aws-builders/amazon-bedrock-knowledge-bases-fsx-for-ontap-s3-access-points-self-service-ai-curation-via-3poe</link>
      <guid>https://dev.to/aws-builders/amazon-bedrock-knowledge-bases-fsx-for-ontap-s3-access-points-self-service-ai-curation-via-3poe</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;"Put files in this Windows folder and your AI assistant can use them after the next governed sync" — UC29 reduces the handoff friction around enterprise AI knowledge updates. Business users maintain Amazon Bedrock Knowledge Base content through &lt;strong&gt;Windows Explorer drag &amp;amp; drop&lt;/strong&gt; on an FSx for ONTAP SMB share. No S3 console, no ETL, no copy. Data remains in the file system as the operational source; the S3 Access Point provides a governed access path for ingestion without creating a separate object copy.&lt;/p&gt;

&lt;p&gt;Three maturity stages + one opt-in enhancement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scenario A (manual)&lt;/strong&gt;: User places files → triggers sync from console/CLI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario B (scheduled)&lt;/strong&gt;: EventBridge Scheduler + Step Functions poll every 15 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario C (event-driven)&lt;/strong&gt;: FPolicy detects file placement → real-time KB sync&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid RAG (opt-in)&lt;/strong&gt;: Internal KB answers augmented with real-time web search via AgentCore Web Search Tool (GA June 2026)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vector store: &lt;strong&gt;Amazon S3 Vectors&lt;/strong&gt; — a managed, cost-aware vector store option for Bedrock Knowledge Bases, with metadata filtering available for permission-aware retrieval designs.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns" rel="noopener noreferrer"&gt;github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns&lt;/a&gt; (see &lt;code&gt;solutions/genai/kb-selfservice-curation/&lt;/code&gt; and &lt;code&gt;samconfig.toml.example&lt;/code&gt; for deployment parameters)&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Pattern?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Challenge&lt;/th&gt;
&lt;th&gt;Traditional approach&lt;/th&gt;
&lt;th&gt;This pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge updates blocked on IT&lt;/td&gt;
&lt;td&gt;Ticket → manual ETL&lt;/td&gt;
&lt;td&gt;Business user drags &amp;amp; drops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dual management (NAS + S3 copy)&lt;/td&gt;
&lt;td&gt;Source drifts from S3 replica&lt;/td&gt;
&lt;td&gt;S3 AP reads the single source directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forgotten re-ingestion&lt;/td&gt;
&lt;td&gt;Manual and easy to forget&lt;/td&gt;
&lt;td&gt;Automatic (Scenario B/C)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specialist skills required&lt;/td&gt;
&lt;td&gt;ETL / S3 / Bedrock expertise&lt;/td&gt;
&lt;td&gt;Familiar Windows folder operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answers limited to internal docs&lt;/td&gt;
&lt;td&gt;No current external context&lt;/td&gt;
&lt;td&gt;Hybrid RAG: internal + web search (opt-in)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector store cost&lt;/td&gt;
&lt;td&gt;OpenSearch Serverless ~$175/month minimum&lt;/td&gt;
&lt;td&gt;S3 Vectors: cost-aware pay-per-use profile&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Users drag files into an &lt;strong&gt;AI-dedicated NTFS volume&lt;/strong&gt; (SMB share, ACL-separated by department) on FSx for ONTAP. The same volume is exposed via S3 Access Point as a Bedrock Knowledge Base data source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F33ekl3ijq81dutipoo8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F33ekl3ijq81dutipoo8a.png" alt="Windows Explorer showing the SMB share with 7 role-based folders (sales, marketing, finance, IT, operations, legal, developers)" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Users see a familiar Windows folder structure — each department has its own folder with NTFS ACL separation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqemain6saj2aiwikq8tt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqemain6saj2aiwikq8tt.png" alt="Product catalog files placed via drag &amp;amp; drop in the sales/product-catalog folder" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drag &amp;amp; drop a product spec into the sales folder — that is the only content-maintenance step for the user.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows Explorer (drag &amp;amp; drop)
  → FSx for ONTAP volume (ai_knowledge/)
  → S3 Access Point (read-only, internet-origin)
  → Bedrock Knowledge Base Data Source (inclusionPrefixes: ai-knowledge/)
  → StartIngestionJob → S3 Vectors (vector store) updated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seven business roles (sales / marketing / finance / IT / operations / legal / developers) share the volume with NTFS ACL-based permission separation.&lt;/p&gt;

&lt;p&gt;Design note: S3 Access Points for FSx for ONTAP let S3-compatible AWS services access file data without copying it to an S3 bucket. Access is authorized twice: first through AWS/IAM policies on the access point path, and then through the file-system identity and permissions associated with the access point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid RAG Flow (opt-in)
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;EnableWebSearch=true&lt;/code&gt;, the Query Lambda augments internal KB answers with real-time web information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User question
  ├─→ [1] Bedrock KB RetrieveAndGenerate (internal docs via S3 AP → S3 Vectors)
  ├─→ [2] AgentCore Web Search (us-east-1, cross-region MCP call)
  │       Amazon-operated web index (tens of billions of docs, continuously updated)
  └─→ [3] Bedrock Converse → unified answer with dual citations
            [Internal: product-spec.pdf] + [Web: Market Report 2026](https://...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Scenario B: Scheduled Automation (Step Functions)
&lt;/h2&gt;

&lt;p&gt;The most common production deployment. EventBridge Scheduler triggers a Step Functions workflow every 15 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EventBridge Scheduler (rate(15 minutes))
  └─→ Step Functions State Machine
       ├─→ DetectAndStartIngestion Lambda
       │     • ListObjectsV2 via S3 AP → compare with last-known state
       │     • If changes detected → StartIngestionJob
       │     • If no changes → skip (cost-zero run)
       ├─→ Wait (30s) → CheckIngestionStatus Lambda (poll loop)
       └─→ NotifySuccess / NotifyFailure → SNS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key design choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Differential detection&lt;/strong&gt;: Compares current S3 AP listing against prior state; only triggers ingestion when files actually changed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent&lt;/strong&gt;: Re-running the same schedule with no file changes is a no-op (no wasted Bedrock ingestion cost)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observable&lt;/strong&gt;: Each Step Functions execution is visible in the console with per-state timing and error details&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurable interval&lt;/strong&gt;: The &lt;code&gt;ScheduleExpression&lt;/code&gt; parameter accepts any EventBridge rate/cron expression&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the &lt;strong&gt;required safety net&lt;/strong&gt; for Scenario C (see below) — it catches any files missed during the lost-update window.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scenario C: FPolicy Event-Driven Real-Time Sync
&lt;/h2&gt;

&lt;p&gt;Scenario B's 15-minute polling is replaced by FPolicy real-time detection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows/NFS file operation
  → FPolicy instant detection (CREATE/WRITE/DELETE/RENAME)
  → FPolicy Server → SQS → Bridge Lambda → EventBridge custom bus
  → EventBridge Rule (file_path prefix = ai_knowledge)
  → KB Trigger Lambda (debounce) → StartIngestionJob
  → Bedrock KB → reflected in tens of seconds to minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The FPolicy → SQS → EventBridge front-end reuses the existing &lt;code&gt;solutions/event-driven/fpolicy&lt;/code&gt; pattern infrastructure. UC29 adds only an EventBridge rule and the KB Trigger Lambda.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lost-Update Window (Critical)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcto6v8g44h5ttfkw8kcn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcto6v8g44h5ttfkw8kcn.png" alt="EventBridge rule filtering FPolicy events for ai_knowledge prefix" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The EventBridge rule routes only FPolicy events matching the &lt;code&gt;ai_knowledge&lt;/code&gt; volume path to the KB Trigger Lambda.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Bedrock Ingestion performs a full-source scan at job start time. Files added &lt;em&gt;during&lt;/em&gt; a running job are &lt;strong&gt;not&lt;/strong&gt; included in that execution. Scenario C alone does &lt;strong&gt;not&lt;/strong&gt; guarantee zero missed files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mandatory&lt;/strong&gt;: Always pair Scenario C with Scenario B (periodic reconcile sync) as a safety net. The KB Trigger Lambda skips when a job is already in progress (debounce + ConflictException handling + reserved concurrency = 2).&lt;/p&gt;

&lt;h3&gt;
  
  
  Namespace Pitfall
&lt;/h3&gt;

&lt;p&gt;FPolicy reports ONTAP volume-path namespace (&lt;code&gt;ai_knowledge/...&lt;/code&gt;, underscore). The KB S3 ingestion prefix (&lt;code&gt;ai-knowledge/&lt;/code&gt;, hyphen) is a &lt;strong&gt;different&lt;/strong&gt; namespace. Initial implementation confused the two, causing false-skip. The EventBridge rule and Lambda secondary filter now use a dedicated &lt;code&gt;FPOLICY_PATH_FILTER&lt;/code&gt; parameter for the volume-path namespace.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hybrid RAG: Internal KB + Web Search (opt-in)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;GA at AWS Summit NYC 2026 (June 17, 2026). Powered by AgentCore Web Search Tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enterprise knowledge from FSx for ONTAP is treated as the primary internal source, while public web context is supplemental and untrusted. For questions that benefit from current external context — regulatory updates, market trends, public market information — the Query Lambda can optionally augment answers with real-time web search results.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Internal KB retrieval&lt;/strong&gt; (always): Bedrock KB searches S3 Vectors for relevant chunks from FSx for ONTAP documents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web search&lt;/strong&gt; (opt-in): AgentCore Gateway invokes Amazon's purpose-built web index via MCP protocol&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified answer&lt;/strong&gt;: Bedrock Converse merges both contexts, with internal documents as primary source&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Key Design Decisions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Opt-in&lt;/strong&gt; (&lt;code&gt;EnableWebSearch=false&lt;/code&gt; default)&lt;/td&gt;
&lt;td&gt;Most enterprise QA needs internal data only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graceful degradation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web Search failure → internal-only answer (no error surfaced to user)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Cross-region&lt;/strong&gt; (us-east-1 Gateway)&lt;/td&gt;
&lt;td&gt;Web Search Tool is us-east-1 only; adds ~100-200ms latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Query safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only user's question text is sent to Web Search — never internal document content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Citation separation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[Internal: filename]&lt;/code&gt; vs &lt;code&gt;[Web: title](URL)&lt;/code&gt; — users see exactly which source informed each claim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prompt injection defense&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web results wrapped in &lt;code&gt;&amp;lt;web_search_results&amp;gt;&lt;/code&gt; with explicit "untrusted data" instruction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Acceptable Use compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Source URLs and titles are always displayed (Web Search Tool TOS requirement)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sam deploy &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;EnableWebSearch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;gateway-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayRegion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What are the latest FISC guidelines for cloud data protection?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"answer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Based on internal documentation, our current FISC compliance posture covers... Additionally, [Web: FISC 2026 Guidelines Update](https://example.com/fisc-2026) published last month introduces..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"citations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3://.../legal/compliance/fisc-overview.pdf"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"web_citations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/fisc-2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FISC 2026 Guidelines Update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"web_search_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Verification Highlights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Windows-Identity S3 Access Point with Dedicated AD
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5yiskgokk293fm3z0nru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5yiskgokk293fm3z0nru.png" alt="Windows Explorer Quick Access showing mapped FSx for ONTAP SMB share" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Windows EC2 domain-joined to AWS Managed Microsoft AD, with the FSx SMB share mapped — proving the literal drag &amp;amp; drop experience works end to end.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate the literal Windows drag &amp;amp; drop experience, we built a dedicated AWS Managed Microsoft AD + domain-joined Windows EC2 + AD-joined SVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AD-joined SVM OU&lt;/strong&gt;: AWS Managed AD's &lt;code&gt;OU=Computers&lt;/code&gt; lacks delegation rights → use the domain-name OU (&lt;code&gt;OU=&amp;lt;domain&amp;gt;,DC=...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CIFS share creation&lt;/strong&gt;: Executes against the &lt;strong&gt;filesystem management LIF&lt;/strong&gt;, not the SVM LIF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows-identity S3 AP&lt;/strong&gt;: Works correctly with a running dedicated AD; files dropped in Explorer are readable via S3 AP&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deletion Lifecycle
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsen1lqx0ufp2p8a5l7hd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsen1lqx0ufp2p8a5l7hd.png" alt="Bedrock KB data source showing Sync button and ingestion status" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Bedrock KB data source connected to the FSx for ONTAP S3 AP alias. Click "Sync" for manual ingestion, or let Scenario B/C automate it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F022n7bjwsbny601zthha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F022n7bjwsbny601zthha.png" alt="Step Functions execution graph — all states succeeded" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scenario B's Step Functions workflow: detect changes → start ingestion → poll status → notify on completion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"User deletes a file → AI forgets it" verified end-to-end: file deletion → next sync → &lt;code&gt;numberOfDocumentsDeleted=1&lt;/code&gt; → re-query returns "no information found". Powered by &lt;code&gt;dataDeletionPolicy=DELETE&lt;/code&gt;. For urgent revocation between syncs, call the Ingestion API directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared bandwidth&lt;/strong&gt;: S3 AP reads share the FSx throughput capacity (128/256/512 MBps) with NFS/SMB workloads. Scenario B's 15-minute interval and Scenario C's reserved concurrency (2) throttle ingestion flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bulk re-index&lt;/strong&gt;: For full re-ingestion (e.g., embedding model change), use a &lt;strong&gt;FlexClone volume&lt;/strong&gt; as the Ingestion target — zero impact on production I/O, consistent point-in-time read&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiering&lt;/strong&gt;: Frequently accessed AI knowledge should remain on the SSD tier. Capacity Pool retrieval latency affects GetObject time during ingestion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Search latency&lt;/strong&gt;: Cross-region call to us-east-1 adds ~100-200ms. Total hybrid query latency depends on KB size, model, and network conditions (KB retrieve + Web Search + Converse generation)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Access Control — Three Layers
&lt;/h2&gt;

&lt;p&gt;S3 AP boundaries are volume/prefix-level. For per-user visibility:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Search narrowing&lt;/strong&gt; = Bedrock KB metadata filters (this UC; not AWS authorization)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document-level ACL&lt;/strong&gt; = Amazon Quick S3 Knowledge Base (UC30; user/group-level)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunk-level permission filter&lt;/strong&gt; = Custom Permission-Aware RAG (FC3; AD SID/NTFS ACL for regulated industries)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Web Search results are public information — no ACL filtering needed. However, the &lt;strong&gt;unified answer&lt;/strong&gt; that combines internal + web sources is subject to the same access control as internal-only answers (the internal citations remain permission-scoped).&lt;/p&gt;




&lt;h2&gt;
  
  
  Vector Store: Why S3 Vectors
&lt;/h2&gt;

&lt;p&gt;This pattern uses &lt;strong&gt;Amazon S3 Vectors&lt;/strong&gt; as the Bedrock KB vector store. OpenSearch Serverless remains a valid option when its operational and latency profile fits the workload better.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;OpenSearch Serverless&lt;/th&gt;
&lt;th&gt;S3 Vectors&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Minimum monthly cost&lt;/td&gt;
&lt;td&gt;~$175 (2 OCU)&lt;/td&gt;
&lt;td&gt;Pay-per-use only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost at scale&lt;/td&gt;
&lt;td&gt;OCU-based&lt;/td&gt;
&lt;td&gt;Cost savings for large vector datasets (see AWS documentation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metadata filtering&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Supported (department, owner, role)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permission-Aware RAG compatibility&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;Compatible with metadata-filtered retrieval designs; authorization enforced by application layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure management&lt;/td&gt;
&lt;td&gt;Managed but OCU scaling required&lt;/td&gt;
&lt;td&gt;Managed vector operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;Millions of vectors&lt;/td&gt;
&lt;td&gt;2 billion vectors per index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query latency&lt;/td&gt;
&lt;td&gt;Sub-100ms&lt;/td&gt;
&lt;td&gt;Sub-100ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this project — 28 industry patterns + PoC-to-production lifecycle — S3 Vectors' pay-per-use model is the right fit. We evaluated Bedrock Managed Knowledge Base (GA June 2026, AWS Summit NYC) but chose Custom KB + S3 Vectors for cost control, ACL metadata flexibility, and FSx for ONTAP lifecycle integration (see ADR: &lt;code&gt;docs/investigations/managed-kb-vs-custom-kb-s3vectors.md&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Classification
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Classification&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;KB vectors + metadata&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Inherits source file classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ingestion job status / SNS&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Operational metadata only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudWatch Metrics / Logs&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Aggregate metrics, no file content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Search results&lt;/td&gt;
&lt;td&gt;PUBLIC&lt;/td&gt;
&lt;td&gt;External public information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid answer (internal + web)&lt;/td&gt;
&lt;td&gt;INTERNAL&lt;/td&gt;
&lt;td&gt;Contains internal document citations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For regulated workloads (CUI / FISC / HIPAA), extend &lt;code&gt;shared/data_classification.py&lt;/code&gt; labels. If retention-period requirements apply, use &lt;code&gt;dataDeletionPolicy=RETAIN&lt;/code&gt; and design a separate purge procedure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Monthly estimate&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lambda (sync + query)&lt;/td&gt;
&lt;td&gt;&amp;lt; $5&lt;/td&gt;
&lt;td&gt;Serverless pay-per-use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 API (ListObjects, GetObject)&lt;/td&gt;
&lt;td&gt;&amp;lt; $1&lt;/td&gt;
&lt;td&gt;S3 AP reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventBridge Scheduler&lt;/td&gt;
&lt;td&gt;&amp;lt; $1&lt;/td&gt;
&lt;td&gt;15-min interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock KB Ingestion&lt;/td&gt;
&lt;td&gt;Usage-based&lt;/td&gt;
&lt;td&gt;Per-document embedding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 Vectors&lt;/td&gt;
&lt;td&gt;Usage-based&lt;/td&gt;
&lt;td&gt;Compare with OpenSearch Serverless for your query volume, latency, and operations requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bedrock LLM (query)&lt;/td&gt;
&lt;td&gt;Usage-based&lt;/td&gt;
&lt;td&gt;Nova Pro: $0.0008/1K input tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FPolicy Server (Scenario C)&lt;/td&gt;
&lt;td&gt;~$35&lt;/td&gt;
&lt;td&gt;ECS Fargate (set desiredCount=0 when idle)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AgentCore Web Search (opt-in)&lt;/td&gt;
&lt;td&gt;Per-query pricing (see &lt;a href="https://aws.amazon.com/bedrock/agentcore/pricing/" rel="noopener noreferrer"&gt;AgentCore pricing&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Gateway invocation pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-region transfer (opt-in)&lt;/td&gt;
&lt;td&gt;&amp;lt; $0.02&lt;/td&gt;
&lt;td&gt;us-east-1 ↔ ap-northeast-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Yoshiki0705/FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns.git
&lt;span class="nb"&gt;cd &lt;/span&gt;FSx-for-ONTAP-S3AccessPoints-Serverless-Patterns/solutions/genai/kb-selfservice-curation

&lt;span class="c"&gt;# Install dependencies (shared modules used by Lambda handlers)&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt        &lt;span class="c"&gt;# or: uv pip install -r requirements.txt&lt;/span&gt;

&lt;span class="c"&gt;# Review parameters&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;samconfig.toml.example

&lt;span class="c"&gt;# Build and deploy (requires configured AWS credentials + FSx for ONTAP S3 AP)&lt;/span&gt;
sam build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sam deploy &lt;span class="nt"&gt;--guided&lt;/span&gt;

&lt;span class="c"&gt;# DemoMode=true runs without FSx for ONTAP (regular S3 bucket)&lt;/span&gt;

&lt;span class="c"&gt;# Optional: Enable Web Search hybrid RAG&lt;/span&gt;
sam deploy &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;EnableWebSearch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;gateway-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;AgentCoreGatewayRegion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Governance Note
&lt;/h2&gt;

&lt;p&gt;This article is technical architecture guidance, not legal, compliance, or regulatory advice. Pricing, regional availability, and benchmark numbers are time-sensitive; verify them against current AWS documentation before production use. S3 AP data source boundaries are at volume/prefix granularity — for per-user visibility control, consider Custom Permission-Aware RAG. If retention-period requirements (NARA / FISC) apply, use &lt;code&gt;dataDeletionPolicy=RETAIN&lt;/code&gt; and design purge procedures separately. Web Search Tool usage requires compliance with the Acceptable Use Policy (source citations must be displayed).&lt;/p&gt;




&lt;p&gt;Yoshiki Fujiwara&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonbedrock</category>
      <category>amazonfsxfornetappontap</category>
      <category>s3accesspoints</category>
    </item>
    <item>
      <title>From Logs to Detection: Building a File Security Pipeline in Datadog for FSx for ONTAP</title>
      <dc:creator>Yoshiki Fujiwara(藤原 善基)@AWS Community Builder</dc:creator>
      <pubDate>Sun, 14 Jun 2026 16:44:19 +0000</pubDate>
      <link>https://dev.to/aws-builders/from-logs-to-detection-building-a-file-security-pipeline-in-datadog-for-fsx-for-ontap-2262</link>
      <guid>https://dev.to/aws-builders/from-logs-to-detection-building-a-file-security-pipeline-in-datadog-for-fsx-for-ontap-2262</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For security teams&lt;/strong&gt;: Four threshold monitors + one ML anomaly monitor + four Cloud SIEM detection rules catch mass file deletion, data exfiltration, permission tampering, and unusual geography in under 5 minutes. EventID codes become human-readable operation names. All created via Datadog API — no manual clicking required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For engineers&lt;/strong&gt;: The Log Pipeline (6 processors including GeoIP enrichment) transforms raw ONTAP XML events into searchable, alertable fields. Five Saved Views cover the most common investigation patterns. Total AWS cost remains ~$1.50/month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For architects&lt;/strong&gt;: This pattern demonstrates the full detection-to-response lifecycle — from raw file system audit events through enrichment, categorization, alerting, cross-service correlation, and automated remediation — entirely serverless, entirely as code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FSx for ONTAP → S3 Access Point → Lambda → Datadog Logs API v2
                                              │
                                              ▼
                                   ┌──────────────────────┐
                                   │ Log Pipeline (6)     │
                                   │  • Category Processor│
                                   │  • Status Remapper   │
                                   │  • Date Remapper     │
                                   │  • Attribute Remapper│
                                   │  • GeoIP Enrichment  │
                                   └──────────┬───────────┘
                                              │
                          ┌───────────────────┼───────────────────┐
                          ▼                   ▼                   ▼
                ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
                │ Log Monitors (4)│ │ Cloud SIEM (4)  │ │ Log Archive     │
                │ + Anomaly (1)   │ │ Security Signals│ │ → S3 → Glacier  │
                └────────┬────────┘ └────────┬────────┘ └─────────────────┘
                         │                   │
                         ▼                   ▼
                ┌──────────────────────────────────────┐
                │ Workflow → Slack + Case + Lambda     │
                │          (ONTAP Snapshot remediation)│
                └──────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reading guide&lt;/strong&gt;: Sections 1-9 cover the core pipeline (30 min to deploy). Sections 10+ cover advanced SOC integration (additional 15 min). Jump to Deployment if you want to start immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business value&lt;/strong&gt;: This pipeline reduces mean-time-to-detect (MTTD) for file-based threats from "hours/days" (batch log review) to under 5 minutes (real-time alerting). For regulated environments, it provides continuous compliance evidence with automated archival — replacing manual quarterly reviews with always-on monitoring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is Part 16 of &lt;a href="https://dev.to/aws-builders/why-your-fsx-for-ontap-audit-logs-deserve-better-than-ec2-kod"&gt;Serverless Observability for FSx for ONTAP&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Post-Ingestion Processing Matters
&lt;/h2&gt;

&lt;p&gt;In Part 1, we shipped raw audit events to Datadog. That's necessary but insufficient. Raw events look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4660"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CORP&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;contractor-ext-03"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/share/engineering/designs/prototype-v3.dwg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Audit Failure"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Questions that raw logs can't answer quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is EventID 4660? (Answer: Object Delete)&lt;/li&gt;
&lt;li&gt;Should this alarm? (Answer: depends on volume and context)&lt;/li&gt;
&lt;li&gt;Who should investigate? (Answer: Storage team + SOC)&lt;/li&gt;
&lt;li&gt;What's the user's baseline? (Answer: need faceted historical view)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article builds the processing layers that transform raw data into actionable security intelligence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why EventBridge Scheduler?&lt;/strong&gt; FSx for ONTAP S3 Access Points do not support S3 Event Notifications or EventBridge object-level events. Lambda polls on a schedule and uses checkpointing to process only new files. XML format is chosen for Lambda-native parsing without binary dependencies (vs EVTX which requires Windows-specific libraries).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────────────┐
│ Lambda Handler (Python 3.12)                                     │
│  • Parse XML → Normalize → HEC-compatible JSON                   │
│  • POST to Datadog Logs API v2                                   │
│  • Fields: event_type, user, path, client_ip, svm, result        │
└──────────────────────────────────────────────────────────────────┘
        │  HTTP 202
        ▼
┌──────────────────────────────────────────────────────────────────┐
│ Datadog Log Pipeline: "FSx for ONTAP Audit Logs"                 │
│ Filter: source:fsxn                                              │
│                                                                  │
│ 1. Category Processor → @operation_name                          │
│    4663→Object Access, 4660→Object Delete, 4656→Handle Request   │
│                                                                  │
│ 2. Status Remapper → log severity from @result                   │
│    "Audit Success" → info, "Audit Failure" → error               │
│                                                                  │
│ 3. Date Remapper → @timestamp as official log time               │
│                                                                  │
│ 4. Attribute Remapper → @user→usr.id, @client_ip→network.client  │
└──────────────────────────────────────────────────────────────────┘
        │
        ▼
┌──────────────────────────────────────────────────────────────────┐
│ Datadog Security Monitors (3)                                    │
│                                                                  │
│ • [FSxN] Mass File Deletion    → &amp;gt;50 deletes/5min per user       │
│ • [FSxN] Abnormal Access Volume → &amp;gt;1000 accesses/1h per user     │
│ • [FSxN] Access Failure Spike  → &amp;gt;10 failures/15min per user     │
└──────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Log Pipeline
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkn02l39ljys4zs2ifxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkn02l39ljys4zs2ifxl.png" alt="Datadog Log Pipeline for FSxN" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a Pipeline?
&lt;/h3&gt;

&lt;p&gt;Without a pipeline, every query requires remembering that &lt;code&gt;4660&lt;/code&gt; means "delete" and &lt;code&gt;4663&lt;/code&gt; means "access." With a pipeline, you search &lt;code&gt;@operation_name:Object Delete&lt;/code&gt; — and Datadog handles the translation at ingest time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Pipeline via API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;sm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secretsmanager&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ap-northeast-1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fsxn-datadog-api-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SecretString&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;app_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;datadog/fsxn-app-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SecretString&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PoolManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FSx for ONTAP Audit Logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;processors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category-processor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EventID to Operation Name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;operation_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;categories&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4663&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Object Access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4656&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Handle Request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4660&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Object Delete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4670&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Permission Change&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4658&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Handle Close&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:5140&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Share Access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:5145&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Share Check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4624&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Logon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@event_type:4634&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Logoff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status-remapper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Map result to log status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date-remapper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use event timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attribute-remapper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Map user to usr.id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attribute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usr.id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attribute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preserve_source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;override_on_conflict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attribute-remapper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Map client_ip to network.client.ip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;client_ip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attribute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;network.client.ip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;attribute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preserve_source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;override_on_conflict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.ap1.datadoghq.com/api/v1/logs/config/pipelines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DD-API-KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DD-APPLICATION-KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;app_key&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Pipeline ID = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Site note&lt;/strong&gt;: Replace &lt;code&gt;api.ap1.datadoghq.com&lt;/code&gt; with your Datadog site's API endpoint (e.g., &lt;code&gt;api.datadoghq.com&lt;/code&gt; for US1, &lt;code&gt;api.datadoghq.eu&lt;/code&gt; for EU1).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  EventID Mapping Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;EventID&lt;/th&gt;
&lt;th&gt;Operation Name&lt;/th&gt;
&lt;th&gt;MITRE ATT&amp;amp;CK&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4663&lt;/td&gt;
&lt;td&gt;Object Access&lt;/td&gt;
&lt;td&gt;T1005 (Data from Local System)&lt;/td&gt;
&lt;td&gt;File read/write operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4656&lt;/td&gt;
&lt;td&gt;Handle Request&lt;/td&gt;
&lt;td&gt;T1005&lt;/td&gt;
&lt;td&gt;File handle opened&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4660&lt;/td&gt;
&lt;td&gt;Object Delete&lt;/td&gt;
&lt;td&gt;T1485 (Data Destruction)&lt;/td&gt;
&lt;td&gt;File deleted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4670&lt;/td&gt;
&lt;td&gt;Permission Change&lt;/td&gt;
&lt;td&gt;T1222 (File Permissions Modification)&lt;/td&gt;
&lt;td&gt;ACL/permission modified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4658&lt;/td&gt;
&lt;td&gt;Handle Close&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;File handle closed (low signal)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5140&lt;/td&gt;
&lt;td&gt;Share Access&lt;/td&gt;
&lt;td&gt;T1021.002 (SMB/Windows Admin)&lt;/td&gt;
&lt;td&gt;SMB share connected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5145&lt;/td&gt;
&lt;td&gt;Share Check&lt;/td&gt;
&lt;td&gt;T1135 (Network Share Discovery)&lt;/td&gt;
&lt;td&gt;Share permission checked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4624&lt;/td&gt;
&lt;td&gt;Logon&lt;/td&gt;
&lt;td&gt;T1078 (Valid Accounts)&lt;/td&gt;
&lt;td&gt;Authentication event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4634&lt;/td&gt;
&lt;td&gt;Logoff&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Session ended&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Security Monitors
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd99x3gsbs8suebkpzdp8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd99x3gsbs8suebkpzdp8.png" alt="Datadog Security Monitors for FSxN" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor 1: Mass File Deletion
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mass_delete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[FSxN] Mass File Deletion Detected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;log alert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;logs(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn @event_type:4660&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).index(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).rollup(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).by(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).last(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;) &amp;gt; 50&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;## Mass File Deletion Alert

A user has triggered more than 50 file deletion events within 5 minutes.

**User**: {{@user}}  |  **Count**: {{value}}

### Investigation Steps
1. Check affected paths: `source:fsxn @event_type:4660 @user:{{@user}}`
2. Verify if this is a scheduled cleanup or authorized bulk operation
3. Check the client IP for unexpected sources
4. Correlate with user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s normal deletion patterns

@slack-storage-alerts&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;team:storage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;severity:high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;thresholds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;critical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notify_no_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;renotify_interval&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluation_delay&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why 50?&lt;/strong&gt; In our test environment, normal daily deletions per user stay under 10. The threshold should be tuned based on your environment's baseline — run &lt;code&gt;source:fsxn @event_type:4660 | stats count by @user&lt;/code&gt; over a week to establish what's normal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor 2: Abnormal Access Volume
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;abnormal_access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[FSxN] Abnormal Access Volume&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;log alert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;logs(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn @result:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Audit Success&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="s"&gt;).index(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).rollup(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).by(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).last(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1h&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;) &amp;gt; 1000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;## Abnormal Access Volume Alert

More than 1000 successful file access events in 1 hour.
May indicate data exfiltration or unauthorized bulk access.

**User**: {{@user}}  |  **Count**: {{value}}

### Investigation Steps
1. Review patterns: `source:fsxn @user:{{@user}}`
2. Check if backup jobs or batch operations are running
3. Verify client IP and compare with known locations
4. Check accessed paths for sensitive content

@slack-security-alerts&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;thresholds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;critical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluation_delay&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tuning note&lt;/strong&gt;: Backup service accounts (&lt;code&gt;svc-backup&lt;/code&gt;, &lt;code&gt;svc-indexer&lt;/code&gt;) generate legitimate high-volume access. Exclude them with &lt;code&gt;@user:-svc-*&lt;/code&gt; in the query or create a suppression rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor 3: Access Failure Spike
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;failure_spike&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[FSxN] Access Failure Spike&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;log alert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;logs(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn @result:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Audit Failure&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="s"&gt;).index(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).rollup(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).by(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).last(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;) &amp;gt; 10&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;## Access Failure Spike

More than 10 access failures in 15 minutes.
May indicate unauthorized access attempts or permission misconfiguration.

**User**: {{@user}}  |  **Count**: {{value}}

### Investigation Steps
1. Check failed paths: `source:fsxn @result:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Audit Failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; @user:{{@user}}`
2. Verify if permissions were recently changed
3. Check if user is accessing resources outside their scope
4. Correlate with AD group membership changes

@slack-security-alerts&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;thresholds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;critical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluation_delay&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Saved Views
&lt;/h2&gt;

&lt;p&gt;Five pre-configured views for common investigation patterns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;View&lt;/th&gt;
&lt;th&gt;Query&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FSxN File Deletions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;source:fsxn @event_type:4660&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Monitor triggered, investigating which files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSxN Access Failures&lt;/td&gt;
&lt;td&gt;&lt;code&gt;source:fsxn @result:"Audit Failure"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permission denied investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSxN All Events&lt;/td&gt;
&lt;td&gt;&lt;code&gt;source:fsxn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;General audit stream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSxN Sensitive Share Access&lt;/td&gt;
&lt;td&gt;&lt;code&gt;source:fsxn (@path:*finance* OR @path:*hr* OR @path:*legal*)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sensitive data access review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FSxN After-Hours Access&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;source:fsxn&lt;/code&gt; (filtered by time)&lt;/td&gt;
&lt;td&gt;Off-hours activity detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each view includes pre-configured columns (user, path, client_ip, event_type) so analysts don't need to customize the table every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Facets for One-Click Filtering
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86psvqpt6woh4keun2o6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86psvqpt6woh4keun2o6.png" alt="Datadog Log Explorer with Facets" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Facets add clickable filters to the left sidebar. Create them from any log entry's detail panel:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Facet&lt;/th&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Event Type&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@event_type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter to specific operations (4660=delete, 4663=access)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@operation_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Human-readable version (after pipeline applies)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter by specific user under investigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SVM&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@svm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Isolate events to specific storage virtual machines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File Path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter by directory or share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client IP&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@client_ip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter by source workstation/server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@result&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quick split between success and failure events&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Fields are searchable with &lt;code&gt;@field:value&lt;/code&gt; syntax even without Facets. Facets add UI convenience — they're not required for alerting or saved views.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Cost Reality
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lambda (5-min schedule, ~1s execution)&lt;/td&gt;
&lt;td&gt;~$0.50&lt;/td&gt;
&lt;td&gt;8,640 invocations/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets Manager (2 secrets)&lt;/td&gt;
&lt;td&gt;~$0.80&lt;/td&gt;
&lt;td&gt;API key + APP key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventBridge Scheduler&lt;/td&gt;
&lt;td&gt;~$0.00&lt;/td&gt;
&lt;td&gt;Free tier covers this&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 AP reads&lt;/td&gt;
&lt;td&gt;~$0.05&lt;/td&gt;
&lt;td&gt;Depends on file count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datadog Forwarder Lambda&lt;/td&gt;
&lt;td&gt;~$0.10&lt;/td&gt;
&lt;td&gt;CloudTrail event processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3 Archive storage&lt;/td&gt;
&lt;td&gt;~$0.02&lt;/td&gt;
&lt;td&gt;Glacier tier after 30 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$1.50/month&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datadog log ingestion&lt;/td&gt;
&lt;td&gt;~$0.10/GB&lt;/td&gt;
&lt;td&gt;Conventional pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total (1GB/month)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$1.60/month&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Datadog pricing caveat&lt;/strong&gt;: Log ingestion pricing varies by plan (Conventional vs On-Demand) and contract. The ~$0.10/GB is the list price for conventional plans; actual cost depends on your contract, committed volume, and retention choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud SIEM pricing&lt;/strong&gt;: Cloud SIEM is a separate paid feature (~$0.20/GB analyzed for log detection). A 30-day free trial is available. Security Signals, Detection Rules, and the triage workflow require Cloud SIEM. Log Monitors (threshold alerts to Slack) work without it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Cost optimization patterns
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Filter before shipping&lt;/strong&gt; — Drop low-value EventIDs (4658 Handle Close) at the Lambda level to reduce ingestion volume&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compress payloads&lt;/strong&gt; — Enable gzip on the HTTP POST to reduce egress&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tune audit scope&lt;/strong&gt; — Configure ONTAP &lt;code&gt;vserver audit&lt;/code&gt; to monitor only the shares that matter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index retention&lt;/strong&gt; — Use Datadog's flexible retention (15/30/60/90 days) to match compliance needs vs cost&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  E2E Verification Results
&lt;/h2&gt;

&lt;p&gt;Verified on Datadog AP1 (ap1.datadoghq.com) with paid plan, June 2026:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lambda → Datadog Logs API v2&lt;/td&gt;
&lt;td&gt;✅ HTTP 202&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log Pipeline (5 processors)&lt;/td&gt;
&lt;td&gt;✅ Applied automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category Processor (9 EventIDs)&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;@operation_name&lt;/code&gt; populated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status Remapper&lt;/td&gt;
&lt;td&gt;✅ Failure events marked as error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Date Remapper&lt;/td&gt;
&lt;td&gt;✅ Event timestamp used (not ingest time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attribute Remapper (usr.id)&lt;/td&gt;
&lt;td&gt;✅ Enables Datadog user features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mass Delete Monitor&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;ALERT triggered&lt;/strong&gt; (55 events &amp;gt; threshold 50)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access Failure Monitor&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;ALERT triggered&lt;/strong&gt; (12 events &amp;gt; threshold 10)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abnormal Access Monitor&lt;/td&gt;
&lt;td&gt;✅ Active (OK — high threshold by design)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anomaly Monitor (ML)&lt;/td&gt;
&lt;td&gt;✅ Active (learning baseline)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Saved Views (5)&lt;/td&gt;
&lt;td&gt;✅ Accessible from Views dropdown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Facets (8 custom)&lt;/td&gt;
&lt;td&gt;✅ Created via UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard (10 widgets)&lt;/td&gt;
&lt;td&gt;✅ FSx ONTAP Audit Log Overview&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log-based Metrics (4)&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;fsxn.audit.*&lt;/code&gt; in Metrics Explorer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensitive Data Scanner (5 rules)&lt;/td&gt;
&lt;td&gt;✅ PII detection active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud SIEM Detection Rules (4)&lt;/td&gt;
&lt;td&gt;✅ Security Signals generated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudTrail Forwarder&lt;/td&gt;
&lt;td&gt;✅ Logs arriving in Datadog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GeoIP Enrichment&lt;/td&gt;
&lt;td&gt;✅ Country/city populated on client_ip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GuardDuty Correlation Rule&lt;/td&gt;
&lt;td&gt;✅ Cross-service detection active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Automation&lt;/td&gt;
&lt;td&gt;✅ Monitor → Slack + Case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Case Management (FSXN project)&lt;/td&gt;
&lt;td&gt;✅ Project + template case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SOC Triage Runbook&lt;/td&gt;
&lt;td&gt;✅ 7-step Notebook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log Archive (S3 → Glacier)&lt;/td&gt;
&lt;td&gt;✅ source:fsxn archived&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snapshot Remediation Lambda&lt;/td&gt;
&lt;td&gt;✅ Deployed (fsxn-snapshot-remediation)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Log-based Metrics
&lt;/h2&gt;

&lt;p&gt;Log-based metrics extract numerical values from logs at ingest time — you get metric-resolution dashboards and anomaly detection without paying for log retention beyond the evaluation window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Created via Datadog API (no UI needed)
&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fsxn.audit.delete_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# Delete events grouped by user/SVM
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fsxn.audit.access_failure_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Failures by user/SVM/client_ip
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fsxn.audit.event_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# All events by event_type/SVM
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fsxn.audit.unique_users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# Active users
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mpppmz2l4v35r574c2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5mpppmz2l4v35r574c2i.png" alt="Log-based Metrics Configuration" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anomaly detection&lt;/strong&gt; on &lt;code&gt;fsxn.audit.delete_count&lt;/code&gt; — Datadog's built-in anomaly monitor catches unusual deletion patterns without manual thresholds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLO tracking&lt;/strong&gt; — Define an SLO on access failure rate (&lt;code&gt;fsxn.audit.access_failure_count / fsxn.audit.event_count&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost efficiency&lt;/strong&gt; — Metrics are retained for 15 months at metric resolution (vs log retention at full-text cost)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Sensitive Data Scanner
&lt;/h2&gt;

&lt;p&gt;Audit logs frequently contain PII in file paths (&lt;code&gt;/hr/EMP-123456-performance-review.xlsx&lt;/code&gt;) and user contexts. Datadog's Sensitive Data Scanner catches these before they reach analysts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;What It Catches&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Employee ID (&lt;code&gt;EMP-\d{6}&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Employee records in paths&lt;/td&gt;
&lt;td&gt;PII exposure prevention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JP Phone (&lt;code&gt;0[789]0-\d{4}-\d{4}&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Mobile numbers in filenames&lt;/td&gt;
&lt;td&gt;Privacy protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email in Path&lt;/td&gt;
&lt;td&gt;Customer emails in file names&lt;/td&gt;
&lt;td&gt;Data minimization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credit Card&lt;/td&gt;
&lt;td&gt;CC numbers in documents&lt;/td&gt;
&lt;td&gt;PCI-DSS technical control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My Number&lt;/td&gt;
&lt;td&gt;Japanese national ID&lt;/td&gt;
&lt;td&gt;Sensitive PII detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Compliance note&lt;/strong&gt;: Sensitive Data Scanner is a &lt;strong&gt;technical detection and redaction control&lt;/strong&gt;. It does not constitute full APPI/GDPR/PCI-DSS compliance, which requires organizational measures (consent management, purpose limitation, data subject rights, etc.). Consult your legal/compliance team for regulatory assessment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6qlfxkkm50epd5b1u0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6qlfxkkm50epd5b1u0u.png" alt="Sensitive Data Scanner" width="799" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Matched patterns are &lt;strong&gt;partially redacted&lt;/strong&gt; at ingest — the first 3 characters remain for identification, the rest is replaced with &lt;code&gt;[REDACTED]&lt;/code&gt;. This preserves investigation capability while protecting the data subject.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enhanced Dashboard
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F751ugwm1gnhwzzyo8pfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F751ugwm1gnhwzzyo8pfl.png" alt="Enhanced Dashboard — 10 Widgets" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The SOC-focused dashboard provides at-a-glance visibility into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Who&lt;/strong&gt; is generating the most activity (top users, top IPs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What&lt;/strong&gt; operations dominate (sunburst by operation/SVM)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where&lt;/strong&gt; access is concentrated (hot paths)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When&lt;/strong&gt; failures spike (timeline with per-user breakdown)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trend&lt;/strong&gt; from log-based metrics (delete rate over time)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cloud SIEM Security Signals
&lt;/h2&gt;

&lt;p&gt;Beyond log monitors (which notify via Slack/PagerDuty), Security Signals integrate with Datadog's SOC workflow — triage, investigation, and response all in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Monitors vs Cloud SIEM Detection Rules
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Log Monitors&lt;/th&gt;
&lt;th&gt;Cloud SIEM Detection Rules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Alert notification (Slack/PagerDuty/email)&lt;/td&gt;
&lt;td&gt;Security Signal (appears in Security Signals panel)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Triage&lt;/td&gt;
&lt;td&gt;Manual (click alert → investigate)&lt;/td&gt;
&lt;td&gt;Built-in triage workflow (Open → In Progress → Archived)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MITRE mapping&lt;/td&gt;
&lt;td&gt;Manual tags&lt;/td&gt;
&lt;td&gt;Native MITRE ATT&amp;amp;CK framework integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Correlation&lt;/td&gt;
&lt;td&gt;Single query&lt;/td&gt;
&lt;td&gt;Cross-log-source correlation possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Case integration&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Direct "Create Case" from signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Operational alerts (DevOps/SRE)&lt;/td&gt;
&lt;td&gt;Security investigation (SOC/IR teams)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Recommendation&lt;/strong&gt;: Use both. Log Monitors for immediate Slack notification to storage team. Cloud SIEM Detection Rules for SOC triage workflow and MITRE-mapped investigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkanywlx3y6n7t5u4iqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkanywlx3y6n7t5u4iqb.png" alt="Cloud SIEM Detection Rules" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three detection rules generate Security Signals when FSxN audit logs match threat patterns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;MITRE ATT&amp;amp;CK&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mass File Deletion&lt;/td&gt;
&lt;td&gt;T1485 Data Destruction&lt;/td&gt;
&lt;td&gt;&amp;gt;50 deletes/5min per user&lt;/td&gt;
&lt;td&gt;Critical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brute Force File Access&lt;/td&gt;
&lt;td&gt;T1110 Brute Force&lt;/td&gt;
&lt;td&gt;&amp;gt;20 failures/15min per user+IP&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permission Tampering&lt;/td&gt;
&lt;td&gt;T1222 File Permissions Modification&lt;/td&gt;
&lt;td&gt;&amp;gt;5 changes/10min per user&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Creating a Security Signal rule via API
&lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FSxN: Mass File Deletion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;log_detection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn @event_type:4660&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;groupByFields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aggregation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete_events&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dataSource&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cases&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;condition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete_events &amp;gt; 50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;critical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Critical&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;condition&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete_events &amp;gt; 20&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;High&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluationWindow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keepAlive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxSignalDuration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;detectionMethod&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User {{@user}} deleted {{value}} files in 5 min. T1485.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source:fsxn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;technique:T1485-data-destruction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each signal includes investigation steps and response guidance directly in the signal panel — analysts don't need to leave the Security Signals view to understand what happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud SIEM Setup Steps
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cqngqkwacopqohlugcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cqngqkwacopqohlugcg.png" alt="Cloud SIEM Onboarding — Index Configuration" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Security → Cloud SIEM → Get Started&lt;/li&gt;
&lt;li&gt;Skip Content Packs (FSxN is a custom source)&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;fsxn&lt;/code&gt; as a log source → Enable as Trial&lt;/li&gt;
&lt;li&gt;Configure Cloud SIEM Index (default: 450 days retention)&lt;/li&gt;
&lt;li&gt;Detection rules are automatically applied to incoming &lt;code&gt;source:fsxn&lt;/code&gt; logs&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Workflow Automation
&lt;/h2&gt;

&lt;p&gt;When a critical monitor fires, the Workflow automatically triggers response actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Monitor Alert → @workflow-fsxn-security-alert-response → Slack notification + Investigation links
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow (&lt;code&gt;fsxn-security-alert-response&lt;/code&gt;) is linked to monitors via the &lt;code&gt;@workflow-&amp;lt;handle&amp;gt;&lt;/code&gt; mention syntax in the monitor message. No additional configuration needed — just add the mention to any monitor's notification body.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extensions&lt;/strong&gt; (via Datadog Workflow builder):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-create Jira ticket with investigation context&lt;/li&gt;
&lt;li&gt;Query Active Directory for user's manager&lt;/li&gt;
&lt;li&gt;Invoke &lt;code&gt;fsxn-snapshot-remediation&lt;/code&gt; Lambda for evidence preservation (deployed — see Automated Snapshot Remediation)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Investigation Notebook
&lt;/h2&gt;

&lt;p&gt;A pre-built 5-step investigation template guides analysts through alert triage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Widget&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Identify Scope&lt;/td&gt;
&lt;td&gt;Event type distribution timeline&lt;/td&gt;
&lt;td&gt;Timeseries (bars)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. User Timeline&lt;/td&gt;
&lt;td&gt;Delete events by user over time&lt;/td&gt;
&lt;td&gt;Timeseries (line)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Affected Files&lt;/td&gt;
&lt;td&gt;Top 20 deleted paths&lt;/td&gt;
&lt;td&gt;Top List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Client IP Analysis&lt;/td&gt;
&lt;td&gt;Top 10 source IPs&lt;/td&gt;
&lt;td&gt;Top List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Conclusion&lt;/td&gt;
&lt;td&gt;Root cause, impact, action template&lt;/td&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Access at: Notebooks → "FSxN Audit Log Investigation Template"&lt;/p&gt;

&lt;p&gt;Each step includes pre-configured queries — analysts just adjust the time window and user filter to match the alert context.&lt;/p&gt;




&lt;h2&gt;
  
  
  RBAC and Access Control
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;FSxN Security Analyst&lt;/code&gt; role provides scoped access to audit logs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Permissions&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FSxN Security Analyst&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;logs_read_data&lt;/code&gt;, &lt;code&gt;logs_read_index_data&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;SOC analysts investigating file access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datadog Standard Role&lt;/td&gt;
&lt;td&gt;Full access&lt;/td&gt;
&lt;td&gt;Storage admins managing pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Assign users to this role to grant log access without exposing infrastructure metrics or APM data. Combined with Saved Views, analysts see only the investigation tools relevant to their role.&lt;/p&gt;




&lt;h2&gt;
  
  
  OTel Collector Bridge
&lt;/h2&gt;

&lt;p&gt;For teams already running OpenTelemetry Collector, an alternative delivery path routes FSxN logs through OTel with trace context injection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# otel-bridge/collector-config.yaml (excerpt)&lt;/span&gt;
&lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;protocols&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;0.0.0.0&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;4318&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

&lt;span class="na"&gt;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service.name&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ontap-audit&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;upsert&lt;/span&gt;
  &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;log_statements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;log&lt;/span&gt;
        &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;set(attributes["ddsource"], "fsxn")&lt;/span&gt;

&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;datadog&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${env:DD_API_KEY}&lt;/span&gt;
      &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${env:DD_SITE:-ap1.datadoghq.com}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits over direct Lambda→Datadog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;trace_id injection&lt;/strong&gt; for distributed tracing correlation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-backend fanout&lt;/strong&gt; (Datadog + Grafana + S3 in parallel)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribute enrichment&lt;/strong&gt; at collector level (team, environment tags)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sampling&lt;/strong&gt; for high-volume environments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge-side PII redaction&lt;/strong&gt; — Mask sensitive fields before they leave your AWS account (stronger than relying solely on Datadog's Sensitive Data Scanner)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Edge redaction pattern&lt;/strong&gt;: Use OTel's &lt;code&gt;transform&lt;/code&gt; processor to hash &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;client_ip&lt;/code&gt; and truncate &lt;code&gt;path&lt;/code&gt; to directory level BEFORE export to Datadog. This ensures PII never crosses your network boundary — even if Datadog's SDS configuration is misconfigured or disabled, your data is already protected at the source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status&lt;/strong&gt;: Config syntax verified. Integration testing requires deploying OTel Collector on ECS (see &lt;a href="https://dev.tolink-to-part-7"&gt;Part 7&lt;/a&gt; for the ECS-based Collector pattern used with Grafana and Honeycomb).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Log Archives and Compliance
&lt;/h2&gt;

&lt;p&gt;For regulatory retention (adjust based on your organization's audit policy), a dedicated CloudFormation template deploys an S3 archive with Glacier lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; integrations/datadog/template-log-archive.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-datadog-archive &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;DatadogExternalId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;from-datadog-integration-page&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;RetentionDays&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;GlacierRetentionDays&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2555 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separates concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detection&lt;/strong&gt; — Hot logs in Datadog (15-30 day index retention)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt; — Cold archive in S3 → Glacier (7+ years)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Investigation&lt;/strong&gt; — Rehydrate specific time ranges on demand&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Anomaly Detection (ML-based)
&lt;/h2&gt;

&lt;p&gt;Beyond static thresholds, the anomaly monitor on &lt;code&gt;fsxn.audit.delete_count&lt;/code&gt; uses Datadog's agile algorithm to learn each user's baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Anomaly monitor — no manual threshold needed
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;avg(last_4h):anomalies(
    sum:fsxn.audit.delete_count{*} by {user}.as_count(),
    &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agile&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, 3, direction=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;above&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
) &amp;gt;= 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user who normally deletes 5 files/day suddenly deletes 200, the alert fires — even though 200 is well below the static "50 in 5 minutes" threshold. This catches slow, sustained exfiltration that threshold-based monitors miss.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Baseline period&lt;/strong&gt;: The anomaly algorithm needs ~2 weeks of data to build confidence. Deploy early — it stays silent during the learning period.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Cardinality Management
&lt;/h2&gt;

&lt;p&gt;⚠️ Log-based metrics with &lt;code&gt;group_by: user&lt;/code&gt; create one time series per unique user. For organizations with 10,000+ users:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Recommended group_by&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fsxn.audit.event_count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;svm only&lt;/td&gt;
&lt;td&gt;Broad metric, low cardinality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fsxn.audit.delete_count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;user, svm&lt;/td&gt;
&lt;td&gt;Targeted, high signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fsxn.audit.access_failure_count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;user, svm, client_ip&lt;/td&gt;
&lt;td&gt;Investigation-focused&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fsxn.audit.unique_users&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;user&lt;/td&gt;
&lt;td&gt;Intentionally per-user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Monitor cardinality in Metrics Summary (&lt;code&gt;fsxn.audit.*&lt;/code&gt;). Datadog bills per unique tag-value combination — keep per-user grouping only on metrics where individual user behavior matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Different from Splunk/CrowdStrike?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Datadog&lt;/th&gt;
&lt;th&gt;Splunk (Part 8)&lt;/th&gt;
&lt;th&gt;CrowdStrike (Part 15)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Delivery protocol&lt;/td&gt;
&lt;td&gt;Logs API v2 (JSON)&lt;/td&gt;
&lt;td&gt;HEC (JSON)&lt;/td&gt;
&lt;td&gt;HEC (JSON)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline config&lt;/td&gt;
&lt;td&gt;API-driven (Python)&lt;/td&gt;
&lt;td&gt;props.conf / UI&lt;/td&gt;
&lt;td&gt;LogScale parser YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitor creation&lt;/td&gt;
&lt;td&gt;API (&lt;code&gt;POST /api/v1/monitor&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Saved searches + alerts&lt;/td&gt;
&lt;td&gt;CQL + alert actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EventID mapping&lt;/td&gt;
&lt;td&gt;Category Processor&lt;/td&gt;
&lt;td&gt;eval/lookup&lt;/td&gt;
&lt;td&gt;LogScale parser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Identity correlation&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;usr.id&lt;/code&gt; attribute&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;user&lt;/code&gt; field&lt;/td&gt;
&lt;td&gt;Falcon Identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;td&gt;❌ (paid only for logs)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API management&lt;/td&gt;
&lt;td&gt;✅ Full (Pipeline + Monitor + Dashboard)&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The key Datadog advantage: &lt;strong&gt;everything is API-manageable&lt;/strong&gt;. Pipeline, monitors, dashboards, and saved views can all be created, updated, and version-controlled through the Datadog API — making infrastructure-as-code for observability fully achievable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production Recommendations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use the API, not the UI&lt;/strong&gt; — Version-control your Pipeline, Monitor, and Dashboard definitions in a setup script. When you need to adjust thresholds or add EventIDs, it's a code change with review.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Separate APP key from API key&lt;/strong&gt; — The API key ships logs; the APP key manages configuration. Store both in Secrets Manager with different IAM policies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exclude service accounts&lt;/strong&gt; — Add &lt;code&gt;@user:-svc-*&lt;/code&gt; to monitor queries or create Datadog suppression rules for known batch accounts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with Warning, promote to Critical&lt;/strong&gt; — Deploy monitors with Warning thresholds first, observe for 1-2 weeks, then tighten to Critical after confirming the baseline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connect to incident workflow&lt;/strong&gt; — Route Critical monitors to PagerDuty/Slack and include investigation links (Saved View URLs) in the alert message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable Log Archives for compliance&lt;/strong&gt; — Configure S3 archive with Glacier lifecycle for FISC/SOC2 retention requirements. Rehydrate on demand for historical investigation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Workflow Automation for response&lt;/strong&gt; — Configure Datadog Workflows to automatically create Jira tickets, trigger Slack quick-actions, or invoke Lambda remediation when critical monitors fire.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manage with Terraform for production&lt;/strong&gt; — For enterprise/multi-org deployments, use the &lt;a href="https://registry.terraform.io/providers/DataDog/datadog/latest" rel="noopener noreferrer"&gt;Datadog Terraform Provider&lt;/a&gt; to version-control Pipelines, Monitors, and Detection Rules. Separate API key (&lt;code&gt;logs_write&lt;/code&gt; only) from APP key (admin-level, CI/CD pipeline only).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apply IAM Permissions Boundary&lt;/strong&gt; — In large organizations, apply a Permissions Boundary to the log-shipping Lambda role to prevent privilege escalation. The boundary should allow only &lt;code&gt;s3:GetObject&lt;/code&gt;, &lt;code&gt;s3:ListBucket&lt;/code&gt;, &lt;code&gt;secretsmanager:GetSecretValue&lt;/code&gt;, and &lt;code&gt;logs:*&lt;/code&gt; (CloudWatch).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encrypt with customer-managed keys (CMK)&lt;/strong&gt; — For regulated environments, enable &lt;a href="https://docs.datadoghq.com/account_management/org_settings/#log-management" rel="noopener noreferrer"&gt;Datadog Log Management Encryption&lt;/a&gt; with your KMS CMK, and configure the S3 archive bucket with SSE-KMS. This ensures audit logs are encrypted with keys you control at every stage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tune detection rules (anti-alert-fatigue)&lt;/strong&gt; — Run all new Cloud SIEM rules in "Warning / dev" status for 2 weeks. Whitelist known service accounts with &lt;code&gt;@usr.id:-svc-*&lt;/code&gt; in queries. Review false positives weekly and adjust thresholds or add suppression rules before promoting to Critical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Integrity: Handle HTTP 429/5xx&lt;/strong&gt; — Datadog Logs API v2 returns HTTP 202 (accepted, not indexed). On HTTP 429 (rate limit) or 5xx (transient), implement exponential backoff (base 1s, max 5 retries). After final failure, route the complete HEC payload to SQS DLQ for replay. Never drop logs silently.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Deploy the CloudFormation stack (Lambda + Scheduler + DLQ + Alarms)&lt;/span&gt;
aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; integrations/datadog/template.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-datadog-integration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;FsxS3AccessPointArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arn:aws:s3:&amp;lt;region&amp;gt;:&amp;lt;account&amp;gt;:accesspoint/&amp;lt;name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;DatadogApiKeySecretArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;secret-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;DatadogSite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap1.datadoghq.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM

&lt;span class="c"&gt;# 2. Deploy full observability (Pipeline + Monitors + Metrics + Scanner)&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DD_API_KEY_SECRET_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"fsxn-datadog-api-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DD_APP_KEY_SECRET_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"datadog/fsxn-app-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DD_SITE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ap1.datadoghq.com"&lt;/span&gt;
bash integrations/datadog/scripts/setup-full-observability.sh

&lt;span class="c"&gt;# 3. (Optional) Deploy Log Archive for compliance&lt;/span&gt;
aws cloudformation deploy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; integrations/datadog/template-log-archive.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--stack-name&lt;/span&gt; fsxn-datadog-archive &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameter-overrides&lt;/span&gt; &lt;span class="nv"&gt;DatadogExternalId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;external-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_NAMED_IAM

&lt;span class="c"&gt;# 4. Create Facets (guided manual step)&lt;/span&gt;
bash integrations/datadog/scripts/setup-facets.sh

&lt;span class="c"&gt;# 5. Enable Cloud SIEM (UI: Security → Cloud SIEM → Get Started → select fsxn)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Time from zero to full detection capability: &lt;strong&gt;~45 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-Deployment Checklist
&lt;/h3&gt;

&lt;p&gt;Before deploying to production, confirm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] FSx audit configuration confirmed (XML format, rotation schedule)&lt;/li&gt;
&lt;li&gt;[ ] S3 Access Point created and Lambda role authorized&lt;/li&gt;
&lt;li&gt;[ ] Datadog API Key + APP Key stored in Secrets Manager&lt;/li&gt;
&lt;li&gt;[ ] Datadog site region confirmed (AP1/US1/EU1)&lt;/li&gt;
&lt;li&gt;[ ] Data classification sign-off: audit logs contain user PII (usernames, IPs, file paths) — confirm external transmission is approved per organization policy&lt;/li&gt;
&lt;li&gt;[ ] Retention requirements defined (Datadog index retention + S3 archive lifecycle)&lt;/li&gt;
&lt;li&gt;[ ] On-call/escalation path defined for Critical signals&lt;/li&gt;
&lt;li&gt;[ ] Service accounts identified for monitor exclusion (&lt;code&gt;svc-*&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Cloud SIEM trial or paid plan confirmed (for Security Signals)&lt;/li&gt;
&lt;li&gt;[ ] Network path validated (VPC-external Lambda or NAT Gateway for S3 AP access)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. API-first beats UI-first
&lt;/h3&gt;

&lt;p&gt;Creating the Pipeline via API took 30 seconds. Doing it through the UI takes 5 minutes of clicking through dropdowns. More importantly, the API approach is repeatable, reviewable, and version-controlled.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Facets are UX, not functionality
&lt;/h3&gt;

&lt;p&gt;Every field is searchable with &lt;code&gt;@field:value&lt;/code&gt; whether or not you create a Facet. Facets just add sidebar convenience. Don't block on Facet setup — your monitors work without them.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Category Processor is the key transformation
&lt;/h3&gt;

&lt;p&gt;Without it, analysts need to memorize Windows EventID codes. With it, &lt;code&gt;@operation_name:Object Delete&lt;/code&gt; is immediately understandable. This single processor provides more investigative value than any other pipeline step.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Evaluation delay prevents false positives
&lt;/h3&gt;

&lt;p&gt;The 60-second &lt;code&gt;evaluation_delay&lt;/code&gt; on monitors accounts for ingestion latency. Without it, you get spurious alerts when log batches arrive slightly out of order.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Saved Views are investigation shortcuts
&lt;/h3&gt;

&lt;p&gt;When a monitor fires at 3 AM, the on-call engineer needs to investigate immediately. Pre-built Saved Views with the right columns and filters eliminate setup time during incidents.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Anomaly detection needs baseline data
&lt;/h3&gt;

&lt;p&gt;The anomaly monitor requires at least 2 weeks of historical data to build a reliable baseline. Deploy it early — it won't generate false positives during the learning period (it simply stays silent until confident).&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Cloud SIEM and Log Monitors are complementary
&lt;/h3&gt;

&lt;p&gt;Log Monitors give you fast Slack/PagerDuty notifications for the on-call team. Cloud SIEM Detection Rules give SOC analysts a structured triage workflow with MITRE mapping. Deploy both — they serve different audiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. GeoIP is free threat intelligence
&lt;/h3&gt;

&lt;p&gt;The GeoIP Processor is zero-cost and instantly useful. Even in a pure on-premises environment, unusual geography flags VPN misconfiguration, compromised credentials, or travel you weren't expecting.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Forwarder deployment enables an ecosystem
&lt;/h3&gt;

&lt;p&gt;Once the Datadog Forwarder Lambda is deployed, enabling CloudTrail, GuardDuty, Lambda logs, or any other AWS log source is a single S3 notification configuration — no new infrastructure needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  CloudTrail Correlation (Cross-Service Detection)
&lt;/h2&gt;

&lt;p&gt;A dedicated detection rule correlates FSxN audit events with AWS CloudTrail context. When the signal fires, the investigation message includes pre-built queries for cross-service correlation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source:cloudtrail @userIdentity.arn:*&amp;lt;username&amp;gt;*     → IAM actions
source:guardduty                                      → GuardDuty findings
source:vpc @network.client.ip:&amp;lt;suspicious-ip&amp;gt;         → Network flows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule (&lt;code&gt;FSxN: Suspicious Deletion After IAM Role Assumption&lt;/code&gt;) fires on &amp;gt;30 deletions in 10 minutes and embeds a correlation checklist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Was there a recent &lt;code&gt;AssumeRole&lt;/code&gt; or &lt;code&gt;ConsoleLogin&lt;/code&gt; from an unusual IP?&lt;/li&gt;
&lt;li&gt;Did the user's permissions change in the last 24 hours?&lt;/li&gt;
&lt;li&gt;Is the client IP in the corporate VPN range?&lt;/li&gt;
&lt;li&gt;Are there GuardDuty findings for this account?&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This rule activates fully once CloudTrail logs are flowing to Datadog via the AWS Integration. The FSxN detection works immediately; CloudTrail queries return results after integration setup.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  SOC Triage Runbook
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5s1i83yaifkdnm8qiq1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5s1i83yaifkdnm8qiq1k.png" alt="SOC Triage Runbook" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A 7-step Notebook guides analysts from signal to resolution:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Signal Context&lt;/td&gt;
&lt;td&gt;Verify user, IP, time, volume&lt;/td&gt;
&lt;td&gt;Timeseries widget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. User Verification&lt;/td&gt;
&lt;td&gt;Check AD status, role changes, maintenance windows&lt;/td&gt;
&lt;td&gt;Manual checklist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Impact Assessment&lt;/td&gt;
&lt;td&gt;Identify affected files and directories&lt;/td&gt;
&lt;td&gt;Top List (paths)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Cross-Service Correlation&lt;/td&gt;
&lt;td&gt;CloudTrail, GuardDuty, VPC Flow Logs&lt;/td&gt;
&lt;td&gt;Query templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Decision Matrix&lt;/td&gt;
&lt;td&gt;Map conditions to response actions&lt;/td&gt;
&lt;td&gt;Decision table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Response Actions&lt;/td&gt;
&lt;td&gt;Disable account, snapshot, notify, ticket&lt;/td&gt;
&lt;td&gt;Checklist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Post-Incident&lt;/td&gt;
&lt;td&gt;Update thresholds, document, lessons learned&lt;/td&gt;
&lt;td&gt;Checklist&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Accessible at: &lt;strong&gt;Notebooks → "FSxN Security Signal Triage Runbook"&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Case Management
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzgfuf56nzt02apc3rrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzgfuf56nzt02apc3rrx.png" alt="Case Management — FSXN Project" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cases provide structured investigation tracking across the SOC team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project&lt;/strong&gt;: &lt;code&gt;FSXN&lt;/code&gt; — All FSx for ONTAP security investigations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case creation&lt;/strong&gt;: Manual from Security Signals, or auto-create via Workflow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priority levels&lt;/strong&gt;: P1 (critical mass deletion) through P4 (informational)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle&lt;/strong&gt;: Open → In Progress → Resolved → Closed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a critical signal fires, the workflow creates a case automatically with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signal link and context&lt;/li&gt;
&lt;li&gt;Affected user and IP&lt;/li&gt;
&lt;li&gt;Investigation notebook link&lt;/li&gt;
&lt;li&gt;Response checklist&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Threat Intelligence (GeoIP Enrichment)
&lt;/h2&gt;

&lt;p&gt;The Log Pipeline's GeoIP Processor automatically enriches every FSxN log with geographic data from the &lt;code&gt;client_ip&lt;/code&gt; field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@client_ip: 10.0.5.99 → @network.client.geoip: { country: "JP", city: "Tokyo", ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A detection rule flags access from unexpected countries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Rule: "FSxN: File Access from Unusual Geography"
# Query: source:fsxn -@network.client.geoip.country:JP -@network.client.geoip.country:US
# Threshold: &amp;gt;5 events/15min from non-JP/US IPs
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This catches compromised credentials being used from abroad without needing an external threat intelligence feed — Datadog's built-in GeoIP database handles the enrichment at ingest time.&lt;/p&gt;




&lt;h2&gt;
  
  
  GuardDuty Correlation
&lt;/h2&gt;

&lt;p&gt;A detection rule correlates FSxN deletion events with GuardDuty findings from the same source IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FSxN: &amp;gt;10 deletions/30min from IP X
  + GuardDuty finding for IP X (UnauthorizedAccess, Recon, Trojan)
  = Critical Security Signal with full context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule's investigation message includes pre-built GuardDuty queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source:guardduty @detail.resource.instanceDetails.networkInterfaces.privateIpAddress:{{@client_ip}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GuardDuty findings flow to Datadog via the same Forwarder Lambda that handles CloudTrail — no additional setup needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Automated Snapshot Remediation
&lt;/h2&gt;

&lt;p&gt;When mass deletion is confirmed (Critical signal reviewed by analyst), the Workflow invokes &lt;code&gt;fsxn-snapshot-remediation&lt;/code&gt; Lambda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Security Signal (Critical) → Analyst confirms → Workflow → Lambda → ONTAP REST API → Snapshot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Lambda:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receives volume name, SVM, and reason from the Workflow&lt;/li&gt;
&lt;li&gt;Authenticates to ONTAP via Secrets Manager credentials&lt;/li&gt;
&lt;li&gt;Creates a timestamped snapshot: &lt;code&gt;remediation_20260614_215530_mass_deletion&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Returns snapshot name and status for the Case record
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Lambda invocation payload (from Datadog Workflow)
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;volume_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finance_share&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;svm_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ProductionSVM&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mass deletion detected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CORP&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;suspicious-user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Configuration&lt;/strong&gt;: Set &lt;code&gt;ONTAP_MGMT_IP&lt;/code&gt; and &lt;code&gt;ONTAP_CREDENTIALS_SECRET_ARN&lt;/code&gt; environment variables on the Lambda to point to your FSx for ONTAP management endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLS note&lt;/strong&gt;: The Lambda uses &lt;code&gt;cert_reqs="CERT_NONE"&lt;/code&gt; for ONTAP REST API calls because FSx for ONTAP uses self-signed certificates by default. In production, upload the ONTAP CA certificate to the Lambda layer (&lt;code&gt;/opt/certs/ontap-ca.pem&lt;/code&gt;) and configure &lt;code&gt;urllib3.PoolManager(ca_certs="/opt/certs/ontap-ca.pem")&lt;/code&gt; to validate the connection.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Snapshot Storm Prevention (Cooldown)
&lt;/h3&gt;

&lt;p&gt;To prevent runaway Snapshot creation during sustained mass-deletion events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before creating snapshot, check for recent remediation snapshots
&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mgmt_ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/api/storage/volumes/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;vol_uuid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/snapshots&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?name=remediation_*&amp;amp;order_by=create_time desc&amp;amp;max_records=1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;snaps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;records&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;snaps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;last_snap_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snaps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;create_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Skip if a remediation snapshot was created in the last 15 minutes
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_within_cooldown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_snap_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skipped — cooldown active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ONTAP limits&lt;/strong&gt;: Each volume supports up to 1023 Snapshots. The cooldown prevents hitting this limit during sustained attack scenarios.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Remediation Audit Trail
&lt;/h3&gt;

&lt;p&gt;The Lambda invocation itself must be auditable — proving that the Snapshot was created by an authorized pipeline, not a rogue actor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudTrail&lt;/strong&gt;: Lambda invocation recorded with &lt;code&gt;InvokedBy: workflow.datadoghq.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ONTAP audit log&lt;/strong&gt;: Snapshot creation appears as an administrative event with the API user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datadog Case&lt;/strong&gt;: Snapshot name and status recorded in the Case timeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda CloudWatch Logs&lt;/strong&gt;: Full request/response logged with correlation ID&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;This article covered the complete detection-to-response lifecycle. Future enhancements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Datadog Threat Intel feeds&lt;/strong&gt; — When Datadog makes the Threat Intel Indicators API available on AP1, feed internal IP reputation lists for richer enrichment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-SVM snapshot orchestration&lt;/strong&gt; — Extend the remediation Lambda to snapshot across multiple SVMs in parallel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated account lockout&lt;/strong&gt; — Chain the Workflow to invoke AD lockout via Systems Manager Run Command&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yoshiki0705/fsxn-observability-integrations" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>datadog</category>
      <category>security</category>
      <category>amazonfsxfornetappontap</category>
    </item>
  </channel>
</rss>
