Skip to main content

People — Groups and Users

Group Entity

apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
name: team-payments
annotations:
github.com/team-slug: team-payments # links to GitHub team for SSO
platform.myorg/role: developer
platform.myorg/domains: "payments"
platform.myorg/slack-channel: "#team-payments"
scaffolder.backstage.io/template: create-group
spec:
type: team
profile:
displayName: Team Payments
email: team-payments@myorg.com
parent: engineering
children: []
members: [jane-doe, john-smith]

User Entity

apiVersion: backstage.io/v1alpha1
kind: User
metadata:
name: jane-doe
annotations:
github.com/user-login: jane-doe # links SSO login to catalog entity
platform.myorg/role: developer
platform.myorg/environments: "dev,staging"
scaffolder.backstage.io/template: create-user
spec:
profile:
displayName: Jane Doe
email: jane.doe@myorg.com
memberOf: [team-payments]

Platform Roles

RoleKubernetesArgoCDdev/stagingprodPlatform ns
viewerviewreadonly✅ read✅ read
developereditdeveloper✅ full❌ blocked
leadeditdomain-admin✅ full✅ full
platform-engineeradmindomain-admin✅ full✅ full

developer prod block is enforced at the RBAC level — RoleBindings for prod namespaces are simply not created. ArgoCD enforces it via policy pattern matching on namespace names (payments/*-prod-*).

RBAC — Group Bindings (Preferred over User Bindings)

RoleBindings use Group subjects. Adding or removing a user from the GitHub team or IdP group automatically grants or revokes access — no Kubernetes changes needed:

subjects:
- kind: Group
name: team-payments # GitHub: myorg/team-payments | Okta/Azure AD: team-payments
apiGroup: rbac.authorization.k8s.io

Group Hierarchy (Org Chart)

engineering (department)
├── team-payments (team) ← create-group template
│ └── squad-gateway (squad)
└── team-platform (team)

Built from spec.parent and spec.children in the Group entity. The github.com/team-slug annotation enables "Owned by my team" catalog filters.