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.

install
source · Clone the upstream repo
git clone https://github.com/aRustyDev/agents
Claude Code · Install into ~/.claude/skills/
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"
manifest: content/skills/openmetadata-ops/SKILL.md
source content

OpenMetadata 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
LevelPurposeCan Own Assets
OrganizationCompany root, auto-createdNo
Business UnitTop-tier organizational unitNo
DivisionMid-tier under Business UnitNo
DepartmentTeam under DivisionNo
GroupLowest level, contains usersYes

Create Team

Via UI:

  1. Navigate to Settings → Teams
  2. Click Add Team
  3. Select team type (BusinessUnit, Division, Department, Group)
  4. Set parent team
  5. 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:

  1. Navigate to Settings → Users
  2. Click Add User
  3. Enter email, name, select teams
  4. 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:

  1. Go to Profile → Access Token
  2. Click Generate New Token
  3. Set expiration (optional)
  4. 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

BotPurposeDefault Role
ingestion-bot
Metadata ingestion pipelinesIngestion Bot Role
automator-bot
Automation workflowsAutomator Role

Create Custom Bot

Via UI:

  1. Navigate to Settings → Integrations → Bots
  2. Click Add Bot
  3. Enter bot name and description
  4. Select or create role
  5. 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:

  1. Navigate to Settings → Integrations → Bots
  2. Select the bot
  3. 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:

  1. Navigate to Settings → Integrations → Bots
  2. Select the bot
  3. Click Revoke & Regenerate Token
  4. Update all systems using the old token
  5. 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

RoleDescriptionKey Permissions
AdminFull platform accessAll operations on all resources
Data ConsumerRead-only accessViewBasic on most entities
Data StewardGovernance operationsEdit descriptions, tags, glossary
Ingestion Bot RolePipeline operationsCreate/edit services and entities

Create Custom Role

Via UI:

  1. Navigate to Settings → Roles
  2. Click Add Role
  3. Enter name and description
  4. 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

RuleEffectDescription
isOwner()
ConditionUser/team owns the resource
inTeam('team-name')
ConditionUser belongs to team
hasDomain('domain')
ConditionResource is in domain
hasTag('tag-fqn')
ConditionResource 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

OperationDescription
Create
Create new entities
Delete
Delete entities
ViewAll
View all entity fields including sensitive data
ViewBasic
View basic fields (name, description, tags)
Edit
Edit entity properties
EditDescription
Edit description only
EditTags
Edit tags and classifications
EditOwner
Change entity owner
EditLineage
Modify lineage edges
EditCustomFields
Modify custom properties

Authentication Configuration

Supported Providers

ProviderTypeNotes
OpenMetadata (built-in)JWTDevelopment only
GoogleOIDCGoogle Workspace SSO
OktaOIDCOkta SSO
Azure ADOIDCMicrosoft Entra ID
Auth0OIDCAuth0 SSO
AWS CognitoOIDCAWS Cognito User Pools
OneLoginOIDCOneLogin SSO
KeycloakOIDCSelf-hosted OIDC
Custom OIDCOIDCAny 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:

  1. Deploy Keycloak
  2. Configure LDAP User Federation in Keycloak
  3. Configure OpenMetadata to use Keycloak as OIDC provider

Custom Properties Administration

Create Custom Property Type

Via UI:

  1. Navigate to Settings → Custom Properties
  2. Select entity type (Table, Dashboard, etc.)
  3. Click Add Property
  4. 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

  1. Check JWT token validity:

    # Decode token at jwt.io or:
    echo $JWT_TOKEN | cut -d. -f2 | base64 -d | jq .
    
  2. Verify token expiration (

    exp
    claim)

  3. Check issuer matches configuration

Problem: Bot ingestion failing

  1. Verify bot has

    Ingestion Bot Role
    :

    curl "http://localhost:8585/api/v1/bots/name/ingestion-bot?fields=botUser" \
      -H "Authorization: Bearer ${ADMIN_TOKEN}"
    
  2. Check role policies weren't modified

  3. Regenerate bot token if expired

Authorization Issues

Problem: 403 Forbidden

  1. Check user's roles:

    curl "http://localhost:8585/api/v1/users/name/john.doe?fields=roles,teams" \
      -H "Authorization: Bearer ${ADMIN_TOKEN}"
    
  2. Verify role has required policy

  3. Check policy conditions (isOwner, inTeam, etc.)

Problem: User can't see entities

  1. Verify
    ViewBasic
    or
    ViewAll
    permission
  2. Check team hierarchy - user must be in a Group
  3. Verify entity isn't soft-deleted

Common Fixes

IssueSolution
Token expiredRegenerate token in UI
Missing permissionsAdd policy to role
User not in teamAdd user to Group-type team
Bot not workingCheck role assignment, regenerate token
SSO login failingVerify 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&timestamp=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

  1. Never use built-in auth in production - always configure SSO
  2. Rotate bot tokens periodically (every 90 days recommended)
  3. Use least-privilege roles - create specific policies per team
  4. Audit admin access regularly

Team Structure

  1. Use Groups for ownership - only Groups can own assets
  2. Mirror org structure - Business Unit → Division → Department → Group
  3. Assign domain owners - use domains for cross-team governance

Bot Management

  1. Create purpose-specific bots - don't reuse ingestion-bot
  2. Document bot purposes in descriptions
  3. Monitor bot token usage in audit logs
  4. Disable unused bots rather than deleting

References