Apache Polaris controls access through role-based access control with four levels: a privilege is granted to a catalog role, the catalog role is granted to a principal role, and the principal role is assigned to a principal. Privileges never attach to a person directly. The two privileges that matter most, TABLE_READ_DATA and TABLE_WRITE_DATA, are the only ones that cause Polaris to issue short-lived storage credentials, and they sit outside the metadata grant that covers everything else.
Most catalog security discussions stop at “it supports RBAC.” That tells you nothing. Every system supports RBAC. What matters is where the boundaries fall, what a grant actually permits, and whether someone holding read access to a table's metadata can also read its bytes.
In Polaris those are different questions with different answers, and the gap between them is the most interesting design decision in the whole model.
What This Covers
The four-level grant chain and why it has four levels rather than two, the full privilege list for tables, views, namespaces, catalogs and policies, the deliberate split between metadata access and data access, how credential vending turns a privilege into a time-limited key, and where this model breaks down if you try to express row-level rules with it.
The Grant Chain Has Four Links
Four hops from a person to a permission. Every grant in Polaris follows this shape.
Read it right to left and it makes more sense. A privilege is an action on a securable object. Securable objects in Polaris are catalogs, namespaces, Iceberg tables, views and policies. That list is the complete surface over which permissions can be expressed.
Privileges are granted to a catalog role. A catalog role belongs to one catalog and holds a set of permissions for actions inside it. You might have a catalog role called Catalog readers with read-only privileges, and another called Catalog contributor with read and write.
Catalog roles are granted to principal roles. A principal role groups people and services by what they do: Data_engineer, Data_scientist. Both relationships are many-to-many, so one catalog role can serve several principal roles and one principal role can hold several catalog roles.
Principal roles are assigned to principals, which are the actual identities that authenticate.
Here is the rule that trips people up: you do not grant privileges to a principal role. The docs are explicit about it. You configure object permissions at the catalog role level, then grant catalog roles to principal roles. If you find yourself wanting to attach a privilege straight to Data_engineer, the model is telling you to make a catalog role.
Why four levels instead of two
Two levels would be simpler. Grant privileges to a role, assign the role to a person. Done.
The extra layer exists because catalogs are the unit of ownership and principal roles are the unit of job function, and those two things do not line up. Your finance catalog and your marketing catalog have different owners who want to define their own roles. Your data engineers work across both.
Splitting catalog roles from principal roles lets the finance team define what “contributor” means inside finance without coordinating with marketing, and lets a platform team grant Data_engineer access to both by composing existing roles. Collapse the levels and every permission change becomes a cross-team negotiation.
Bootstrapping: Where the First Principal Comes From
Every RBAC system has a chicken and egg problem. Someone has to create the first principal, and that someone cannot have been granted the right to do so by a principal that does not exist yet.
Polaris resolves this at bootstrap time through its admin tool, which initialises the metastore for a realm and establishes the root credentials. That is a deployment operation, not a catalog operation, and it happens before the service starts serving requests.
Treat those root credentials the way you would treat a database superuser password. They exist to create the real admin principals and then should not be used again. If your runbook has engineers authenticating as root to fix things, the audit trail stops being useful on day one.
Because realms are isolated, bootstrapping is per realm. A new tenant means a new bootstrap, which is a feature rather than a chore: there is no shared root identity that spans tenants.
The Full Privilege List
Polaris names privileges after the object and the action. Here is the complete set, which is worth reading once because several names do not mean what you would guess.
Table privileges
TABLE_CREATE register a table with the catalog
TABLE_DROP drop a table from the catalog
TABLE_LIST list any table in the catalog
TABLE_READ_PROPERTIES read properties of the table
TABLE_WRITE_PROPERTIES configure properties for the table
TABLE_READ_DATA receive short-lived read-only storage credentials
TABLE_WRITE_DATA receive short-lived read and write storage credentials
TABLE_FULL_METADATA all table privileges EXCEPT READ_DATA and WRITE_DATA
TABLE_ATTACH_POLICY attach a policy to a table
TABLE_DETACH_POLICY detach a policy from a table
View, namespace, catalog and policy privileges
Views follow the same shape with VIEW_CREATE, VIEW_DROP, VIEW_LIST, VIEW_READ_PROPERTIES, VIEW_WRITE_PROPERTIES and VIEW_FULL_METADATA. There is no VIEW_READ_DATA, because reading a view resolves to reading the tables underneath it, and those carry their own grants.
Namespaces add NAMESPACE_CREATE, NAMESPACE_DROP, NAMESPACE_LIST, NAMESPACE_READ_PROPERTIES, NAMESPACE_WRITE_PROPERTIES, NAMESPACE_FULL_METADATA, plus policy attach and detach. NAMESPACE_LIST is broader than it sounds: it covers listing any object in the namespace, including nested namespaces and tables.
Catalog privileges are where the powerful grants live. CATALOG_MANAGE_ACCESS carries the ability to grant and revoke privileges on objects in the catalog and to grant catalog roles to principal roles. That is the privilege that lets someone expand their own access, so treat it the way you would treat a database GRANT OPTION.
CATALOG_MANAGE_CONTENT is the big one. It encompasses CATALOG_MANAGE_METADATA, TABLE_FULL_METADATA, NAMESPACE_FULL_METADATA, VIEW_FULL_METADATA, TABLE_WRITE_DATA, TABLE_READ_DATA, CATALOG_READ_PROPERTIES and CATALOG_WRITE_PROPERTIES. Granting it is close to granting everything short of access management.
Policies get POLICY_CREATE, POLICY_READ, POLICY_WRITE, POLICY_LIST, POLICY_DROP, POLICY_FULL_METADATA, POLICY_ATTACH and POLICY_DETACH. POLICY_DROP only works on a policy that is not attached to anything, which stops someone deleting a policy out from under the objects relying on it.
Metadata Access and Data Access Are Not the Same Grant
TABLE_FULL_METADATA grants everything except the two privileges that produce storage credentials.
This is the part worth internalising. TABLE_FULL_METADATA sounds like the everything privilege for a table. It is not. It grants all table privileges except TABLE_READ_DATA and TABLE_WRITE_DATA, which have to be granted individually.
So a principal can hold TABLE_FULL_METADATA and be able to list the table, read its properties, see its schema, attach policies to it, even drop it, while never receiving a credential that lets them read a single row.
That sounds strange until you think about who needs which. A data catalog crawler needs to enumerate tables and read schemas. A governance tool needs to attach policies. A cost analysis job needs table properties. None of them need the data. Under a single combined privilege they would all get it anyway.
The inverse matters too. TABLE_READ_DATA is described in the docs as enabling reading data “by receiving short-lived read-only storage credentials from the catalog.” The privilege is not an abstract permission that some downstream system enforces. It is the thing that causes Polaris to call your cloud provider and mint a key.
A warning that belongs in your onboarding docs
Table and view properties are readable metadata. Any principal with TABLE_READ_PROPERTIES or TABLE_FULL_METADATA can read them, and the same applies to the view equivalents. The Polaris docs say this plainly: do not store passwords, tokens, access keys or other secrets in table or view properties.
The same applies at the catalog level. Catalog properties are returned to authenticated clients through the Iceberg REST config response. They are client-visible by design.
Credential Vending Turns a Privilege Into a Key
No engine holds a standing key. Every read gets a credential scoped to one path and a short life.
When an engine loads a table and holds the right data privilege, Polaris does not hand back a permanent credential. It asks your cloud provider for a temporary one, scoped as tightly as the provider allows.
On AWS, Polaris calls STS AssumeRole with an inline session policy scoped to the specific table locations and to the read, list and write operations the caller is authorized to perform. The response carries the access key, secret, session token and an expiry timestamp, marked as credential material and never logged. Alongside them come configuration properties: the region, and a refresh endpoint the client can call to renew before expiry.
On Azure, Polaris generates a User Delegation SAS token scoped to the container and path prefix the caller can reach. Azure caps User Delegation SAS validity at seven days. That is a platform limit, not a Polaris setting, and it constrains how you design long-running jobs.
Compare this to the common alternative. Give Spark an instance profile with bucket-wide access, then write bucket policies to narrow it. Now your permission model lives in two systems that do not know about each other, and the catalog's opinion about who may read a table has no bearing on whether they can.
How Grants Are Stored and Evaluated
Grants live in the metastore alongside the entities they apply to, as grant records. That matters for two reasons.
First, the permission graph is operational data. It needs backups, and it needs to be part of your disaster recovery plan. Losing the metastore does not lose your Iceberg tables, since those are files in object storage, but it does lose every grant and every catalog registration. Recovering the data without the grants means a table nobody is allowed to read.
Second, evaluation happens on the request path. When an engine calls loadTable, Polaris walks from the authenticated principal through its principal roles to their catalog roles to the grants on the target object. That walk is fast, but it is not free, and it is one of the reasons the metastore needs sizing for planning concurrency rather than table count.
The realm id is part of the primary key in the persistence layer, so grant records from one realm cannot be returned when resolving another. Isolation is enforced by the schema rather than by remembering to add a filter.
What the client actually receives
The credential arrives inside the table load response, split across two maps. Sensitive material goes in the credentials map, marked as credential kind, and Polaris does not log it. Non-sensitive settings go in the config map.
For AWS that means the access key, secret, session token and expiry timestamp land in credentials, while the region and refresh endpoint land in config. For an S3-compatible store such as MinIO or Apache Ozone, the endpoint URL and the path-style access flag also appear in config. On native AWS S3 those two are absent entirely.
That absence is diagnostic. If a client works against a local MinIO and fails against production S3, look at whether it was depending on a config property that only appears for S3-compatible stores.
A Worked Example
Roles are the unit of change. People come and go, the grant graph stays stable.
Alice is a service admin. She creates principals, catalogs and namespaces, and configures access control. Bob is a data engineer who uses Apache Spark.
Alice creates a principal for Bob and grants it the Data_engineer principal role. Data_engineer has been granted two catalog roles: Catalog contributor, which carries read and write privileges on tables in that catalog, and Catalog readers, which carries read-only privileges.
Bob's name appears in exactly one place: the assignment of a principal role to his principal. He does not appear in any privilege grant. When a second engineer joins, Alice assigns the same principal role and the new engineer inherits the entire permission set. When the team's access needs to change, Alice changes the catalog role once.
This is the practical payoff of four levels. The grant graph stays stable while people move through it.
Where This Model Runs Out
Polaris expresses permissions on objects. Catalogs, namespaces, tables, views, policies. It does not express row-level or column-level rules, and pretending otherwise leads to trouble.
If you need to say “this analyst sees EU customers only,” that logic belongs in the layer above: a view that filters, or a semantic layer that applies the rule at query time. Polaris can control who reads the view, which is the right division of labour, but the filter itself is not a Polaris concept.
For teams whose authorization rules already live somewhere else, Polaris supports external Policy Decision Points, including Open Policy Agent. If your policies are already written in Rego and reviewed through your normal change process, wiring Polaris to consult them beats maintaining a parallel copy that drifts.
Five Misconfigurations Worth Checking For
Granting CATALOG_MANAGE_CONTENT as a default
It encompasses metadata management for tables, namespaces and views, plus both data privileges, plus catalog property access. It is close to full control. It shows up as a default because it makes things work, and then nobody narrows it.
Secrets in table properties
Any principal with TABLE_READ_PROPERTIES can read them, and TABLE_FULL_METADATA includes that. Connection strings and tokens end up there more often than anyone admits, usually because a pipeline tool wrote them.
One principal shared by every job
It works, and it destroys attribution. When a table gets dropped at 03:00 the grant records will tell you a principal did it, and that principal will be called something like etl-service and be used by forty jobs.
Principal roles named after teams
Teams reorganise. Job functions do not. A role called platform-team becomes wrong the moment the org chart changes, while data-engineer stays accurate for years.
Assuming a view hides the table underneath
Views have no VIEW_READ_DATA privilege. Reading a view resolves to reading its underlying tables, and those carry their own grants. A view is not a security boundary on its own, it is a convenience that still depends on what the reader can reach beneath it.
Designing Grants You Can Live With
Start from job functions, not from tables
Write down the four or five things people actually do: build pipelines, run analysis, govern, operate. Those become principal roles. Resist creating a principal role per team, because teams reorganise and job functions do not.
Keep CATALOG_MANAGE_ACCESS rare
Anyone holding it can widen their own access. It should sit with a small admin role and nowhere else. If you find it inside a role that engineers hold, you have effectively granted everyone everything with extra steps.
Grant data privileges last and separately
Use TABLE_FULL_METADATA for anything that needs to see the catalog, and add TABLE_READ_DATA only where reading rows is the actual job. The split exists precisely so you can do this, and most tools that connect to a catalog need far less than they ask for.
Audit by role, not by person
Because privileges never attach to principals, the question “what can Bob do?” is answered by walking his principal roles to their catalog roles to their grants. That path is the audit trail. It is also why you should keep role names meaningful, since they are what anyone reviewing access will actually read.
Common Questions
Can I grant a privilege directly to a person?
No, and the model is built to prevent it. Privileges go to catalog roles, catalog roles go to principal roles, principal roles go to principals. The indirection is what makes access reviewable, because you audit a handful of roles rather than hundreds of individual grants.
Does TABLE_FULL_METADATA let someone read my data?
No. It grants every table privilege except TABLE_READ_DATA and TABLE_WRITE_DATA. A principal with it can list the table, read its schema and properties, and even drop it, without ever receiving storage credentials.
What happens when a vended credential expires mid-query?
Polaris returns a refresh endpoint alongside the credential so clients can renew before expiry. The Iceberg SDKs use it. Long-running jobs on Azure need more care because User Delegation SAS tokens are capped at seven days by the platform.
Can I use my existing policy engine instead?
Yes. Polaris supports external Policy Decision Points, with Open Policy Agent as the documented path. If your authorization rules already live in Rego and go through your normal review process, that is usually better than maintaining a second copy inside the catalog.
How do I express column or row level rules?
Not in Polaris. It secures objects, not slices of them. Put the filter in a view or in a semantic layer above the catalog, and use Polaris to control who can read that view.
Do grants apply across realms?
No. Realms are isolated, including principals and grant records, and the realm id is part of the metastore primary key. A grant in one realm has no meaning in another.
Where Dremio Fits
Dremio co-created Apache Polaris and donated it to the Apache Software Foundation. Dremio's Open Catalog is built on Polaris, so the access model described here is the same one operating behind Dremio, and the credentials handed to a query are scoped the same way.
Because the catalog enforces authorization before issuing a credential, every engine connecting to it gets a consistent answer. You configure access once rather than configuring it in Spark, again in Trino, and again in whatever arrives next year.
Above the catalog, Dremio's semantic layer is where the rules Polaris deliberately does not express belong. Row filters, column masking and business definitions live there, applied at query time, while the catalog keeps doing the job it is good at.
The Question Worth Asking Your Current Catalog
Can a principal read a table's bytes without a grant that says so, and can you prove it?
In Polaris the answer is structural. Reading data requires TABLE_READ_DATA, that privilege is what triggers credential issuance, and the credential that comes back is scoped to one path and expires. There is no side door where a broad IAM role quietly grants what the catalog refused.
Most catalogs cannot make that claim, because they never held the keys in the first place. Take your current setup, revoke the catalog grant for one table, and try to read it anyway. What happens next tells you whether your catalog is enforcing access or just describing it.
There is a broader point buried in the metadata and data split. Polaris treats “knowing a table exists” and “being able to read it” as different permissions, and most systems do not. That distinction is what lets a catalog be genuinely shared across an organisation. Discovery tools, governance tools and cost tools can all enumerate everything without any of them holding a key to the contents.
Get that separation right and the catalog becomes the place people look to find data. Get it wrong and every integration becomes a security review, so teams stop registering tables and go back to sharing bucket paths in chat.
For a full treatment of the catalog layer, download Apache Polaris: The Definitive Guide by Alex Merced, Andrew Madson, and Tomer Shiran, free from Dremio.
Intro to Dremio, Nessie, and Apache Iceberg on Your Laptop
Editor’s note, September 2026. This post was published in September 2023 and some product details have changed since. Nessie is still available and self-deployable under the Apache-2.0 licence, and it remains the clearest implementation of catalog-level branching. It is not an Apache Software Foundation project, and its development has slowed considerably. For how the current […]
Aug 16, 2023·Dremio Blog: News Highlights
5 Use Cases for the Dremio Lakehouse
With its capabilities in on-prem to cloud migration, data warehouse offload, data virtualization, upgrading data lakes and lakehouses, and building customer-facing analytics applications, Dremio provides the tools and functionalities to streamline operations and unlock the full potential of data assets.
Aug 24, 2026·Dremio Blog: Open Data Insights
Migrating to Apache Iceberg: Strategies for Every Source System
This is Part 15, the final article of a 15-part Apache Iceberg Masterclass. Part 14 covered hands-on Dremio Cloud. This article covers the three migration strategies and how to execute a zero-downtime migration using the view swap pattern. Most organizations do not start with Iceberg. They have years of data in Hive tables, data warehouses, CSV files, databases, […]