Three Snowflake RBAC Anti-Patterns We See Every Engagement
Snowflake’s role hierarchy is one of the cleaner permission systems in the modern data stack — and it is also one of the most misconfigured. Every audit we run, the same three anti-patterns turn up. None of them are exotic. All of them are quiet.
If your warehouse has been growing for three years without a periodic re-look, it is almost certainly running at least one of these.
Anti-pattern one: functional roles bleeding into account roles
The intended Snowflake pattern is two-tier:
- Functional roles describe what a user does —
analyst_marketing,engineer_etl,bi_viewer. These get grants on objects. - Account roles describe what a user is — typically
sysadmin,securityadmin,useradmin. These get role-management grants only.
The anti-pattern: somebody decides it is easier to attach an object grant
directly to sysadmin “just for this one warehouse.” Six months later,
half a dozen functional roles inherit from sysadmin for unrelated
reasons, and a junior analyst with a marketing_analyst role can now
query a payroll table because of a transitive grant nobody traced.
Find it: walk the role graph from any privileged account role downward. Anything that is not a role-management grant on an account role is a candidate for migration to a functional role.
Snowflake’s
SHOW GRANTS ON ROLE sysadminis the single most useful command we run on day one. If the output has more than three lines that are not role-management grants, you have this anti-pattern.
Anti-pattern two: default warehouse with too much grant
Every Snowflake user has a default warehouse — the one their session
attaches to if they don’t specify one. The convenient pattern is a single
shared compute_wh that everyone defaults to.
The anti-pattern: that shared default warehouse has USAGE granted to
PUBLIC (or to a role that PUBLIC inherits from). Now any service
account, any third-party app, any one-off integration credential can
attach to it and run queries — using your credits, on your bill, with no
clear attribution.
Find it: SHOW GRANTS TO ROLE PUBLIC. If a warehouse appears, you have
this anti-pattern. The fix is straightforward: revoke from PUBLIC, grant
explicitly to functional roles that should have access, set
STATEMENT_TIMEOUT_IN_SECONDS and RESOURCE_MONITOR on the warehouse so
runaway queries cap themselves.
Anti-pattern three: the BI tool that reads more than you think
Sigma, Tableau, Looker, Mode — each connects to Snowflake with a service
account. The convenient pattern: give that service account a role with
broad USAGE on multiple databases so analysts can join anywhere they
need to.
The anti-pattern: that service account role can also read tables in schemas the BI tool was never supposed to touch — billing, audit logs, HR. The dashboard never queries them, but the service account could. If the BI tool’s credentials leak, or a malicious internal user pivots through the BI tool’s query history, those tables are reachable.
Find it: query SHOW GRANTS TO ROLE <bi_service_role> and compare against
the actual datasets the BI tool exposes to end users. Any database that
the BI tool grants access to but never surfaces in a workbook is a
candidate to revoke.
The pattern across all three
Every one of these anti-patterns starts as a convenience: a quick grant to unblock a specific request. None of them are flagged by Snowflake’s UI. None of them break anything that someone would notice.
The fix in all three cases is the same: a quarterly walk of the role
graph from sysadmin downward, and a written record of why every grant
exists. If nobody can name the request that justified a grant, it gets
revoked.
What we’d do
If you have not run a Snowflake RBAC review in twelve months, this is what Lattice (our two-week data-pipeline audit) covers — all three anti-patterns above, plus lineage tracing for sensitive joins and a priority-ranked hardening list. See Lattice → · Book a discovery call →