Skip to content

Catalog and Entity Model

The portal is built on the Backstage software catalog. The catalog is the spine of every other feature: cost, security, compliance and network views, and the agents, all start from an entity in the catalog and follow its relations. This page explains which entity kinds exist, how they are filled from Azure and Entra ID, and what a workload team has to do so that their workload shows up with the right owner.

Entity kinds

Kind API version Meaning Created from
Workload xebia.com/v1 An application, service or capability that consumes cloud resources. The unit most views start from. Tagged Azure subscriptions, optionally enriched from repository files
Domain backstage.io/v1alpha1 A business area that groups workloads The domain tag on subscriptions, or a repository file
Organisation xebia.com/v1 A customer or internal organisation that owns one or more domains The organisation tag on subscriptions. Domains without one fall back to a single default organisation.
Group backstage.io/v1alpha1 A team, as a security group in Entra ID Microsoft Graph
User backstage.io/v1alpha1 A person Microsoft Graph
Fragment xebia.com/v1 A partial description of another entity, used to merge several sources The Azure providers and repository files
Customer xebia.com/v1 A customer of the provider, with an owner Catalog files; the kind is loaded only in the provider's own environment

A workload has this shape:

apiVersion: xebia.com/v1
kind: Workload
metadata:
  name: my-workload
spec:
  owner: group:default/my-team   # required, a Group
  dependsOn:                     # optional, other workloads
    - other-workload
  domain: platform               # optional
  externalUris:                  # optional, see Network insights
    - https://api.example.com
    - https://api.example.com/orders

Only owner is required. All string fields need a minimum length; the catalog rejects entities that do not validate.

Relations

The catalog processor creates these relations from the Workload spec.

From the spec Relation (and inverse)
owner ownedBy / ownerOf between workload and group
dependsOn dependsOn / dependencyOf between workloads
domain partOf / hasPart between workload and domain

The views use a five-level hierarchy: organisation, domain, team, workload, subscription. A cost, security or compliance view for a domain or team is the roll-up of its workloads and their subscriptions.

Subscription annotations

A workload is linked to its Azure subscriptions by annotations of the form azure.com/subscription-selector.<key>, with the value <tenant-id>/<subscription-id>. The key names a slot, for example one per environment. All Azure plugins read these annotations to know which subscriptions to query. A workload with more than one subscription (for example non-production and production) shows each subscription separately and the sum per workload.

How entities get into the catalog

flowchart LR
    arg["Azure Resource Graph<br/>subscription tags and<br/>Application Gateway listeners"] --> frag["Fragment entities"]
    ado["Azure DevOps<br/>catalog-info.yaml files"] --> frag
    frag --> merge["Merged Entities module<br/>groups by kind, namespace, name"]
    merge --> wl["Workload, Domain,<br/>Organisation entities"]
    wl --> proc["Entity model module<br/>validates, adds relations"]
    graph["Microsoft Graph<br/>users and groups"] --> cat["Catalog"]
    proc --> cat

The Backstage catalog accepts an entity once per kind, namespace and name. A second source with the same name would be rejected as a conflict. The portal therefore lets each source describe a Fragment of the entity, and a Merged Entities module combines the fragments into one entity before the catalog processes it.

Step What happens
1 The Azure Resource Graph module reads subscriptions and derives workload, domain and organisation fragments from the tags. A second provider reads Application Gateway listener host names and derives fragments from them. Both run on a schedule that is set in configuration. The shared production configuration sets one hour for the Application Gateway provider.
2 The Azure DevOps catalog provider reads catalog-info.yaml files from repositories (every 30 minutes in the reference configuration) and can add fragments or entities.
3 The merged entity provider asks the catalog for all fragments, groups them by target kind, namespace and name and merges them into one entity. Fragments that come from a YAML file win over other fragments. Within each group the order is by fragment name, so the result is stable.
4 The entity model module validates the Workload and creates the relations.

A fragment has the same envelope as the target entity, but only apiVersion, kind and metadata.name are required, so a source can provide just the fields it knows:

apiVersion: xebia.com/v1
kind: Fragment
metadata:
  name: my-unique-fragment-name
spec:
  apiVersion: xebia.com/v1
  kind: Workload
  metadata:
    name: my-target-entity-name
  spec:
    # only the fields this source knows

Fragments can target a Workload, a Domain or an Organisation.

Tags that drive the catalog

The Azure provider reads these tags on subscriptions. The defaults can be renamed in the provider configuration (Configuration).

Tag (default) Effect
workload Marks a subscription as part of a workload and names it
owner The owner group of the workload
domain The domain of the workload (optional)
organisation The organisation the domain belongs to (optional)
name A readable title for the entity (optional)
description A description (optional)
external-uris Comma-separated list of absolute HTTP or HTTPS URIs that belong to the workload, used to match Application Gateway WAF logs (optional)

Notes on external-uris:

  • Whitespace around entries is ignored and invalid entries are dropped.
  • The URIs of all subscriptions of the same workload are merged and stored on the workload as spec.externalUris.
  • Example: https://api.example.com, https://api.example.com/orders.

Spokes of the platform

A spoke that the platform deploys already carries the tags workload and owner (see the required tags in the Spoke JSON reference and Naming and tags). In addition the spoke deployment sets a hidden tag with JSON metadata:

{
  "workloadShortName": "<workload>",
  "productTeamGroupNames": ["<team group name>"]
}

The provider reads workloadShortName as the workload and the first non-empty entry of productTeamGroupNames as the owner. Because the spoke deployment fills it, a spoke needs no extra manual tagging to appear in the catalog. Invalid JSON is ignored with a warning.

Which source wins when both the hidden tag and the plain tags exist is set by the option spokeMetadataOverridable (default false: the hidden metadata wins, the plain tags are the fallback; true reverses it). Keep the default for spokes of the platform.

Users and groups

Users and groups are ingested from Microsoft Graph (in the reference configuration: enabled users and security-enabled groups, once an hour). The portal signs users in by matching the e-mail address of the sign-in to a User entity, see Authentication and access.

Owner values in tags may be plain group names or entity references. With the feature flag features.microsoftGraphGroupNameNormalization enabled, the portal applies a naming convention to Entra ID group names:

Input Result
Plain owner tag, for example SG-AZ-LZ_<org>_engineers Mapped with the convention to a group in a namespace derived from the name (for example group:sg-az-lz-<org>/engineers)
Entity reference, for example group:default/Some_Group Structure kept, catalog-style normalisation applied to the parts
Flag off Plain tag mapped to group:default/<normalised name>

Group naming convention

With the flag on, a group is ingested only if its name ends in _engineers, _users, _admins or _standard_changes (after normalisation). Groups with other names are dropped by the transformer and cannot own a workload. This convention is specific to the provider's group naming. Check it before you enable the flag for another customer.

What a workload team does

  1. Make sure the subscription of the workload has the workload and owner tags. For spokes of the platform this is done at deployment.
  2. Add the domain tag if the workload belongs to a domain, and external-uris if the workload sits behind an Application Gateway with WAF.
  3. Optionally add a catalog-info.yaml to a repository to add descriptions, dependencies or documentation. It is picked up on the next scan.
  4. Wait for the next run of the providers (up to an hour for tags, up to thirty minutes for repository files in the reference configuration) before you look for the change.

If a workload has no owner, or an owner that does not exist as a group, the insight views cannot attribute its cost and show it as UNKNOWN, and nobody can see its sensitive detail (Authentication and access).