Pangolin implements a hierarchical role-based access control system to manage permissions across tenants, catalogs, and resources.
Key Features:
- 3-tier role hierarchy (Root, TenantAdmin, TenantUser)
- Granular permission scopes (Catalog, Namespace, Asset, Tag)
- Service user support for programmatic access
- Tenant isolation
- Scope: Global (all tenants)
- Permissions: Full system access
- Can:
- Create/delete tenants
- Manage all users across all tenants
- Access all catalogs and resources
- Configure system-wide settings
Use Case: System administrators
- Scope: Single tenant
- Permissions: Full access within their tenant
- Can:
- Create/delete users in their tenant
- Create/delete catalogs, warehouses
- Manage permissions for their tenant
- Create service users
- Create federated catalogs
Cannot:
- Access other tenants
- Create new tenants
- Modify system settings
Use Case: Team leads, data platform administrators
- Scope: Single tenant with granular permissions
- Permissions: Based on assigned permissions
- Can:
- Read/write to authorized catalogs
- Create tables in authorized namespaces
- Query authorized tables
Cannot:
- Create users or service users
- Modify tenant settings
- Access unauthorized resources
Use Case: Data engineers, data scientists, analysts
Permissions apply to an entire catalog and all its namespaces/tables.
Example: Grant user read access to analytics catalog
{
"user_id": "uuid",
"scope": "Catalog",
"resource": "analytics",
"action": "Read"
}Permissions apply to a specific namespace and its tables.
Example: Grant user write access to sales.transactions namespace
{
"user_id": "uuid",
"scope": "Namespace",
"resource": "analytics/sales",
"action": "Write"
}Permissions apply to a specific table or view.
Example: Grant user read access to specific table
{
"user_id": "uuid",
"scope": "Asset",
"resource": "analytics/sales/transactions",
"action": "Read"
}- Read: View metadata, query data
- Write: Create tables, insert/update data
- Delete: Drop tables, delete data
- Admin: Full control (create, read, update, delete)
POST /api/v1/users
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"username": "data_engineer",
"email": "engineer@example.com",
"password": "secure-password",
"role": "tenant-user"
}POST /api/v1/users/{user_id}/roles
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"role-id": "role-uuid"
}POST /api/v1/permissions
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"user-id": "optional-user-uuid",
"role-id": "optional-role-uuid",
"scope": "Catalog",
"resource": "analytics",
"action": "Read"
}DELETE /api/v1/permissions/{permission_id}
Authorization: Bearer <admin-token>Service users are programmatic identities with API key authentication. See Service Users for details.
Key Points:
- Service users inherit the same RBAC system
- Can be assigned TenantAdmin or TenantUser roles
- Authenticate via
X-API-Keyheader - Support expiration and rotation
Grant minimum necessary permissions:
- Use TenantUser role by default
- Grant catalog-level access only when needed
- Prefer namespace or asset-level permissions
Create dedicated service users for each use case:
- ci_pipeline_user (Write to staging catalog)
- analytics_reader (Read from analytics catalog)
- etl_processor (Write to raw, read from staging)
Review user permissions periodically:
GET /api/v1/users/{user_id}/permissionsWhen available, use groups to manage permissions for teams.
Review audit logs for unauthorized access attempts:
GET /api/v1/audit?user_id={user_id}Permissions follow a hierarchical model:
Root
└─ TenantAdmin (Tenant A)
└─ TenantUser (Catalog: analytics)
└─ Namespace: sales
└─ Asset: transactions
Rules:
- Root has access to everything
- TenantAdmin has access to all resources in their tenant
- TenantUser permissions are explicitly granted
- More specific permissions override general ones
# Create user
POST /api/v1/users
{
"username": "data_engineer",
"role": "tenant-user"
}
# Grant catalog-level write access
POST /api/v1/permissions
{
"user-id": "uuid",
"scope": "Catalog",
"resource": "analytics",
"action": "Write"
}# Create user
POST /api/v1/users
{
"username": "analyst",
"role": "tenant-user"
}
# Grant namespace-level read access
POST /api/v1/permissions
{
"user-id": "uuid",
"scope": "Namespace",
"resource": "analytics/sales",
"action": "Read"
}# Create service user
POST /api/v1/service-users
{
"name": "ci_pipeline",
"role": "tenant-user",
"expires_in_days": 90
}
# Grant write access to staging catalog
POST /api/v1/permissions
{
"user-id": "service_user_uuid",
"scope": "Catalog",
"resource": "staging",
"action": "Write"
}Cause: User lacks required permissions.
Solution:
- Check user's role:
GET /api/v1/users/{user_id} - List user's permissions:
GET /api/v1/users/{user_id}/permissions - Grant missing permission
Cause: Permission cache or session issue.
Solution:
- Re-authenticate to get new JWT token
- Verify permission was created:
GET /api/v1/permissions
- Service Users - API key authentication
- Authentication - User authentication
- Audit Logs - Access monitoring
- Permissions System - Permission details