{"id":6000,"date":"2026-11-01T18:20:00","date_gmt":"2026-11-01T18:20:00","guid":{"rendered":"https:\/\/www.cmsgalaxy.com\/blog\/?p=6000"},"modified":"2026-11-01T18:20:00","modified_gmt":"2026-11-01T18:20:00","slug":"datasecops-agency-snowflake-case","status":"publish","type":"post","link":"https:\/\/www.cmsgalaxy.com\/blog\/datasecops-agency-snowflake-case\/","title":{"rendered":"A DataSecOps Case Study: One Agency&#8217;s Snowflake Reset"},"content":{"rendered":"<p>Willowmere Studio builds dashboards for clinic groups \u2014 twelve people, one warehouse, and a client list that trusts them with appointment records. On a Tuesday morning in March, their lead engineer found a query log entry that made her stomach drop: a service account had exported a 40-gigabyte slice of the client data platform overnight. It turned out to be the client&#8217;s own nightly job, running with credentials nobody had reviewed since onboarding. But the scare did its work. Here is how one twelve-person agency rebuilt its data protection in six weeks using <strong>DataSecOps<\/strong> \u2014 the discipline Satori Cyber&#8217;s chief scientist Ben Herzberg named in August 2021, which embeds security into the everyday churn of data and the people touching it. The name is vendor shorthand rather than a standard, but the six weeks changed how Willowmere works, and the specific walls they hit inside one warehouse will look familiar to anyone running a similar stack.<\/p>\n<h2>Week one: the inventory nobody wanted to do<\/h2>\n<p>First came the uncomfortable spreadsheet. Every table, every copy, every forgotten sandbox. The agency found eleven locations holding client-identifying fields, of which four were clones nobody remembered creating. An old staging snapshot from a 2024 migration sat in a schema named <em>tmp_dont_delete<\/em> \u2014 it did get deleted, but only after someone confirmed no job referenced it. The lesson the team repeats to clients now: you cannot protect tables you cannot name. Discovery ran on the warehouse&#8217;s own object listings plus a scanner pass, and the scanner&#8217;s output needed a human second look, because automated classifiers are never fully accurate \u2014 the machine flagged a free-text notes column correctly but missed that an ID field embedded birth dates in its digits. Two people spent a full day confirming tags by hand, and that day remains the cheapest insurance the agency ever bought.<\/p>\n<h2>Week two: the paywall surprise<\/h2>\n<p>Then came the first hard wall. Masking policies and row access controls in Snowflake require the Enterprise edition or higher, and Willowmere was running a tier two steps below. The upgrade conversation with the founders was short once framed as a client-retention issue \u2014 the alternative was telling clinic groups their appointment data sat in an unmasked table readable by every developer account. The same week, the team retired password-only sign-ins for human users and turned on multifactor authentication, ahead of the phased deadline that runs through 2026. That single Tuesday fix would have blunted the credential-stolen campaign pattern of 2024 \u2014 the one tracked as UNC5537, where infostealer-exposed passwords without MFA let attackers walk into roughly 165 tenant organisations and pull data out through COPY INTO exports while the platform itself stayed clean.<\/p>\n<h2>Weeks three and four: DataSecOps policies misbehave<\/h2>\n<p>Writing the first masking policy taught the team the engine&#8217;s personality. The rule that ties masking policies to tags allows only one policy of each data type to hang on any given tag, so planning the tag taxonomy came first \u2014 a half-hour of whiteboarding that saved a week of rework. Then a subtler trap: once a policy attaches to a tag, you cannot swap in a different policy object; the only move is modifying the policy body with a SET BODY statement. Their first attempt to &#8220;just replace it&#8221; failed with a permissions error that cost an afternoon of confusion. The team also learned what row policies do not do: they filter reads, but they do not stop inserts, so a poorly scoped writer could still stuff rows into a table it could not see. Writes got their own controls.<\/p>\n<h2>Week five: the history that lags<\/h2>\n<p>The access-review habit hit the second wall: latency. The warehouse&#8217;s ACCESS_HISTORY view, the team found, keeps 365 days of read history \u2014 genuinely useful \u2014 but with up to a three-hour lag, and failed queries do not appear at all. An investigator chasing an active incident therefore sees the recent past slightly out of focus, like watching a replay with a delay. Willowmere&#8217;s compromise: weekly reviews of the history for pattern-watching, and a runbook note that anything fresher than three hours must come from live query telemetry, not the history view. Their review now has teeth, too \u2014 grants expire on dates, and the quarterly walk revokes what went quiet, not merely re-approves it.<\/p>\n<h2>Week six: writing it down<\/h2>\n<p>The rebuild ended not with tooling but with a document: the classification standard (what counts as IDENTIFIER, who confirms scanner output), the request workflow (a request names the table, the reason, the end date; the client&#8217;s data owner approves it like a pull request; the pipeline applies it), and the review calendar. The founders approved one budget line \u2014 the tier upgrade \u2014 and nothing else. Everything else was habit. For teams starting from a similar scare, the sequencing matters: inventory first, tier and MFA second, policies third, history fourth, paperwork last.<\/p>\n<h2>What the story teaches about DataSecOps<\/h2>\n<p>A scare is a terrible way to learn governance but an excellent motivator, and Willowmere&#8217;s six weeks compressed what the DataSecOps loop describes on paper: discover, classify, codify, enforce, watch exits, read history, prune. The order mattered more than the tools \u2014 every week&#8217;s work depended on the previous week&#8217;s artefact. The full scope and vocabulary of the approach \u2014 including how its boundaries meet neighbouring practices \u2014 is documented in the <a href=\"https:\/\/www.xopsschool.com\/datasecops\/\">Ops Atlas DataSecOps entry<\/a>. For the pipeline discipline underneath warehouse work, our overview of <a href=\"https:\/\/www.cmsgalaxy.com\/blog\/navigating-dataops-courses-certifications-and-professional-services\/\">DataOps courses, certifications and professional services<\/a> maps the training options; the governance habit that keeps delivery itself accountable is covered in this piece on <a href=\"https:\/\/www.cmsgalaxy.com\/blog\/scmgalaxy-os-helps-organizations-govern-the-complete-software-delivery-lifecycle\/\">governing the complete software delivery lifecycle<\/a>; and the perimeter side of the same story \u2014 what your own digital footprint leaks \u2014 sits in <a href=\"https:\/\/www.cmsgalaxy.com\/blog\/the-complete-guide-to-url-management-organize-monitor-and-protect-your-digital-footprint\/\">our guide to URL management and footprint protection<\/a>.<\/p>\n<ul>\n<li>Name every copy: clones and old snapshots held half of Willowmere&#8217;s sensitive data.<\/li>\n<li>Check your tier before promising masking \u2014 Enterprise and above is where the controls live.<\/li>\n<li>Plan tag-to-policy mapping first; policies attach once and only the body can change (SET BODY).<\/li>\n<li>Row policies guard reads, not inserts \u2014 writes need separate controls.<\/li>\n<li>Access history has a three-hour lag and hides failed queries; use live telemetry for fresh incidents.<\/li>\n<li>MFA beats forensics: the 2024 tenant breaches rode stolen passwords that MFA would have stopped.<\/li>\n<\/ul>\n<p>Willowmere still runs twelve people. What changed is that the next Tuesday-morning query log surprise will find a team with tags on their tables, expiries on their grants, and a document that says who decided all of it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Willowmere Studio, twelve people, one export scare: a six-week DataSecOps rebuild through Snowflake tiers, masking policy quirks and access-history lag.<\/p>\n","protected":false},"author":14,"featured_media":6001,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1455],"tags":[],"class_list":["post-6000","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-development"],"_links":{"self":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts\/6000","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/comments?post=6000"}],"version-history":[{"count":1,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts\/6000\/revisions"}],"predecessor-version":[{"id":6033,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/posts\/6000\/revisions\/6033"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/media\/6001"}],"wp:attachment":[{"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/media?parent=6000"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/categories?post=6000"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmsgalaxy.com\/blog\/wp-json\/wp\/v2\/tags?post=6000"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}