Modeling Ownership with Backstage Groups

Ownership is the backbone of a portal: it decides who gets paged, who can edit an entity, and who a cost report is addressed to. Get the Group model right and every downstream feature — RBAC, on-call, notifications — resolves cleanly; get it wrong and each of those inherits the mess. This how-to models teams as Backstage Group entities with sensible hierarchy and ownership edges. It extends Team & Permission Models within Authentication, RBAC & Security Governance.

Prerequisites

  • Backstage 1.20+ with the catalog populated with services.
  • A source of truth for teams — an org chart, an HR feed, or directory groups from Mapping LDAP Groups to Portal Roles.
  • Agreement on what a “team” is: the unit that owns services and carries on-call, not every ad-hoc chat channel.
  • A convention for group naming so references stay stable as the org changes.
Prerequisites for the group model A populated catalog, a team source of truth, an agreed team definition, and naming conventions enable clean ownership. populated catalog team source of truth team definition naming convention Clean ownership resolvable
Naming stability matters most — a group name is referenced by every service it owns, so renames ripple widely.

Exact Configuration

  1. Model teams as Group entities with a hierarchy that mirrors the org, using parent and children.

    # groups.yaml
    apiVersion: backstage.io/v1alpha1
    kind: Group
    metadata:
      name: payments
    spec:
      type: team
      parent: fintech
      children: []
      members: [asmith, bjones]
    
  2. Attach ownership on the service, pointing spec.owner at the group, not an individual.

    # catalog-info.yaml
    kind: Component
    metadata:
      name: payments-api
    spec:
      type: service
      owner: group:default/payments
      lifecycle: production
    
  3. Keep membership fresh by ingesting from the directory rather than hand-editing member lists.

    # app-config.yaml — reuse the LDAP/Entra ingestion so members stay current
    catalog:
      providers:
        ldap:
          default:
            groups:
              dn: ou=groups,dc=example,dc=com
    
Group hierarchy and ownership A parent group contains team groups whose members own services, so ownership resolves down a clean tree. fintech (parent) payments team ledger team owns payments-api owns ledger-svc
A shallow, org-shaped tree lets ownership and escalation walk up the hierarchy — services own to teams, teams roll up to a parent.

Validation

# Requires curl, jq
# 1. Every service resolves to a Group owner, not a person
curl -s "${PORTAL_URL}/api/catalog/entities?filter=kind=component" \
  | jq '[.[] | select(.spec.owner | startswith("group:") | not) | .metadata.name]'
# Expected: [] — no service owned by an individual

# 2. Group hierarchy resolves parents and children
curl -s "${PORTAL_URL}/api/catalog/entities/by-name/group/default/payments" \
  | jq '{parent: .spec.parent, members: (.spec.members | length)}'
# Expected: a parent and a non-zero member count

# 3. No orphaned owners (owner group actually exists)
curl -s "${PORTAL_URL}/api/catalog/entities?filter=kind=component" \
  | jq -r '.[].spec.owner' | sort -u
# Expected: every value maps to a real Group entity
Ownership model validation checks Services own to groups, the hierarchy resolves, and no owner reference is orphaned. Owns to groups no individuals Hierarchy resolves parent + members No orphans owner exists
The orphaned-owner sweep is worth running in CI — a service pointing at a deleted group silently pages nobody.

Edge Cases & Troubleshooting

Symptom Root Cause Resolution
Service owned by a person spec.owner set to a User Repoint to the owning Group
Owner group does not exist Group deleted or renamed Recreate or update the reference; enforce in CI
Membership always stale Members hand-edited in YAML Ingest members from the directory instead
On-call resolves nobody Group has no members Ensure ingestion populates spec.members
Reorg breaks references Group renamed Keep stable names; alias old names during transition
Ownership-model pitfalls by class Person-owners and missing groups are reference issues; stale and empty membership are freshness issues. References person owner missing group → group owner + CI check Freshness stale members empty group → ingest membership
An empty owning group is as bad as no owner — it resolves to a team with nobody to page, so validate member counts, not just existence.

Frequently Asked Questions

Should ownership ever point at an individual?

Almost never for a service. People change teams and leave; a group persists and its membership updates. The rare exception is a genuinely personal artifact — a scratch project — and even then a group of one is more future-proof than a raw user reference.

How deep should the group hierarchy go?

As shallow as your org allows while still letting escalation and reporting roll up. Two or three levels — team, department, org — is plenty for most companies. Deep trees make ownership queries slow and confuse escalation; model the levels that carry real responsibility and stop there.