Kubernetes Ingestor logo

Backstage Kubernetes Ingestor Plugin

Created by terasky.com

Kubernetes Ingestor is a Backstage backend plugin that turns live Kubernetes resources into Backstage catalog entities. It discovers standard workloads and custom resources, then keeps the catalog in sync as things change in your clusters. It handles Crossplane claims and XRDs out of the box, so platform and app teams see the same source of truth inside Backstage.

Beyond discovery, the plugin can generate software templates from XRDs. You can publish those to GitHub, GitLab, or Bitbucket, or download the YAML when needed. It also creates API entities for XRDs, maps relationships between components and the APIs they provide or consume, and supports multi cluster setups and namespace filters. If you rely on custom GVKs, you can add them so they become first class catalog entries as well.

Typical use cases include pulling existing services into Backstage without hand writing catalog files, keeping metadata fresh during frequent deploys, and offering Crossplane driven templates that fit a GitOps flow with pull requests. Teams can control scope with annotations and choose opt in or opt out ingestion patterns. You get a simple way to organize systems and relationships while the plugin does the heavy lifting behind the scenes. Setup expects cluster access and the right permissions.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install with the new backend system

Add dependencies

Copy
yarn --cwd packages/backend add @terasky/backstage-plugin-kubernetes-ingestor
yarn --cwd packages/backend add @terasky/backstage-plugin-scaffolder-backend-module-terasky-utils
yarn --cwd packages/backend add @backstage/plugin-scaffolder-backend-module-github @backstage/plugin-scaffolder-backend-module-gitlab @backstage/plugin-scaffolder-backend-module-bitbucket

Register the backend modules

Edit packages/backend/src/index.ts

Copy
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

// Kubernetes Ingestor backend module
backend.add(import('@terasky/backstage-plugin-kubernetes-ingestor'));

// Scaffolder modules for template publishing
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-gitlab'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-bitbucket'));
backend.add(import('@terasky/backstage-plugin-scaffolder-backend-module-terasky-utils'));

backend.start();

Configure the plugin

Add to app-config.yaml

Copy
kubernetesIngestor:
  mappings:
    namespaceModel: 'cluster'
    nameModel: 'name-cluster'
    titleModel: 'name'
    systemModel: 'namespace'
    referencesNamespaceModel: 'default'
  components:
    enabled: true
    taskRunner:
      frequency: 10
      timeout: 600
    excludedNamespaces:
      - kube-public
      - kube-system
    customWorkloadTypes:
      - group: pkg.crossplane.io
        apiVersion: v1
        plural: providers
  crossplane:
    enabled: true
    claims:
      ingestAllClaims: true
    xrds:
      enabled: true
      publishPhase:
        allowedTargets: ['github.com', 'gitlab.com']
        target: github
        git:
          repoUrl: github.com?owner=org&repo=templates
          targetBranch: main
        allowRepoSelection: true
      taskRunner:
        frequency: 10
        timeout: 600

Configure your clusters

Point Backstage to your Kubernetes clusters and use the service account token

Copy
kubernetes:
  clusterLocatorMethods:
    - type: config
      clusters:
        - name: prod
          url: https://your-api-server
          authProvider: serviceAccount
          serviceAccountToken: ${K8S_SA_TOKEN}
          skipTLSVerify: true

You can set the token through an env var

Copy
export K8S_SA_TOKEN='paste-your-token'

Set Kubernetes RBAC and service account

You can apply a full setup in one go

Copy
kubectl apply --filename - <<'EOF'
apiVersion: v1
kind: Namespace
metadata:
  name: backstage-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: backstage-user
  namespace: backstage-system
---
apiVersion: v1
kind: Secret
metadata:
  name: backstage-token
  namespace: backstage-system
  annotations:
    kubernetes.io/service-account.name: backstage-user
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: backstage-kubernetes-ingestor-rbac
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- kind: ServiceAccount
  name: backstage-user
  namespace: backstage-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: backstage-crd-viewer
rules:
- apiGroups:
  - apiextensions.k8s.io
  resources:
  - customresourcedefinitions
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: backstage-crossplane-ingestion-crd-rbac
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: backstage-crd-viewer
subjects:
- kind: ServiceAccount
  name: backstage-user
  namespace: backstage-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: backstage-crossplane-ingestion-rbac
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: crossplane-view
subjects:
- kind: ServiceAccount
  name: backstage-user
  namespace: backstage-system
EOF

Fetch the token

Copy
kubectl get secret -n backstage-system backstage-token -o jsonpath='{.data.token}' | base64 --decode

Paste the token into the serviceAccountToken field in app-config.yaml or export it as K8S_SA_TOKEN

Set Git access for template publishing

Copy
export GITHUB_TOKEN=your-token
export GITLAB_TOKEN=your-token
export BITBUCKET_TOKEN=your-token

Install with the old backend system

Support status

This plugin ships as a backend module for the new backend system. It does not include a legacy router. The simplest path in a legacy repo is to adopt the new backend entry point inside packages backend. You can keep your existing code in git and move over in one change.

Quick path in a legacy repo

Replace your backend bootstrap with the new backend entry point. Then add the module as shown above

Edit packages/backend/src/index.ts

Copy
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

backend.add(import('@backstage/plugin-app-backend'));
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-scaffolder-backend'));

// Add the Kubernetes Ingestor module
backend.add(import('@terasky/backstage-plugin-kubernetes-ingestor'));

// Add publishing modules
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-gitlab'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-bitbucket'));
backend.add(import('@terasky/backstage-plugin-scaffolder-backend-module-terasky-utils'));

backend.start();

Keep the same app-config.yaml and RBAC from the new backend steps

Use it in the frontend

Make sure the Catalog and Scaffolder pages are visible

The plugin creates entities in the catalog. It also registers software templates. You view them on the Catalog and Create pages. Add these routes if your app does not have them

Edit packages/app/src/App.tsx

Copy
import React from 'react';
import { FlatRoutes } from '@backstage/core-components';
import { CatalogIndexPage, CatalogEntityPage } from '@backstage/plugin-catalog';
import { ScaffolderPage } from '@backstage/plugin-scaffolder';
import { Route } from 'react-router';

export const AppRoutes = () => (
  <FlatRoutes>
    <Route path="/catalog" element={<CatalogIndexPage />} />
    <Route path="/catalog/:namespace/:kind/:name" element={<CatalogEntityPage />} />
    <Route path="/create" element={<ScaffolderPage />} />
  </FlatRoutes>
);

If you do not have the frontend packages installed, add them

Copy
yarn --cwd packages/app add @backstage/plugin-catalog @backstage/plugin-scaffolder

No extra frontend import is needed for this plugin. The backend will populate the catalog and templates. You will see components appear in Catalog. You will see generated templates on the Create page

Optional Crossplane setup notes

If you run Crossplane and want claim and XR ingestion with template generation, keep crossplane enabled in the config shown above. The RBAC section already grants the needed access for CRDs and Crossplane resources

Optional configuration tweaks

You can narrow ingestion to specific clusters

Copy
kubernetesIngestor:
  allowedClusterNames:
    - prod

You can add more custom workload types

Copy
kubernetesIngestor:
  components:
    customWorkloadTypes:
      - group: apps.example.com
        apiVersion: v1
        plural: applications
        singular: application

You can switch to opt in ingestion

Copy
kubernetesIngestor:
  components:
    onlyIngestAnnotatedResources: true

Changelog

This changelog is produced from commits made to the Kubernetes Ingestor plugin since 4 months ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Features

  • Add annotations terasky.backstage.io/name and terasky.backstage.io/title to override the generated component name and title for claims XRs and Kubernetes resources #82 merged 27 days ago
  • Add cluster and kind tags for XR and claim based components #82 merged 27 days ago

Improvements

  • Change architecture to use the Kubernetes backend plugin proxy endpoint The plugin now relies on the backend for auth and cluster discovery This supports custom cluster locators and custom auth that work with the backend proxy #82 merged 27 days ago

Bug fixes

  • Fix an issue where kind and apiVersion are not always returned for some Kubernetes workload types #82 merged 27 days ago

Compatibility

  • Support Backstage 1.42.5 #82 merged 27 days ago

Set up Backstage in minutes with Roadie