Agents openmetadata-ops
Administer OpenMetadata platform including users, teams, bots, roles, policies, and security. Use when managing access control, configuring SSO, creating service accounts, setting up team hierarchies, or troubleshooting authentication issues.
git clone https://github.com/aRustyDev/agents
T=$(mktemp -d) && git clone --depth=1 https://github.com/aRustyDev/agents "$T" && mkdir -p ~/.claude/skills && cp -r "$T/content/skills/openmetadata-ops" ~/.claude/skills/arustydev-agents-openmetadata-ops && rm -rf "$T"
content/skills/openmetadata-ops/SKILL.mdOpenMetadata Operations
Guide for administering OpenMetadata platform: users, teams, bots, roles, policies, security configuration, and operational tasks.
When to Use This Skill
- Managing users and team hierarchies
- Creating and configuring bots (service accounts)
- Setting up roles and policies (RBAC/ABAC)
- Configuring SSO and authentication providers
- Managing JWT tokens and API access
- Troubleshooting authentication and authorization issues
This Skill Does NOT Cover
- Building OpenMetadata SDKs (see
)openmetadata-sdk-dev - Using SDKs/APIs to build integrations (see
)openmetadata-dev - Deploying OpenMetadata infrastructure (Kubernetes, Docker)
- Database administration for OpenMetadata backend
Team Hierarchy
Team Types
OpenMetadata uses a hierarchical team structure:
Organization (root) ├── Business Unit │ ├── Division │ │ ├── Department │ │ │ └── Group ← Only Groups can own Data Assets │ │ └── Group │ └── Department │ └── Group └── Business Unit └── Group
| Level | Purpose | Can Own Assets |
|---|---|---|
| Organization | Company root, auto-created | No |
| Business Unit | Top-tier organizational unit | No |
| Division | Mid-tier under Business Unit | No |
| Department | Team under Division | No |
| Group | Lowest level, contains users | Yes |
Create Team
Via UI:
- Navigate to Settings → Teams
- Click Add Team
- Select team type (BusinessUnit, Division, Department, Group)
- Set parent team
- Add team name, display name, description
Via API:
curl -X PUT "http://localhost:8585/api/v1/teams" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "data-engineering", "displayName": "Data Engineering", "description": "Data platform team", "teamType": "Group", "parents": [{"id": "parent-team-uuid", "type": "team"}] }'
Team Policies
Assign policies to teams for inherited permissions:
curl -X PATCH "http://localhost:8585/api/v1/teams/${TEAM_ID}" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -H "Content-Type: application/json-patch+json" \ -d '[ { "op": "add", "path": "/policies/-", "value": {"id": "policy-uuid", "type": "policy"} } ]'
User Management
Add User
Via UI:
- Navigate to Settings → Users
- Click Add User
- Enter email, name, select teams
- Assign roles
Via API:
curl -X PUT "http://localhost:8585/api/v1/users" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "john.doe", "email": "john.doe@company.com", "displayName": "John Doe", "teams": [{"id": "team-uuid", "type": "team"}], "roles": [{"id": "role-uuid", "type": "role"}] }'
Assign Role to User
curl -X PATCH "http://localhost:8585/api/v1/users/${USER_ID}" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -H "Content-Type: application/json-patch+json" \ -d '[ { "op": "add", "path": "/roles/-", "value": {"id": "data-steward-role-uuid", "type": "role"} } ]'
Generate User Access Token
Users can generate personal access tokens:
- Go to Profile → Access Token
- Click Generate New Token
- Set expiration (optional)
- Copy token immediately (shown only once)
Bots (Service Accounts)
What Are Bots?
Bots are service accounts for automated processes:
- Ingestion pipelines
- External integrations
- Scheduled jobs
- CI/CD automation
Built-in Bots
| Bot | Purpose | Default Role |
|---|---|---|
| Metadata ingestion pipelines | Ingestion Bot Role |
| Automation workflows | Automator Role |
Create Custom Bot
Via UI:
- Navigate to Settings → Integrations → Bots
- Click Add Bot
- Enter bot name and description
- Select or create role
- Copy generated JWT token
Via API:
# Create bot curl -X PUT "http://localhost:8585/api/v1/bots" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "ci-cd-bot", "displayName": "CI/CD Bot", "description": "Bot for CI/CD pipeline metadata updates", "botUser": { "name": "ci-cd-bot", "email": "ci-cd-bot@openmetadata.org", "isBot": true } }'
Get Bot JWT Token
Via UI:
- Navigate to Settings → Integrations → Bots
- Select the bot
- Click Revoke & Regenerate Token or view existing token
Via API:
# Get bot details including auth mechanism curl "http://localhost:8585/api/v1/bots/name/ingestion-bot?fields=botUser" \ -H "Authorization: Bearer ${ADMIN_TOKEN}"
Bot Token Validation
Validate bot tokens at jwt.io or programmatically:
import jwt def validate_bot_token(token: str, public_key: str) -> dict: """Validate and decode bot JWT token.""" try: payload = jwt.decode( token, public_key, algorithms=["RS256"], issuer="open-metadata.org", ) assert payload.get("isBot") == True return payload except jwt.ExpiredSignatureError: raise ValueError("Token expired - regenerate in UI") except jwt.InvalidTokenError as e: raise ValueError(f"Invalid token: {e}")
Bot Token Rotation
Rotate bot tokens periodically:
- Navigate to Settings → Integrations → Bots
- Select the bot
- Click Revoke & Regenerate Token
- Update all systems using the old token
- Verify ingestion pipelines are working
Roles and Policies
Access Control Model
OpenMetadata uses hybrid RBAC + ABAC:
Authorization Decision = f(User, Resource, Operation) Where: - User = Identity + Roles + Teams - Resource = Entity Type + Attributes (owner, domain, tags) - Operation = Create, Edit, Delete, ViewAll, EditOwner, etc.
Built-in Roles
| Role | Description | Key Permissions |
|---|---|---|
| Admin | Full platform access | All operations on all resources |
| Data Consumer | Read-only access | ViewBasic on most entities |
| Data Steward | Governance operations | Edit descriptions, tags, glossary |
| Ingestion Bot Role | Pipeline operations | Create/edit services and entities |
Create Custom Role
Via UI:
- Navigate to Settings → Roles
- Click Add Role
- Enter name and description
- Add policies to the role
Via API:
curl -X PUT "http://localhost:8585/api/v1/roles" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "DataEngineer", "displayName": "Data Engineer", "description": "Role for data engineering team", "policies": [ {"id": "policy-uuid-1", "type": "policy"}, {"id": "policy-uuid-2", "type": "policy"} ] }'
Policy Structure
Policies contain rules that define permissions:
{ "name": "TableEditPolicy", "rules": [ { "name": "AllowEditTables", "resources": ["table"], "operations": ["Create", "Edit", "Delete"], "effect": "allow", "condition": "isOwner()" } ] }
Common Policy Rules
| Rule | Effect | Description |
|---|---|---|
| Condition | User/team owns the resource |
| Condition | User belongs to team |
| Condition | Resource is in domain |
| Condition | Resource has specific tag |
Create Policy
curl -X PUT "http://localhost:8585/api/v1/policies" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "TeamOwnershipPolicy", "displayName": "Team Ownership Policy", "description": "Allow team members to edit owned resources", "rules": [ { "name": "EditOwnedResources", "resources": ["table", "dashboard", "pipeline"], "operations": ["Edit", "EditDescription", "EditTags"], "effect": "allow", "condition": "isOwner()" } ] }'
Operations Reference
| Operation | Description |
|---|---|
| Create new entities |
| Delete entities |
| View all entity fields including sensitive data |
| View basic fields (name, description, tags) |
| Edit entity properties |
| Edit description only |
| Edit tags and classifications |
| Change entity owner |
| Modify lineage edges |
| Modify custom properties |
Authentication Configuration
Supported Providers
| Provider | Type | Notes |
|---|---|---|
| OpenMetadata (built-in) | JWT | Development only |
| OIDC | Google Workspace SSO | |
| Okta | OIDC | Okta SSO |
| Azure AD | OIDC | Microsoft Entra ID |
| Auth0 | OIDC | Auth0 SSO |
| AWS Cognito | OIDC | AWS Cognito User Pools |
| OneLogin | OIDC | OneLogin SSO |
| Keycloak | OIDC | Self-hosted OIDC |
| Custom OIDC | OIDC | Any OIDC-compliant provider |
Note: OpenMetadata does not support multiple auth providers simultaneously.
Configure SSO (Example: Okta)
1. Create Okta Application:
- Sign in to Okta Admin Console
- Navigate to Applications → Create App Integration
- Select OIDC - OpenID Connect and Web Application
- Set redirect URI:
http://localhost:8585/callback
2. Configure OpenMetadata:
# openmetadata.yaml authenticationConfiguration: provider: okta publicKeyUrls: - https://your-domain.okta.com/oauth2/default/v1/keys authority: https://your-domain.okta.com/oauth2/default clientId: <your-client-id> callbackUrl: http://localhost:8585/callback
3. Configure Frontend:
# openmetadata.yaml (continued) authorizerConfiguration: className: org.openmetadata.service.security.DefaultAuthorizer containerRequestFilter: org.openmetadata.service.security.JwtFilter adminPrincipals: - admin@company.com principalDomain: company.com
LDAP/Active Directory
For LDAP integration, use an OIDC proxy like Keycloak:
- Deploy Keycloak
- Configure LDAP User Federation in Keycloak
- Configure OpenMetadata to use Keycloak as OIDC provider
Custom Properties Administration
Create Custom Property Type
Via UI:
- Navigate to Settings → Custom Properties
- Select entity type (Table, Dashboard, etc.)
- Click Add Property
- Configure name, type, description
Via API:
curl -X PUT "http://localhost:8585/api/v1/metadata/types/name/table/customProperties" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "dataClassification", "description": "Data classification level", "propertyType": { "id": "enum-type-uuid", "type": "type" }, "customPropertyConfig": { "config": { "values": ["Public", "Internal", "Confidential", "Restricted"] } } }'
List Custom Properties
curl "http://localhost:8585/api/v1/metadata/types/name/table?fields=customProperties" \ -H "Authorization: Bearer ${ADMIN_TOKEN}"
Troubleshooting
Authentication Issues
Problem: 401 Unauthorized
-
Check JWT token validity:
# Decode token at jwt.io or: echo $JWT_TOKEN | cut -d. -f2 | base64 -d | jq . -
Verify token expiration (
claim)exp -
Check issuer matches configuration
Problem: Bot ingestion failing
-
Verify bot has
:Ingestion Bot Rolecurl "http://localhost:8585/api/v1/bots/name/ingestion-bot?fields=botUser" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" -
Check role policies weren't modified
-
Regenerate bot token if expired
Authorization Issues
Problem: 403 Forbidden
-
Check user's roles:
curl "http://localhost:8585/api/v1/users/name/john.doe?fields=roles,teams" \ -H "Authorization: Bearer ${ADMIN_TOKEN}" -
Verify role has required policy
-
Check policy conditions (isOwner, inTeam, etc.)
Problem: User can't see entities
- Verify
orViewBasic
permissionViewAll - Check team hierarchy - user must be in a Group
- Verify entity isn't soft-deleted
Common Fixes
| Issue | Solution |
|---|---|
| Token expired | Regenerate token in UI |
| Missing permissions | Add policy to role |
| User not in team | Add user to Group-type team |
| Bot not working | Check role assignment, regenerate token |
| SSO login failing | Verify redirect URI, check OIDC config |
Operational Tasks
Backup Considerations
Critical data to back up:
- Database (MySQL/PostgreSQL)
- Elasticsearch indices
- JWT signing keys
- Configuration files
Audit Logging
OpenMetadata tracks changes via:
- Entity version history
- Change events in Elasticsearch
- API audit logs
Query audit events:
curl "http://localhost:8585/api/v1/events?entityType=table×tamp=1704067200000" \ -H "Authorization: Bearer ${ADMIN_TOKEN}"
Health Checks
# API health curl "http://localhost:8585/api/v1/system/health" # Elasticsearch health curl "http://localhost:8585/api/v1/search/health"
Best Practices
Security
- Never use built-in auth in production - always configure SSO
- Rotate bot tokens periodically (every 90 days recommended)
- Use least-privilege roles - create specific policies per team
- Audit admin access regularly
Team Structure
- Use Groups for ownership - only Groups can own assets
- Mirror org structure - Business Unit → Division → Department → Group
- Assign domain owners - use domains for cross-team governance
Bot Management
- Create purpose-specific bots - don't reuse ingestion-bot
- Document bot purposes in descriptions
- Monitor bot token usage in audit logs
- Disable unused bots rather than deleting
References
- OpenMetadata Security Guide
- Roles and Policies
- Team Management
- SSO Configuration
- Using SDKs/APIs for integrationsopenmetadata-dev
- Implementing SDKs for new languagesopenmetadata-sdk-dev