Ticket queues cannot keep pace with AI teams and agent pipelines requesting data. Policy-as-code moves the access decision to query time, tied to classification tags instead of table names, with a step-by-step comparison, an RBAC vs. ABAC vs. tag table, and a worked example.
By

Billy Allocca

Table of Contents
Policy-as-Code for AI Data Access: How Platform Engineering Teams Are Replacing Manual Access Reviews
Policy-as-code for AI data access is the practice of writing data access rules as versioned, machine-readable policy that the data platform evaluates at query time, so a request from an analyst, a training pipeline, or an AI agent is allowed, filtered, or masked automatically based on the requester's attributes and the data's classification tags, with every decision logged.
Manual approval already fails at human request volume. In StrongDM's 2022 survey of 600 DevOps professionals, 57 percent of organizations said infrastructure access requests take days or weeks to approve, and 52 percent of development teams had missed a deadline because of access delays [1]. An IBM analysis published in March 2026 put the typical turnaround for a data request at one to four weeks [2]. AI teams multiply the queue: CyberArk's 2025 identity security survey counted 82 machine identities for every human identity and named AI as the largest creator of new identities with privileged access in 2025 [3].
The platform teams absorbing this load are becoming the norm. Gartner projects that by 2026, 80 percent of large software engineering organizations will run platform engineering teams as internal providers of reusable services, up from 45 percent in 2022 [4]. Those teams inherit data access governance, and codified policy is the only model that lets them carry it without adding reviewers.
If you want the architectural argument for why the access boundary for humans and AI has to be one layer, read the companion post One Governance Model for Data and AI.
Why Does Ticket-Based Data Access Approval Break Under AI Workloads?
Ticket-based approval breaks because it grants named objects to named people, and AI workloads change both sides of that pairing faster than a reviewer can read. A ticket-based access review is a workflow in which a requester files for a specific table or bucket, a data owner inspects the request, and an administrator grants a static permission. That model assumes a stable set of requesters and tables and a request rate a human can process.
An AI feature team violates every assumption. A retrieval pipeline touches dozens of tables in its first week and adds more as embeddings improve. A retraining job needs the same tables under a service identity that did not exist last quarter. An agent requests data on behalf of whichever user triggered it, at 2 a.m., across domains. Each case generates a ticket that asks a reviewer to recall column sensitivity from memory. StrongDM found that 55 percent of IT, security, and DevOps staff keep backdoor access to systems and 53 percent share credentials across teams, which is what a two-week front door produces [1].
Step | Ticket-based access review | Policy-as-code |
|---|---|---|
1. Request | Engineer files a ticket naming tables and a justification | Engineer's role and the dataset's tags already exist; the request is the query itself |
2. Triage | Platform team routes the ticket to a data owner | Policy engine evaluates the request in milliseconds against the rule set |
3. Review | Owner reads the ticket, checks which columns hold PII, asks follow-up questions | Rules encode the PII decision once; classification tags carry it per column |
4. Approval | Owner approves, often with conditions typed into a comment | Decision is allow, deny, filter, or mask, returned as structured output |
5. Provisioning | Admin writes a grant in the warehouse, another in object storage, another in Spark | Enforcement points across engines read the same decision |
6. Audit | Ticket ID and grant are reconciled manually during quarterly certification | Every decision is logged with subject, resource, tags, and outcome at request time |
7. Change | New table added to the dataset triggers a new ticket cycle | New table inherits the dataset's tags and is governed on creation |
8. Revocation | Grant persists until someone remembers to remove it | Access ends when the attribute or tag that granted it changes |
Elapsed time is measured in weeks on the left and milliseconds on the right, and the right column produces its audit evidence as a byproduct of operating.
What Does Policy-as-Code Look Like for a Data Estate?
Policy-as-code for data means the access rule lives in a text file under version control, is evaluated by an engine separate from the systems that enforce it, and returns a decision those systems apply. HashiCorp's Sentinel documentation defines the general idea as "writing code in a high-level language to manage and automate policies" so that "version control, automated testing, and automated deployment" apply to policy as they apply to software [5].
The engine most platform teams know is Open Policy Agent (OPA), a general-purpose policy engine that "decouples policy decision-making from policy enforcement": a service queries OPA with JSON input and receives a decision back [6]. Policies are written in Rego, OPA's declarative language, which "lets you express desired rules and decisions as code" [7]. Infrastructure teams already run this pattern through OPA Gatekeeper, "a validating and mutating webhook that enforces CRD-based policies executed by Open Policy Agent" at Kubernetes admission [8]. The data-layer equivalent exists: Trino's OPA access control plugin sends each request's identity and target resource to OPA and applies the returned decision, including row filtering and column masking [9].
Attribute-based access control (ABAC) is the authorization model these engines implement. NIST SP 800-162 defines it as a method in which authorization "is determined by evaluating attributes associated with the subject, object, requested operations, and, in some cases, environment conditions against policy" [10]. Data classification supplies the object attributes: a label such as PII or PCI attached to a table or column in a catalog like DataHub, where tags apply at the dataset level or to individual schema fields [11].
A data access policy qualifies as policy-as-code when it meets every item on this list:
The rule is stored as text in a repository with history, diffs, and pull-request review.
The rule references subject attributes (role, team, tenant) and object attributes (classification tags), never individual usernames or table names.
The rule is evaluated per request, at query time, by an engine that returns allow, deny, filter, or mask.
The same rule governs every engine that can reach the data, so a Spark job and a Trino query and a direct object read see identical outcomes.
The evaluation is logged with enough detail that an auditor can replay why a specific request was allowed.
The rule can be tested against sample requests in CI before it reaches production.
What Is the Difference Between RBAC, ABAC, and Tag-Driven Classification?
The three models take different inputs, and the input determines how many policies you maintain. Role-based access control (RBAC) assigns permissions to roles and roles to users, which works until roles multiplied by tables outgrows anyone's ability to review the grid; NIST SP 800-162 notes that RBAC needs a new role or permission each time a new combination of need and object appears [10].
Dimension | RBAC | ABAC | Tag-driven classification |
|---|---|---|---|
Decision input | Subject's role | Subject, object, action, and environment attributes | Subject's role or attributes mapped to the object's classification tag |
Where the rule lives | Per-object grant tables in each engine | Central policy engine evaluated at request time | Central policy engine plus tags in the data catalog |
Policy count grows with | Roles multiplied by objects | Number of distinct rules, independent of object count | Number of tags multiplied by roles, independent of object count |
New table added | New grants required in every engine | Governed if its attributes are known to the engine | Governed the moment it inherits the dataset's tag |
Column masking | Manual view or per-engine masking policy | Expressed as a rule on column attributes | Expressed once per tag (for example, mask any column tagged PII for non-privileged roles) |
Audit answer to "who could see this column" | Reconstruct from grants across engines | Query the policy log | Query the policy log and the tag history |
Typical failure | Role explosion and stale grants | Attribute sources drift or are incomplete | Untagged assets fall through to default rules |
Apache Ranger implements the third column directly. It evaluates tag policies before resource policies, and "a single authorization policy for a tag can be used to authorize access to resources across various Hadoop components, which eliminates the need to create separate policies in each component" [12]. If any tag policy denies, the request is denied; only when no tag policy applies does Ranger fall back to a resource-based policy [12]. Ranger also carries the masking and row-filter primitives tag rules need, including partial masks, nullification, and custom expressions [13].
What Happens When an AI Team Requests Customer Transaction Data in Each Model?
The same request produces a weeks-long approval in one model and a masked result set in the other. Assume a fraud-detection team wants to train on payments.transactions, which holds card numbers, customer IDs, merchant IDs, amounts, and timestamps, and later wants an agent to query the same table on behalf of analysts.
Stage | Ticket-based model | Policy-as-code model |
|---|---|---|
Day 0, the ask | Team lead files a ticket for read access to | Team's service identity already carries role |
Day 0 to 3, triage | Platform team identifies the payments data owner and forwards the ticket | Not applicable; a policy already states that role |
Day 3 to 10, review | Owner asks whether the team needs raw card numbers, waits for a reply, consults security about tokenization | Not applicable; the masking decision was made once when the |
Day 10 to 14, provisioning | Admin creates a masked view in the warehouse, grants the role in Spark separately, and opens a bucket policy for the training job's object reads | Not applicable; the first Spark read, Trino query, and object read are each evaluated against the same rule and return hashed card numbers and tokenized customer IDs |
Week 6, scope grows | Team adds |
|
Month 3, the agent | Team requests a service account for an agent; reviewer cannot evaluate what the agent will ask, so the grant is either too broad or refused | The agent runs under the identity of the analyst who invoked it plus its own agent role; every query it issues is evaluated per request, and the agent sees the same masked columns the analyst would |
Quarterly audit | Certification pulls grant lists from three systems and matches them to ticket IDs | Auditor queries the decision log for every read of |
The left column consumed about two weeks of calendar time and four people's attention before the first row was read, and it repeats for the second table. The right column consumed the time to evaluate a rule, because the decisions that used to happen inside the ticket happened once, in code, when the PCI and PII tag policies were reviewed.
Why Not Just Automate the Ticket Queue?
Automating approvals speeds up the wrong step. Workflow tools can auto-approve template matches, route by data domain, and expire grants after 90 days, and each reduces reviewer load. But the output of the fastest ticket system is still a static grant to a named object in a specific engine. It does not follow the data when a table joins the dataset, and it cannot evaluate an agent's request that did not exist when the grant was written.
The caveat runs the other way too. Policy-as-code depends on the quality of its attributes: an untagged table falls through to whatever default you set, and a role assigned too broadly in the identity provider is broad everywhere the policy engine trusts it. Classification effort moves from every ticket to the catalog, once per dataset. That trade is the only version that scales with request volume instead of headcount, and NIST's zero trust architecture reaches the same conclusion from the security side: authorization is a discrete decision made per resource request, by a policy engine, and enforced at the point of access [14].
The adjacent question of what to put in the policy for column-level protection is covered in Column-Level Security in the AI Era, and the question of what the data owner promises the consumer is covered in Data Contracts for AI. The decision log this section describes is also the access half of a provenance trail; the training-data half is covered in The Data Lineage Imperative.
NexusOne Generates Policies From Catalog Tags and Enforces Them at Query Time
NexusOne runs tag-driven policy-as-code as the mechanism of its governance layer. Identity is federated from Active Directory, Okta, LDAP, or SAML into one Keycloak layer, with users, groups, and roles scoped per tenant. Classification comes from DataHub: you tag a dataset once, at table or column level, and map roles to tags in the NexusOne portal. Policies then generate in Apache Ranger at the bucket, schema, and table level, and Ranger enforces them simultaneously across Trino, Apache Spark, Apache Kyuubi, and S3 object storage per object, so the fraud team's Spark job and an analyst's Trino query return the same hashed card column. When a table is added or a schema changes, the policies update without a ticket.
Agents inherit the same model. The AI & Data Control Plane evaluates every agent and MCP request at the boundary under the invoking identity, blocks PII and jailbreak attempts with the reason logged, applies per-role token budgets, and records each request, so one log covers humans and agents (Enterprise AI Governance: Why One Control Plane Is the Only Scalable Answer makes the case). The stack runs identically on-prem, in your cloud, hybrid, or air-gapped, on open formats such as Apache Iceberg. To walk through your own access-request backlog against this model, book an expert consultation.
Key Takeaways
Manual access review fails at human request rates already; 57 percent of organizations report approvals take days or weeks, and AI teams and agents multiply the request volume [1][3].
Policy-as-code moves the access decision to query time, where a policy engine evaluates subject attributes against data classification tags and returns allow, deny, filter, or mask.
Tag-driven classification keeps policy count proportional to tags multiplied by roles instead of roles multiplied by tables, so new tables are governed on creation.
OPA with Rego, Gatekeeper, Sentinel, and Ranger tag policies are proven implementations of the same pattern at the infrastructure and data layers.
Automating the ticket queue produces faster static grants; it does not produce per-request, per-engine, agent-aware enforcement.
NexusOne generates Ranger policies from DataHub tags and enforces them across Trino, Spark, Kyuubi, and S3 under one Keycloak identity for humans and agents.
FAQ
What Is Policy-as-Code in Data Governance for AI?
Policy-as-code in data governance is the practice of writing access rules as versioned text that a policy engine evaluates at request time instead of encoding them as manual approvals and static grants. For AI workloads, the rules reference the requester's role or attributes and the data's classification tags, so a training pipeline or agent is allowed, filtered, or masked automatically. Open Policy Agent and Apache Ranger tag policies are the two most common engines for this pattern in a data estate [6][12].
How Does Automated Data Access Control Work for AI Teams and Agents?
Automated data access control gives each AI team a role and each service or agent an identity in one identity provider, tags datasets and columns with classifications in the catalog, and writes rules that map roles to tags. When a job or agent issues a query, the engine evaluates the request against those rules and returns a decision the query engine enforces, including column masking and row filtering. Because the evaluation is per request, an agent acting for a user sees exactly what that user is allowed to see, and every decision is logged.
How Should an Enterprise Enforce Data Access Policy Across Multiple Engines for AI?
Enforce the policy in one engine that every compute and storage path consults, so the same rule governs a Trino query, a Spark job, and a direct object read. Apache Ranger evaluates tag-based policies before resource-based policies and applies one tag rule across every component it protects, which removes the need to define the same rule per engine [12]. Trino also supports Open Policy Agent as its authorization engine, sending identity and resource details as JSON and applying the returned decision [9].
How Do You Replace Manual Data Access Reviews With Automation?
Start by classifying the datasets AI teams request most and tagging them at the column level for PII, PCI, or equivalent categories. Define roles in the identity provider that correspond to how teams consume data, then write rules that map each role to each tag with an explicit allow, mask, or deny outcome and review those rules in pull requests. Point every engine at the same policy decision point, and treat the decision log as the audit evidence. Tickets remain for the exceptions the rules do not cover, which is where reviewer time belongs.
References
New Research: 57% of Organizations Take Days or Weeks for Infrastructure Access to be Approved (2022 Access-Productivity Gap Report), StrongDM, https://www.strongdm.com/press/organizations-take-days-or-weeks-for-infrastructure-access
Data delivery delays are slowing decisions more than you think, IBM Think, https://www.ibm.com/think/insights/data-access-delays-slowing-decisions
2025 Identity Security Landscape Report, CyberArk, https://www.cyberark.com/threat-landscape/
Platform Engineering, Gartner, https://www.gartner.com/en/infrastructure-and-it-operations-leaders/topics/platform-engineering
Policy as Code, HashiCorp Sentinel Documentation, https://developer.hashicorp.com/sentinel/docs/concepts/policy-as-code
Open Policy Agent Documentation: Introduction, Open Policy Agent, https://www.openpolicyagent.org/docs
Policy Language (Rego), Open Policy Agent, https://www.openpolicyagent.org/docs/policy-language
Introduction, OPA Gatekeeper Documentation, https://open-policy-agent.github.io/gatekeeper/website/docs/
Open Policy Agent access control, Trino Documentation, https://trino.io/docs/current/security/opa-access-control.html
NIST SP 800-162, Guide to Attribute Based Access Control (ABAC) Definition and Considerations, NIST, https://csrc.nist.gov/pubs/sp/800/162/upd2/final
Tags, DataHub Documentation, https://docs.datahub.com/docs/tags
Tag Based Policies, Apache Ranger Wiki, https://cwiki.apache.org/confluence/display/RANGER/Tag+Based+Policies
Row-level filtering and column-masking using Apache Ranger policies in Apache Hive, Apache Ranger Wiki, https://cwiki.apache.org/confluence/display/RANGER/Row-level+filtering+and+column-masking+using+Apache+Ranger+policies+in+Apache+Hive
NIST SP 800-207, Zero Trust Architecture, NIST, https://csrc.nist.gov/pubs/sp/800/207/final

