Configuration¶
platform.example.org is a documentation placeholder
Every field below is shown under the API group platform.example.org, which ships in this repository's XRDs, Compositions, examples, and Argo CD health configuration. It is not a production API group — replace it everywhere in the XRDs (spec.group), the Compositions (spec.compositeTypeRef.apiVersion and the Composition input apiVersion), the examples, and your own request manifests before adopting this API in production. See Public base, private environment overlay below for how to keep a public reference and a private production fork in sync.
This is the field-by-field reference for the four custom resources this repository defines. It is the companion to the worked examples under examples/catalog/ — see Reference → Catalog.
GrafanaCloudStackRequest¶
The primary API, at platform.example.org/v1beta1. It is namespaced so teams or environments can be separated with Kubernetes namespaces and RBAC.
| Field | Default | Description |
|---|---|---|
spec.displayName | required | Human-readable Grafana Cloud stack name (1-128 chars). |
spec.slug | required | Immutable Grafana Cloud stack slug and external identity. Must equal metadata.name, and must match ^[a-z0-9]+$ (3-32 chars). Grafana Cloud stack slugs are globally unique. |
spec.region | required | Grafana Cloud region slug, must match ^prod-[a-z0-9-]+-[0-9]+$ (e.g. prod-us-central-0). |
spec.usage | required | Generic usage classification and output-secret path segment. Must match ^[a-z0-9-]+$ (1-32 chars). |
spec.profile | standard | Platform-owned configuration profile selected by the request. |
spec.changeReference | "" | Optional generic request/change identifier published in the output document (max 128 chars). |
spec.configurationItemReference | "" | Optional generic configuration-item identifier published in the output document (max 128 chars). |
spec.baselineDashboards.enabled | true | Creates three baseline folder/dashboard pairs (billing/usage, telemetry endpoints, stack home). |
spec.telemetryAccess.enabled | true | Creates a stack-scoped, rotating telemetry publisher access policy and mirrors its token to a derived AWS Secrets Manager path. |
spec.plugins | [] | List of {slug, version} plugin installations owned by this request. Max 30 items. version defaults to latest. |
spec.reconciliation.dashboards | createOnly | One of enforced, createOnly. Controls whether Crossplane repairs later UI edits to baseline dashboard JSON. |
spec.reconciliation.homePreference | createOnly | One of enforced, createOnly. Controls whether Crossplane repairs later UI changes to the organization home dashboard. |
spec.sso.mode | disabled | One of enforced, createOnly, observeOnly, disabled. See SSO. |
spec.sso.profile | "" | Selects a platform-owned SSO profile and Secret reference. Required (non-empty) unless mode: disabled. |
spec.monthlyReport.enabled | false | Enables a scheduled monthly usage report (requires an applicable Grafana Cloud plan and report capability). |
spec.monthlyReport.recipients | [] | Report recipient email addresses, max 20. Required (non-empty) when enabled: true. |
spec.monthlyReport.replyTo | "" | Report reply-to address. Required (non-empty) when enabled: true. |
spec.incidentIntegration.enabled | false | Creates four OnCall outgoing webhooks (test/production firing and resolved) and two Alerting contact points calling a platform-owned relay. |
spec.incidentIntegration.profile | "" | Selects a platform-owned relay URL and Secret reference. Required (non-empty) when enabled: true. |
spec.incidentIntegration.templateMode | createOnly | One of enforced, createOnly. Controls whether Crossplane repairs or preserves later OnCall outgoing-webhook data-template edits. |
Validation rules¶
The XRD enforces these with CEL validation, rejected at admission time rather than left to the composition function:
metadata.namemust equalspec.slug.spec.slugis immutable after creation.- An enabled
monthlyReportrequires non-emptyrecipientsandreplyTo. sso.modeother thandisabledrequires a non-emptysso.profile.- An enabled
incidentIntegrationrequires a non-emptyincidentIntegration.profile.
Status fields¶
| Field | Description |
|---|---|
status.outputSecretPath | The external path the generated administrator document was published to. |
status.telemetrySecretPath | The external path the generated telemetry document was published to. |
status.stack.id | The Grafana Cloud stack ID once observed. |
status.stack.url | The stack's Grafana URL once observed. |
Access APIs¶
Three additional APIs sit beside the stack request. All three reference a stack by spec.stackRef.name, which must be the GrafanaCloudStackRequest name (and per-stack ProviderConfig name) in the same namespace.
GrafanaCustomRoleBinding¶
One Team, one custom Role, one whole-role RoleAssignment. A compact pattern for a unique custom role bound to a directory-synced team.
| Field | Default | Description |
|---|---|---|
spec.stackRef.name | required | Target stack. |
spec.team.name | required | Team display name (1-190 chars). |
spec.team.groups | required | Identity-provider groups synced to this team, 1-50 entries. |
spec.role.name | required | Custom role display name. |
spec.role.uid | required | Custom role UID, must match ^[a-zA-Z0-9._-]+$. |
spec.role.displayName | "" | Optional display name shown in Grafana. |
spec.role.description | "" | Optional description (max 1024 chars). |
spec.role.permissions | required | List of {action, scope} pairs, 1-200 entries. scope is optional per entry. |
GrafanaTeamAccess¶
One Team plus zero-to-many custom and fixed-role assignments. Use this for directory sync, direct membership, team preferences, additive custom roles, and existing fixed roles.
| Field | Default | Description |
|---|---|---|
spec.stackRef.name | required | Target stack. |
spec.team.name | required | Team display name (1-190 chars). |
spec.team.email | "" | Optional team email (max 254 chars). |
spec.team.members | [] | Direct members by Grafana login email; each user must already exist. Max 100. |
spec.team.externalGroups | [] | Identity-provider groups synchronized through Grafana Team Sync. Max 50. |
spec.team.ignoreExternallySyncedMembers | true | When true, provider membership reconciliation ignores members supplied by Team Sync while still managing the direct member set declared in Git. |
spec.team.preferences.homeDashboardUid | "" | Team home dashboard UID (max 190 chars). |
spec.team.preferences.theme | "" | One of "", light, dark, system. |
spec.team.preferences.timezone | "" | One of "", utc, browser. |
spec.team.preferences.weekStart | "" | One of "", sunday, monday, saturday. |
spec.customRoles | [] | List of custom role objects (same shape as GrafanaCustomRoleBinding.spec.role, plus optional group and hidden). Max 20, keyed by uid. |
spec.fixedRoleUids | [] | Existing Grafana fixed-role UIDs assigned item-by-item, to avoid whole-role assignment collisions. Max 50. |
GrafanaTeamAccess uses RoleAssignmentItem rather than the whole-set RoleAssignment resource, so independently owned team bundles are additive — see Architecture → reconciliation and ownership.
GrafanaContentAccessPolicy¶
The complete ACL for one Folder or Dashboard. Only one policy may own a given target.
| Field | Default | Description |
|---|---|---|
spec.stackRef.name | required | Target stack. |
spec.target.kind | required | Folder or Dashboard. |
spec.target.ref.name | one of name/uid | Kubernetes name of a provider Folder/Dashboard managed resource. |
spec.target.ref.uid | one of name/uid | Existing Grafana folder/dashboard UID when no managed-resource reference is available. |
spec.permissions | required | List of grants, 1-100 entries. Each entry sets exactly one of basicRole, teamRef, or userId, plus a permission of View, Edit, or Admin. |
GrafanaContentAccessPolicy manages the entire ACL for its target; omitting an entry removes it on the next enforced reconciliation. Put every grant for a target — including basic-role grants that should remain — into the one policy that owns it.
Platform configuration¶
The Composition input (a GrafanaVendingConfig object embedded in platform/apis/v1beta1.yaml) is the platform-owned policy boundary. It controls:
| Field | Description |
|---|---|
organizationProviderConfigName | The namespaced ProviderConfig used for organization-level Cloud operations. |
outputSecretPrefix | The external path prefix for generated per-stack documents. |
secretStoreRef | Either a namespaced SecretStore or a ClusterSecretStore. |
ssoProfiles | Approved OAuth or SAML settings and Secret references. |
incidentProfiles | Approved relay URLs and authorization Secret references. |
Consumers select a profile by name in spec.sso.profile or spec.incidentIntegration.profile. They cannot supply an arbitrary identity endpoint, client secret, incident URL, or authorization value directly in a stack request — see SSO.
Public base, private environment overlay¶
The reusable implementation and a live environment have different publication boundaries:
| Public reference owns | Private environment owns |
|---|---|
| Provider and function packages at immutable digests | Approved public-reference Git commit |
| XRD schemas and Composition behaviour | Production API group under a controlled domain |
| Non-destructive lifecycle policy | Secret-store kind/name, cloud region, and workload identity |
| Placeholder SSO and incident profile shapes | Real endpoints and ExternalSecret remote paths |
| Comprehensive request with reserved example identities | Globally unique stack slug, intended recipients, user IDs, groups, and verified fixed-role UIDs |
An Argo CD Application can source platform/ directly from this repository at an immutable commit. Its Kustomize patches can replace the four XRD group-qualified names, each XRD spec.group, and each Composition spec.compositeTypeRef.apiVersion; the stack Composition input apiVersion must be patched as well. A second source in the same Application can point at a small private directory containing only the environment SecretStore, ExternalSecrets, and organization ProviderConfig. This keeps one Argo owner while avoiding a copied platform implementation.
Do not put a patched live request in this public repository's enabled/ directory — that publishes a real cloud-resource identity and couples a production deployment to mutable public data. Keep enabled requests or overlays in a private GitOps repository, and pin public platform and catalog sources to reviewed commits.
Next steps¶
- Reference → Catalog — every worked example and what it demonstrates.
- SSO — the four OAuth/SAML providers and the four reconciliation modes.
- Architecture — how these fields flow through Crossplane into managed resources.