# TeraSky Backstage Plugins
TeraSky's Backstage Plugins is an open-source monorepo containing 53 Backstage plugins built and tested against Backstage version 1.50.3. The collection covers Kubernetes resource ingestion, Crossplane and KRO integration, VCF Automation/Operations management, ScaleOps cost optimization, SpectroCloud cluster lifecycle, developer tooling (DevPod, Spring Initializer, Template Builder), authentication modules (VCF SSO, SpectroCloud OIDC), policy enforcement (Kyverno), and AI tooling support via Model Context Protocol (MCP) backends for the Scaffolder, RBAC, and Catalog. Every plugin is published independently to npm under the `@terasky/` namespace, follows Backstage's new frontend system with `/alpha` exports, and ships permission-framework integration out of the box.
The repository uses a Yarn 4 workspace monorepo layout — source code lives in `plugins/*`, the host Backstage app lives in `packages/app` and `packages/backend`, and MkDocs-based documentation lives in `site/docs/`. The backbone of the collection is the `@terasky/backstage-plugin-kubernetes-ingestor` backend plugin, which auto-discovers Kubernetes workloads, Crossplane XRDs/Claims, KRO RGDs/Instances, and generic CRDs and registers them as Components, Resources, APIs, and Software Templates in the catalog. Frontend plugins build on top of this foundation to display graphs, YAML viewers, policy reports, cost data, and vendor-specific resource cards, while MCP backend plugins expose catalog, scaffolder, and RBAC capabilities to AI agents.
---
## Plugin Installation and Registration — Backend (New System)
All backend plugins are registered by passing a dynamic import to `backend.add()` in `packages/backend/src/index.ts`. No manual provider wiring is needed with the new backend system.
```typescript
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
// Kubernetes resource auto-ingestion
backend.add(import('@terasky/backstage-plugin-kubernetes-ingestor'));
// Crossplane resource permissions backend
backend.add(import('@terasky/backstage-plugin-crossplane-resources-backend'));
// KRO resource permissions backend
backend.add(import('@terasky/backstage-plugin-kro-resources-backend'));
// ScaleOps cost data + MCP actions
backend.add(import('@terasky/backstage-plugin-scaleops-backend'));
// VCF Automation API proxy + permissions
backend.add(import('@terasky/backstage-plugin-vcf-automation-backend'));
// VCF Operations metrics backend
backend.add(import('@terasky/backstage-plugin-vcf-operations-backend'));
// SpectroCloud API proxy + MCP actions
backend.add(import('@terasky/backstage-plugin-spectrocloud-backend'));
// SpectroCloud catalog ingestor
backend.add(import('@terasky/backstage-plugin-spectrocloud-ingestor'));
// SpectroCloud cluster supplier for Kubernetes plugin
backend.add(import('@terasky/backstage-plugin-spectrocloud-cluster-provider'));
// SpectroCloud OIDC auth backend
backend.add(import('@terasky/backstage-plugin-spectrocloud-auth-backend'));
// VCF SSO OIDC auth backend
backend.add(import('@terasky/backstage-plugin-vcfsso-auth-backend'));
// Educates training portal backend
backend.add(import('@terasky/backstage-plugin-educates-backend'));
// MCP backends for AI agents
backend.add(import('@terasky/plugin-scaffolder-mcp-backend'));
backend.add(import('@terasky/plugin-rbac-mcp-backend'));
backend.add(import('@terasky/backstage-plugin-catalog-mcp-backend'));
backend.add(import('@terasky/backstage-plugin-ai-rules-plugin-backend'));
// Kyverno permissions backend
backend.add(import('@terasky/backstage-plugin-kyverno-policy-reports-backend'));
// Kubernetes resources permissions backend
backend.add(import('@terasky/backstage-plugin-kubernetes-resources-permissions-backend'));
// Module Federation CDN loader
backend.add(import('@terasky/backstage-plugin-module-federation-cdn-backend'));
// VCF Automation catalog ingestor
backend.add(import('@terasky/backstage-plugin-vcf-automation-ingestor'));
// VCFA VKS cluster supplier
backend.add(import('@terasky/backstage-plugin-vcfa-vks-cluster-provider'));
// Scaffolder custom actions (claim-template, crd-template, catalog-info-cleaner)
backend.add(import('@terasky/backstage-plugin-scaffolder-backend-module-terasky-utils'));
// Spring Boot project generator scaffolder action
backend.add(import('@terasky/backstage-plugin-scaffolder-backend-module-spring-initializer'));
backend.start();
```
---
## Plugin Installation and Registration — Frontend (New System)
All frontend plugins with a `/alpha` export are added to `createApp({ features: [...] })` in `packages/app/src/App.tsx`. This replaces manual `EntityPage.tsx` wiring.
```typescript
// packages/app/src/App.tsx
import { createApp } from '@backstage/frontend-defaults';
const app = createApp({
features: [
// Auto-injects Crossplane tabs on matching entity pages
import('@terasky/backstage-plugin-crossplane-resources-frontend/alpha'),
// KRO resource overview + graph tabs
import('@terasky/backstage-plugin-kro-resources-frontend/alpha'),
// ScaleOps cost optimization card
import('@terasky/backstage-plugin-scaleops-frontend/alpha'),
// DevPod "Open in DevPod" overview card
import('@terasky/backstage-plugin-devpod/alpha'),
// Kyverno policy reports tab + overview card
import('@terasky/backstage-plugin-kyverno-policy-reports/alpha'),
// Kubernetes dependency graph + resource list tabs
import('@terasky/backstage-plugin-kubernetes-resources-frontend/alpha'),
// VCF Automation deployment/resource/project views
import('@terasky/backstage-plugin-vcf-automation/alpha'),
// VCF Operations metrics view
import('@terasky/backstage-plugin-vcf-operations/alpha'),
// SpectroCloud cluster + profile entity cards
import('@terasky/backstage-plugin-spectrocloud/alpha'),
// SpectroCloud OIDC frontend API ref
import('@terasky/backstage-plugin-spectrocloud-auth/alpha'),
// SpectroCloud Kubernetes auth module extension
import('@terasky/backstage-plugin-spectrocloud-kubernetes-auth-module/alpha'),
// Educates workshop browser page
import('@terasky/backstage-plugin-educates/alpha'),
// Entity scaffolder tab with template list
import('@terasky/backstage-plugin-entity-scaffolder-content/alpha'),
// GitOps manifest updater scaffolder field extension
import('@terasky/backstage-plugin-gitops-manifest-updater/alpha'),
// GitOps manifest updater scaffolder field extension
import('@terasky/backstage-plugin-terraform-scaffolder/alpha'),
// Spring Boot project configurator field extension
import('@terasky/backstage-plugin-spring-initializer/alpha'),
// Template Builder WYSIWYG editor page
import('@terasky/backstage-plugin-template-builder/alpha'),
// AI Rules frontend
import('@terasky/backstage-plugin-ai-rules/alpha'),
// CRD-type API documentation renderer
import('@terasky/backstage-plugin-api-docs-module-crd/alpha'),
// Frontend Extensions introspection page
import('@terasky/backstage-plugin-frontend-extensions-explorer/alpha'),
// Config-driven sign-in page
import('@terasky/backstage-plugin-app-module-global-signin-page/alpha'),
// VCF SSO frontend OAuth2 client
import('@terasky/backstage-plugin-vcfsso-auth/alpha'),
],
});
export default app.createRoot();
```
---
## Kubernetes Ingestor — Full Configuration
`@terasky/backstage-plugin-kubernetes-ingestor` is the central backend plugin that auto-discovers Kubernetes workloads, Crossplane Claims/XRDs, KRO Instances/RGDs, and generic CRDs, and registers them as catalog entities and Software Templates.
```yaml
# app-config.yaml
kubernetesIngestor:
# Whether to generate API entities of type "crd" (requires api-docs-module-crd) or "openapi"
ingestAPIsAsCRDs: true
# Default owner when no terasky.backstage.io/owner annotation is present
defaultOwner: platform-engineering-team
# Inherit owner annotation from the Namespace when the workload has none
inheritOwnerFromNamespace: true
# Map metadata fields to Backstage entity metadata
mappings:
namespaceModel: 'cluster' # cluster | namespace | default
nameModel: 'name-cluster' # name-cluster | name-namespace | name-kind | name | uid
titleModel: 'name' # name | name-cluster | name-namespace
systemModel: 'cluster-namespace' # cluster | namespace | cluster-namespace | default
referencesNamespaceModel: 'default' # default | same
# Map SA-authenticated cluster names to OIDC cluster names for frontend use
clusterNameMapping:
mode: 'prefix-replacement' # or 'explicit'
sourcePrefix: 'sa-'
targetPrefix: 'oidc-'
# Only ingest from specific clusters (omit to ingest from all non-OIDC clusters)
allowedClusterNames:
- sa-production
- sa-staging
# Standard Kubernetes workload ingestion
components:
enabled: true
ingestAsResources: false # true → create Resource entities instead of Component
onlyIngestAnnotatedResources: false # true → require terasky.backstage.io/add-to-catalog
disableDefaultWorkloadTypes: false
taskRunner:
frequency: 10 # seconds between syncs
timeout: 600 # max seconds per sync cycle
excludedNamespaces:
- kube-system
- kube-public
customWorkloadTypes:
- group: pkg.crossplane.io
apiVersion: v1
plural: providers
defaultType: service
- group: networking.k8s.io
apiVersion: v1
plural: ingresses
defaultType: ingress
ingestAsResources: true # per-type override
# Crossplane Claims and XRDs
crossplane:
enabled: true
claims:
ingestAllClaims: true
ingestAsResources: false
xrds:
enabled: true
ingestAllXRDs: true
ingestOnlyAsAPI: false # true → API entities only, no Software Templates
convertDefaultValuesToPlaceholders: true
taskRunner:
frequency: 10
timeout: 600
publishPhase:
allowedTargets: ['github.com', 'gitlab.com']
target: github
allowRepoSelection: true
requestUserCredentialsForRepoUrl: false
git:
repoUrl: github.com?owner=my-org&repo=backstage-templates
targetBranch: main
# KRO (Kubernetes Resource Orchestrator)
kro:
enabled: true
instances:
ingestAsResources: false
rgds:
enabled: true
ingestOnlyAsAPI: false
taskRunner:
frequency: 10
timeout: 600
publishPhase:
target: github
allowRepoSelection: true
git:
repoUrl: github.com?owner=my-org&repo=backstage-templates
targetBranch: main
# Generic CRDs (by label selector or explicit list)
genericCRDTemplates:
ingestOnlyAsAPI: false
crdLabelSelector:
key: terasky.backstage.io/generate-form
value: "true"
crds:
- certificates.cert-manager.io
# Auto-add ArgoCD annotation when the resource has Argo tracking labels
argoIntegration: true
```
---
## Kubernetes Ingestor — Kubernetes Annotations on Workloads
Kubernetes resource annotations control how entities appear in Backstage. The ingestor reads these annotations at ingestion time.
```yaml
# Example Deployment with all supported annotations
apiVersion: apps/v1
kind: Deployment
metadata:
name: petstore
namespace: web-apps
annotations:
# --- Identity ---
terasky.backstage.io/title: "Petstore API"
terasky.backstage.io/description: "OpenAPI Petstore demo service"
terasky.backstage.io/owner: "group:default/platform-team"
terasky.backstage.io/system: "ecommerce-platform"
terasky.backstage.io/component-type: "service"
terasky.backstage.io/lifecycle: "production"
# --- API auto-registration (choose one) ---
# Option 1: runtime fetch via $text directive
terasky.backstage.io/provides-api-from-def: "http://petstore.example.com/api/v3/openapi.json"
# Option 2: fetch-and-embed at ingestion time
# terasky.backstage.io/provides-api-from-url: "http://petstore.example.com/swagger.json"
# Option 3: resolve endpoint from another K8s resource
# terasky.backstage.io/provides-api-from-resource-ref: |
# {
# "kind": "Service", "name": "petstore-svc", "apiVersion": "v1",
# "path": "/swagger/openapi.json", "target-protocol": "http",
# "target-port": "80", "target-field": ".status.loadBalancer.ingress[0].ip"
# }
# --- Catalog opt-in/opt-out (when onlyIngestAnnotatedResources: true) ---
terasky.backstage.io/add-to-catalog: "true"
# terasky.backstage.io/exclude-from-catalog: "true"
# --- Source manifest URL (for GitOps Manifest Updater) ---
terasky.backstage.io/source-file-url: "https://github.com/my-org/gitops/blob/main/web-apps/petstore/deployment.yaml"
spec:
replicas: 3
selector:
matchLabels:
app: petstore
template:
metadata:
labels:
app: petstore
spec:
containers:
- name: petstore
image: swaggerapi/petstore3:latest
```
---
## Kubernetes Ingestor — Delta / Incremental Updates
The `KubernetesEntityProvider` exposes a `deltaUpdate()` method for pushing individual resource changes without waiting for the next full sync cycle.
```typescript
import { DeltaEvent } from '@terasky/backstage-plugin-kubernetes-ingestor';
// Upsert: re-fetches the resource from the cluster and updates catalog entities
await provider.deltaUpdate({
action: 'upsert',
apiVersion: 'apps/v1',
kind: 'Deployment',
name: 'petstore',
namespace: 'web-apps',
clusterName: 'sa-production',
});
// Delete: removes all catalog entities for the resource
await provider.deltaUpdate({
action: 'delete',
apiVersion: 'apps/v1',
kind: 'Deployment',
name: 'petstore',
namespace: 'web-apps',
clusterName: 'sa-production',
});
// Delete with explicit entity refs (needed when annotation-based naming was used)
await provider.deltaUpdate({
action: 'delete',
apiVersion: 'apps/v1',
kind: 'Deployment',
name: 'petstore',
namespace: 'web-apps',
clusterName: 'sa-production',
entityNames: ['Component:default/my-custom-named-petstore'],
});
// Notes:
// - deltaUpdate() throws if the initial full sync has not yet completed.
// - Shared System entities are never removed on a single resource delete.
// - Concurrent calls are serialized internally via a mutex.
```
---
## Crossplane Resources Frontend — Entity Page Integration (Legacy System)
`@terasky/backstage-plugin-crossplane-resources-frontend` renders Claims, Composite Resources, Managed Resources, and a dependency graph for entities ingested by the Kubernetes Ingestor.
```typescript
// packages/app/src/components/catalog/EntityPage.tsx
import {
CrossplaneResourcesTableSelector,
CrossplaneOverviewCardSelector,
CrossplaneResourceGraphSelector,
useResourceGraphAvailable,
useResourcesListAvailable,
IfCrossplaneOverviewAvailable,
IfCrossplaneResourceGraphAvailable,
IfCrossplaneResourcesListAvailable,
} from '@terasky/backstage-plugin-crossplane-resources-frontend';
import {
CrossplaneApiClient,
crossplaneApiRef,
} from '@terasky/backstage-plugin-crossplane-resources-frontend';
import { createApiFactory, discoveryApiRef, fetchApiRef } from '@backstage/core-plugin-api';
// Register the API client (packages/app/src/apis.ts)
export const apis: AnyApiFactory[] = [
createApiFactory({
api: crossplaneApiRef,
deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },
factory: ({ discoveryApi, fetchApi }) =>
new CrossplaneApiClient(discoveryApi, fetchApi),
}),
];
// Entity page component
const CrossplaneEntityPage = () => {
const isResourcesListAvailable = useResourcesListAvailable();
const isResourceGraphAvailable = useResourceGraphAvailable();
return (
);
};
// Wire to entity switch
const componentPage = (
);
```
---
## Crossplane Resources Backend — Permission Framework
`@terasky/backstage-plugin-crossplane-resources-backend` integrates with Backstage's permission framework. Permissions can be managed via a CSV file with the community RBAC plugin.
```yaml
# app-config.yaml
permission:
enabled: true
rbac:
policies-csv-file: /etc/backstage/permissions.csv
policyFileReload: true
pluginsWithPermission:
- kubernetes
- crossplane
```
```csv
# permissions.csv — grant a role all Crossplane read permissions
p, role:default/platform-team, crossplane.claims.list, read, allow
p, role:default/platform-team, crossplane.claims.view-yaml, read, allow
p, role:default/platform-team, crossplane.claims.show-events, read, allow
p, role:default/platform-team, crossplane.composite-resources.list, read, allow
p, role:default/platform-team, crossplane.composite-resources.view-yaml, read, allow
p, role:default/platform-team, crossplane.composite-resources.show-events, read, allow
p, role:default/platform-team, crossplane.managed-resources.list, read, allow
p, role:default/platform-team, crossplane.managed-resources.view-yaml, read, allow
p, role:default/platform-team, crossplane.managed-resources.show-events, read, allow
p, role:default/platform-team, crossplane.additional-resources.list, read, allow
p, role:default/platform-team, crossplane.additional-resources.view-yaml, read, allow
p, role:default/platform-team, crossplane.additional-resources.show-events, read, allow
p, role:default/platform-team, crossplane.resource-graph.show, read, allow
p, role:default/platform-team, crossplane.overview.view, read, allow
g, group:default/all_users, role:default/platform-team
```
---
## KRO Resources Frontend — Entity Page Integration
`@terasky/backstage-plugin-kro-resources-frontend` visualizes KRO RGD instances, managed resources, and dependency graphs.
```typescript
// packages/app/src/components/catalog/EntityPage.tsx
import {
IfKroOverviewAvailable,
IfKroResourceGraphAvailable,
IfKroResourcesListAvailable,
isKroAvailable,
KroOverviewCard,
KroResourceGraph,
KroResourceTable,
useKroResourceListAvailable,
useKroResourceGraphAvailable,
} from '@terasky/backstage-plugin-kro-resources-frontend';
const KroEntityPage = () => {
const isKroResourceListAvailable = useKroResourceListAvailable();
const isKroResourceGraphAvailable = useKroResourceGraphAvailable();
return (
);
};
const componentPage = (
);
```
---
## ScaleOps Backend — Configuration and MCP Actions
`@terasky/backstage-plugin-scaleops-backend` proxies ScaleOps cost optimization data and exposes 5 MCP actions for AI agents.
```yaml
# app-config.yaml
scaleops:
baseUrl: https://scaleops.example.com
linkToDashboard: true # include dashboard URLs in MCP action output
authentication:
enabled: true
type: internal # or 'ldap'
user: ${SCALEOPS_USER}
password: ${SCALEOPS_PASSWORD}
```
```json
// MCP action: query cost optimization data for a workload
// Action: scaleops_get_recommendations
{
"workloadName": "petstore",
"namespace": "web-apps",
"clusterName": "production"
}
// Expected response (with linkToDashboard: true)
{
"workloads": [
{
"workloadName": "petstore",
"namespace": "web-apps",
"currentCost": 42.5,
"optimizedCost": 18.3,
"savingsPercent": 56.9,
"cpuRecommendation": { "request": "100m", "limit": "200m" },
"memoryRecommendation": { "request": "128Mi", "limit": "256Mi" },
"dashboardUrl": "https://scaleops.example.com/cost-report/compute?searchTerms=petstore&..."
}
]
}
```
---
## Scaffolder Backend Module — TeraSky Utils (Custom Actions)
`@terasky/backstage-plugin-scaffolder-backend-module-terasky-utils` adds three scaffolder actions: `terasky:claim-template`, `terasky:crd-template`, and `terasky:catalog-info-cleaner`.
```yaml
# Software Template using terasky:claim-template
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: provision-postgres
title: Provision PostgreSQL via Crossplane
spec:
owner: platform-team
type: service
parameters:
- title: Database Configuration
required: [xrName, xrNamespace, clusters]
properties:
xrName:
type: string
title: Database name
xrNamespace:
type: string
title: Namespace
default: databases
clusters:
type: array
title: Target clusters
items:
type: string
enum: [production, staging]
size:
type: string
enum: [small, medium, large]
default: small
version:
type: string
default: "15"
steps:
- id: generate-claim
name: Generate Crossplane Claim YAML
action: terasky:claim-template
input:
parameters: ${{ parameters }}
apiVersion: db.example.com/v1alpha1
kind: PostgreSQLInstance
clusters: ${{ parameters.clusters }}
removeEmptyParams: true
excludeParams: [xrName, xrNamespace, clusters, targetBranch, repoUrl]
- id: publish
name: Push to Git
action: publish:github:pull-request
input:
repoUrl: github.com?owner=my-org&repo=gitops
branchName: provision-${{ parameters.xrName }}
title: "Provision PostgreSQL: ${{ parameters.xrName }}"
description: Auto-generated by Backstage
output:
links:
- title: Pull Request
url: ${{ steps.publish.output.remoteUrl }}
- title: Download Manifest
url: data:application/yaml;charset=utf-8,${{ steps['generate-claim'].output.manifestEncoded }}
```
```yaml
# Software Template using terasky:catalog-info-cleaner
steps:
- id: fetch-entity
name: Fetch Entity
action: catalog:fetch
input:
entityRef: ${{ parameters.entity }}
- id: clean-entity
name: Clean Entity Manifest for Git
action: terasky:catalog-info-cleaner
input:
entity: ${{ steps['fetch-entity'].output.entity }}
# Output: steps['clean-entity'].output.manifest (raw YAML)
# steps['clean-entity'].output.filePath (path written to workspace)
```
---
## Scaffolder MCP Backend — AI-Driven Template Execution
`@terasky/plugin-scaffolder-mcp-backend` exposes 7 MCP actions enabling AI agents to discover and execute Backstage Software Templates programmatically.
```yaml
# app-config.yaml — minimal config, no extra keys required
permission:
enabled: true
rbac:
policies-csv-file: /etc/backstage/permissions.csv
pluginsWithPermission:
- scaffolder
```
```json
// MCP action 1: list_software_templates
// Input: {} (no required fields)
// Returns: array of template names, titles, and descriptions
// MCP action 2: get_software_template_parameter_schema
{ "templateRef": "template:default/provision-postgres" }
// Returns: full JSON Schema of the template's parameters
// MCP action 3: run_software_template — executes template and waits for completion
{
"templateRef": "template:default/provision-postgres",
"parameters": {
"xrName": "my-db",
"xrNamespace": "databases",
"clusters": ["production"],
"size": "small",
"version": "15"
}
}
// Returns: { "taskId": "task:abc123", "status": "completed", "output": { ... } }
// MCP action 4: list_software_template_actions
// Returns: all registered scaffolder actions with their IDs and descriptions
// MCP action 5: get_software_template_action_details
{ "actionId": "terasky:claim-template" }
// Returns: full input/output JSON Schema for the action
// MCP action 6: list_software_template_extensions
// Returns: all registered scaffolder field extensions
// MCP action 7: get_software_template_extension_details
{ "extensionId": "GitOpsManifestUpdater" }
// Returns: field extension schema and usage documentation
```
---
## Catalog MCP Backend — AI Catalog Queries
`@terasky/backstage-plugin-catalog-mcp-backend` exposes 5 MCP actions for querying the Backstage Catalog. No additional configuration beyond standard catalog setup is needed.
```json
// MCP action 1: get_entities_by_owner
{ "owner": "group:default/platform-team" }
// Returns: all entities owned by that group
// MCP action 2: get_entities_by_annotation
{ "annotation": "github.com/project-slug", "value": "my-org/petstore" }
// Returns: entities matching the annotation key+value (omit value for key-only search)
// MCP action 3: get_entity_types_for_kind
{ "kind": "Component" }
// Returns: ["service", "website", "library", "crossplane-claim", "kro-instance", ...]
// MCP action 4: get_all_entities_by_kind_and_type
{ "kind": "Component", "type": "crossplane-claim" }
// Returns: all Component entities of type crossplane-claim
// MCP action 5: get_entities_with_custom_query — flexible query with field selection
{
"filter": "kind=Component,spec.type=service,spec.owner=group:default/platform-team",
"fields": "kind,metadata.name,metadata.namespace,spec.type,spec.owner,metadata.annotations"
}
// Returns: matched entities with only the requested fields (reduces payload size)
// Tip: use comma-separated filters without spaces; field selection is highly recommended
// for large catalogs (1000+ entities)
```
---
## RBAC MCP Backend — AI Permission Management
`@terasky/plugin-rbac-mcp-backend` exposes 10 MCP actions for managing RBAC policies. Users must have `permission.policy.*` admin permissions.
```bash
# Create admin role via REST API (required before using MCP actions)
curl -X POST http://localhost:7007/api/permission/roles \
-H "Content-Type: application/json" \
-d '{
"memberReferences": ["user:default/admin"],
"name": "role:default/rbac-admin",
"metadata": { "description": "RBAC administrators" }
}'
```
```csv
# Grant RBAC admin permissions via CSV
p, role:default/rbac-admin, permission.policy.read, read, allow
p, role:default/rbac-admin, permission.policy.create, create, allow
p, role:default/rbac-admin, permission.policy.update, update, allow
p, role:default/rbac-admin, permission.policy.delete, delete, allow
g, user:default/admin, role:default/rbac-admin
```
```json
// MCP action: create_role_with_permissions — creates role and grants permissions atomically
{
"roleName": "role:default/developers",
"memberReferences": ["group:default/engineering"],
"permissions": [
{ "permission": "scaffolder.task.read", "action": "read" },
{ "permission": "scaffolder.task.create", "action": "create" },
{ "permission": "scaffolder-template", "action": "read" },
{ "permission": "catalog-entity", "action": "read" }
]
}
// MCP action: list_roles — list all roles
{}
// MCP action: delete_role
{ "roleName": "role:default/old-role" }
```
---
## VCF Automation Backend — API Endpoints and Configuration
`@terasky/backstage-plugin-vcf-automation-backend` proxies VCF Automation APIs and exposes REST endpoints consumed by the frontend plugin.
```yaml
# app-config.yaml — single instance
vcfAutomation:
name: vcfa-prod
majorVersion: 9 # 8 or 9
orgName: my-org # required for VCF 9+
organizationType: all-apps # 'vm-apps' (default) or 'all-apps'
baseUrl: https://vcfa.example.com
authentication:
username: ${VCFA_USERNAME}
password: ${VCFA_PASSWORD}
```
```yaml
# app-config.yaml — multi-instance
vcfAutomation:
instances:
- name: vcfa-eu
baseUrl: https://vcfa-eu.example.com
majorVersion: 9
orgName: eu-org
organizationType: all-apps
authentication:
username: ${VCFA_EU_USER}
password: ${VCFA_EU_PASS}
- name: vcfa-us
baseUrl: https://vcfa-us.example.com
majorVersion: 8
authentication:
username: ${VCFA_US_USER}
password: ${VCFA_US_PASS}
domain: corp.example.com
```
```bash
# REST endpoints exposed by the backend plugin
GET /api/vcf-automation/deployments # list all deployments
GET /api/vcf-automation/deployments/:id # deployment details
GET /api/vcf-automation/deployments/:id/resources # resources in a deployment
POST /api/vcf-automation/deployments/:id/operations # trigger deployment operation
GET /api/vcf-automation/resources/:id # resource details
GET /api/vcf-automation/projects # list all projects
GET /api/vcf-automation/projects/:id # project details
GET /api/vcf-automation/supervisor-resources # paginated supervisor resources
GET /api/vcf-automation/supervisor-namespaces # supervisor namespaces
POST /api/vcf-automation/resources/:resourceId/power-actions/:action # execute VM power action
PUT /api/vcf-automation/standalone-vms/:ns/:nsName/:vmName/power-state # standalone VM power
GET /api/vcf-automation/events # stream VCF events
```
---
## VCF Operations Backend — Multi-Instance Configuration
`@terasky/backstage-plugin-vcf-operations-backend` connects to VCF Operations instances to surface metrics data in Backstage.
```yaml
# app-config.yaml
vcfOperations:
instances:
- name: prod-vcf-primary
baseUrl: https://vcf-prod-01.example.com
majorVersion: 9
relatedVCFAInstances: # link to VCF Automation instances
- vcfa-prod
authentication:
username: ${VCF_OPS_USERNAME}
password: ${VCF_OPS_PASSWORD}
- name: staging-vcf
baseUrl: https://vcf-staging.example.com
majorVersion: 8
authentication:
username: ${VCF_OPS_STAGING_USER}
password: ${VCF_OPS_STAGING_PASS}
domain: staging.local
```
---
## SpectroCloud Plugins — Authentication, Ingestion, and Frontend Cards
The SpectroCloud plugin family covers OIDC auth, catalog ingestion, Kubernetes cluster supply, and entity cards.
```yaml
# app-config.yaml — SpectroCloud OIDC auth backend
auth:
environment: production
providers:
spectrocloud:
production:
clientId: ${SPECTROCLOUD_CLIENT_ID}
clientSecret: ${SPECTROCLOUD_CLIENT_SECRET}
metadataUrl: https://spectrocloud.example.com/.well-known/openid-configuration
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail
```
```yaml
# app-config.yaml — SpectroCloud ingestor
spectrocloud:
baseUrl: https://spectrocloud.example.com
apiKey: ${SPECTROCLOUD_API_KEY}
taskRunner:
frequency: 300 # sync every 5 minutes
timeout: 600
```
```typescript
// packages/app/src/components/catalog/EntityPage.tsx (legacy system)
import {
SpectroCloudClusterCard,
SpectroCloudClusterProfileCard,
} from '@terasky/backstage-plugin-spectrocloud';
const spectroCloudClusterPage = (
{/* shows K8s version, attached profiles, cloud type, kubeconfig download */}
);
const spectroCloudProfilePage = (
{/* shows profile version, attached clusters */}
);
// Route entity types to their pages
// In EntitySwitch:
// case 'spectrocloud-cluster' → spectroCloudClusterPage
// case 'spectrocloud-cluster-profile' → spectroCloudProfilePage
```
---
## VCF SSO Authentication — Backend and Frontend
`@terasky/backstage-plugin-vcfsso-auth-backend` and `@terasky/backstage-plugin-vcfsso-auth` provide VCF SSO OIDC authentication with automatic handling of VCF SSO's non-standard `acct` claim.
```yaml
# app-config.yaml
auth:
environment: production
providers:
vcfsso:
production:
clientId: ${VCFSSO_CLIENT_ID}
clientSecret: ${VCFSSO_CLIENT_SECRET}
metadataUrl: https://vcf-sso.example.com/oidc/endpoint/VCFSSO
callbackUrl: https://backstage.example.com/api/auth/vcfsso/handler/frame
prompt: login # force re-authentication on every sign-in
signIn:
resolvers:
- resolver: emailMatchingUserEntityProfileEmail # matches acct claim to spec.profile.email
- resolver: emailLocalPartMatchingUserEntityName # fallback: local part of acct to entity name
allowedDomains:
- example.com
```
```typescript
// packages/app/src/App.tsx — add VCF SSO sign-in (legacy system)
import { vcfSsoAuthApiRef } from '@terasky/backstage-plugin-vcfsso-auth';
import { createApiFactory, discoveryApiRef, oauthRequestApiRef } from '@backstage/core-plugin-api';
export const apis: AnyApiFactory[] = [
createApiFactory({
api: vcfSsoAuthApiRef,
deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef },
factory: ({ discoveryApi, oauthRequestApi }) =>
OAuth2.create({
discoveryApi,
oauthRequestApi,
provider: { id: 'vcfsso', title: 'VCF SSO', icon: () => null },
defaultScopes: ['openid', 'profile', 'email'],
environment: 'production',
}),
}),
];
```
---
## Global Sign-In Page Module — Configuration-Driven Auth Providers
`@terasky/backstage-plugin-app-module-global-signin-page` replaces hardcoded sign-in page TypeScript with YAML configuration. Supports all core Backstage auth providers plus SpectroCloud and VCF SSO.
```yaml
# app-config.yaml
signinPage:
enableGuestProvider: false # NEVER true in production
providers:
microsoft:
enabled: true
title: Corporate SSO
message: Sign in with your corporate Microsoft account
github:
enabled: true
title: GitHub
message: External contributors — sign in with GitHub
okta:
enabled: true
title: Okta SSO
message: Enterprise users — sign in with Okta
spectrocloud:
enabled: false
vcfsso:
enabled: true
title: VCF SSO
message: Sign in using VCF SSO
google:
enabled: false
gitlab:
enabled: false
bitbucket:
enabled: false
openshift:
enabled: false
```
---
## Kyverno Policy Reports — Frontend Integration
`@terasky/backstage-plugin-kyverno-policy-reports` displays Kyverno PolicyReport results for Kubernetes workloads on entity pages.
```typescript
// packages/app/src/components/catalog/EntityPage.tsx
import {
KyvernoPolicyReportsTable,
KyvernoOverviewCard,
KyvernoCrossplanePolicyReportsTable,
KyvernoCrossplaneOverviewCard,
} from '@terasky/backstage-plugin-kyverno-policy-reports';
// Standard workloads: overview card + full table
const overviewContent = (
{/* pass/warn/fail summary */}
);
const serviceEntityPage = (
);
// Crossplane entities: use Crossplane-specific variants
const crossplaneEntityPage = (
);
```
---
## DevPod Plugin — "Open in DevPod" Card
`@terasky/backstage-plugin-devpod` adds a development environment launcher card to the entity overview page.
```typescript
// packages/app/src/components/catalog/EntityPage.tsx
import { DevpodComponent, isDevpodAvailable } from '@terasky/backstage-plugin-devpod';
const overviewContent = (
{/* IDE selector + "Open in DevPod" button + CLI command display */}
);
```
```yaml
# Entity annotation to enable DevPod for a component
# (required on the catalog entity for isDevpodAvailable to return true)
metadata:
annotations:
terasky.backstage.io/devpod-enabled: "true"
```
---
## GitOps Manifest Updater — Scaffolder Field Extension
`@terasky/backstage-plugin-gitops-manifest-updater` provides a `GitOpsManifestUpdater` scaffolder field extension that reads a CRD/XRD OpenAPI schema from a Git-stored manifest URL and renders a dynamic form, then creates a GitHub PR with the updated YAML.
```typescript
// packages/app/src/App.tsx (legacy system registration)
import { GitOpsManifestUpdaterExtension } from '@terasky/backstage-plugin-gitops-manifest-updater';
import { ScaffolderFieldExtensions } from '@backstage/plugin-scaffolder-react';
const routes = (
}>
);
```
```yaml
# Software Template using the GitOpsManifestUpdater field
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: update-kubernetes-manifest
title: Update Kubernetes Manifest via GitOps
spec:
parameters:
- title: GitOps Manifest Updater
required: [gitOpsManifestUpdater]
properties:
gitOpsManifestUpdater:
title: Update Parameters
type: object
ui:field: GitOpsManifestUpdater
steps:
- id: create-pull-request
name: Create PR
action: publish:github:pull-request
input:
repoUrl: ${{ 'github.com?owner=' + steps['parse-url'].output.result.owner + '&repo=' + steps['parse-url'].output.result.repo }}
branchName: backstage-update-${{ parameters.entity }}
title: Updating Kubernetes YAML for ${{ parameters.entity }}
output:
links:
- title: Pull Request
url: ${{ steps['create-pull-request'].output.remoteUrl }}
# Entity annotation providing the source manifest URL:
# terasky.backstage.io/source-file-url: "https://github.com/my-org/gitops/blob/main/clusters/prod/my-claim.yaml"
```
---
## Kubernetes Resources Frontend — Dependency Graph
`@terasky/backstage-plugin-kubernetes-resources-frontend` visualizes Kubernetes resource dependency graphs for catalog entities.
```yaml
# app-config.yaml — proxy to the kubernetes-dependency-tracker service
proxy:
endpoints:
'/kubernetes-resources/production':
target: 'http://k8s-dependency-tracker.example.com'
changeOrigin: true
headers:
Authorization: 'Bearer ${K8S_SA_TOKEN}'
```
```yaml
# Entity annotation wiring
metadata:
annotations:
terasky.backstage.io/kubernetes-resource-name: 'my-deployment'
terasky.backstage.io/kubernetes-resource-kind: 'Deployment'
terasky.backstage.io/kubernetes-resource-api-version: 'apps/v1'
terasky.backstage.io/kubernetes-resource-namespace: 'web-apps'
backstage.io/managed-by-origin-location: 'production' # must match proxy cluster name
```
```typescript
// packages/app/src/components/catalog/EntityPage.tsx
import {
KubernetesResourcesPage,
KubernetesResourceGraph,
isKubernetesResourcesAvailable,
} from '@terasky/backstage-plugin-kubernetes-resources-frontend';
const serviceEntityPage = (
);
```
---
## API Docs Module CRD — CRD API Documentation Renderer
`@terasky/backstage-plugin-api-docs-module-crd` renders Backstage API entities of type `crd` with an interactive documentation viewer modelled after doc.crds.dev.
```yaml
# Backstage API entity of type "crd" — registered automatically by kubernetes-ingestor
# or manually via catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: application-deployment-crd
title: Application Deployment CRD
tags: [kubernetes, crd, deployment]
spec:
type: crd # triggers the api-docs-module-crd renderer
lifecycle: production
owner: platform-team
system: application-platform
definition: |
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: applicationdeployments.platform.example.com
spec:
group: platform.example.com
names:
kind: ApplicationDeployment
plural: applicationdeployments
shortNames: [appd]
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: [spec]
properties:
spec:
type: object
required: [image, replicas]
properties:
image:
type: string
description: Container image to deploy
replicas:
type: integer
description: Number of replicas (1–100)
minimum: 1
maximum: 100
default: 3
regions:
type: array
description: Target deployment regions
items:
type: string
enum: [us-east-1, us-west-2, eu-west-1]
```
---
## Educates — Training Workshop Browser
`@terasky/backstage-plugin-educates` adds a `/educates` route for browsing and launching Educates training workshops.
```yaml
# app-config.yaml — Educates backend configuration
educates:
portals:
- name: platform-training
url: https://training-portal.example.com
accessToken: ${EDUCATES_ACCESS_TOKEN}
```
```typescript
// packages/app/src/App.tsx (legacy system)
import { EducatesPage } from '@terasky/backstage-plugin-educates';
import { SchoolIcon } from '@material-ui/icons';
// Add route
const routes = (
} />
);
// Add sidebar entry (packages/app/src/components/Root/Root.tsx)
```
---
## Spring Initializer — Spring Boot Project Scaffolder Field
`@terasky/backstage-plugin-spring-initializer` provides a `SpringInitializer` scaffolder field extension backed by start.spring.io.
```yaml
# app-config.yaml — proxy configuration
proxy:
endpoints:
'/spring-initializer':
target: 'https://start.spring.io'
changeOrigin: true
springInitializer:
endpoint: 'https://start.spring.io'
proxyPath: '/spring-initializer'
```
```yaml
# Software Template using the SpringInitializer field
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: spring-boot-service
title: Create Spring Boot Service
spec:
parameters:
- title: Spring Boot Configuration
properties:
springConfig:
title: Spring Configuration
type: object
ui:field: SpringInitializer
- title: Repository Location
required: [repoUrl]
properties:
repoUrl:
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts: [github.com]
steps:
- id: generate-spring
name: Generate Spring Boot Project
action: terasky:spring-initializer
input:
type: ${{ parameters.springConfig.type }}
language: ${{ parameters.springConfig.language }}
bootVersion: ${{ parameters.springConfig.bootVersion }}
groupId: ${{ parameters.springConfig.groupId }}
artifactId: ${{ parameters.springConfig.artifactId }}
name: ${{ parameters.springConfig.name }}
description: ${{ parameters.springConfig.description }}
packageName: ${{ parameters.springConfig.packageName }}
packaging: ${{ parameters.springConfig.packaging }}
javaVersion: ${{ parameters.springConfig.javaVersion }}
dependencies: ${{ parameters.springConfig.dependencies }}
- id: publish
name: Publish to GitHub
action: publish:github
input:
repoUrl: ${{ parameters.repoUrl }}
defaultBranch: main
```
---
## Module Federation CDN Backend — Dynamic Plugin Loading from CDN
`@terasky/backstage-plugin-module-federation-cdn-backend` enables Backstage dynamic frontend plugins to be loaded directly from a CDN without copying files into `dynamic-plugins-root`.
```yaml
# app-config.yaml
cdn:
- pluginName: "@my-org/backstage-plugin-dashboard"
publicPath: "https://cdn.example.com/plugins/dashboard/"
- pluginName: "@my-org/backstage-plugin-metrics"
publicPath: "https://cdn.example.com/plugins/metrics/"
# Versioned path for blue/green or canary deployments
- pluginName: "@my-org/backstage-plugin-example"
publicPath: "https://cdn.example.com/plugins/example/v1.2.3/"
# Environment variable substitution
- pluginName: "@my-org/backstage-plugin-other"
publicPath: "${CDN_BASE_URL}/plugins/other/"
```
```bash
# Verify CDN-hosted plugins are registered after backend restart
curl -s http://localhost:7007/api/dynamic-features/remotes | jq '.[].name'
# Expected output:
# "@my-org/backstage-plugin-dashboard"
# "@my-org/backstage-plugin-metrics"
# The CDN must serve mf-manifest.json at: mf-manifest.json
# CORS header required: Access-Control-Allow-Origin: *
```
---
## Frontend Extensions Explorer — NFS Introspection
`@terasky/backstage-plugin-frontend-extensions-explorer` provides a live read-only introspection page for the Backstage New Frontend System extension tree. No backend plugin or network calls are required.
```typescript
// The plugin reads directly from the appTreeApiRef runtime API at render time.
// No manual registration is needed when using the /alpha export.
// Access the page at: /frontend-extensions-explorer
// Internal data source (for reference):
import { useApi, appTreeApiRef } from '@backstage/frontend-plugin-api';
const { tree } = useApi(appTreeApiRef).getTree();
// tree.nodes: ReadonlyMap
// Each AppNode has:
// node.spec.disabled: boolean
// node.instance: object | undefined (undefined = not running)
// node.spec.config: object | null (applied app-config.yaml overrides)
// Extension status:
// spec.disabled === true → "Disabled"
// spec.disabled === false && instance defined → "Enabled"
// spec.disabled === false && instance missing → "Not Running"
```
---
## Entity Scaffolder Content — Embedded Template Tab
`@terasky/backstage-plugin-entity-scaffolder-content` embeds a filtered Software Template list and form directly on an entity's page tab.
```typescript
// packages/app/src/components/catalog/EntityPage.tsx
import {
EntityScaffolderContent,
isScaffolderAvailable,
} from '@terasky/backstage-plugin-entity-scaffolder-content';
import { stringifyEntityRef } from '@backstage/catalog-model';
const serviceEntityPage = (
template.metadata?.labels?.target === 'component',
},
]}
buildInitialState={entity => ({
entity: stringifyEntityRef(entity),
})}
ScaffolderFieldExtensions={
}
/>
);
```
---
TeraSky's Backstage Plugins are purpose-built for platform engineering teams managing Kubernetes-heavy, multi-cloud environments. The primary pattern is to install the `kubernetes-ingestor` backend plugin once and let it automatically populate the catalog with hundreds of entities — standard workloads, Crossplane XRD/Claim pairs, KRO RGDs/Instances, and generic CRDs — each linked to generated Software Templates that let developers self-serve infrastructure without leaving Backstage. Frontend plugins layer on top to add Crossplane/KRO resource graphs, Kyverno policy compliance views, ScaleOps cost recommendations, and vendor-specific cards for VCF Automation, VCF Operations, and SpectroCloud, while MCP backend plugins (Scaffolder, Catalog, RBAC) expose these capabilities to AI agents and automation tooling.
Integration follows a consistent pattern: all plugins support the Backstage New Frontend System (register via `createApp({ features: [...] })`), all backend plugins use the new `backend.add(import(...))` pattern, permission-framework integration is provided out of the box and configured entirely through CSV policies or the community RBAC plugin, and configuration is expressed declaratively in `app-config.yaml` with environment variable substitution for secrets. Teams can adopt individual plugins independently — for example, starting with only the kubernetes-ingestor and api-docs-module-crd to document CRDs, then progressively adding the MCP backends to enable AI-assisted catalog queries and scaffolding — without committing to the entire plugin suite.