Red Hat Developer Hub 1.10

Red Hat Developer Hub documentation

Complete documentation for Red Hat Developer Hub.

Red Hat Customer Content Services

Abstract

The complete Red Hat Developer Hub documentation, organized by category.

Preface

The complete Red Hat Developer Hub documentation, organized by category.

Chapter 1. Discover

1.1. Discover

Evaluate Red Hat Developer Hub capabilities, understand the system architecture, explore integrations, and assess the value proposition before deployment.

1.2. Evaluate RHDH capabilities

1.2.1. Evaluate RHDH capabilities

Assess internal developer platform benefits, review system architecture, explore AI assistant capabilities, understand platform integrations, and verify supported platforms before adoption.

1.2.2. Why Internal developer platforms?

1.2.2.1. Why Internal developer platforms?

Internal developer platforms (IDPs) provide a unified interface that enables developer self-service for provisioning environments, deploying code, and accessing APIs. By centralizing these tools, IDPs reduce complexity across development workflows.

Why IDPs matter
IDPs address the challenges of modern software delivery by enabling self-service, enforcing standards, and improving the developer experience.
For organizations
  • Scalability: RHDH enables consistent developer onboarding and application delivery across growing teams and environments.
  • Security: Role-based access control (RBAC) and integration with enterprise systems ensure access is managed securely and in line with compliance requirements.
  • Operational efficiency: By removing manual handoffs and centralizing key development workflows, RHDH improves time to value and increases return on engineering investment.
For platform engineers
  • Curated platforms: Platform teams can design reusable templates and integrations aligned with organizational policies and developer needs.
  • Central configuration: Infrastructure and policies are defined as code and centrally managed, reducing drift and maintenance costs.
  • Governance at scale: Policies and best practices are embedded into developer workflows using automation and templates, without adding friction to the process.
For developers
  • Faster onboarding: Developers can use learning paths, software templates, and software catalog to deploy compliant services within minutes, without depending on other teams for setup.
  • Reduced cognitive load: Developers can find tools, documentation, and deployment environments in one place, eliminating the need to switch between systems or manage disconnected resources.
  • Self-service workflows: Developers can create applications or environments on-demand, without raising tickets or waiting for approvals.
  • Built-in standards: Developers can use preconfigured templates that enforce secure, compliant workflows without requiring manual setup.
  • Cross-team visibility: Developers can discover shared service catalogs and documentation to improve reuse and reduce duplication.
  • Higher productivity: Developers can dedicate more time to building features and less time to configuring infrastructure or resolving toolchain inconsistencies.
1.2.2.1.1. Key features
Centralized dashboard
Access development tools, CI/CD pipelines, APIs, monitoring tools, and documentation from a single interface. Integrate with systems such as Git, Red Hat OpenShift Container Platform, Kubernetes, and Jira.
Learning paths
Guide developers through structured tutorials and onboarding steps. Help teams build skills with internal and Red Hat training resources in one place.
Plugins and integrations
Extend RHDH with verified plugins that add new functionality without downtime. Dynamically integrate with supported tools such as Tekton for pipelines, GitOps for deployment automation, Nexus Repository for artifact storage, and JFrog Artifactory. RHDH also supports connecting to Red Hat OpenShift Container Platform, CI/CD systems, and security scanners through Red Hat-curated extensions.
Role-based access control (RBAC)
Manage user access with robust security permissions tailored to organizational needs.
Software catalog
Search, view, and manage services, APIs, and libraries from a central inventory. Track ownership, metadata, and component health in one place.
Software templates
Accelerate project setup by using preconfigured templates for CI/CD, runtime, and security. Standardize implementation while enabling developer autonomy.
Tech docs
Create, store, and view technical documentation alongside code. Make content searchable, consistently formatted, and accessible through the portal.
Scalability
Support growing teams and applications while maintaining access to the same tools and services.

1.2.2.2. Understanding internal developer platforms

Internal developer platforms (IDPs) provide a unified interface that enables developer self-service for provisioning environments, deploying code, and accessing APIs. By centralizing these tools, IDPs reduce complexity across development workflows.

Why IDPs matter
IDPs address the challenges of modern software delivery by enabling self-service, enforcing standards, and improving the developer experience.
For organizations
  • Scalability: RHDH enables consistent developer onboarding and application delivery across growing teams and environments.
  • Security: Role-based access control (RBAC) and integration with enterprise systems ensure access is managed securely and in line with compliance requirements.
  • Operational efficiency: By removing manual handoffs and centralizing key development workflows, RHDH improves time to value and increases return on engineering investment.
For platform engineers
  • Curated platforms: Platform teams can design reusable templates and integrations aligned with organizational policies and developer needs.
  • Central configuration: Infrastructure and policies are defined as code and centrally managed, reducing drift and maintenance costs.
  • Governance at scale: Policies and best practices are embedded into developer workflows using automation and templates, without adding friction to the process.
For developers
  • Faster onboarding: Developers can use learning paths, software templates, and software catalog to deploy compliant services within minutes, without depending on other teams for setup.
  • Reduced cognitive load: Developers can find tools, documentation, and deployment environments in one place, eliminating the need to switch between systems or manage disconnected resources.
  • Self-service workflows: Developers can create applications or environments on-demand, without raising tickets or waiting for approvals.
  • Built-in standards: Developers can use preconfigured templates that enforce secure, compliant workflows without requiring manual setup.
  • Cross-team visibility: Developers can discover shared service catalogs and documentation to improve reuse and reduce duplication.
  • Higher productivity: Developers can dedicate more time to building features and less time to configuring infrastructure or resolving toolchain inconsistencies.
1.2.2.2.1. Key features
Centralized dashboard
Access development tools, CI/CD pipelines, APIs, monitoring tools, and documentation from a single interface. Integrate with systems such as Git, Red Hat OpenShift Container Platform, Kubernetes, and Jira.
Learning paths
Guide developers through structured tutorials and onboarding steps. Help teams build skills with internal and Red Hat training resources in one place.
Plugins and integrations
Extend RHDH with verified plugins that add new functionality without downtime. Dynamically integrate with supported tools such as Tekton for pipelines, GitOps for deployment automation, Nexus Repository for artifact storage, and JFrog Artifactory. RHDH also supports connecting to Red Hat OpenShift Container Platform, CI/CD systems, and security scanners through Red Hat-curated extensions.
Role-based access control (RBAC)
Manage user access with robust security permissions tailored to organizational needs.
Software catalog
Search, view, and manage services, APIs, and libraries from a central inventory. Track ownership, metadata, and component health in one place.
Software templates
Accelerate project setup by using preconfigured templates for CI/CD, runtime, and security. Standardize implementation while enabling developer autonomy.
Tech docs
Create, store, and view technical documentation alongside code. Make content searchable, consistently formatted, and accessible through the portal.
Scalability
Support growing teams and applications while maintaining access to the same tools and services.

1.2.3. System architecture for deployment strategy planning

1.2.3.1. System architecture for deployment strategy planning

Understanding Red Hat Developer Hub client-server architecture helps you plan deployments for horizontal scaling, high availability, and efficient data synchronization across the Software Catalog.

By understanding the RHDH architecture, you can perform the following planning tasks:

Plan scalable deployments
Deploy multiple backend instances behind a load balancer to manage increased load.
Ensure high availability
Configure database replication and cache clustering to eliminate single points of failure.
Optimize resource allocation
Assign infrastructure resources based on which components require persistent storage or high-performance memory.

The following diagram shows the RHDH internal architecture (frontend and backend) and its external dependencies, such as authentication providers, load balancers, and databases:

System architecture diagram for Red Hat Developer Hub

The RHDH architecture includes three primary layers. While the data layer (PostgreSQL and optional Redis cache) stores the indexed Software Catalog, the source of truth remains in external systems, such as Git repositories, CI/CD platforms, and other integrations. Catalog providers continuously scan these external systems and synchronize data to the database for fast querying.

1.2.3.1.1. Frontend (Client)

The frontend is a browser-based single-page application (SPA). Use the frontend interface to browse the Software Catalog, interact with plugins, and connect to external integrations. The frontend communicates with the backend exclusively using REST API calls.

1.2.3.1.2. Backend (Service Layer)

The backend provides REST API endpoints for the frontend. It manages the Software Catalog (an inventory of your organization’s software components, APIs, and resources) and handles authentication.

The stateless design allows you to scale the backend horizontally by running multiple instances behind a load balancer. The backend externalizes all persistent state to a PostgreSQL database, including:

  • Catalog entities
  • Task history
  • Session data (managed through a database-backed session store)
1.2.3.1.3. External data dependencies

RHDH requires PostgreSQL for persistence. For production environments, use a logical cache to improve performance.

PostgreSQL database
Stores indexed Software Catalog entities (synchronized from external systems such as Git repositories and CI/CD platforms), profiles, authentication data, and backend state. You must configure PostgreSQL with high availability (HA) for production deployments.
Redis Cache (Optional)
Configure Redis as a shared logical cache across backend instances to improve performance for frequently accessed data, such as rendered TechDocs and catalog entities.
Tip

The default in-memory cache is suitable only for single-instance deployments. You must use Redis for production deployments with multiple backend instances to ensure cache consistency.

1.2.3.2. System architecture for deployment planning

Understanding Red Hat Developer Hub client-server architecture helps you plan deployments for horizontal scaling, high availability, and efficient data synchronization across the Software Catalog.

By understanding the RHDH architecture, you can perform the following planning tasks:

Plan scalable deployments
Deploy multiple backend instances behind a load balancer to manage increased load.
Ensure high availability
Configure database replication and cache clustering to eliminate single points of failure.
Optimize resource allocation
Assign infrastructure resources based on which components require persistent storage or high-performance memory.

The following diagram shows the RHDH internal architecture (frontend and backend) and its external dependencies, such as authentication providers, load balancers, and databases:

System architecture diagram for Red Hat Developer Hub

The RHDH architecture includes three primary layers. While the data layer (PostgreSQL and optional Redis cache) stores the indexed Software Catalog, the source of truth remains in external systems, such as Git repositories, CI/CD platforms, and other integrations. Catalog providers continuously scan these external systems and synchronize data to the database for fast querying.

1.2.3.2.1. Frontend (Client)

The frontend is a browser-based single-page application (SPA). Use the frontend interface to browse the Software Catalog, interact with plugins, and connect to external integrations. The frontend communicates with the backend exclusively using REST API calls.

1.2.3.2.2. Backend (Service Layer)

The backend provides REST API endpoints for the frontend. It manages the Software Catalog (an inventory of your organization’s software components, APIs, and resources) and handles authentication.

The stateless design allows you to scale the backend horizontally by running multiple instances behind a load balancer. The backend externalizes all persistent state to a PostgreSQL database, including:

  • Catalog entities
  • Task history
  • Session data (managed through a database-backed session store)
1.2.3.2.3. External data dependencies

RHDH requires PostgreSQL for persistence. For production environments, use a logical cache to improve performance.

PostgreSQL database
Stores indexed Software Catalog entities (synchronized from external systems such as Git repositories and CI/CD platforms), profiles, authentication data, and backend state. You must configure PostgreSQL with high availability (HA) for production deployments.
Redis Cache (Optional)
Configure Redis as a shared logical cache across backend instances to improve performance for frequently accessed data, such as rendered TechDocs and catalog entities.
Tip

The default in-memory cache is suitable only for single-instance deployments. You must use Redis for production deployments with multiple backend instances to ensure cache consistency.

1.2.3.3. Deploy multiple stateless instances

Achieving high availability in Red Hat Developer Hub requires implementing redundancy and failover for both the backend service and its data dependencies. This is accomplished through horizontal scaling, database replication, and shared caching to ensure continuous operation during component failures.

1.2.3.3.1. Deploy multiple stateless instances

RHDH backend uses a stateless design to support horizontal scaling. PostgreSQL stores persistent data and the database manages sessions, allowing multiple backend instances to serve any request simultaneously. To improve performance, you can configure an optional logical cache by using Redis.

To maintain backend availability, observe the following architectural requirements:

Deploy multiple backend instances
Run at least two backend instances for basic HA.
Configure a load balancer
Use platform-provided load balancing, such as OpenShift Routes, Kubernetes Ingress, or cloud provider load balancers.
Enable health checks
Configure the load balancer to probe backend health and remove failed instances from rotation.
Disable session affinity (sticky sessions)
Database-backed sessions allow any instance to serve any request.
1.2.3.3.2. Implement database HA

RHDH operations rely on PostgreSQL for persistence. A database outage renders the deployment non-functional until the database is restored. For production deployments, you must configure PostgreSQL with high availability (primary-replica replication) to minimize downtime.

Important

If you use catalog providers exclusively, the database acts as an indexed cache. You do not require disaster recovery backups because you can repopulate catalog data from external sources of truth, such as Git repositories, CI/CD platforms, and monitoring tools.

1.2.3.3.3. Implement cache HA

Configuring Redis as a shared logical cache improves production performance by sharing cached data across multiple backend instances. A shared cache makes sure that all instances access the same processed data, such as rendered TechDocs.

If the logical cache fails, the platform remains functional, but you might experience the following symptoms:

  • Slower response times due to cache misses.
  • Increased database load because the backend must fetch data from PostgreSQL.
  • No impact on authentication or core functionality.

For maximum performance stability in production, configure Redis with high availability using Redis Sentinel for small deployments or Redis Cluster for larger deployments.

1.2.4. Developer Lightspeed AI virtual assistant capabilities

1.2.4.1. Developer Lightspeed AI virtual assistant capabilities

Understand the Red Hat Developer Lightspeed for Red Hat Developer Hub AI assistant architecture and system design to plan backend deployment and integration with Red Hat Developer Hub.

1.2.4.2. Chat assistance with Developer Lightspeed for RHDH

Use Developer Lightspeed for RHDH to find product information, discover features, and resolve technical questions using natural language prompts directly within the RHDH console.

Important

Developer Lightspeed for RHDH uses a FAB instead of a sidebar navigation item. If your environment uses another global FAB, you must move the existing button or disable it to prevent interface elements from overlapping. In your dynamic plugin configuration file, make the following update:

- package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
  disabled: true
  pluginConfig:
    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-bulk-import:
          mountPoints:
            - mountPoint: global.floatingactionbutton/config
              importName: BulkImportPage # Example
              config:
                slot: 'bottom-left'
                icon: BulkImportIcon
                label: 'Bulk import'
                toolTip: 'Register multiple repositories in bulk'
                to: /bulk-import
          translationResources:
          - importName: bulkImportTranslations
            module: Alpha
            ref: bulkImportTranslationRef
          appIcons:
          - name: bulkImportIcon
            importName: BulkImportIcon
          dynamicRoutes:
          - path: /bulk-import
            importName: BulkImportPage
            menuItem:
              icon: bulkImportIcon
              text: Bulk import
              textKey: menuItem.bulkImport
Lightspeed chatbot on the home page

1.2.4.3. AI response monitoring and context management

Developer Lightspeed for RHDH provides features to track the AI reasoning process and keep the context of your development tasks.

Thinking cards
An expandable thinking card is displayed while the AI processes a query. A pulse animation indicates the reasoning phase. You can expand the card to view detailed reasoning or collapse it to minimize screen clutter.
Tool call transparency
An expandable card displays details for Model Context Protocol (MCP) tool calls, which you can use to monitor background processes.
Context-aware citations
Retrieval-Augmented Generation (RAG) citations appear only when the AI uses internal documentation. This makes sure that general knowledge responses remain concise.
Context preservation during model changes
When you select a different AI model, Developer Lightspeed for RHDH starts a new conversation. This keeps your earlier chats available in your history.
Structural readability
The interface formats headings and bullet points automatically to make sure responses are scannable.

1.2.4.4. AI reference and tool-calling capabilities through Lightspeed Core Service

Review the core components managed by the Lightspeed Core Service(LCORE) sidecar container to plan integrations with large language models (LLM) and tool runtime providers.

The LCORE container deploys as a sidecar to extend RHDH functionality. The container integrates and manages the following core architectural components:

  • Large language model (LLM) inference providers
  • Model Context Protocol (MCP) or Retrieval Augmented Generation (RAG) tool runtime providers

    Important

    Verify that your model supports tool calling before you enable MCP features. Using an incompatible model results in error messages.

  • Safety providers
  • Vector database settings

LCORE also manages critical operational configuration and key data, specifically:

  • User feedback collection
  • MCP server configuration
  • Chat history

Developer Lightspeed for RHDH sends prompts and receives LLM responses through the LCORE sidecar.

1.2.4.5. Red Hat Developer Lightspeed for Red Hat Developer Hub architecture for your AI backend deployment

Review the Developer Lightspeed for RHDH component architecture to plan your system layout and coordinate connections with your artificial intelligence (AI) backend deployment.

The architecture relies on the Lightspeed Core Service (LCORE) container, which operates as the primary intermediary layer to manage Developer Lightspeed for RHDH functionality and console user interactions. By default, the interface appears as a floating action button (FAB) on all platforms that host RHDH.

1.2.4.6. Configure safety guards in Red Hat Developer Hub

To protect users from insecure or harmful AI model outputs, Red Hat Developer Hub (RHDH) uses Llama Guard as a default safety shield. You must configure these guards to align with your organization’s security policies.

Default safety guard configuration
The system uses Llama Guard as the default safety shield. Override these settings in the run.yaml file.
Note

The external_providers_dir parameter defaults to null and is no longer required in your configuration.

Overriding safety guards
To implement custom security layers or different safety shields, you must define a new safety provider within a custom run.yaml file.
Disabling safety guards
To run RHDH without safety guards, you must use the run-no-guard.yaml configuration file.
Important

Running without safety guards increases the risk of invalid model output. Only use this configuration in secure development environments.

Applying the no-guard configuration
To run the system without a safety guard, perform these steps:

Procedure

  1. Add the following YAML file as a config map to your namespace:

    version: 2
    image_name: redhat-ai-dev-llama-stack-no-guard
    apis:
      - agents
      - inference
      - safety
      - tool_runtime
      - vector_io
      - files
    container_image:
    external_providers_dir:
    providers:
      agents:
        - config:
            persistence:
              agent_state:
                namespace: agents
                backend: kv_default
              responses:
                table_name: responses
                backend: sql_default
          provider_id: meta-reference
          provider_type: inline::meta-reference
      inference:
        - provider_id: ${env.ENABLE_VLLM:+vllm}
          provider_type: remote::vllm
          config:
            url: ${env.VLLM_URL:=}
            api_token: ${env.VLLM_API_KEY:=}
            max_tokens: ${env.VLLM_MAX_TOKENS:=4096}
            tls_verify: ${env.VLLM_TLS_VERIFY:=true}
        - provider_id: ${env.ENABLE_OLLAMA:+ollama}
          provider_type: remote::ollama
          config:
            url: ${env.OLLAMA_URL:=http://localhost:11434}
        - provider_id: ${env.ENABLE_OPENAI:+openai}
          provider_type: remote::openai
          config:
            api_key: ${env.OPENAI_API_KEY:=}
        - provider_id: ${env.ENABLE_VERTEX_AI:+vertexai}
          provider_type: remote::vertexai
          config:
            project: ${env.VERTEX_AI_PROJECT:=}
            location: ${env.VERTEX_AI_LOCATION:=us-central1}
        - provider_id: sentence-transformers
          provider_type: inline::sentence-transformers
          config: {}
      tool_runtime:
        - provider_id: model-context-protocol
          provider_type: remote::model-context-protocol
          config: {}
        - provider_id: rag-runtime
          provider_type: inline::rag-runtime
          config: {}
      vector_io:
        - provider_id: faiss
          provider_type: inline::faiss
          config:
            persistence:
              namespace: vector_io::faiss
              backend: faiss_kv
      files:
        - provider_id: localfs
          provider_type: inline::localfs
          config:
            storage_dir: /tmp/llama-stack-files
            metadata_store:
              table_name: files_metadata
              backend: sql_files
    storage:
      backends:
        kv_default:
          type: kv_sqlite
          db_path: /tmp/kvstore.db
        sql_default:
          type: sql_sqlite
          db_path: /tmp/sql_store.db
        sql_files:
          type: sql_sqlite
          db_path: /rag-content/vector_db/rhdh_product_docs/1.9/files_metadata.db
        faiss_kv:
          type: kv_sqlite
          db_path: /rag-content/vector_db/rhdh_product_docs/1.9/faiss_store.db
      stores:
        metadata:
          namespace: registry
          backend: faiss_kv
        inference:
          table_name: inference_store
          backend: sql_default
          max_write_queue_size: 10000
          num_writers: 4
        conversations:
          table_name: openai_conversations
          backend: sql_default
    registered_resources:
      models:
        - model_id: sentence-transformers/all-mpnet-base-v2
          metadata:
            embedding_dimension: 768
          model_type: embedding
          provider_id: sentence-transformers
          provider_model_id: /rag-content/embeddings_model
      tool_groups:
        - provider_id: rag-runtime
          toolgroup_id: builtin::rag
      vector_dbs:
        - vector_db_id: rhdh-product-docs-1_8
          embedding_model: sentence-transformers/all-mpnet-base-v2
          embedding_dimension: 768
          provider_id: faiss
    server:
      auth:
      host:
      port: 8321
      quota:
      tls_cafile:
      tls_certfile:
      tls_keyfile:
  2. Mount the config map to your Llama Stack container at /app-root/run.yaml to make sure it overrides the default image file:

    name: llama-stack
    volumeMounts:
    - mountPath: /app-root/run.yaml
      subPath: run.yaml
      name: llama-stack-config
  3. Configure the required volume:

    volumes:
    - name: llama-stack-config
      configMap:
        name: llama-stack-config

    where:

    llama-stack-config
    The config map where you added the new no-guard configuration file.
  4. Restart the deployment if it does not trigger an automatic rollout.

1.2.4.7. Manage chats

Manage your chat history and configuration in RHDH to organize your workspace, resume earlier tasks, or find past solutions.

Chat menu options

Prerequisites

  • You have configured the Developer Lightspeed for RHDH plugin in Red Hat Developer Hub.
  • You have logged in to the portal.

Procedure

  1. Click the Open Lightspeed floating action button (FAB) at the lower right of the screen to open the chat overlay.
  2. Optional: Configure the interface display and server settings:

    • Click the Chatbot options icon (⋮) to view chat history or start a new chat.
    • Click the Display mode icon and select any of the following views:

      Chat display options
      • Overlay: A floating window is displayed over the current page content.

        Lightspeed overlay mode
      • Dock to window: A panel attaches to the right side of the screen. Activating this mode automatically closes the quick start panel if it is already open.

        Lightspeed docked mode
      • Fullscreen: A dedicated page opens for intensive chat sessions. This mode displays a revised header containing the Lightspeed logo and a horizontal tab bar, which replaces the previous main menu. Bookmark the URL in your browser to save a direct link to the chat interface.

        Lightspeed full-screen mode
      • Optional: Toggle Enable pinned chats/Disable pinned chats to enable or hide the pinned chats. The system enables this option by default.
      • Available only if MCP is configured: Manage Model Context Protocol connections.

        Lightspeed chat mcp mode
  3. Start a chat or load an earlier session:

    • Enter a prompt: Type a query in the Enter a prompt for Lightspeed chat field and press Enter.
    • Use a sample: Click a prompt tile.
    • Change the AI model: Select a model from the model selector dropdown menu inside the prompt bar.

      Lightspeed chat AI model
    • Attach a file: Click the (+) icon on the left of the prompt bar to upload a .yaml, .json, or .txt file. Descriptive text clarifies the function of the icon.

      1. Click the file name to open the preview model.
      2. View or edit the content of the file:

        Lightspeed file attachment preview
    • Use voice: Click the Use microphone icon. The microphone and send buttons are located on the right side of the prompt bar.
    • Control AI generation: Use the control buttons on the right side of the prompt bar. Click the start/send (>) button to submit queries, or click the stop ([]) button to halt AI generation.

      Lightspeed file attachment preview
    • Resume a chat: Select a title from the Recent list.
  4. Organize your chat history:

    • Start a new topic: Click New chat to reset the assistant’s context. When the history panel is collapsed, you must click the Edit square icon to create a new chat.

      Lightspeed new chat
    • Search history: Enter a keyword in the Search field.
    • Rename a session: Click Options next to a chat title, select Rename, and enter a new name.

      Rename chat option
    • Pin a chat: Click Options next to a chat title and select Pin. The chat moves to the Pinned group.
    • Sort chats: Click Sort control and choose a sorting criteria, such as Date (Newest first).

      Chat sorting options
    • Delete a chat: Click Options next to a chat title and select Delete.

      Delete chat option
    • Expand or collapse the panel: Click the Expand/collapse icon to toggle the history panel.

      Collapse chat option
      Note

      The expanded panel is resizable up to a defined maximum width.

  5. Optional: To hide the interface, if you are in the Overlay or Dock to window mode, click the Close Lightspeed icon (X) to hide the window. If you are in Fullscreen mode, revert to the other modes and click the Close Lightspeed icon (X). The system preserves your active query and history.
  6. Optional: In Fullscreen mode, bookmark the URL in your browser to save a direct link to the chat interface.

Verification

  1. The main window displays the active chat or selected history.
  2. The chat history list reflects renamed, pinned, or deleted entries.

1.2.4.8. Best results for assistant queries

To resolve technical blockers and accelerate development tasks, you must structure your queries to give specific context to the AI assistant. Using precise prompts makes sure that Developer Lightspeed for RHDH generates relevant code snippets, architectural advice, or platform-specific instructions.

Use the following strategies to improve the accuracy of the assistant’s output during your development workflow:

Specify technologies
Instead of asking "How do I use templates?", ask "How do I create a Software Template that scaffolds a Node.js service with a CI/CD pipeline".
Give context
Include details about your environment, such as "I am deploying to OpenShift; how do I set up my catalog-info.yaml to show pod health?".
Use conversation context
Ask follow-up questions to refine an earlier answer. For example, if the assistant gives a code snippet, you can ask "Now rewrite that using TypeScript interfaces."
Validate with citations
Check the provided documentation links and citations in the response to verify that the generated advice aligns with your organization’s official standards.
Improve assistant accuracy
Rate the utility of responses by selecting the Thumbs up or Thumbs down icons. This feedback helps tune the model for your organization’s specific requirements.
Important

To keep your data secure, do not include sensitive personal information, plain text credentials, or confidential business data in your queries.

1.2.5. AI model evaluation data to select the right AI model

1.2.5.1. AI model evaluation data to select the right AI model

Use the Red Hat Developer Lightspeed for Red Hat Developer Hub evaluation framework to validate the performance, accuracy, and reliability of Developer Lightspeed for RHDH.

With this automated toolset, you can measure how effectively various large language models (LLMs) answer questions based on Red Hat Developer Hub documentation.

Table 1.1. Components of the evaluation framework

ComponentDescription

Evaluation framework

Contains the core logic and scripts used to run evaluations.

Datasets

Includes the input files used to test the model.

Evaluation metrics integration

Provides scoring through various metrics, including Ragas, DeepEval, and custom metrics. Ragas is the primary metric used to validate Developer Lightspeed for RHDH performance.

1.2.5.2. Configure the evaluation environment to validate model accuracy

Set up the evaluation environment to validate the performance and accuracy of Developer Lightspeed for RHDH. Configure this evaluation to ensure the model correctly interprets documentation and provides dependable answers.

Important

Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

By performing these evaluations, you minimize the risk of the model delivering incorrect or hallucinated information to users in production.

Prerequisites

  • Install uv for Python package management (Python 3.11 or later).

Procedure

  1. Clone the evaluation repository and navigate to the directory:

    git clone https://github.com/lightspeed-core/lightspeed-evaluation
    cd lightspeed-evaluation
  2. Synchronize the environment and install dependencies:

    uv sync
  3. Configure the environment variables for the judge LLM. You can create a .env file in the root directory or export the keys directly to your terminal.

    • If you use Gemini, you must set the Gemini API key:

      export GEMINI_API_KEY="your-google-api-key"
    • If you use OpenAI, you must set the OpenAI API key:

      export OPENAI_API_KEY="your-key"
  4. Optional: If you test with a live service, set your Developer Lightspeed for RHDH service API key:

    export API_KEY="your-lightspeed-service-key"

Verification

  • Verify that the environment is synchronized and the virtual environment is active:

    uv run python --version

    The output must return Python 3.11 or later.

1.2.5.3. Prepare evaluation datasets to verify AI-generated responses

Prepare evaluation data sets to test the performance of Developer Lightspeed for RHDH. You can use pre-generated AI data sets for specific Red Hat Developer Hub releases or generate custom AI data sets from your own documentation.

Prerequisites

  • You must clone the evaluation repository to your local machine.

Procedure

  1. Download pre-generated data sets: Use this method to test the performance of specific RHDH releases. These data sets are generated using Ragas testset generation for RAG.

    1. In your terminal, navigate to the /dataset folder in the evaluation repository.
    2. Locate the .evaluation_dataset_yaml files. These files are pre-configured for the evaluation tool.
    3. To test a historical release, switch to the corresponding branch.

      For example, to access the Red Hat Developer Hub 1.8 data set, switch to the 1.8 branch.

      Important

      The main branch contains work-in-progress (WIP) data sets. Avoid using this branch for stable evaluations.

  2. Generate custom data sets: Use this method to create a new test set from your own technical documentation.

    1. Generate a diverse set of question-and-answer (Q&A) pairs by following the Ragas test data generation documentation.
    2. Ensure your Q&A pairs match the required format by reviewing the evaluation data structure configuration.

Verification

  • Verify that your custom data set matches the required schema before you start the evaluation run.

1.2.5.4. Run performance tests to ensure AI response reliability

Use the evaluation framework to run performance tests in either static mode to evaluate pre-recorded responses or dynamic mode to call a live service.

These evaluations identify performance gaps, allow you to compare different large language models (LLMs), and ensure that Developer Lightspeed for RHDH provides reliable information to users.

Prerequisites

Procedure

  1. Download the system.yaml configuration template from the repository.
  2. Configure the parameters in the system.yaml file based on your evaluation mode:

    FieldDescription

    llm

    Defines the judge LLM that scores the responses, such as gemini-2.5-pro.

    api.enabled

    Set to false for static mode to use pre-filled data. Set to true for dynamic mode to call a live service.

    api.api_base

    (Required for dynamic mode only) Provide the URL of your Developer Lightspeed for RHDH service.

    api.endpoint_type

    Specify the service configuration type: streaming or query.

  3. Execute the evaluation by using the lightspeed-eval command:

    lightspeed-eval \
      --system-config config/system.yaml \
      --eval-data config/evaluation_data.yaml \
      --output-dir ./my_evaluation_results

Verification

  • Navigate to the specified output directory and verify that the generated reports contain the model performance scores.

1.2.5.5. Analyze evaluation results to identify performance gaps

Determine the performance of Developer Lightspeed for RHDH and identify documentation areas that require model improvement by analyzing evaluation results in the repository. You can use these reports to compare performance across different large language models (LLMs) and topics.

Prerequisites

Procedure

  1. In the root of the repository, navigate to the version-specific folder within the /evaluation-result directory.
  2. Open the following files to evaluate performance:

    • Model Pass Rate: Compare the overall performance between different LLMs.
    • Topic Pass Rate: Identify performance trends and gaps within specific documentation areas.

Verification

  • Verify that the reports display data visualizations or metrics consistent with your recent evaluation run.

1.2.5.6. Evaluation metrics and historical data reference

Use the available metrics to evaluate the performance of Developer Lightspeed for RHDH at the conversation turn level.

These metrics provide a standardized way to measure the accuracy and reliability of the generated responses and the retrieved content.

MetricDescription

Faithfulness

Measures how well the answer is derived solely from the retrieved context.

Context recall

Measures whether the retrieved context contains all information required to answer the question.

Context relevance

Verifies if the retrieved documentation chunks are relevant to the user query.

Context precision without reference

Measures the ratio of useful information within the retrieved documentation chunks.

Answer correctness

Compares the generated response against the expected ground-truth response. This custom metric is implemented in the evaluation tool.

1.2.5.7. Release report and historical data

Use the latest Q&A data set and evaluation results to monitor the current performance of Developer Lightspeed for RHDH.

Access version-specific branches that contain the data sets and evaluation results required to track improvements or regressions across product releases.

Important

The main branch contains work-in-progress data for versions currently under development. For stable evaluations or historical tracking, you must switch to the branch associated with a specific release.

Release versionBranch nameData included

Latest stable

Most recent version branch

The current question and answer (Q&A) data set and evaluation results.

Historical

Previous version branches

Data sets and evaluation results for previous releases to track regressions.

1.2.6. Build a private knowledge base with Developer Lightspeed for RHDH Notebooks

1.2.6.1. Build a private knowledge base with Developer Lightspeed for RHDH Notebooks

Use Developer Lightspeed for RHDH notebooks to create isolated research environments. These workspaces allow you to analyze project data securely by using a large language model (LLM) grounded in your specific documentation.

Important

Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

1.2.6.2. Create isolated research workspaces

Organize your work into individual notebook sessions to keep research topics separate and private.

Notebook upload option

Procedure

  1. In the RHDH interface, click the Open Lightspeed floating action button (FAB).
  2. In your Developer Lightspeed for RHDH page, select the Notebooks tab.
  3. Click Create a new notebook to start a new workspace.
  4. Optional: To manage your workspaces, click the More options icon on a notebook card to Rename, Delete, or add Tags to the session.

    Notebook rename option
    Notebook delete option
    Notebook tabs option

Verification

  • Confirm the new notebook card appears on the My Notebooks dashboard.

1.2.6.3. Provide project context to the AI

To receive answers tailored to your project, upload and manage relevant source material in your active session.

Procedure

  1. Open a Notebook card from the dashboard.
  2. Add resources by using one of the following methods:

    • In the sidebar, click the Add (+) icon.
    • In the main user interface, click Upload a resource.

      Notebook upload option
  3. Select and upload your local files. Supported formats include .txt, .md, .pdf, .docx, .log, .yaml, and .json.
  4. Adhere to the following constraints:

    File size
    Individual files or URL content must be 20MB or smaller.
    Notebook Capacity
    The total token count per session must not exceed 100k.
    Unsupported content
    Avoid scanned PDF images without text, audio, video, and general image files.
    Persistence requirement
    The internal SQL and KV stores must be mapped to a persistent backend to maintain the 100k token context across sessions.
  5. Wait for the system to process and vectorize the files. This might take several seconds for larger PDFs.

Verification

  • Ensure the uploaded files appear in the Resources list in the sidebar with a Processed status.

1.2.6.4. Extract and verify document-based insights

After providing context, use the AI to perform reasoning across your files and verify the accuracy of the responses.

Lightspeed Notebook chat preview

Prerequisites

  • You have uploaded documents or URLs to the active chat session to establish context.

    Note

    If no documents are uploaded, you cannot communicate with the AI.

    Procedure

    1. Enter a question in the prompt bar at the bottom of the screen.
    2. Analyze the response. The AI identifies relationships across all uploaded documents and URLs in the session.
    3. To verify accuracy, click the Sources chip to view the specific document excerpts used to generate the answer.
    4. Manage your workflow by using the history panel in the sidebar to expand or collapse previous interactions.

Verification

  • Confirm that the Sources panel displays the correct filenames and text snippets corresponding to the AI’s response.

1.2.7. Platform integrations for toolchain connectivity

1.2.7.1. Platform integrations for toolchain connectivity

Red Hat Developer Hub integrates seamlessly with Red Hat OpenShift Container Platform and other tools, enabling comprehensive development and deployment workflows across enterprise.

1.2.7.1.1. Integration with Red Hat OpenShift Container Platform

Red Hat Developer Hub is fully integrated with Red Hat OpenShift Container Platform, offering:

  • Operators to manage application lifecycle.
  • Access to advanced OpenShift capabilities such as service mesh, serverless functions, GitOps, and distributed tracing.
  • Pipelines and GitOps plugins for streamlined cloud-native workflows.
1.2.7.1.2. Integration with Red Hat Advanced Developer Suite - secure supply chain

Red Hat Advanced Developer Suite - secure supply chain (RHADS - ssc) enhances Red Hat Developer Hub by providing secure CI/CD capabilities that integrate security measures into every stage of the development process.

While Red Hat Developer Hub focuses on the inner loop (code, build, and test), RHADS - ssc manages the outer loop, automating:

  • Code scanning
  • Image building
  • Vulnerability detection
  • Deployment

RHADS - ssc includes tools such as Red Hat Trusted Artifact Signer (TAS) for code integrity, Red Hat Trusted Profile Analyzer (TPA) for automated Software build of Materials (SBOM) creation, and Red Hat Advanced Cluster Security (ACS) for vulnerability scanning.

1.2.7.1.3. Extending Backstage with Red Hat Developer Hub

Red Hat Developer Hub which is a fully supported, enterprise-grade productized version of upstream Backstage extends the upstream project by adding:

  • Enhanced search capabilities that aggregate data from CI/CD pipelines, cloud providers, source control, and more.
  • A centralized software catalog for locating applications, APIs, and resources.
  • Automation through open-source plugins that expand the Backstage core functionality.
  • Simplified technical documentation using Markdown and GitHub, with integrated search for easy navigation.

1.2.7.2. Integrations in Red Hat Developer Hub

Red Hat Developer Hub integrates seamlessly with Red Hat OpenShift Container Platform and other tools, enabling comprehensive development and deployment workflows across enterprise.

1.2.7.2.1. Integration with Red Hat OpenShift Container Platform

Red Hat Developer Hub is fully integrated with Red Hat OpenShift Container Platform, offering:

  • Operators to manage application lifecycle.
  • Access to advanced OpenShift capabilities such as service mesh, serverless functions, GitOps, and distributed tracing.
  • Pipelines and GitOps plugins for streamlined cloud-native workflows.
1.2.7.2.2. Integration with Red Hat Advanced Developer Suite - secure supply chain

Red Hat Advanced Developer Suite - secure supply chain (RHADS - ssc) enhances Red Hat Developer Hub by providing secure CI/CD capabilities that integrate security measures into every stage of the development process.

While Red Hat Developer Hub focuses on the inner loop (code, build, and test), RHADS - ssc manages the outer loop, automating:

  • Code scanning
  • Image building
  • Vulnerability detection
  • Deployment

RHADS - ssc includes tools such as Red Hat Trusted Artifact Signer (TAS) for code integrity, Red Hat Trusted Profile Analyzer (TPA) for automated Software build of Materials (SBOM) creation, and Red Hat Advanced Cluster Security (ACS) for vulnerability scanning.

1.2.7.2.3. Extending Backstage with Red Hat Developer Hub

Red Hat Developer Hub which is a fully supported, enterprise-grade productized version of upstream Backstage extends the upstream project by adding:

  • Enhanced search capabilities that aggregate data from CI/CD pipelines, cloud providers, source control, and more.
  • A centralized software catalog for locating applications, APIs, and resources.
  • Automation through open-source plugins that expand the Backstage core functionality.
  • Simplified technical documentation using Markdown and GitHub, with integrated search for easy navigation.

1.2.8. Supported platforms

Verify platform compatibility and life cycle support for Red Hat Developer Hub versions to plan deployments and ensure continued product support.

Additional resources

1.2.9. Red Hat Developer Hub support

The Red Hat Customer Portal provides resources to help you troubleshoot issues and get support for Red Hat Developer Hub. You can use the Red Hat Customer Portal for the following purposes:

  • To search or browse through the Red Hat Knowledgebase of technical support articles about Red Hat products.
  • To create a support case for Red Hat Global Support Services (GSS), select Red Hat Developer Hub as the product and select the appropriate product version.

1.2.9.1. Collect diagnostic data for support cases

When opening a support case for RHDH deployment, configuration, or runtime issues, providing comprehensive diagnostic data accelerates troubleshooting and reduces time to resolution.

The RHDH must-gather tool collects diagnostic data from RHDH deployments in a single operation.

This tool gathers platform information, deployment configurations, application logs, routes or ingress configurations, and namespace state in a standardized format optimized for support analysis.

The RHDH must-gather tool is available on Red Hat OpenShift Container Platform (OpenShift Container Platform) 4.18 and later using the oc adm must-gather command, and on Kubernetes platforms including Microsoft Azure Kubernetes Service, Amazon Elastic Kubernetes Service, and Google Kubernetes Engine using a Helm chart deployment.

To collect and attach diagnostic data to your support case, see Collect diagnostic data to streamline support resolution.

Chapter 2. Get started

2.1. Get Started

Set up your first Red Hat Developer Hub instance, configure authentication, and navigate the platform interface to start using developer portal capabilities.

2.2. Set up the first RHDH instance

2.2.1. Set up the first RHDH instance

Install the operator, prepare external services, provision custom configuration, enable authentication, and start your instance for production workloads.

2.2.2. Checklist to run your first Red Hat Developer Hub (RHDH) instance in production

With the default configuration, Developer Hub runs with a minimal feature set that does not require secure connection to external services such as an identity provider, a Git provider, and external PostgreSQL and Redis databases.

Using critical features requires the following additional configuration:

For resiliency
  • Use an external PostgreSQL database.
  • Enable high-availability.
For performance
  • Enable assets caching to an external Redis database.
For security
  • Use secure connections to your external services.
  • Provision users and enable authentication.
  • Enable role-based access control, and configure the permission policy by using the Web UI.
For adapting to your environment
  • Enable GitHub repository discovery.
  • Customize Developer Hub appearance with your logo.

2.2.3. Install the Operator

As an administrator, you can install the Red Hat Developer Hub Operator. Authorized users can use the Operator to install Red Hat Developer Hub on Red Hat OpenShift Container Platform (OpenShift Container Platform) and supported Kubernetes platforms.

For more information about supported platforms and versions, see the Red Hat Developer Hub Life Cycle page.

Containers are available for the following CPU architectures:

  • AMD64 and Intel 64 (x86_64)

Prerequisites

Important

You can upgrade Red Hat Developer Hub directly from any earlier version to the latest release without installing intermediate versions. However, you must review the release notes for every skipped version to identify breaking changes or required migration steps. For example, if upgrading from version 1.5 to 1.7, check the release notes for both 1.6 and 1.7.

Procedure

  1. In the OpenShift Container Platform web console, find and install the Red Hat Developer Hub Operator from the software catalog.

    For the detailed console steps, see Installing from the software catalog by using the web console in the Red Hat OpenShift Container Platform documentation.

  2. On the Install Operator page, configure the following options:

    1. From the Update channel drop-down menu, select fast or fast-1.10.

      Important

      The fast channel includes all of the updates available for a particular version. Any update might introduce unexpected changes in your Red Hat Developer Hub deployment. Check the release notes for details about any potentially breaking changes.

      The fast-1.10 channel only provides z-stream updates, for example, updating from version 1.10.1 to 1.10.2. If you want to update the Red Hat Developer Hub y-version in the future, for example, updating from 1.10 to 2.1, you must switch to the fast-2.1 channel manually.

    2. From the Version drop-down menu, select the version of the Red Hat Developer Hub Operator that you want to install.
    3. For Installation mode, keep the default All namespaces on the cluster option.

      Note

      The Specific namespace on the cluster option is not currently supported.

    4. For Installed Namespace, select Operator recommended Namespace to use the default rhdh-operator namespace.

      Important

      For enhanced security, better control over the Operator lifecycle, and preventing potential privilege escalation, install the Red Hat Developer Hub Operator in a dedicated default rhdh-operator namespace. You can restrict other users' access to the Operator resources through role bindings or cluster role bindings.

      You can also install the Operator in another namespace by creating the necessary resources, such as an Operator group. For more information, see Installing global Operators in custom namespaces.

      However, if the Red Hat Developer Hub Operator shares a namespace with other Operators, then it shares the same update policy as well, preventing the customization of the update policy. For example, if one Operator is set to manual updates, the Red Hat Developer Hub Operator update policy is also set to manual. For more information, see Colocation of Operators in a namespace.

    5. Select the Update approval method and click Install.

Verification

  • Navigate to Ecosystem > Installed Operators and verify that the Red Hat Developer Hub Operator status is Succeeded.

2.2.4. Prepare your external services

Red Hat Developer Hub relies on external services for production use, including a PostgreSQL database, Redis cache, GitHub API access, and an identity provider.

PostgreSQL database
Developer Hub stores data in a PostgreSQL database. Use an external database for resiliency and include it in your disaster recovery plan.
Redis cache
For efficiency, Developer Hub caches plugin and TechDocs assets when you provide a Redis cache server.
GitHub API access
Provide credentials to a GitHub app to enable access to the GitHub API for repository discovery.
Connection to your identity provider
Provide credentials to your identity provider to enable user provisioning and authentication.

Procedure

  1. Get your external PostgreSQL database connection strings and certificates.

    postgres-host
    Your PostgreSQL instance Domain Name System (DNS) or IP address.
    postgres-port
    Your PostgreSQL instance port number, such as 5432.
    postres-username
    The user name to connect to your PostgreSQL instance.
    postgres-password
    The password to connect to your PostgreSQL instance.
    postgres-ca.pem, postgres-key.key, postgres-crt.pem
    For security, use TLS certificates to secure the connection to the database.
  2. Get your Redis cache server connection string, such as rediss://user:pass@cache.example.com:6379. For security, consider using a rediss secure server connection.
  3. Create a GitHub App to allow Developer Hub to access the GitHub API for repository. Opt for a GitHub App instead of an OAuth app to use fine-grained permissions, gain more control over which repositories the application can access, and use short-lived tokens.

    1. Register a GitHub App with the following configuration:

      GitHub App name
      Enter a unique name identifying your GitHub App, such as integrating-with-rhdh-<GUID>.
      Homepage URL
      Enter your Developer Hub URL: https://<my_developer_hub_domain>.
      Authorization callback URL
      Enter your Developer Hub authentication backend URL: https://<my_developer_hub_domain>/api/auth/github/handler/frame.
      Webhook
      Clear "Active", as this is not needed for authentication and catalog providers.
      App permissions

      Select permissions to define the level of access for the app. Adapt permissions to your needs:

      Reading software components
      Contents
      Read-only
      Commit statuses
      Read-only
      Reading organization data
      Members
      Read-only
      Publishing software templates

      Set permissions if you intend to use the same GitHub App for software templates.

      Administration
      Read & write (for creating repositories)
      Contents
      Read & write
      Metadata
      Read-only
      Pull requests
      Read & write
      Issues
      Read & write
      Workflows
      Read & write (if templates include GitHub workflows)
      Variables
      Read & write (if templates include GitHub Action Repository Variables)
      Secrets
      Read & write (if templates include GitHub Action Repository Secrets)
      Environments
      Read & write (if templates include GitHub Environments)
      Organization permissions
      Members
      Read-only
      Where can this GitHub App be installed?
      Select Only on this account.
    2. In the GeneralClients secrets section, click Generate a new client secret.
    3. In the GeneralPrivate keys section, click Generate a private key.
    4. In the Install App tab, choose an account to install your GitHub App on.
    5. Save the following values for the next step:
  4. App ID
  5. Client ID
  6. Client secret
  7. Private key

2.2.5. Provision your custom configuration

Provision custom config maps and secrets on Red Hat OpenShift Container Platform (RHOCP) to configure Red Hat Developer Hub before running the application.

Tip

On Red Hat OpenShift Container Platform, you can skip this step to run Developer Hub with the default config map and secret. Your changes on this configuration might get reverted on Developer Hub restart.

Prerequisites

  • By using the OpenShift CLI (oc), you have access, with developer permissions, to the OpenShift cluster aimed at containing your Developer Hub instance.

Procedure

  1. For security, store your secrets as environment variables values in an OpenShift Container Platform secret, rather than in plain text in your configuration files. Collect all your secrets in the secrets.txt file, with one secret per line in KEY=value form.

    Enter your authentication secrets.

  2. Author your custom app-config.yaml file. This is the main Developer Hub configuration file. You need a custom app-config.yaml file to avoid the Developer Hub installer to revert user edits during upgrades. When your custom app-config.yaml file is empty, Developer Hub is using default values.

    • To prepare a deployment with the Red Hat Developer Hub Operator on OpenShift Container Platform, you can start with an empty file.
    • To prepare a deployment with the Red Hat Developer Hub Helm chart, or on Kubernetes, enter the Developer Hub base URL in the relevant fields in your app-config.yaml file to ensure proper functionality of Developer Hub. The base URL is what a Developer Hub user sees in their browser when accessing Developer Hub. The relevant fields are baseUrl in the app and backend sections, and origin in the backend.cors subsection:

      Configuring the baseUrl in app-config.yaml:

      app:
        title: Red Hat Developer Hub
        baseUrl: https://<my_developer_hub_domain>
      
      backend:
        auth:
          externalAccess:
            - type: legacy
              options:
                subject: legacy-default-config
                secret: "${BACKEND_SECRET}"
        baseUrl: https://<my_developer_hub_domain>
        cors:
          origin: https://<my_developer_hub_domain>
    • Optionally, enter your configuration such as:

  3. Author your custom dynamic-plugins.yaml file to enable plugins. By default, Developer Hub enables a minimal plugin set, and disables plugins that require configuration or secrets, such as the GitHub repository discovery plugin and the Role-based access control (RBAC) plugin.

    Enable the GitHub repository discovery and the RBAC features:

    dynamic.plugins.yaml

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github
        disabled: false
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

  4. Provision your custom configuration files to your OpenShift Container Platform cluster.

    1. Create the <my-rhdh-project> project aimed at containing your Developer Hub instance.

      $ oc create namespace my-rhdh-project
    2. Create config maps for your app-config.yaml and dynamic-plugins.yaml files in the <my-rhdh-project> project.

      $ oc create configmap my-rhdh-app-config --from-file=app-config.yaml --namespace=my-rhdh-project
      $ oc create configmap dynamic-plugins-rhdh --from-file=dynamic-plugins.yaml --namespace=my-rhdh-project

      You can also create the config maps by using the web console.

    3. Provision your secrets.txt file to the my-rhdh-secrets secret in the <my-rhdh-project> project.

      $ oc create secret generic my-rhdh-secrets --from-file=secrets.txt --namespace=my-rhdh-project

      You can also create the secret by using the web console.

2.2.6. Enable initial authentication to verify user access

2.2.6.1. Enable initial authentication to verify user access

Configure authentication methods, set up guest access for testing, and integrate your identity provider to verify user access.

2.2.6.2. Authentication methods and identity provider selection

2.2.6.2.1. Authentication methods and identity provider selection

Review available authentication methods and identity provider options to select the appropriate approach for your organization.

2.2.6.3. Configure guest access to safely test early deployments

2.2.6.3.1. Configure guest access to safely test early deployments

Enable guest access to test role and policy creation without configuring an authentication provider.

Use guest access with the role-based access control (RBAC) front-end plugin to allow a user to test role and policy creation without the need to set up and configure an authentication provider.

Note

Guest access is not recommended for production.

2.2.6.4. Integrate your chosen identity provider

2.2.6.4.1. Integrate your chosen identity provider

Enable authentication with your main identity provider to allow users to sign in to Red Hat Developer Hub using their organizational credentials.

2.2.7. Use the Red Hat Developer Hub Operator to run Developer Hub with your custom configuration

Use the Developer Hub Operator to run Red Hat Developer Hub with your custom configuration by creating a Backstage custom resource (CR).

The custom resource can mount files from your custom config maps and inject environment variables from your custom secrets.

Prerequisites

Procedure

  1. Author your Backstage CR in a my-rhdh-custom-resource.yaml file to use your custom config maps and secrets.

    my-rhdh-custom-resource.yaml custom resource example with dynamic plugins and RBAC policies config maps, and external PostgreSQL database secrets.

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <my-rhdh-custom-resource>
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
        extraEnvs:
          envs:
            - name: HTTP_PROXY
              value: 'http://10.10.10.105:3128'
            - name: HTTPS_PROXY
              value: 'http://10.10.10.106:3128'
            - name: NO_PROXY
              value: 'localhost,example.org'
          secrets:
             - name: my-rhdh-secrets
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
        replicas: 2
      database:
        enableLocalDb: false

    application
    appConfig
    Register your my-rhdh-app-config and rbac-policies config maps.
    dynamicPluginsConfigMapName
    Register your dynamic-plugins-rhdh config map.
    extraEnvs
    env
    Enter your proxy environment variables.
    secrets
    Register your <my_product_secrets> and my-rhdh-database-secrets secrets.
    extraFiles
    secrets
    Register the postgres-crt.pem, postgres-ca.pem, and postgres-key.key files contained in the my-rhdh-database-certificates-secrets secret.
    replicas
    Enable high availability (HA) by increasing the replicas count to a value higher or equal to 2.
    database
    enableLocalDb
    Use your external PostgreSQL database rather than the internal PostgreSQL database.
  2. Apply your Backstage CR to start or update your Developer Hub instance.

    $ oc apply --filename=my-rhdh-custom-resource.yaml --namespace=my-rhdh-project

2.2.8. Configure the default theme mode

You can switch the RHDH interface between light, dark, or auto mode (which matches your system preference).

Note

In RHDH, theme configurations are used to change the look and feel of different UI components. So, you might notice changes in different UI components, such as buttons, tabs, sidebars, cards, and tables along with some changes in background color and font used on the RHDH pages.

Prerequisites

  • You are logged in to the RHDH web console.

Procedure

  1. From the Developer Hub web console, click Settings.
  2. From the Appearance panel, select Light, Dark, or Auto to change the theme mode.

    Theme mode selection in the Appearance panel

Verification

  • The interface immediately updates to reflect the selected theme.

2.2.9. RBAC policy files

Developer Hub uses external policy files to define role-based access control (RBAC) rules. Two files work together to control permissions: a CSV file for standard policies and a YAML file for conditional policies.

rbac-policy.csv

Uses Casbin syntax with two entry types:

  • p entries define policy rules (p, role, resource, action, effect).
  • g entries define role assignments (g, user, role).
rbac-conditional-policies.yaml
Defines conditional policies with criteria-based filtering for fine-grained access control.

Provisioning

Both files are provisioned together in a single config map, such as, rbac-policies. Reference the files from app-config.yaml by using the following fields:

  • permission.rbac.policies-csv-file for the CSV path.
  • permission.rbac.conditionalPoliciesFile for the conditional policies YAML path.

Chapter 3. Plan

3.1. Plan

Evaluate deployment methods, sizing requirements, and scaling benchmarks to provision the right infrastructure for Red Hat Developer Hub. Planning decisions made before installation define long-term platform performance, operational cost, and upgrade flexibility.

3.2. Plan your deployment architecture and scale

3.2.1. Plan your deployment architecture and scale

Choose the right deployment method, assign compute and storage resources, and establish performance baselines before installing Red Hat Developer Hub. Architecture decisions made during planning affect cluster resource use, database resilience, and future scaling capacity.

3.2.2. Sizing requirements for cluster resource provisioning

3.2.2.1. Sizing requirements for cluster resource provisioning

Find the CPU, memory, and storage requirements for Red Hat Developer Hub application pods, databases, and Operator components. Correct resource provisioning prevents out-of-memory failures and ensures the platform meets target response times under expected user loads.

3.2.2.2. Compute and storage resource guidelines

Plan infrastructure resources for Red Hat Developer Hub deployments using sizing requirements for the application, database, and Operator.

Table 1 lists the sizing requirements for installing and running Red Hat Developer Hub, including Developer Hub application, database components, and Operator. Table 2 lists recommended sizing requirements for external PostgreSQL deployment based on the deployment scale.

ComponentsRed Hat Developer Hub applicationRed Hat Developer Hub databaseRed Hat Developer Hub Operator

Central Processing Unit (CPU)

4 vCPU

2 vCPU

1 vCPU

Memory

16 GB

8 GB

1500 Mi

Storage size

2 GB

20 GB

50 Mi

Replicas

2 or more

3 or more

1 or more

Sizing legendSmall-scaleMid-scaleLarge-scaleEnterprise-scale

Application usage

up to 5 thousand entities, up to 50 concurrent users

5–20 thousand entities, 50–150 concurrent users

20–50 thousand entities, 150–400 concurrent users

50–150 thousand entities, 400–800 concurrent users

vCPU

2

4

8

16

Memory

8 GiB

16 GiB

32 GiB

64 GiB

Storage

50 GiB

100 GiB

200 GiB

500 GiB

Number of replicas

1

2

2-3

3+

PostgreSQL Database HA

1 primary

1 primary, 1 standby

1 primary, 1 synchronous standby

1 primary, 1 synchronous standby, 1 asynchronous replica

Table 3 lists recommended PostgreSQL performance tuning parameters based on the deployment scale for an external PostgreSQL deployment. Set shared_buffers to approximately 1/4 of the allocated database memory and effective_cache_size to approximately 1/2 of the allocated database memory. For more information, see the PostgreSQL tuning guide.

Sizing legendMemoryshared_bufferseffective_cache_size

Small-scale

8 GiB

2 GB

4 GB

Mid-scale

16 GiB

4 GB

8 GB

Large-scale

32 GiB

8 GB

16 GB

Enterprise-scale

64 GiB

16 GB

32 GB

Note

Using an external PostgreSQL instance is recommended for production deployments.

3.2.3. Compare the Helm chart and Operator deployment methods

3.2.3.1. Compare the Helm chart and Operator deployment methods

Evaluate the Helm chart and Operator installation methods to select the approach that matches your platform capabilities and operational model. The deployment method determines how you manage upgrades, configure high availability, and integrate with cluster lifecycle tools.

3.2.3.2. Pros and cons of each deployment method

When planning your Red Hat Developer Hub deployment, you must choose between the Helm chart and Operator installation methods. Use the following table to choose the method that aligns with your operational model and team capabilities:

Helm chartOperator

Platform requirements

  • You deploy across multiple Kubernetes platforms (EKS, GKE, AKS).
  • You need maximum portability across different environments.

Platform requirements

  • You primarily use OpenShift Container Platform.
  • Your platform has Operator Lifecycle Manager (OLM) installed.

Setup and deployment priorities

  • You want the simplest initial setup.
  • You prefer fewer deployment steps to get started.
  • You are familiar with Helm workflows.

Setup and deployment priorities

  • You prioritize long-term automation over initial simplicity.
  • You accept more initial setup complexity for ongoing operational benefits.
  • You want integrated lifecycle management from the start.

Update preferences

  • You want full control over update timing.
  • You test updates in stages across environments.
  • You manage updates manually on your schedule.

Update preferences

  • You want automated update availability through subscription channels.
  • You prefer continuous reconciliation of desired state.
  • You want less operational overhead for maintaining Developer Hub.

Team capabilities

  • Your team has Helm expertise.
  • You want direct access to Kubernetes resources.
  • You prefer hands-on management and troubleshooting.

Team capabilities

  • Your team follows Kubernetes-native Operator patterns.
  • You want built-in lifecycle management.
  • You are comfortable working with custom resources.

Control and customization needs

  • You need direct control over all Kubernetes resources.
  • You want full visibility into generated manifests.
  • You prefer to inspect and modify deployed resources directly.

Control and customization needs

  • You prefer declarative configuration through custom resources.
  • You want validation and reconciliation by the Operator.
  • You value standardized deployment patterns across your organization.

Both installation methods are fully supported by Red Hat. Choose the method that best matches your operational priorities, platform requirements, and team expertise.

For detailed installation instructions, see Installing Red Hat Developer Hub on OpenShift Container Platform.

3.2.4. Scale your deployment using enterprise performance benchmarks

3.2.4.1. Scale your deployment using enterprise performance benchmarks

Apply enterprise-scale benchmarks to plan resource allocation for growing catalog sizes and concurrent user loads. Benchmark data enables capacity planning that matches infrastructure investment to actual usage patterns and growth projections.

Chapter 4. Install

4.1. Install

Deploy Red Hat Developer Hub on OpenShift Container Platform, managed hyperscaler environments, or air-gapped infrastructure to establish your developer portal.

4.2. Install on OpenShift Container Platform to leverage existing Red Hat infrastructure

4.2.1. Install on OpenShift Container Platform to leverage existing Red Hat infrastructure

Install Red Hat Developer Hub on Red Hat OpenShift Container Platform by using either the Red Hat Developer Hub Operator or the Helm chart.

4.2.2. Compare the Helm chart and Operator deployment methods

You can install Red Hat Developer Hub on OpenShift Container Platform by using one of the following installers:

The Red Hat Developer Hub Operator
  • Ready for immediate use in OpenShift Container Platform after an administrator installs it with OperatorHub
  • Uses Operator Lifecycle Management (OLM) to manage automated subscription updates on OpenShift Container Platform
  • Requires preinstallation of Operator Lifecycle Management (OLM) to manage automated subscription updates on Kubernetes
The Red Hat Developer Hub Helm chart
  • Ready for immediate use in both OpenShift Container Platform and Kubernetes
  • Requires manual installation and management

For guidance on choosing between the Helm chart and Operator based on your operational requirements and team capabilities, see Compare the Helm chart and Operator to choose the optimal deployment method.

Important

You must set the baseUrl in app-config.yaml to match the external URL of your Developer Hub instance, such as https://<my_developer_hub_domain>. This value is required for the Red Hat Developer Hub to function correctly. If it is not set, front-end and back-end services cannot communicate properly, and features might not work as expected.

4.2.3. Install on OpenShift Container Platform using the Operator

4.2.3.1. Install on OpenShift Container Platform using the Operator

You can install Red Hat Developer Hub on OpenShift Container Platform by using the Red Hat Developer Hub Operator in the OpenShift Container Platform console.

4.2.3.2. Install the Operator

As an administrator, you can install the Red Hat Developer Hub Operator. Authorized users can use the Operator to install Red Hat Developer Hub on Red Hat OpenShift Container Platform (OpenShift Container Platform) and supported Kubernetes platforms.

For more information about supported platforms and versions, see the Red Hat Developer Hub Life Cycle page.

Containers are available for the following CPU architectures:

  • AMD64 and Intel 64 (x86_64)

Prerequisites

Important

You can upgrade Red Hat Developer Hub directly from any earlier version to the latest release without installing intermediate versions. However, you must review the release notes for every skipped version to identify breaking changes or required migration steps. For example, if upgrading from version 1.5 to 1.7, check the release notes for both 1.6 and 1.7.

Procedure

  1. In the OpenShift Container Platform web console, find and install the Red Hat Developer Hub Operator from the software catalog.

    For the detailed console steps, see Installing from the software catalog by using the web console in the Red Hat OpenShift Container Platform documentation.

  2. On the Install Operator page, configure the following options:

    1. From the Update channel drop-down menu, select fast or fast-1.10.

      Important

      The fast channel includes all of the updates available for a particular version. Any update might introduce unexpected changes in your Red Hat Developer Hub deployment. Check the release notes for details about any potentially breaking changes.

      The fast-1.10 channel only provides z-stream updates, for example, updating from version 1.10.1 to 1.10.2. If you want to update the Red Hat Developer Hub y-version in the future, for example, updating from 1.10 to 2.1, you must switch to the fast-2.1 channel manually.

    2. From the Version drop-down menu, select the version of the Red Hat Developer Hub Operator that you want to install.
    3. For Installation mode, keep the default All namespaces on the cluster option.

      Note

      The Specific namespace on the cluster option is not currently supported.

    4. For Installed Namespace, select Operator recommended Namespace to use the default rhdh-operator namespace.

      Important

      For enhanced security, better control over the Operator lifecycle, and preventing potential privilege escalation, install the Red Hat Developer Hub Operator in a dedicated default rhdh-operator namespace. You can restrict other users' access to the Operator resources through role bindings or cluster role bindings.

      You can also install the Operator in another namespace by creating the necessary resources, such as an Operator group. For more information, see Installing global Operators in custom namespaces.

      However, if the Red Hat Developer Hub Operator shares a namespace with other Operators, then it shares the same update policy as well, preventing the customization of the update policy. For example, if one Operator is set to manual updates, the Red Hat Developer Hub Operator update policy is also set to manual. For more information, see Colocation of Operators in a namespace.

    5. Select the Update approval method and click Install.

Verification

  • Navigate to Ecosystem > Installed Operators and verify that the Red Hat Developer Hub Operator status is Succeeded.

4.2.3.3. Provision your custom configuration

Provision custom config maps and secrets on Red Hat OpenShift Container Platform (RHOCP) to configure Red Hat Developer Hub before running the application.

Tip

On Red Hat OpenShift Container Platform, you can skip this step to run Developer Hub with the default config map and secret. Your changes on this configuration might get reverted on Developer Hub restart.

Prerequisites

  • By using the OpenShift CLI (oc), you have access, with developer permissions, to the OpenShift cluster aimed at containing your Developer Hub instance.

Procedure

  1. For security, store your secrets as environment variables values in an OpenShift Container Platform secret, rather than in plain text in your configuration files. Collect all your secrets in the secrets.txt file, with one secret per line in KEY=value form.

    Enter your authentication secrets.

  2. Author your custom app-config.yaml file. This is the main Developer Hub configuration file. You need a custom app-config.yaml file to avoid the Developer Hub installer to revert user edits during upgrades. When your custom app-config.yaml file is empty, Developer Hub is using default values.

    • To prepare a deployment with the Red Hat Developer Hub Operator on OpenShift Container Platform, you can start with an empty file.
    • To prepare a deployment with the Red Hat Developer Hub Helm chart, or on Kubernetes, enter the Developer Hub base URL in the relevant fields in your app-config.yaml file to ensure proper functionality of Developer Hub. The base URL is what a Developer Hub user sees in their browser when accessing Developer Hub. The relevant fields are baseUrl in the app and backend sections, and origin in the backend.cors subsection:

      Configuring the baseUrl in app-config.yaml:

      app:
        title: Red Hat Developer Hub
        baseUrl: https://<my_developer_hub_domain>
      
      backend:
        auth:
          externalAccess:
            - type: legacy
              options:
                subject: legacy-default-config
                secret: "${BACKEND_SECRET}"
        baseUrl: https://<my_developer_hub_domain>
        cors:
          origin: https://<my_developer_hub_domain>
    • Optionally, enter your configuration such as:

  3. Author your custom dynamic-plugins.yaml file to enable plugins. By default, Developer Hub enables a minimal plugin set, and disables plugins that require configuration or secrets, such as the GitHub repository discovery plugin and the Role-based access control (RBAC) plugin.

    Enable the GitHub repository discovery and the RBAC features:

    dynamic.plugins.yaml

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github
        disabled: false
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

  4. Provision your custom configuration files to your OpenShift Container Platform cluster.

    1. Create the <my-rhdh-project> project aimed at containing your Developer Hub instance.

      $ oc create namespace my-rhdh-project
    2. Create config maps for your app-config.yaml and dynamic-plugins.yaml files in the <my-rhdh-project> project.

      $ oc create configmap my-rhdh-app-config --from-file=app-config.yaml --namespace=my-rhdh-project
      $ oc create configmap dynamic-plugins-rhdh --from-file=dynamic-plugins.yaml --namespace=my-rhdh-project

      You can also create the config maps by using the web console.

    3. Provision your secrets.txt file to the my-rhdh-secrets secret in the <my-rhdh-project> project.

      $ oc create secret generic my-rhdh-secrets --from-file=secrets.txt --namespace=my-rhdh-project

      You can also create the secret by using the web console.

4.2.4. Install on OpenShift Container Platform using the Helm chart

4.2.4.1. Install on OpenShift Container Platform using the Helm chart

You can install Red Hat Developer Hub on OpenShift Container Platform by using the Helm chart with one of the following methods:

  • The OpenShift Container Platform console
  • The Helm CLI

4.2.4.2. Deploy from the web console

You can use a Helm chart to install Developer Hub on the Red Hat OpenShift Container Platform web console.

Helm is a package manager on OpenShift Container Platform that provides the following features:

  • Applies regular application updates using custom hooks
  • Manages the installation of complex applications
  • Provides charts that you can host on public and private servers
  • Supports rolling back to earlier application versions

The Red Hat Developer Hub Helm chart is available in the Helm catalog on OpenShift Dedicated and OpenShift Container Platform.

Prerequisites

Procedure

  1. From the Developer perspective on the Developer Hub web console, click +Add.
  2. From the Developer Catalog panel, click Helm Chart.
  3. In the Filter by keyword box, enter Developer Hub and click the Red Hat Developer Hub card.
  4. From the Red Hat Developer Hub page, click Create.
  5. From your cluster, copy the OpenShift Container Platform router host (for example: apps.<clusterName>.com).
  6. Select the radio button to configure the Developer Hub instance with either the form view or YAML view. The Form view is selected by default.

    • Using Form view

      1. To configure the instance with the Form view, go to Root SchemaglobalEnable service authentication within Red Hat Developer Hub instance and paste your OpenShift Container Platform router host into the field on the form.
    • Using YAML view

      1. To configure the instance with the YAML view, paste your OpenShift Container Platform router hostname in the global.clusterRouterBase parameter value as shown in the following example:

        global:
          auth:
            backend:
              enabled: true
          clusterRouterBase: apps.<clusterName>.com
  7. Edit the other values if needed.
  8. Click Create and wait for the database and Developer Hub to start.
  9. Click the Open URL icon to start using the Developer Hub platform.

    Helm chart installation in the OpenShift web console
    Note

    The host information is copied and can be accessed by the Developer Hub backend.

    When an OpenShift Container Platform route is generated automatically, the host value for the route is inferred and the same host information is sent to the Developer Hub. Also, if the Developer Hub is present on a custom domain by setting the host manually using values, the custom host takes precedence.

Troubleshooting

  • Your developer-hub pod might be in a CrashLoopBackOff state if the Developer Hub container cannot access the configuration files. This error is indicated by the following log:

    Loaded config from app-config-from-configmap.yaml, env
    ...
    2023-07-24T19:44:46.223Z auth info Configuring "database" as KeyStore provider type=plugin
    Backend failed to start up Error: Missing required config value at 'backend.database.client'

    To resolve the error, verify the configuration files.

4.2.4.3. Deploy with the Helm CLI

You can use the Helm CLI to install Red Hat Developer Hub on Red Hat OpenShift Container Platform.

Prerequisites

  • You have installed the OpenShift CLI (oc) on your workstation.
  • You have logged in to your OpenShift Container Platform account.
  • A user with the OpenShift Container Platform admin role has configured the appropriate roles and permissions within your project to create an application. For more information about OpenShift Container Platform roles, see Using RBAC to define and apply permissions.
  • You have created a project in OpenShift Container Platform. For more information about creating a project in OpenShift Container Platform, see Red Hat OpenShift Container Platform documentation.
  • You have installed the Helm CLI tool.

Procedure

  1. Create and activate the <my-rhdh-project> OpenShift Container Platform project:

    NAMESPACE=<emphasis><rhdh></emphasis>
    oc new-project ${NAMESPACE} || oc project ${NAMESPACE}
  2. Install the Red Hat Developer Hub Helm chart:

    helm upgrade redhat-developer-hub -i https://github.com/openshift-helm-charts/charts/releases/download/redhat-redhat-developer-hub-1.10.1/redhat-developer-hub-1.10.1.tgz
  3. Configure your Developer Hub Helm chart instance with the Developer Hub database password and router base URL values from your OpenShift Container Platform cluster:

    PASSWORD=$(oc get secret redhat-developer-hub-postgresql -o jsonpath="{.data.password}" | base64 -d)
    CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//')
    helm upgrade redhat-developer-hub -i "https://github.com/openshift-helm-charts/charts/releases/download/redhat-redhat-developer-hub-1.10.1/redhat-developer-hub-1.10.1.tgz" \
        --set global.clusterRouterBase="$CLUSTER_ROUTER_BASE" \
        --set global.postgresql.auth.password="$PASSWORD"
  4. Display the running Developer Hub instance URL:

    echo "https://redhat-developer-hub-$NAMESPACE.$CLUSTER_ROUTER_BASE"

Verification

  • Open the running Developer Hub instance URL in your browser to use Developer Hub.

Additional resources

4.3. Install on managed hyperscaler environments to integrate with cloud resources

4.3.1. Install on managed hyperscaler environments to integrate with cloud resources

Install Red Hat Developer Hub on managed cloud Kubernetes platforms by following a clear installation path for your specific hyperscaler environment, so you can get Developer Hub running on EKS, GKE, AKS, or OpenShift Dedicated without having to adapt generic instructions.

4.3.2. Install on Amazon Elastic Kubernetes Service (EKS) using the Operator

4.3.2.1. Install on Amazon Elastic Kubernetes Service (EKS) using the Operator

Install Red Hat Developer Hub on EKS by using the Red Hat Developer Hub Operator with the Operator Lifecycle Manager (OLM) framework for over-the-air updates and catalogs.

To benefit from over-the-air updates and catalogs provided by Operator-based applications distributed with the Operator Lifecycle Manager (OLM) framework, consider installing Red Hat Developer Hub by using the Red Hat Developer Hub Operator distributed in the Red Hat Container Registry.

On EKS, the most notable differences over an OpenShift-based installation are:

  • The OLM framework and the Red Hat Container Registry are not built-in.
  • The Red Hat Container Registry pull-secret is not managed globally.
  • To expose the application, Ingresses replace OpenShift Routes.

For clarity, sections highlight these platform-specific additional steps.

4.3.2.2. Install the Operator using OLM to automate deployments

Install the Red Hat Developer Hub Operator on EKS by using the Operator Lifecycle Manager (OLM) framework.

The Red Hat Container Registry (registry.redhat.io), based on the Operator Lifecycle Manager (OLM) framework, has a distribution of the Red Hat Developer Hub Operator, aimed at managing your Red Hat Developer Hub instance lifecycle.

However, on Amazon Elastic Kubernetes Service (EKS):

  • The Operator Lifecycle Manager (OLM) framework and the Red Hat Container Registry are not built-in.
  • The Red Hat Container Registry pull-secret is not managed globally.

Therefore, install the OLM framework, the Red Hat Container Registry, and provision your Red Hat Container Registry pull secret to install Developer Hub Operator.

Prerequisites

Procedure

  1. Create the rhdh-operator namespace to contain the Red Hat Developer Hub Operator:

    $ kubectl create namespace rhdh-operator
  2. Create a pull secret using your Red Hat credentials to pull the container images from the protected Red Hat Container Registry (registry.redhat.io):

    $ kubectl -n rhdh-operator create secret docker-registry rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<redhat_user_name> \
        --docker-password=<redhat_password> \
        --docker-email=<email>
  3. Create a catalog source that has the Red Hat operators:

    $ cat <<EOF | kubectl -n rhdh-operator apply -f -
    apiVersion: operators.coreos.com/v1alpha1
    kind: CatalogSource
    metadata:
      name: redhat-catalog
    spec:
      sourceType: grpc
      image: registry.redhat.io/redhat/redhat-operator-index:v4.21
      secrets:
      - "rhdh-pull-secret"
      displayName: Red Hat Operators
    EOF
  4. Create an operator group to manage your operator subscriptions:

    $ cat <<EOF | kubectl apply -n rhdh-operator -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: rhdh-operator-group
    EOF
  5. Create a subscription to install the Red Hat Developer Hub Operator:

    $ cat <<EOF | kubectl apply -n rhdh-operator -f -
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: rhdh
      namespace: rhdh-operator
    spec:
      channel: fast
      installPlanApproval: Automatic
      name: rhdh
      source: redhat-catalog
      sourceNamespace: rhdh-operator
      startingCSV: rhdh-operator.v1.10.1
    EOF
  6. To wait until the Operator deployment finishes to be able to run the next step, run:

    $ until kubectl -n rhdh-operator get deployment rhdh-operator &>/dev/null; do
      echo -n .
      sleep 3
    done
    echo "RHDH Operator Deployment created"
  7. Include your pull secret name in the Operator deployment manifest, to avoid ImagePullBackOff errors:

    $ kubectl -n rhdh-operator patch deployment \
        rhdh-operator --patch '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"rhdh-pull-secret"}]}}}}' \
        --type=merge

Verification

  • Verify the deployment name:

    $ kubectl get deployment -n rhdh-operator

4.3.2.3. Provision your custom configuration

Provision custom config maps and secrets on Amazon Elastic Kubernetes Service (EKS) to configure Red Hat Developer Hub before running the application.

Tip

On Red Hat OpenShift Container Platform, you can skip this step to run Developer Hub with the default config map and secret. Your changes on this configuration might get reverted on Developer Hub restart.

Prerequisites

  • By using the Kubernetes CLI ('kubectl'), you have access, with developer permissions, to the OpenShift cluster aimed at containing your Developer Hub instance.

Procedure

  1. For security, store your secrets as environment variables values in an OpenShift Container Platform secret, rather than in plain text in your configuration files. Collect all your secrets in the secrets.txt file, with one secret per line in KEY=value form.

    Enter your authentication secrets.

  2. Author your custom app-config.yaml file. This is the main Developer Hub configuration file. You need a custom app-config.yaml file to avoid the Developer Hub installer to revert user edits during upgrades. When your custom app-config.yaml file is empty, Developer Hub is using default values.

    • To prepare a deployment with the Red Hat Developer Hub Operator on OpenShift Container Platform, you can start with an empty file.
    • To prepare a deployment with the Red Hat Developer Hub Helm chart, or on Kubernetes, enter the Developer Hub base URL in the relevant fields in your app-config.yaml file to ensure proper functionality of Developer Hub. The base URL is what a Developer Hub user sees in their browser when accessing Developer Hub. The relevant fields are baseUrl in the app and backend sections, and origin in the backend.cors subsection:

      Configuring the baseUrl in app-config.yaml:

      app:
        title: Red Hat Developer Hub
        baseUrl: https://<my_developer_hub_domain>
      
      backend:
        auth:
          externalAccess:
            - type: legacy
              options:
                subject: legacy-default-config
                secret: "${BACKEND_SECRET}"
        baseUrl: https://<my_developer_hub_domain>
        cors:
          origin: https://<my_developer_hub_domain>
    • Optionally, enter your configuration such as:

  3. Author your custom dynamic-plugins.yaml file to enable plugins. By default, Developer Hub enables a minimal plugin set, and disables plugins that require configuration or secrets, such as the GitHub repository discovery plugin and the Role-based access control (RBAC) plugin.

    Enable the GitHub repository discovery and the RBAC features:

    dynamic.plugins.yaml

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github
        disabled: false
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

  4. Provision your custom configuration files to your EKS cluster.

    1. Create the <my-rhdh-project> namespace aimed at containing your Developer Hub instance.

      $ oc create namespace my-rhdh-project
    2. Create config maps for your app-config.yaml and dynamic-plugins.yaml files in the <my-rhdh-project> project.

      $ oc create configmap my-rhdh-app-config --from-file=app-config.yaml --namespace=my-rhdh-project
      $ oc create configmap dynamic-plugins-rhdh --from-file=dynamic-plugins.yaml --namespace=my-rhdh-project

      You can also create the config maps by using the web console.

    3. Provision your secrets.txt file to the my-rhdh-secrets secret in the <my-rhdh-project> project.

      $ oc create secret generic my-rhdh-secrets --from-file=secrets.txt --namespace=my-rhdh-project

      You can also create the secret by using the web console.

4.3.2.4. Provision a pull secret to access the container registry

On Amazon Elastic Kubernetes Service (EKS), provision your Red Hat Container Registry pull secret in your Red Hat Developer Hub instance namespace because the pull secret is not managed globally.

On Amazon Elastic Kubernetes Service (EKS), the Red Hat Container Registry pull-secret is not managed globally. Therefore add your pull-secret in your Red Hat Developer Hub instance namespace.

Prerequisites

  • Your credentials to the Red Hat Container Registry:

    • <redhat_user_name>
    • <redhat_password>
    • <email>
  • You created the {my-rhdh-project} namespace on EKS to host your Developer Hub instance.

Procedure

  1. Create a pull secret using your Red Hat credentials to pull the container images from the protected Red Hat Container Registry (registry.redhat.io):

    $ kubectl -n {my-rhdh-namespace} create secret docker-registry my-rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<redhat_user_name> \
        --docker-password=<redhat_password> \
        --docker-email=<email>
  2. To enable pulling Developer Hub images from the Red Hat Container Registry, add the image pull secret in the default service account within the namespace where the Developer Hub instance is being deployed:

    $ kubectl patch serviceaccount default \
        -p '{"imagePullSecrets": [{"name": "my-rhdh-pull-secret"}]}' \
        -n {my-rhdh-namespace}

4.3.2.5. Deploy a custom configuration using an Operator

Use the Red Hat Developer Hub Operator to deploy Developer Hub with custom configuration by creating a custom resource that mounts config maps and injects secrets.

Prerequisites

  • By using the Kubernetes CLI ('kubectl'), you have access, with developer permissions, to the EKS cluster aimed at containing your Developer Hub instance.
  • Your administrator has installed the Red Hat Developer Hub Operator in the cluster.
  • You have provisioned your custom config maps and secrets in your <my-rhdh-project> project.
  • You have a working default storage class, such as the Elastic Block Store (EBS) storage add-on, configured in your EKS cluster.

Procedure

  1. Author your Backstage CR in a my-rhdh-custom-resource.yaml file to use your custom config maps and secrets.

    Minimal my-rhdh-custom-resource.yaml custom resource example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh-custom-resource
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
        extraFiles:
          mountPath: /opt/app-root/src
        route:
          enabled: true
      database:
        enableLocalDb: true

    my-rhdh-custom-resource.yaml custom resource example with dynamic plugins and RBAC policies config maps, and external PostgreSQL database secrets:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <my-rhdh-custom-resource>
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
        route:
          enabled: true
      database:
        enableLocalDb: false
    Mandatory fields
    No fields are mandatory. You can create an empty Backstage CR and run Developer Hub with the default configuration.
    Optional fields
    spec.application.appConfig.configMaps
    Enter your config map name list.

    Mount files in the my-rhdh-app-config config map:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config

    Mount files in the my-rhdh-app-config and rbac-policies config maps:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
    spec.application.extraEnvs.envs

    Optionally, enter your additional environment variables that are not secrets, such as your proxy environment variables.

    Inject your HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables:

    spec:
      application:
        extraEnvs:
          envs:
            - name: HTTP_PROXY
              value: 'http://10.10.10.105:3128'
            - name: HTTPS_PROXY
              value: 'http://10.10.10.106:3128'
            - name: NO_PROXY
              value: 'localhost,example.org'
    spec.application.extraEnvs.secrets

    Enter your environment variables secret name list.

    Inject the environment variables in your Red Hat Developer Hub secret:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>

    Inject the environment variables in the Red Hat Developer Hub and my-rhdh-database-secrets secrets:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
    Note

    <my_product_secrets> is your preferred Developer Hub secret name, specifying the identifier for your secret configuration within Developer Hub.

    spec.application.extraFiles.secrets

    Enter your certificates files secret name and files list.

    Mount the postgres-crt.pem, postgres-ca.pem, and postgres-key.key files contained in the my-rhdh-database-certificates-secrets secret:

    spec:
      application:
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
    spec.database.enableLocalDb

    Enable or disable the local PostgreSQL database.

    Disable the local PostgreSQL database generation to use an external postgreSQL database:

    spec:
      database:
        enableLocalDb: false

    On a development environment, use the local PostgreSQL database:

    spec:
      database:
        enableLocalDb: true
    spec.deployment
    Optionally, enter your deployment configuration.
  2. Apply your Backstage CR to start or update your Developer Hub instance:

    $ oc apply --filename=my-rhdh-custom-resource.yaml --namespace=my-rhdh-project

4.3.2.6. Expose your Operator instance using an Ingress resource

On Amazon Elastic Kubernetes Service (EKS), Kubernetes ingresses replace OpenShift Container Platform routes. The Red Hat Developer Hub Operator does not create ingresses. Therefore, to access your Developer Hub instance via a domain name, create the required ingresses on EKS and point your domain name to it.

Prerequisites

Procedure

  1. Create an Ingress manifest file, named rhdh-ingress.yaml, specifying your Developer Hub service name as follows:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-rhdh-ingress
      annotations:
        alb.ingress.kubernetes.io/scheme: internet-facing
        alb.ingress.kubernetes.io/target-type: ip
        # TODO: Using an ALB HTTPS Listener requires a certificate for your own domain. Fill in the ARN of your certificate, e.g.:
        alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-xxx:xxxx:certificate/xxxxxx
        alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
        alb.ingress.kubernetes.io/ssl-redirect: '443'
        external-dns.alpha.kubernetes.io/hostname: <my_developer_hub_domain>
    spec:
      ingressClassName: alb
      rules:
        - host: <my_developer_hub_domain>
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: my-rhdh-custom-resource
                  port:
                    name: http-backend
    EOF

    Replace <my_developer_hub_domain> with your Developer Hub domain name and update the value of alb.ingress.kubernetes.io/certificate-arn with your certificate ARN.

  2. Update your required domain name, (for example, in Route 53 or your external DNS service) to point to the provisioned IP address. Elastic Kubernetes Service provisions an Application Load Balancer (ALB) with a corresponding IP address.
  3. To deploy the created Ingress, run:

    $ kubectl -n my-rhdh-project apply -f rhdh-ingress.yaml

Verification

  • Wait until the DNS name is responsive, indicating that your Developer Hub instance is ready for use.

4.3.3. Deploy on Amazon EKS using the Helm chart

Deploy Developer Hub on EKS by using the Helm chart for building, testing, and deploying applications.

When you install the Developer Hub Helm chart in Elastic Kubernetes Service (EKS), it orchestrates the deployment of a Developer Hub instance, which provides a robust developer platform within the AWS ecosystem.

Prerequisites

Procedure

  1. Go to your terminal and run the following command to add the Helm chart repository containing the Developer Hub chart to your local Helm registry:

    $ helm repo add openshift-helm-charts https://charts.openshift.io/
  2. Create a pull secret using the following command:

    $ kubectl create secret docker-registry rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<user_name> \
        --docker-password=<password> \
        --docker-email=<email>

    + Replace <user_name> with your username, <password> with your password, and <email> with your email address.

    The created pull secret pulls the Developer Hub images from the Red Hat Container Registry.

  3. Create a file named values.yaml using the following template:

    global:
      # TODO: Set your application domain name.
      host: <your Developer Hub domain name>
    
    
    route:
      enabled: false
    
    
    upstream:
      service:
        # NodePort is required for the ALB to route to the Service
        type: NodePort
    
    
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: alb
    
    
          alb.ingress.kubernetes.io/scheme: internet-facing
    
    
          # TODO: Using an ALB HTTPS Listener requires a certificate for your own domain. Fill in the ARN of your certificate, e.g.:
          alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:xxx:xxxx:certificate/xxxxxx
    
    
          alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    
    
          alb.ingress.kubernetes.io/ssl-redirect: '443'
    
    
          # TODO: Set your application domain name.
          external-dns.alpha.kubernetes.io/hostname: <your rhdh domain name>
    
    
      backstage:
        image:
          pullSecrets:
          - rhdh-pull-secret
        podSecurityContext:
          # you can assign any random value as fsGroup
          fsGroup: 2000
      postgresql:
        image:
          pullSecrets:
          - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            # you can assign any random value as fsGroup
            fsGroup: 3000
      volumePermissions:
        enabled: true
  4. Update your required domain name, (for example, in Route 53 or your external DNS service) to point to the provisioned IP address. Elastic Kubernetes Service provisions an Application Load Balancer (ALB) with a corresponding IP address.
  5. Run the following command in your terminal to deploy Developer Hub using the latest version of Helm Chart and using the values.yaml file created in the earlier step:

    $ helm install rhdh \
      openshift-helm-charts/redhat-developer-hub \
      [--version 1.10.1] \
      --values /path/to/values.yaml

Verification

Wait until the DNS name is responsive, indicating that your Developer Hub instance is ready for use.

4.3.4. Install on Google Kubernetes Engine (GKE) using the Operator

4.3.4.1. Install on Google Kubernetes Engine (GKE) using the Operator

Install Red Hat Developer Hub on GKE by using the Red Hat Developer Hub Operator with the Operator Lifecycle Manager (OLM) framework for over-the-air updates and catalogs.

To benefit from over-the-air updates and catalogs provided by Operator-based applications distributed with the Operator Lifecycle Manager (OLM) framework, consider installing Red Hat Developer Hub by using the Red Hat Developer Hub Operator distributed in the Red Hat Container Registry.

On GKE, the most notable differences over an OpenShift-based installation are:

  • The OLM framework and the Red Hat Container Registry are not built-in.
  • The Red Hat Container Registry pull-secret is not managed globally.
  • To expose the application, Ingresses replace OpenShift Routes.

For clarity, sections highlight these platform-specific additional steps.

4.3.4.2. Install the Operator using OLM to automate deployments

Install the Red Hat Developer Hub Operator on GKE by using the Operator Lifecycle Manager (OLM) framework.

The Red Hat Container Registry (registry.redhat.io), based on the Operator Lifecycle Manager (OLM) framework, has a distribution of the Red Hat Developer Hub Operator, aimed at managing your Red Hat Developer Hub instance lifecycle.

However, on Google Kubernetes Engine (GKE):

  • The Operator Lifecycle Manager (OLM) framework and the Red Hat Container Registry are not built-in.
  • The Red Hat Container Registry pull-secret is not managed globally.

Therefore, install the OLM framework, the Red Hat Container Registry, and provision your Red Hat Container Registry pull secret to install Developer Hub Operator.

Prerequisites

Procedure

  • Connect to your GKE cluster:

    $ gcloud container clusters get-credentials <cluster_name> --location=<cluster_location>
    <cluster_name>
    Enter your GKE cluster name.
    <cluster_location>

    Enter your GKE cluster location.

    1. Create the rhdh-operator namespace to contain the Red Hat Developer Hub Operator:

      $ kubectl create namespace rhdh-operator
    2. Create a pull secret using your Red Hat credentials to pull the container images from the protected Red Hat Container Registry (registry.redhat.io):

      $ kubectl -n rhdh-operator create secret docker-registry rhdh-pull-secret \
          --docker-server=registry.redhat.io \
          --docker-username=<redhat_user_name> \
          --docker-password=<redhat_password> \
          --docker-email=<email>
    3. Create a catalog source that has the Red Hat operators:

      $ cat <<EOF | kubectl -n rhdh-operator apply -f -
      apiVersion: operators.coreos.com/v1alpha1
      kind: CatalogSource
      metadata:
        name: redhat-catalog
      spec:
        sourceType: grpc
        image: registry.redhat.io/redhat/redhat-operator-index:v4.21
        secrets:
        - "rhdh-pull-secret"
        displayName: Red Hat Operators
      EOF
    4. Create an operator group to manage your operator subscriptions:

      $ cat <<EOF | kubectl apply -n rhdh-operator -f -
      apiVersion: operators.coreos.com/v1
      kind: OperatorGroup
      metadata:
        name: rhdh-operator-group
      EOF
    5. Create a subscription to install the Red Hat Developer Hub Operator:

      $ cat <<EOF | kubectl apply -n rhdh-operator -f -
      apiVersion: operators.coreos.com/v1alpha1
      kind: Subscription
      metadata:
        name: rhdh
        namespace: rhdh-operator
      spec:
        channel: fast
        installPlanApproval: Automatic
        name: rhdh
        source: redhat-catalog
        sourceNamespace: rhdh-operator
        startingCSV: rhdh-operator.v1.10.1
      EOF
    6. To wait until the Operator deployment finishes to be able to run the next step, run:

      $ until kubectl -n rhdh-operator get deployment rhdh-operator &>/dev/null; do
        echo -n .
        sleep 3
      done
      echo "RHDH Operator Deployment created"
    7. Include your pull secret name in the Operator deployment manifest, to avoid ImagePullBackOff errors:

      $ kubectl -n rhdh-operator patch deployment \
          rhdh-operator --patch '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"rhdh-pull-secret"}]}}}}' \
          --type=merge

Verification

  • Verify the deployment name:

    $ kubectl get deployment -n rhdh-operator

4.3.4.3. Provision your custom configuration

Provision custom config maps and secrets on Google Kubernetes Engine (GKE) to configure Red Hat Developer Hub before running the application.

Tip

On Red Hat OpenShift Container Platform, you can skip this step to run Developer Hub with the default config map and secret. Your changes on this configuration might get reverted on Developer Hub restart.

Prerequisites

  • By using the Kubernetes CLI ('kubectl'), you have access, with developer permissions, to the OpenShift cluster aimed at containing your Developer Hub instance.

Procedure

  1. For security, store your secrets as environment variables values in an OpenShift Container Platform secret, rather than in plain text in your configuration files. Collect all your secrets in the secrets.txt file, with one secret per line in KEY=value form.

    Enter your authentication secrets.

  2. Author your custom app-config.yaml file. This is the main Developer Hub configuration file. You need a custom app-config.yaml file to avoid the Developer Hub installer to revert user edits during upgrades. When your custom app-config.yaml file is empty, Developer Hub is using default values.

    • To prepare a deployment with the Red Hat Developer Hub Operator on OpenShift Container Platform, you can start with an empty file.
    • To prepare a deployment with the Red Hat Developer Hub Helm chart, or on Kubernetes, enter the Developer Hub base URL in the relevant fields in your app-config.yaml file to ensure proper functionality of Developer Hub. The base URL is what a Developer Hub user sees in their browser when accessing Developer Hub. The relevant fields are baseUrl in the app and backend sections, and origin in the backend.cors subsection:

      Configuring the baseUrl in app-config.yaml:

      app:
        title: Red Hat Developer Hub
        baseUrl: https://<my_developer_hub_domain>
      
      backend:
        auth:
          externalAccess:
            - type: legacy
              options:
                subject: legacy-default-config
                secret: "${BACKEND_SECRET}"
        baseUrl: https://<my_developer_hub_domain>
        cors:
          origin: https://<my_developer_hub_domain>
    • Optionally, enter your configuration such as:

  3. Author your custom dynamic-plugins.yaml file to enable plugins. By default, Developer Hub enables a minimal plugin set, and disables plugins that require configuration or secrets, such as the GitHub repository discovery plugin and the Role-based access control (RBAC) plugin.

    Enable the GitHub repository discovery and the RBAC features:

    dynamic.plugins.yaml

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github
        disabled: false
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

  4. Provision your custom configuration files to your GKE cluster.

    1. Create the <my-rhdh-project> namespace aimed at containing your Developer Hub instance.

      $ oc create namespace my-rhdh-project
    2. Create config maps for your app-config.yaml and dynamic-plugins.yaml files in the <my-rhdh-project> project.

      $ oc create configmap my-rhdh-app-config --from-file=app-config.yaml --namespace=my-rhdh-project
      $ oc create configmap dynamic-plugins-rhdh --from-file=dynamic-plugins.yaml --namespace=my-rhdh-project

      You can also create the config maps by using the web console.

    3. Provision your secrets.txt file to the my-rhdh-secrets secret in the <my-rhdh-project> project.

      $ oc create secret generic my-rhdh-secrets --from-file=secrets.txt --namespace=my-rhdh-project

      You can also create the secret by using the web console.

4.3.4.4. Provision a pull secret to access the container registry

On Google Kubernetes Engine (GKE), provision your Red Hat Container Registry pull secret in your Red Hat Developer Hub instance namespace because the pull secret is not managed globally.

On Google Kubernetes Engine (GKE), the Red Hat Container Registry pull-secret is not managed globally. Therefore add your pull-secret in your Red Hat Developer Hub instance namespace.

Prerequisites

  • Your credentials to the Red Hat Container Registry:

    • <redhat_user_name>
    • <redhat_password>
    • <email>
  • You created the {my-rhdh-project} namespace on GKE to host your Developer Hub instance.

Procedure

  1. Create a pull secret using your Red Hat credentials to pull the container images from the protected Red Hat Container Registry (registry.redhat.io):

    $ kubectl -n {my-rhdh-namespace} create secret docker-registry my-rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<redhat_user_name> \
        --docker-password=<redhat_password> \
        --docker-email=<email>
  2. To enable pulling Developer Hub images from the Red Hat Container Registry, add the image pull secret in the default service account within the namespace where the Developer Hub instance is being deployed:

    $ kubectl patch serviceaccount default \
        -p '{"imagePullSecrets": [{"name": "my-rhdh-pull-secret"}]}' \
        -n {my-rhdh-namespace}

4.3.4.5. Deploy a custom configuration using an Operator

Use the Red Hat Developer Hub Operator to deploy Developer Hub with custom configuration by creating a custom resource that mounts config maps and injects secrets.

Prerequisites

  • By using the Kubernetes CLI ('kubectl'), you have access, with developer permissions, to the GKE cluster aimed at containing your Developer Hub instance.
  • Your administrator has installed the Red Hat Developer Hub Operator in the cluster.
  • You have provisioned your custom config maps and secrets in your <my-rhdh-project> project.
  • You have a working default storage class, such as the Elastic Block Store (EBS) storage add-on, configured in your EKS cluster.

Procedure

  1. Author your Backstage CR in a my-rhdh-custom-resource.yaml file to use your custom config maps and secrets.

    Minimal my-rhdh-custom-resource.yaml custom resource example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh-custom-resource
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
        extraFiles:
          mountPath: /opt/app-root/src
        route:
          enabled: true
      database:
        enableLocalDb: true

    my-rhdh-custom-resource.yaml custom resource example with dynamic plugins and RBAC policies config maps, and external PostgreSQL database secrets:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <my-rhdh-custom-resource>
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
        route:
          enabled: true
      database:
        enableLocalDb: false
    Mandatory fields
    No fields are mandatory. You can create an empty Backstage CR and run Developer Hub with the default configuration.
    Optional fields
    spec.application.appConfig.configMaps
    Enter your config map name list.

    Mount files in the my-rhdh-app-config config map:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config

    Mount files in the my-rhdh-app-config and rbac-policies config maps:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
    spec.application.extraEnvs.envs

    Optionally, enter your additional environment variables that are not secrets, such as your proxy environment variables.

    Inject your HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables:

    spec:
      application:
        extraEnvs:
          envs:
            - name: HTTP_PROXY
              value: 'http://10.10.10.105:3128'
            - name: HTTPS_PROXY
              value: 'http://10.10.10.106:3128'
            - name: NO_PROXY
              value: 'localhost,example.org'
    spec.application.extraEnvs.secrets

    Enter your environment variables secret name list.

    Inject the environment variables in your Red Hat Developer Hub secret:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>

    Inject the environment variables in the Red Hat Developer Hub and my-rhdh-database-secrets secrets:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
    Note

    <my_product_secrets> is your preferred Developer Hub secret name, specifying the identifier for your secret configuration within Developer Hub.

    spec.application.extraFiles.secrets

    Enter your certificates files secret name and files list.

    Mount the postgres-crt.pem, postgres-ca.pem, and postgres-key.key files contained in the my-rhdh-database-certificates-secrets secret:

    spec:
      application:
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
    spec.database.enableLocalDb

    Enable or disable the local PostgreSQL database.

    Disable the local PostgreSQL database generation to use an external postgreSQL database:

    spec:
      database:
        enableLocalDb: false

    On a development environment, use the local PostgreSQL database:

    spec:
      database:
        enableLocalDb: true
    spec.deployment
    Optionally, enter your deployment configuration.
  2. Apply your Backstage CR to start or update your Developer Hub instance:

    $ oc apply --filename=my-rhdh-custom-resource.yaml --namespace=my-rhdh-project

4.3.4.6. Expose your Operator instance using an Ingress resource

On Google Kubernetes Engine (GKE), Kubernetes ingresses replace OpenShift Container Platform routes. The Red Hat Developer Hub Operator does not create ingresses. Therefore, to access your Developer Hub instance via a domain name, create the required ingresses on GKE and point your domain name to it.

Prerequisites

  • You have installed Red Hat Developer Hub by using the Red Hat Developer Hub Operator.
  • You have configured a domain name for your Developer Hub instance.
  • You have reserved a static external Premium IPv4 Global IP address that is not attached to any virtual machine (VM). For more information see Reserve a new static external IP address
  • You have configured the DNS records for your domain name to point to the IP address that you reserved.

    Note

    You need to create an A record with the value equal to the IP address. This process can take up to one hour to propagate.

Procedure

  1. Create a Google-managed certificate manifest file, named managed-certificate.yaml:

    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: my-rhdh-certificate-name
    spec:
      domains:
        - <my_developer_hub_domain>

    For more information about setting up a Google-managed certificate, see Setting up a Google-managed certificate.

  2. Deploy the managed certificate:

    $ kubectl -n my-rhdh-project apply -f managed-certificate.yaml
  3. Create a front-end config manifest file, named frontend-config.yaml, to set a policy for redirecting to HTTPS.

    apiVersion: networking.gke.io/v1beta1
    kind: FrontendConfig
    metadata:
      name: my-ingress_security_config
    spec:
      sslPolicy: gke-ingress-ssl-policy-https
      redirectToHttps:
        enabled: true

    For more information about setting a policy to redirect to HTTPS, see HTTP to HTTPS redirects.

  4. Deploy the front-end config:

    $ kubectl -n my-rhdh-project apply -f frontend-config.yaml
  5. Create an ingress manifest file, named rhdh-ingress.yaml, specifying your Developer Hub service name, and using your managed certificate and your front-end config:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-rhdh-ingress
      annotations:
        kubernetes.io/ingress.class: "gce"
        kubernetes.io/ingress.global-static-ip-name: <ADDRESS_NAME>
        networking.gke.io/managed-certificates: my-rhdh-certificate-name
        networking.gke.io/v1beta1.FrontendConfig: my-ingress_security_config
    spec:
      ingressClassName: gce
      rules:
        - host: <my_developer_hub_domain>
          http:
            paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: my-rhdh-custom-resource
                  port:
                    name: http-backend
  6. Deploy the ingress:

    $ kubectl -n my-rhdh-project apply -f rhdh-ingress.yaml

Verification

  1. Wait for the system to provision the ManagedCertificate. This process can take a couple of hours.
  2. Access RHDH with https://<my_developer_hub_domain>.

4.3.5. Deploy on GKE using the Helm chart

Deploy Developer Hub on GKE by using the Helm chart for building, testing, and deploying applications.

When you install the Developer Hub Helm chart in Google Kubernetes Engine (GKE), it orchestrates the deployment of a Developer Hub instance, which provides a robust developer platform within the GKE ecosystem.

Prerequisites

  • You have subscribed to the Red Hat Container Registry (registry.redhat.io). For more information, see Red Hat Container Registry Authentication.
  • You have installed kubectl. For more information, see Install the kubectl tool.
  • You have installed the Google Cloud CLI. For more information, see Install the gcloud CLI.
  • You have logged in to your Google account and created a GKE Autopilot or GKE Standard cluster.
  • You have configured a domain name for your Developer Hub instance.
  • You have reserved a static external Premium IPv4 Global IP address that is not attached to any VM. For more information see Reserve a new static external IP address
  • You have configured the DNS records for your domain name to point to the IP address that you reserved.
  • Make sure that your system meets the minimum sizing requirements. See Sizing requirements for Red Hat Developer Hub.

    Note

    You need to create an A record with the value equal to the IP address. This process can take up to one hour to propagate.

  • You have installed Helm 3 or the latest. For more information, see Installing Helm.

Procedure

  1. Go to your terminal and run the following command to add the Helm chart repository containing the Developer Hub chart to your local Helm registry:

    helm repo add openshift-helm-charts https://charts.openshift.io/
  2. Create a pull secret using the following command:

    $ kubectl -n <your_namespace> create secret docker-registry rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<user_name> \
        --docker-password=<password> \
        --docker-email=<email>

    + Replace <your_namespace> with your GKE namespace, <user_name> with your username, <password> with your password, and <email> with your email address.

    The created pull secret pulls the Developer Hub images from the Red Hat Container Registry.

  3. Set up a Google-managed certificate by creating a ManagedCertificate object that you must attach to the ingress:

    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: <rhdh_certificate_name>
    spec:
      domains:
        - <rhdh_domain_name>

    For more information about setting up a Google-managed certificate, see Setting up a Google-managed certificate.

  4. Create a FrontendConfig object to set a policy for redirecting to HTTPS. You must attach this policy to the ingress:

    apiVersion: networking.gke.io/v1beta1
    kind: FrontendConfig
    metadata:
      name: <ingress_security_config>
    spec:
      sslPolicy: gke-ingress-ssl-policy-https
      redirectToHttps:
        enabled: true

    For more information about setting a policy to redirect to HTTPS, see HTTP to HTTPS redirects.

  5. Create a file named values.yaml using the following template:

    Example values.yaml file:

    global:
      host: <rhdh_domain_name>
    route:
      enabled: false
    upstream:
      service:
        type: NodePort
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: gce
          kubernetes.io/ingress.global-static-ip-name: <ADDRESS_NAME>
          networking.gke.io/managed-certificates: <rhdh_certificate_name>
          networking.gke.io/v1beta1.FrontendConfig: <ingress_security_config>
        className: gce
      backstage:
        image:
          pullSecrets:
          - rhdh-pull-secret
        podSecurityContext:
          fsGroup: 2000
      postgresql:
        image:
          pullSecrets:
          - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            fsGroup: 3000
      volumePermissions:
        enabled: true
  6. Run the following command in your terminal to deploy Developer Hub using the latest version of Helm Chart and using the values.yaml file:

    $ helm -n <your_namespace> install -f values.yaml <your_deploy_name> \
      openshift-helm-charts/redhat-developer-hub \
      --version 1.10.1

    For the latest Helm Chart version, see this Helm Charts repository.

Verification

  1. Confirm that the deployment is complete.

    $ kubectl get deploy <your_deploy_name>-developer-hub -n <your_namespace>
  2. Verify that the deployment created the service and ingress:

    $ kubectl get service -n <your_namespace>
    $ kubectl get ingress -n <your_namespace>
    Note

    Wait for the system to provision the ManagedCertificate. This process can take a couple of hours.

  3. Access RHDH with https://<my_developer_hub_domain>.
  4. To upgrade your deployment, use the following command:

    $ helm -n <your_namespace> upgrade -f values.yaml <your_deploy_name> openshift-helm-charts/redhat-developer-hub --version <UPGRADE_CHART_VERSION>
  5. To delete your deployment, use the following command:

    $ helm -n <your_namespace> delete <your_deploy_name>

4.3.6. Install on Microsoft Azure Kubernetes Service (AKS) using the Operator

4.3.6.1. Install on Microsoft Azure Kubernetes Service (AKS) using the Operator

Install Red Hat Developer Hub on AKS by using the Red Hat Developer Hub Operator with the Operator Lifecycle Manager (OLM) framework for over-the-air updates and catalogs.

To benefit from over-the-air updates and catalogs provided by Operator-based applications distributed with the Operator Lifecycle Manager (OLM) framework, consider installing Red Hat Developer Hub by using the Red Hat Developer Hub Operator distributed in the Red Hat Container Registry.

On AKS, the most notable differences over an OpenShift-based installation are:

  • The OLM framework and the Red Hat Container Registry are not built-in.
  • The Red Hat Container Registry pull-secret is not managed globally.
  • To expose the application, Ingresses replace OpenShift Routes.

For clarity, sections highlight these platform-specific additional steps.

4.3.6.2. Install the Operator using OLM to automate deployments

Install the Red Hat Developer Hub Operator on AKS by using the Operator Lifecycle Manager (OLM) framework.

The Red Hat Container Registry (registry.redhat.io), based on the Operator Lifecycle Manager (OLM) framework, has a distribution of the Red Hat Developer Hub Operator, aimed at managing your Red Hat Developer Hub instance lifecycle.

However, on Microsoft Azure Kubernetes Service (AKS):

  • The Operator Lifecycle Manager (OLM) framework and the Red Hat Container Registry are not built-in.
  • The Red Hat Container Registry pull-secret is not managed globally.

Therefore, install the OLM framework, the Red Hat Container Registry, and provision your Red Hat Container Registry pull secret to install Developer Hub Operator.

Prerequisites

Procedure

  1. Create the rhdh-operator namespace to contain the Red Hat Developer Hub Operator:

    $ kubectl create namespace rhdh-operator
  2. Create a pull secret using your Red Hat credentials to pull the container images from the protected Red Hat Container Registry (registry.redhat.io):

    $ kubectl -n rhdh-operator create secret docker-registry rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<redhat_user_name> \
        --docker-password=<redhat_password> \
        --docker-email=<email>
  3. Create a catalog source that has the Red Hat operators:

    $ cat <<EOF | kubectl -n rhdh-operator apply -f -
    apiVersion: operators.coreos.com/v1alpha1
    kind: CatalogSource
    metadata:
      name: redhat-catalog
    spec:
      sourceType: grpc
      image: registry.redhat.io/redhat/redhat-operator-index:v4.21
      secrets:
      - "rhdh-pull-secret"
      displayName: Red Hat Operators
    EOF
  4. Create an operator group to manage your operator subscriptions:

    $ cat <<EOF | kubectl apply -n rhdh-operator -f -
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: rhdh-operator-group
    EOF
  5. Create a subscription to install the Red Hat Developer Hub Operator:

    $ cat <<EOF | kubectl apply -n rhdh-operator -f -
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: rhdh
      namespace: rhdh-operator
    spec:
      channel: fast
      installPlanApproval: Automatic
      name: rhdh
      source: redhat-catalog
      sourceNamespace: rhdh-operator
      startingCSV: rhdh-operator.v1.10.1
    EOF
  6. To wait until the Operator deployment finishes to be able to run the next step, run:

    $ until kubectl -n rhdh-operator get deployment rhdh-operator &>/dev/null; do
      echo -n .
      sleep 3
    done
    echo "RHDH Operator Deployment created"
  7. Include your pull secret name in the Operator deployment manifest, to avoid ImagePullBackOff errors:

    $ kubectl -n rhdh-operator patch deployment \
        rhdh-operator --patch '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"rhdh-pull-secret"}]}}}}' \
        --type=merge

Verification

  • Verify the deployment name:

    $ kubectl get deployment -n rhdh-operator

4.3.6.3. Provision your custom configuration

Provision custom config maps and secrets on Microsoft Azure Kubernetes Service (AKS) to configure Red Hat Developer Hub before running the application.

Tip

On Red Hat OpenShift Container Platform, you can skip this step to run Developer Hub with the default config map and secret. Your changes on this configuration might get reverted on Developer Hub restart.

Prerequisites

  • By using the Kubernetes CLI ('kubectl'), you have access, with developer permissions, to the OpenShift cluster aimed at containing your Developer Hub instance.

Procedure

  1. For security, store your secrets as environment variables values in an OpenShift Container Platform secret, rather than in plain text in your configuration files. Collect all your secrets in the secrets.txt file, with one secret per line in KEY=value form.

    Enter your authentication secrets.

  2. Author your custom app-config.yaml file. This is the main Developer Hub configuration file. You need a custom app-config.yaml file to avoid the Developer Hub installer to revert user edits during upgrades. When your custom app-config.yaml file is empty, Developer Hub is using default values.

    • To prepare a deployment with the Red Hat Developer Hub Operator on OpenShift Container Platform, you can start with an empty file.
    • To prepare a deployment with the Red Hat Developer Hub Helm chart, or on Kubernetes, enter the Developer Hub base URL in the relevant fields in your app-config.yaml file to ensure proper functionality of Developer Hub. The base URL is what a Developer Hub user sees in their browser when accessing Developer Hub. The relevant fields are baseUrl in the app and backend sections, and origin in the backend.cors subsection:

      Configuring the baseUrl in app-config.yaml:

      app:
        title: Red Hat Developer Hub
        baseUrl: https://<my_developer_hub_domain>
      
      backend:
        auth:
          externalAccess:
            - type: legacy
              options:
                subject: legacy-default-config
                secret: "${BACKEND_SECRET}"
        baseUrl: https://<my_developer_hub_domain>
        cors:
          origin: https://<my_developer_hub_domain>
    • Optionally, enter your configuration such as:

  3. Author your custom dynamic-plugins.yaml file to enable plugins. By default, Developer Hub enables a minimal plugin set, and disables plugins that require configuration or secrets, such as the GitHub repository discovery plugin and the Role-based access control (RBAC) plugin.

    Enable the GitHub repository discovery and the RBAC features:

    dynamic.plugins.yaml

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github
        disabled: false
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

  4. Provision your custom configuration files to your AKS cluster.

    1. Create the <my-rhdh-project> namespace aimed at containing your Developer Hub instance.

      $ oc create namespace my-rhdh-project
    2. Create config maps for your app-config.yaml and dynamic-plugins.yaml files in the <my-rhdh-project> project.

      $ oc create configmap my-rhdh-app-config --from-file=app-config.yaml --namespace=my-rhdh-project
      $ oc create configmap dynamic-plugins-rhdh --from-file=dynamic-plugins.yaml --namespace=my-rhdh-project

      You can also create the config maps by using the web console.

    3. Provision your secrets.txt file to the my-rhdh-secrets secret in the <my-rhdh-project> project.

      $ oc create secret generic my-rhdh-secrets --from-file=secrets.txt --namespace=my-rhdh-project

      You can also create the secret by using the web console.

4.3.6.4. Provision a pull secret to access the container registry

On Microsoft Azure Kubernetes Service (AKS), provision your Red Hat Container Registry pull secret in your Red Hat Developer Hub instance namespace because the pull secret is not managed globally.

On Microsoft Azure Kubernetes Service (AKS), the Red Hat Container Registry pull-secret is not managed globally. Therefore add your pull-secret in your Red Hat Developer Hub instance namespace.

Prerequisites

  • Your credentials to the Red Hat Container Registry:

    • <redhat_user_name>
    • <redhat_password>
    • <email>
  • You created the {my-rhdh-project} namespace on AKS to host your Developer Hub instance.

Procedure

  1. Create a pull secret using your Red Hat credentials to pull the container images from the protected Red Hat Container Registry (registry.redhat.io):

    $ kubectl -n {my-rhdh-namespace} create secret docker-registry my-rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<redhat_user_name> \
        --docker-password=<redhat_password> \
        --docker-email=<email>
  2. To enable pulling Developer Hub images from the Red Hat Container Registry, add the image pull secret in the default service account within the namespace where the Developer Hub instance is being deployed:

    $ kubectl patch serviceaccount default \
        -p '{"imagePullSecrets": [{"name": "my-rhdh-pull-secret"}]}' \
        -n {my-rhdh-namespace}

4.3.6.5. Deploy a custom configuration using an Operator

Use the Red Hat Developer Hub Operator to deploy Developer Hub with custom configuration by creating a custom resource that mounts config maps and injects secrets.

Prerequisites

  • By using the Kubernetes CLI ('kubectl'), you have access, with developer permissions, to the AKS cluster aimed at containing your Developer Hub instance.
  • Your administrator has installed the Red Hat Developer Hub Operator in the cluster.
  • You have provisioned your custom config maps and secrets in your <my-rhdh-project> project.
  • You have a working default storage class, such as the Elastic Block Store (EBS) storage add-on, configured in your EKS cluster.

Procedure

  1. Author your Backstage CR in a my-rhdh-custom-resource.yaml file to use your custom config maps and secrets.

    Minimal my-rhdh-custom-resource.yaml custom resource example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh-custom-resource
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
        extraFiles:
          mountPath: /opt/app-root/src
        route:
          enabled: true
      database:
        enableLocalDb: true

    my-rhdh-custom-resource.yaml custom resource example with dynamic plugins and RBAC policies config maps, and external PostgreSQL database secrets:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <my-rhdh-custom-resource>
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
        route:
          enabled: true
      database:
        enableLocalDb: false
    Mandatory fields
    No fields are mandatory. You can create an empty Backstage CR and run Developer Hub with the default configuration.
    Optional fields
    spec.application.appConfig.configMaps
    Enter your config map name list.

    Mount files in the my-rhdh-app-config config map:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config

    Mount files in the my-rhdh-app-config and rbac-policies config maps:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
    spec.application.extraEnvs.envs

    Optionally, enter your additional environment variables that are not secrets, such as your proxy environment variables.

    Inject your HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables:

    spec:
      application:
        extraEnvs:
          envs:
            - name: HTTP_PROXY
              value: 'http://10.10.10.105:3128'
            - name: HTTPS_PROXY
              value: 'http://10.10.10.106:3128'
            - name: NO_PROXY
              value: 'localhost,example.org'
    spec.application.extraEnvs.secrets

    Enter your environment variables secret name list.

    Inject the environment variables in your Red Hat Developer Hub secret:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>

    Inject the environment variables in the Red Hat Developer Hub and my-rhdh-database-secrets secrets:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
    Note

    <my_product_secrets> is your preferred Developer Hub secret name, specifying the identifier for your secret configuration within Developer Hub.

    spec.application.extraFiles.secrets

    Enter your certificates files secret name and files list.

    Mount the postgres-crt.pem, postgres-ca.pem, and postgres-key.key files contained in the my-rhdh-database-certificates-secrets secret:

    spec:
      application:
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
    spec.database.enableLocalDb

    Enable or disable the local PostgreSQL database.

    Disable the local PostgreSQL database generation to use an external postgreSQL database:

    spec:
      database:
        enableLocalDb: false

    On a development environment, use the local PostgreSQL database:

    spec:
      database:
        enableLocalDb: true
    spec.deployment
    Optionally, enter your deployment configuration.
  2. Apply your Backstage CR to start or update your Developer Hub instance:

    $ oc apply --filename=my-rhdh-custom-resource.yaml --namespace=my-rhdh-project

4.3.6.6. Expose your Operator instance using an Ingress resource

On Microsoft Azure Kubernetes Service (AKS), Kubernetes ingresses replace OpenShift Container Platform routes. The Red Hat Developer Hub Operator does not create ingresses. Therefore, to access your Developer Hub instance via a domain name, create the required ingresses on AKS and point your domain name to it.

Prerequisites

  • You have installed Red Hat Developer Hub by using the Red Hat Developer Hub Operator.

Procedure

  1. Create an Ingress manifest file, named rhdh-ingress.yaml, specifying your Developer Hub service name as follows:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-rhdh-ingress
      namespace: my-rhdh-project
    spec:
      ingressClassName: webapprouting.kubernetes.azure.com
      rules:
        - http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: my-rhdh-custom-resource
                    port:
                      name: http-backend
  2. To deploy the created Ingress, run the following command:

    $ kubectl -n my-rhdh-project apply -f rhdh-ingress.yaml

Verification

  • Access the deployed Developer Hub using the URL: https://<app_address>, where <app_address> is the Ingress address obtained earlier (for example, https://108.141.70.228).

4.3.7. Deploy on AKS using the Helm chart

Deploy Developer Hub on AKS by using the Helm chart for building, testing, and deploying applications.

You can deploy your Developer Hub application on Azure Kubernetes Service (AKS) to access a comprehensive solution for building, testing, and deploying applications.

When deploying on AKS, be aware of the following platform-specific considerations:

Permissions
Developer Hub containers might meet permission-related errors, such as Permission denied when attempting certain operations. Address this error by adjusting the fsGroup in the PodSpec.securityContext.
Ingress configuration

Configuring ingress is essential for accessing the installed Developer Hub instance. You must enable the Routing add-on, an NGINX-based Ingress Controller, using the following command:

$ az aks approuting enable --resource-group <your_ResourceGroup> --name <your_ClusterName>
Tip

You might need to install the Azure CLI extension aks-preview. If the extension is not installed automatically, you might need to install it manually using the following command:

$ az extension add --upgrade -n aks-preview --allow-preview true
Note

After you install the Ingress Controller, the system deploys the app-routing-system namespace with the Ingress Controller in your cluster. Note the address of your Developer Hub application from the installed Ingress Controller (for example, 108.141.70.228) for later access to the Developer Hub application, later referenced as <app_address>.

$ kubectl get svc nginx --namespace app-routing-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Namespace management

You can create a dedicated namespace for Developer Hub deployment by using the following command:

$ kubectl create namespace <your_namespace>

Prerequisites

  • You have a Microsoft Azure account with active subscription.
  • You have installed the Azure CLI.
  • You have installed the kubectl CLI.
  • You have logged into your cluster using kubectl, and have developer or admin permissions.
  • You have installed Helm 3 or the latest.
  • Make sure that your system meets the minimum sizing requirements. See Sizing requirements for Red Hat Developer Hub.

Procedure

  1. Log in to AKS by running the following command:

    $ az login [--tenant=<optional_directory_name>]
  2. Create a resource group by running the following command:

    $ az group create --name <resource_group_name> --location <location>
    Tip

    You can list available regions by running the following command:

    $ az account list-locations -o table
  3. Create an AKS cluster by running the following command:

    $ az aks create \
    --resource-group <resource_group_name> \
    --name <cluster_name> \
    --enable-managed-identity \
    --generate-ssh-keys

    You can see --help for additional options.

  4. Connect to your cluster by running the following command:

    $ az aks get-credentials --resource-group <resource_group_name> --name <cluster_name>

    The earlier command configures the Kubernetes client and sets the current context in the kubeconfig to point to your AKS cluster.

  5. Open terminal and run the following command to add the Helm chart repository:

    $ helm repo add openshift-helm-charts https://charts.openshift.io/
  6. Create and activate the <my-rhdh-project> namespace:

    DEPLOYMENT_NAME=<redhat-developer-hub>
    NAMESPACE=<rhdh>
    kubectl create namespace ${NAMESPACE}
    kubectl config set-context --current --namespace=${NAMESPACE}
  7. Create a pull secret to pull the Developer Hub images from the Red Hat Container Registry by running the following command:

    $ kubectl -n $NAMESPACE create secret docker-registry rhdh-pull-secret \
        --docker-server=registry.redhat.io \
        --docker-username=<redhat_user_name> \
        --docker-password=<redhat_password> \
        --docker-email=<email>
  8. Create a file named values.yaml using the following template:

    global:
      host: <app_address>
    route:
      enabled: false
    upstream:
      ingress:
        enabled: true
        className: webapprouting.kubernetes.azure.com
        host:
      backstage:
        image:
          pullSecrets:
            - rhdh-pull-secret
        podSecurityContext:
          fsGroup: 3000
      postgresql:
        image:
          pullSecrets:
            - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            fsGroup: 3000
      volumePermissions:
        enabled: true
  9. To install Developer Hub by using the Helm chart, run the following command:

    $ helm -n $NAMESPACE install -f values.yaml $DEPLOYMENT_NAME openshift-helm-charts/redhat-developer-hub --version 1.10.1
  10. Verify the deployment status:

    $ kubectl get deploy $DEPLOYMENT_NAME -n $NAMESPACE
  11. Configure your Developer Hub Helm chart instance with the Developer Hub database password and router base URL values from your cluster:

    PASSWORD=$(kubectl get secret redhat-developer-hub-postgresql -o jsonpath="{.data.password}" | base64 -d)
    CLUSTER_ROUTER_BASE=$(kubectl get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//')
    helm upgrade $DEPLOYMENT_NAME -i "https://github.com/openshift-helm-charts/charts/releases/download/redhat-redhat-developer-hub-1.10.1/redhat-developer-hub-1.10.1.tgz" \
        --set global.clusterRouterBase="$CLUSTER_ROUTER_BASE" \
        --set global.postgresql.auth.password="$PASSWORD"
  12. Display the running Developer Hub instance URL, by running the following command:

    $ echo "https://$DEPLOYMENT_NAME-$NAMESPACE.$CLUSTER_ROUTER_BASE"

Verification

  • Open the running Developer Hub instance URL in your browser to use Developer Hub.

4.3.8. Install on OpenShift Dedicated using the Operator

Deploy Developer Hub on OpenShift Dedicated on Google Cloud using the Operator for centralized lifecycle management and automated updates.

Prerequisites

  • You have a valid Google Cloud account.
  • Your OpenShift Dedicated cluster is running on Google Cloud. For more information, seeCreating a cluster on GCP in Red Hat OpenShift Dedicated documentation.
  • You have administrator access to OpenShift Dedicated cluster and Google Cloud project.
  • Make sure that your system meets the minimum sizing requirements. See Sizing requirements for Red Hat Developer Hub.

Procedure

  1. In the OpenShift Container Platform web console menu, go to Operators > OperatorHub.
  2. In the Filter by keyword field, enter Developer Hub and click the Red Hat Developer Hub Operator card.
  3. On the Red Hat Developer Hub Operator page, click Install.
  4. After the installation completes, navigate to Installed Operators and select Red Hat Developer Hub Operator.
  5. Provision your custom configuration:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config-rhdh
    data:
      "app-config.yaml": |
        app:
          title: Red Hat Developer Hub
          baseUrl: https://__&lt;my_developer_hub_domain&gt;__
        backend:
          auth:
            externalAccess:
                - type: legacy
                  options:
                    subject: legacy-default-config
                    secret: "${BACKEND_SECRET}"
          baseUrl: https://__&lt;my_developer_hub_domain&gt;__
          cors:
            origin: https://__&lt;my_developer_hub_domain&gt;__

    You must create a config map named app-config-rhdh and a Kubernetes Secret containing the BACKEND_SECRET. These resources are used by the Developer Hub instance for authentication and application settings.

    For further steps, see Provisioning your custom Red Hat Developer Hub configuration.

  6. Create a config map named app-config-rhdh that includes your app-config.yaml as shown:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config-rhdh
    data:
      "app-config.yaml": |
        app:
          title: Red Hat Developer Hub
          baseUrl: https://__&lt;my_developer_hub_domain&gt;__
        backend:
          auth:
            externalAccess:
                - type: legacy
                  options:
                    subject: legacy-default-config
                    secret: "${BACKEND_SECRET}"
          baseUrl: https://__&lt;my_developer_hub_domain&gt;__
          cors:
            origin: https://__&lt;my_developer_hub_domain&gt;__
  7. Create a secret named my-rhdh-secrets and add a key named BACKEND_SECRET with a Base64-encoded string as value:

    apiVersion: v1
    kind: Secret
    metadata:
      name: my-rhdh-secrets
    stringData:
      # TODO: Add the necessary auth secrets for service-to-service auth setup
      BACKEND_SECRET: "xxx" # Replace with your Base64-encoded secret
  8. Return to the Developer Hub Operator page and click Create New Instance.
  9. Specify the name and target namespace for the Developer Hub deployment.
  10. Configure required options such as Git integration, secrets, and user permissions.
  11. Review the configuration, select deployment options, and click Create.

Verification

  • To access the Developer Hub, navigate to the Developer Hub URL provided in the OpenShift Container Platform web console.

4.3.9. Deploy on OpenShift Dedicated using the Helm chart

Deploy Developer Hub on OpenShift Dedicated on Google Cloud using Helm for flexible, customizable configuration management.

Prerequisites

Procedure

  1. From the Developer perspective on the Developer Hub web console, click +Add.
  2. From the Developer Catalog panel, click Helm Chart.
  3. In the Filter by keyword box, enter Developer Hub and click the Red Hat Developer Hub card.
  4. From the Red Hat Developer Hub page, click Create.
  5. From your cluster, copy the OpenShift Container Platform router host (for example: apps.<clusterName>.com).
  6. Select the radio button to configure the Developer Hub instance with either the form view or YAML view.

    Important

    Before deploying Developer Hub using the Helm chart, you must define custom configuration settings such as the public baseUrl for your instance. Without setting baseUrl, the application cannot function correctly. You can define this configuration either through the Form view or the YAML view in the Helm install wizard.

    To configure the baseUrl, set the following values in your Helm configuration:

    global:
      app:
        baseUrl: https://<your-developer-hub-link>
      backend:
        baseUrl: https://<your-developer-hub-link>
        cors:
          origin: https://<your-developer-hub-link>

    You can also define additional secrets, plugins, and advanced configuration in your values.yaml file. For full instructions, see: Provisioning your custom Red Hat Developer Hub configuration.

    The Form view is selected by default.

    1. Using Form view

      1. To configure the instance with the Form view, go to Root Schema → global → Enable service authentication within Backstage instance and paste your OpenShift Container Platform router host into the field on the form.
    2. Using YAML view

      1. To configure the instance with the YAML view, paste your OpenShift Container Platform router hostname in the global.clusterRouterBase parameter value as shown in the following example:

        global:
          auth:
            backend:
              enabled: true
          clusterRouterBase: apps.<clusterName>.com
          # other Red Hat Developer Hub Helm Chart configurations
  7. Edit the other values if needed, then click Create and wait for the database and Developer Hub to start.

Verification

  • To access Developer Hub, click the Open URL icon.

4.4. Install in an air-gapped environment

4.4.1. Install in an air-gapped environment

Install Red Hat Developer Hub in a restricted network environment by following a clear installation path that accounts for fully or partially disconnected infrastructure, so you can get Developer Hub running securely without requiring direct internet access.

4.4.2. Isolated network deployments for air-gapped environments

An air-gapped environment ensures security by physically segregating systems from external networks.

Also known as an air-gapped network or isolated network, this isolation prevents unauthorized access, data transfer, or communication between the air-gapped system and external sources.

You can install the Red Hat Developer Hub in an air-gapped environment to ensure security and meet specific regulatory requirements.

Air-gapped environments fall into two types:

Fully disconnected environment
In environments without internet access, a fully disconnected installation ensures that Red Hat Developer Hub can run reliably without external dependencies. This method requires mirroring images to disk and transferring them manually to the air-gapped environment.
Partially disconnected environment
In a partially disconnected environment, the cluster cannot access external registries, for example, registry.redhat.io, but it can access an internal mirror registry. This method requires direct access to an internal mirror registry from the cluster.

4.4.3. Install in an air-gapped environment using the Operator

4.4.3.1. Install in an air-gapped environment using the Operator

Install Red Hat Developer Hub in fully or partially disconnected environments by using the Operator.

4.4.3.2. Mirror Operator images to deploy in fully disconnected networks

Mirror Operator images to disk and transfer them to a fully disconnected environment without internet access.

In environments without internet access (whether for security, compliance, or operational reasons), a fully disconnected installation ensures that Red Hat Developer Hub can run reliably without external dependencies.

If your network has access to the registry through a bastion host, you can use the helper script to install Red Hat Developer Hub.

Prerequisites

  • You have installed GNU sed, GNU tar 1.35 or later, jq 1.7 or later, the oc-mirror tool (recommended on OpenShift Container Platform), the opm CLI tool, Podman 5.3 or later, Skopeo 1.20 or later, the umoci CLI tool, and yq 4.44 or later on your workstation.
  • You have an active oc registry, podman, or skopeo session to the Red Hat Container Registry (registry.redhat.io).
  • Make sure that your system meets the minimum sizing requirements. See Sizing requirements for Red Hat Developer Hub.

Procedure

  1. Download the mirroring script to disk by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/prepare-restricted-environment.sh
  2. Run the mirroring script by using the bash command with the appropriate set of options:

    $ bash prepare-restricted-environment.sh
     --filter-versions "1.10"
     --to-dir <my_pulled_image_location>
     [--use-oc-mirror true]

    where:

    --to-dir <my_pulled_image_location>
    Enter the absolute path to a directory where you want to pull all of the necessary images, for example, /home/user/rhdh-operator-mirror-dir.
    --use-oc-mirror true

    (Recommended on OpenShift Container Platform) Use the oc-mirror OpenShift Container Platform CLI plugin to mirror images.

    Note

    The script can take several minutes to complete as it copies many images to the mirror registry.

  3. Transfer the directory specified by the --to-dir option to your disconnected environment.
  4. From a machine in your disconnected environment that has access to both the cluster and the target mirror registry, run the mirroring script by using the bash command with the appropriate set of options:

    $ bash <my_pulled_image_location>/install.sh
        --from-dir <my_pulled_image_location>
        [--to-registry <my.registry.example.com>]
        [--use-oc-mirror true]

    where:

    <my_pulled_image_location>/install.sh
    Enter the downloaded installation script and the absolute path to the directory where you stored it on your system.
    --from-dir <my_pulled_image_location>
    Enter the directory where you want to pull all of the necessary images.
    --to-registry
    (Optional) Enter the URL for the target mirror registry where you want to mirror the images.
    --use-oc-mirror true

    Recommended on OpenShift Container Platform: Use the oc mirror OpenShift Container Platform CLI plugin to mirror images.

    Important

    If you used oc mirror to mirror the images to disk, you must also use oc mirror to mirror the images from disk due to the folder layout that oc mirror uses.

    Note

    The script can take several minutes to complete as it automatically installs the Red Hat Developer Hub Operator.

  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Export the plugin catalog index and all referenced plugin OCI artifacts to disk by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-dir <my_plugin_mirror_dir>

    where:

    <my_plugin_mirror_dir>

    Enter the absolute path to a directory where you want to export the plugin artifacts, for example, /home/user/rhdh-plugins-mirror.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  3. Transfer the directory specified by the --to-dir option to your disconnected environment.
  4. From a machine in your disconnected environment that has access to the target mirror registry, import the plugin artifacts by running the following command:

    $ bash mirror-plugins.sh \
      --from-dir <my_plugin_mirror_dir> \
      --to-registry <target_registry>

    where:

    <my_plugin_mirror_dir>
    Enter the path to the directory containing the exported plugin artifacts.
    <target_registry>
    Enter the URL of the target mirror registry, for example, registry.example.com.
  1. Create a config map containing a registries.conf file that redirects the install-dynamic-plugins init container to your mirror registry:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-plugin-mirror-conf
    data:
      rhdh-registries.conf: |
        [[registry]]
        prefix = "registry.access.redhat.com/rhdh"
        location = "<target_registry>/rhdh"
    
        [[registry]]
        prefix = "quay.io/rhdh"
        location = "<target_registry>/rhdh"

    where:

    <target_registry>
    Enter the URL of your mirror registry, for example, registry.example.com.
  2. Mount the config map in the install-dynamic-plugins init container by adding the following to your Backstage CR:

    spec:
      application:
        extraFiles:
          configMaps:
            - name: rhdh-plugin-mirror-conf
              key: rhdh-registries.conf
              mountPath: /etc/containers/registries.conf.d
              containers:
                - install-dynamic-plugins
    Note

    Cluster-level mirroring resources such as ImageDigestMirrorSet or ImageContentSourcePolicy do not apply to the install-dynamic-plugins init container because it uses skopeo directly to pull plugin artifacts.

  3. Optional: To enforce signature verification in production environments, create a policy.json config map and mount it in the install-dynamic-plugins init container:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-mirror-policy
    data:
      policy.json: |
        {
          "transports": {
            "docker": {
              "<target_registry>/<namespace>": [
                {
                  "type": "signedBy",
                  "keyType": "GPGKeys",
                  "keyPath": "<path_to_gpg_key>"
                }
              ]
            }
          }
        }

    Then add the following to the extraFiles.configMaps list in your Backstage CR:

            - name: rhdh-mirror-policy
              key: policy.json
              mountPath: /etc/containers
              containers:
                - install-dynamic-plugins

    For a full example CR showing how to configure plugin mirroring when using the Operator, see plugin-mirroring.yaml.

Verification

  1. If you are using Red Hat OpenShift Container Platform, the Red Hat Developer Hub Operator is in the Installed Operators list in the web console.
  2. If you are using a supported Kubernetes platform, you can check the list of pods running in the rhdh-operator namespace by running the following command in your terminal:

    kubectl -n rhdh-operator get pods

Next steps

  1. Use the Operator to create a Red Hat Developer Hub instance on a supported platform. For more information, see the following documentation for the platform that you want to use:

4.4.3.3. Mirror Operator images to local registries for partially disconnected networks

Mirror Operator images directly to a target registry in a partially disconnected environment.

On an OpenShift Container Platform cluster operating on a restricted network, public resources are not available. However, deploying the Red Hat Developer Hub Operator and running Developer Hub requires the following public resources:

  • Operator images (bundle, operator, catalog)
  • Operands images (RHDH, PostgreSQL)

To make these resources available, replace them with their equal resources in a mirror registry accessible to your cluster.

You can use a helper script that mirrors the necessary images and provides the necessary configuration to ensure the system uses those images when installing the Red Hat Developer Hub Operator and creating Developer Hub instances. This script requires a target mirror registry. You likely have a target mirror registry if your cluster is already operating on a disconnected network. If you do not already have a target registry, and if you have an OpenShift Container Platform cluster, you might want to expose and use the internal cluster registry.

When connected to a OpenShift Container Platform cluster, the helper script detects it and automatically exposes the cluster registry. If connected to a Kubernetes cluster, you can manually specify the target registry to mirror the images.

Prerequisites

  • You have installed GNU sed, GNU tar 1.35 or later, jq 1.7 or later, the opm CLI tool, Podman 5.3 or later, Skopeo 1.20 or later, the umoci CLI tool, and yq 4.44 or later on your workstation.
  • You have an active oc registry, podman, or skopeo session to the Red Hat Container Registry (registry.redhat.io).
  • You have an active Skopeo session with administrative access to the target mirror registry.
  • If you are using an OpenShift Container Platform cluster, you have the following prerequisites:

    • Recommended: You have installed the oc-mirror tool, with a version corresponding to the version of your OpenShift Container Platform cluster.
  • If you are using a supported Kubernetes cluster, you have the following prerequisites:

    • You have installed the Operator Lifecycle Manager (OLM) on the disconnected cluster.
    • You have a mirror registry that is reachable from the disconnected cluster.
  • Make sure that your system meets the minimum sizing requirements. See Sizing requirements for Red Hat Developer Hub.

Procedure

  1. In your terminal, navigate to the directory where you want to save the mirroring script.
  2. Download the mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/prepare-restricted-environment.sh
  3. Run the mirroring script by using the bash command with the appropriate set of options:

    $ bash prepare-restricted-environment.sh \
     --filter-versions "1.10" \
      [--to-registry <my.registry.example.com>] \
      [--use-oc-mirror true]

    where:

    --to-registry _<my.registry.example.com>
    Enter the URL for the target mirror registry where you want to mirror the images.
    --use-oc-mirror true

    Optional: Use the oc mirror OpenShift Container Platform CLI plugin to mirror images.

    Note

    The script can take several minutes to complete as it copies many images to the mirror registry.

  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Mirror the plugin catalog index and all referenced plugin OCI artifacts to your target registry by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-registry <target_registry>

    where:

    <target_registry>

    Enter the URL of the target mirror registry, such as, registry.example.com.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  1. Create a config map containing a registries.conf file that redirects the install-dynamic-plugins init container to your mirror registry:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-plugin-mirror-conf
    data:
      rhdh-registries.conf: |
        [[registry]]
        prefix = "registry.access.redhat.com/rhdh"
        location = "<target_registry>/rhdh"
    
        [[registry]]
        prefix = "quay.io/rhdh"
        location = "<target_registry>/rhdh"

    where:

    <target_registry>
    Enter the URL of your mirror registry, for example, registry.example.com.
  2. Mount the config map in the install-dynamic-plugins init container by adding the following to your Backstage CR:

    spec:
      application:
        extraFiles:
          configMaps:
            - name: rhdh-plugin-mirror-conf
              key: rhdh-registries.conf
              mountPath: /etc/containers/registries.conf.d
              containers:
                - install-dynamic-plugins
    Note

    Cluster-level mirroring resources such as ImageDigestMirrorSet or ImageContentSourcePolicy do not apply to the install-dynamic-plugins init container because it uses skopeo directly to pull plugin artifacts.

  3. Optional: To enforce signature verification in production environments, create a policy.json config map and mount it in the install-dynamic-plugins init container:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-mirror-policy
    data:
      policy.json: |
        {
          "transports": {
            "docker": {
              "<target_registry>/<namespace>": [
                {
                  "type": "signedBy",
                  "keyType": "GPGKeys",
                  "keyPath": "<path_to_gpg_key>"
                }
              ]
            }
          }
        }

    Then add the following to the extraFiles.configMaps list in your Backstage CR:

            - name: rhdh-mirror-policy
              key: policy.json
              mountPath: /etc/containers
              containers:
                - install-dynamic-plugins

    For a full example CR showing how to configure plugin mirroring when using the Operator, see plugin-mirroring.yaml.

Verification

  1. If you are using Red Hat OpenShift Container Platform, the Red Hat Developer Hub Operator is in the Installed Operators list in the web console.
  2. If you are using a supported Kubernetes platform, you can check the list of pods running in the rhdh-operator namespace by running the following command in your terminal:

    $ kubectl -n rhdh-operator get pods

Next steps

  1. Use the Operator to create a Red Hat Developer Hub instance on a supported platform. For more information, see the following documentation for the platform that you want to use:

4.4.4. Deploy on OpenShift using Helm in an air-gapped environment

4.4.4.1. Deploy on OpenShift using Helm in an air-gapped environment

Install Red Hat Developer Hub on OpenShift Container Platform in fully or partially disconnected environments by using the Helm chart.

4.4.4.2. Mirror Helm images to deploy in fully disconnected OpenShift networks

Mirror Helm chart images to disk and transfer them to a fully disconnected OpenShift Container Platform environment.

If your network has access to the registry through a bastion host, you can use the Helm chart to install Red Hat Developer Hub.

Prerequisites

  • You have set up your workstation.

    • You have an account in Red Hat Developer portal.
    • You have access to the charts.openshift.io Helm chart repository.
    • You have installed GNU tar 1.35 or later, jq 1.7 or later, the OpenShift CLI (oc), the oc-mirror OpenShift CLI plugin v2, and Skopeo 1.20 or later on your workstation.
  • You have set up your intermediary host.

    • Your host has access to the Red Hat Container Registry (registry.redhat.io).
    • Your host has access to image registry on the destination host. For more information, see the Exposing the registry topic in the OpenShift Container Platform documentation.
  • You have set up your destination host.

Procedure

  1. Create an ImageSetConfiguration file to specify the resources that you want to mirror. For example:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      helm:
        repositories:
          - name: openshift-charts
            url: https://charts.openshift.io
            charts:
              - name: redhat-developer-hub
                version: "1.10"

    where:

    version: "1.10"
    Enter the Red Hat Developer Hub version to mirror.
  2. Mirror the resources specified in the ImageSetConfiguration.yaml file by running the oc mirror command. For example:

    $ oc mirror --v2 -c <mirror_config_directory>/ImageSetConfiguration.yaml file://<mirror_archive_directory>/

    where:

    <mirror_config_directory>
    Enter the location of your image set configuration file on your system, for example, .user.
    <mirror_archive_directory>
    Enter the location of your directory where the system creates the mirror archive, for example, file://.user.
    Note
    1. The --v2 flag is required for OpenShift Container Platform 4.21 and later.
    2. Running the oc mirror command generates a local workspace containing the mirror archive file, the Helm chart, ImageDigestMirrorSet (IDMS) and ImageTagMirrorSet (ITMS) manifests. The IDMS and ITMS manifests contain files that you must apply against the cluster in a later step.

    Example output:

    Creating archive /path/to/mirror-archive/mirror_seq1_000000.tar
  3. Transfer the generated archive file (for example, mirror_seq1_000000.tar) to the air-gapped environment.
  4. Connect to your air-gapped environment and make sure that you are also connected to the following objects:
  5. The local target registry
  6. The target OpenShift Container Platform cluster
  7. From your air-gapped environment, mirror the resources from the archive to the target registry by running the oc mirror command. For example:

    $ oc mirror --v2 -c <image_set_config> --from file://<mirror_archive_directory> docker://<target_registry>

    where:

    <mirror_archive_file>
    Enter the name of the file containing the resources that you want to mirror, for example,mirror_seq1_0000.tar.
    <target_registry>
    Enter the name of the target registry that you want to push the mirrored images to, for example, docker://registry.localhost:5000.
  8. In your workspace, locate the IDMS and ITMS files by running the following command. For example:

    $ ls <workspace_directory>/working-dir/cluster-resources/

    where:

    <workspace_directory>
    Specifies the name of your workspace directory, for example, oc-mirror-workspace.
    <results_directory>
    Specifies the name of your results directory, for example, results-1738070846.
  9. To mirror the Helm chart, deploy the IDMS and ITMS files in the disconnected cluster by running the oc apply command. For example:

    $ oc apply -f <workspace_directory>/working-dir/cluster-resources

    where:

    <workspace_directory>
    Enter the name of your workspace directory, for example, oc-mirror-workspace.
    <results_directory>
    Enter the name of your results directory, for example, results-1738070846.
  10. In your air-gapped environment, deploy the Helm chart to the namespace that you want to use by running the helm install command with namespace and set options. For example:

    CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/[.]*\.//') helm install <rhdh_instance> <workspace_directory>/working-dir/helm/charts/<archive_file> --namespace <your_namespace> --create-namespace \ --set global.clusterRouterBase="$CLUSTER_ROUTER_BASE"

    where:

    <rhdh_instance>
    Enter the name of your Red Hat Developer Hub instance, for example, my-rhdh-project.
    <workspace_directory>
    Enter the name of your workspace directory, for example, oc-mirror-workspace.
    <results_directory>
    Enter the name of your results directory, for example, results-1738070846.
    <archive_file>
    Enter the name of the archive file containing the resources that you want to mirror, for example, redhat-developer-hub-1.4.1.tgz.
    <your_namespace>
    Enter the namespace that you want to deploy the Helm chart to, for example, my-rhdh-project.
  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Export the plugin catalog index and all referenced plugin OCI artifacts to disk by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-dir <my_plugin_mirror_dir>

    where:

    <my_plugin_mirror_dir>

    Enter the absolute path to a directory where you want to export the plugin artifacts, for example, /home/user/rhdh-plugins-mirror.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  3. Transfer the directory specified by the --to-dir option to your disconnected environment.
  4. From a machine in your disconnected environment that has access to the target mirror registry, import the plugin artifacts by running the following command:

    $ bash mirror-plugins.sh \
      --from-dir <my_plugin_mirror_dir> \
      --to-registry <target_registry>

    where:

    <my_plugin_mirror_dir>
    Enter the path to the directory containing the exported plugin artifacts.
    <target_registry>
    Enter the URL of the target mirror registry, for example, registry.example.com.
  1. Create a config map containing a registries.conf file that redirects the install-dynamic-plugins init container to your mirror registry:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-plugin-mirror-conf
    data:
      rhdh-registries.conf: |
        [[registry]]
        prefix = "registry.access.redhat.com/rhdh"
        location = "<target_registry>/rhdh"
    
        [[registry]]
        prefix = "quay.io/rhdh"
        location = "<target_registry>/rhdh"

    where:

    <target_registry>
    Enter the URL of your mirror registry, for example, registry.example.com.
  2. Mount the config map in the install-dynamic-plugins init container by adding the following to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-plugin-mirror-conf
            configMap:
              name: rhdh-plugin-mirror-conf
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-plugin-mirror-conf
                mountPath: /etc/containers/registries.conf.d/rhdh-registries.conf
                subPath: rhdh-registries.conf
                readOnly: true
    Important

    Because of Helm merge limitations, you must include all existing default volumes, volume mounts, and init container fields from the Red Hat Developer Hub Helm chart alongside your additions. Omitting the defaults overwrites them and can break the deployment.

    Note

    Cluster-level mirroring resources, such as ImageDigestMirrorSet or ImageContentSourcePolicy, do not apply to the install-dynamic-plugins init container because it uses skopeo directly to pull plugin artifacts.

  3. Optional: To enforce signature verification in production environments, create a policy.json config map and mount it in the install-dynamic-plugins init container:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-mirror-policy
    data:
      policy.json: |
        {
          "transports": {
            "docker": {
              "<target_registry>/<namespace>": [
                {
                  "type": "signedBy",
                  "keyType": "GPGKeys",
                  "keyPath": "<path_to_gpg_key>"
                }
              ]
            }
          }
        }

    Then add the following volumes and volume mount entries to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-mirror-policy
            configMap:
              name: rhdh-mirror-policy
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-mirror-policy
                mountPath: /etc/containers/policy.json
                subPath: policy.json
                readOnly: true

4.4.4.3. Mirror Helm images to local registries for partially disconnected networks

Mirror Helm chart images directly to a target registry in a partially disconnected OpenShift Container Platform environment.

If your network has access to the registry.redhat.io registry and the charts.openshift.io Helm chart repository, you can deploy your Red Hat Developer Hub instance in your partially disconnected environment.

Prerequisites

  • You have installed Red Hat OpenShift Container Platform 4.18 or later.
  • You have access to the charts.openshift.io Helm chart repository.
  • You have access to the registry.redhat.io.
  • You have access to a mirror registry that the disconnected cluster can reach, for example, the OpenShift Container Platform image registry.
  • You have logged in to your target mirror registry and have permissions to push images to it.
  • You have installed GNU tar 1.35 or later, jq 1.7 or later, the OpenShift CLI (oc), the oc-mirror OpenShift CLI plugin v2 (recommended), and Skopeo 1.20 or later on your workstation.
  • You have an account in Red Hat Developer portal.
  • Make sure that your system meets the minimum sizing requirements. See Sizing requirements for Red Hat Developer Hub.

Procedure

  1. Log in to your OpenShift Container Platform account using the OpenShift CLI (oc) by running the following command:

    $ oc login -u <user> -p <password> https://api.<hostname>:6443
  2. From your disconnected cluster, log in to the image registry that you want to mirror, for example, the OpenShift Container Platform image registry.
  3. Create an ImageSetConfiguration.yaml file to specify the resources that you want to mirror. For example:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      helm:
        repositories:
          - name: openshift-charts
            url: https://charts.openshift.io
            charts:
              - name: redhat-developer-hub
                version: "1.10"
    version: "1.10"
    Enter the Red Hat Developer Hub version to mirror.
  4. Mirror the resources specified in the image set configuration file directly to the target registry by running the oc mirror command. For example:

    $ oc mirror --v2 --config=<mirror_config_directory>/ImageSetConfiguration.yaml docker://<target_mirror_registry>

    where:

    <mirror_config_directory>
    Specifies the location of your image set configuration file on your system, for example, .user.
    <target_mirror_registry>
    Specifies the location and name of your target mirror registry, for example, registry.example:5000.
    Note
    1. The --v2 flag is required for OpenShift Container Platform 4.21 and later.
    2. Running the oc mirror command generates a local workspace containing the Helm chart, ImageDigestMirrorSet (IDMS) and ImageTagMirrorSet (ITMS) manifests. The IDMS and ITMS manifests contain files that you must apply against the cluster in a later step.
  5. In your workspace, locate the ImageDigestMirrorSet (IDMS) and ImageTagMirrorSet (ITMS) files by running the ls command. For example:

    $ ls <workspace_directory>/working-dir/cluster-resources/

    where:

    <workspace_directory>
    Specifies the name of your workspace directory, for example, oc-mirror-workspace.
    <results_directory>
    Specifies the name of your results directory, for example, results-1738070846.
  6. To configure image mirroring, deploy the IDMS and ITMS files in the disconnected cluster by running the oc apply command. For example:

    $ oc apply -f <workspace_directory>/working-dir/cluster-resources

    where:

    <workspace_directory>
    Enter the name of your workspace directory, for example, oc-mirror-workspace.
    <results_directory>
    Enter the name of your results directory, for example, results-1738070846.
  7. In your air-gapped environment, deploy the Helm chart to the namespace that you want to use by running the helm install command with namespace and set options. For example:

    CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/[.]*\.//')
    
    helm install <rhdh_instance> <workspace_directory>/<results_directory>/charts/<archive_file> --namespace <your_namespace> --create-namespace \
      --set global.clusterRouterBase="$CLUSTER_ROUTER_BASE"

    where:

    <rhdh_instance>
    Specifies the name of your Red Hat Developer Hub instance, for example, my-rhdh.
    <workspace_directory>
    Specifies the name of your workspace directory, for example, oc-mirror-workspace.
    <results_directory>
    Specifies the name of your results directory, for example, results-1738070846.
    <archive_file>
    Specifies the name of the archive file containing the resources that you want to mirror, for example, redhat-developer-hub-1.4.1.tgz.
    <your_namespace>
    Specifies the namespace that you want to deploy the Helm chart to, for example, my-rhdh-project.
  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Mirror the plugin catalog index and all referenced plugin OCI artifacts to your target registry by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-registry <target_registry>

    where:

    <target_registry>

    Enter the URL of the target mirror registry, such as, registry.example.com.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  1. Create a config map containing a registries.conf file that redirects the install-dynamic-plugins init container to your mirror registry:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-plugin-mirror-conf
    data:
      rhdh-registries.conf: |
        [[registry]]
        prefix = "registry.access.redhat.com/rhdh"
        location = "<target_registry>/rhdh"
    
        [[registry]]
        prefix = "quay.io/rhdh"
        location = "<target_registry>/rhdh"

    where:

    <target_registry>
    Enter the URL of your mirror registry, for example, registry.example.com.
  2. Mount the config map in the install-dynamic-plugins init container by adding the following to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-plugin-mirror-conf
            configMap:
              name: rhdh-plugin-mirror-conf
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-plugin-mirror-conf
                mountPath: /etc/containers/registries.conf.d/rhdh-registries.conf
                subPath: rhdh-registries.conf
                readOnly: true
    Important

    Because of Helm merge limitations, you must include all existing default volumes, volume mounts, and init container fields from the Red Hat Developer Hub Helm chart alongside your additions. Omitting the defaults overwrites them and can break the deployment.

    Note

    Cluster-level mirroring resources, such as ImageDigestMirrorSet or ImageContentSourcePolicy, do not apply to the install-dynamic-plugins init container because it uses skopeo directly to pull plugin artifacts.

  3. Optional: To enforce signature verification in production environments, create a policy.json config map and mount it in the install-dynamic-plugins init container:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-mirror-policy
    data:
      policy.json: |
        {
          "transports": {
            "docker": {
              "<target_registry>/<namespace>": [
                {
                  "type": "signedBy",
                  "keyType": "GPGKeys",
                  "keyPath": "<path_to_gpg_key>"
                }
              ]
            }
          }
        }

    Then add the following volumes and volume mount entries to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-mirror-policy
            configMap:
              name: rhdh-mirror-policy
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-mirror-policy
                mountPath: /etc/containers/policy.json
                subPath: policy.json
                readOnly: true

4.4.5. Deploy on Kubernetes platforms using Helm in air-gapped environments

4.4.5.1. Deploy on Kubernetes platforms using Helm in air-gapped environments

Install Red Hat Developer Hub on supported Kubernetes platforms in fully or partially disconnected environments by using the Helm chart.

Supported Kubernetes platforms include the following:

  • Microsoft Azure Kubernetes Service
  • Amazon Elastic Kubernetes Service
  • Google Kubernetes Engine

4.4.5.2. Mirror Helm images to deploy in fully disconnected Kubernetes networks

Mirror Helm chart images to disk and transfer them to a fully disconnected Kubernetes environment.

In environments without internet access, a fully disconnected installation ensures that Red Hat Developer Hub can run reliably without external dependencies.

Prerequisites

  • You have installed GNU tar 1.35 or later, Helm 3.13 or later, jq 1.7 or later, Skopeo 1.20 or later, and yq 4.4 or later on your workstation.
  • You authenticated to registry.redhat.io for pulling images by using the skopeo login command.
  • You have access to the Kubernetes cluster with kubectl configured.

Procedure

  1. On the mirroring host, in a terminal, fetch the Helm charts values by running the following commands:

    $ helm repo add <helm_chart_repo_name> https://charts.openshift.io/
    $ helm repo update
    $ helm show values <helm_chart_repo_name>/redhat-developer-hub --version <rhdh_version>  values.default.yaml
    $ helm pull <helm_chart_repo_name>/redhat-developer-hub --version <rhdh_version>

    where

    <helm_chart_repo_name>
    Specifies the name of the Helm chart repository, for example, openshift-helm-charts.
    <rhdh_version>

    Specifies the Red Hat Developer Hub version that you want to use, for example, 1.10.1.

    Note

    The helm pull <helm_chart_repo_name>/redhat-developer-hub --version <rhdh_version> command automatically creates the Helm chart archive file and downloads the Helm chart to your current working directory.

  2. Extract the image digests by running the following commands:

    RHDH_IMAGE=$(yq '.upstream.backstage.image | .registry + "/" + .repository' values.default.yaml)
    RHDH_DIGEST=$(yq '.upstream.backstage.image.tag' values.default.yaml)
    PG_IMAGE=$(yq '.upstream.postgresql.image | .registry + "/" + .repository' values.default.yaml)
    PG_DIGEST=$(yq '.upstream.postgresql.image.tag' values.default.yaml)
  3. Mirror the images to your local archive by running the following commands:

    $ skopeo login registry.redhat.io
    $ skopeo copy --all docker://$RHDH_IMAGE}:$RHDH_DIGEST} dir:./rhdh-hub
    $ skopeo copy --all docker://${PG_IMAGE}:${PG_DIGEST} dir:./postgresql
  4. Transfer the following files and directories to your air-gapped environment:
  5. rhdh-hub directory containing the mirrored Red Hat Developer Hub image.
  6. postgresql directory containing the mirrored PostgreSQL image.
  7. Helm chart archive file, for example, redhat-developer-hub-1.10.1.tgz.
  8. Load the images onto the air-gapped host by running the following commands:

    $ skopeo copy --all dir:./rhdh-hub docker://<mirror_registry_name>/<rhdh_repo_name>:$RHDH_DIGEST}
    
    $ skopeo copy --all dir:./postgresql docker://<mirror_registry_name>/<postgresql_repo_name>:${PG_DIGEST}

    where

    <mirror_registry_name>
    Specifies the name of the target mirror registry that you want to push the images to, for example, registry.example.com.
    <rhdh_repo_name>
    Specifies the name of the repository that stores your Red Hat Developer Hub image, for example, rhdh/rhdh-hub-rhel9. This value must match the name of the Red Hat Developer Hub image that you loaded onto the air-gapped host.
    <postgresql_repo_name>
    Specifies the name of the repository that stores your PostgreSQL image, for example, rhdh/postgresql-15.
  9. Create a values.yaml file for the Kubernetes platform that you want to use and add the following image references to the file to reflect local use:

    upstream:
      backstage:
        image:
          registry: "<mirror_registry_name>"
          repository: <rhdh_repo_name>
          tag: "$RHDH_DIGEST}"
    
      postgresql:
        image:
          registry: "<mirror_registry_name>"
          repository: <postgresql_repo_name>
          tag: "${PG_DIGEST}"

    where

    <mirror_registry_name>
    Specifies the name of the target mirror registry that you want to push the images to, for example, registry.example.com.
    <rhdh_repo_name>
    Specifies the name of the repository that stores your Red Hat Developer Hub image, for example, rhdh/rhdh-hub-rhel9. This value must match the name of the Red Hat Developer Hub image that you loaded onto the air-gapped host.
    <postgresql_repo_name>
    Specifies the name of the repository that stores your PostgreSQL image, for example, rhdh/postgresql-15.
  10. For AKS, use the following values.yaml file template:

    global:
      host: <app_address>
    route:
      enabled: false
    upstream:
      ingress:
        enabled: true
        className: webapprouting.kubernetes.azure.com
        host:
      backstage:
        image:
          pullSecrets:
            - rhdh-pull-secret
        podSecurityContext:
          fsGroup: 3000
      postgresql:
        image:
          pullSecrets:
            - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            fsGroup: 3000
      volumePermissions:
        enabled: true
  11. For EKS, use the following values.yaml file template:

    global:
      # TODO: Set your application domain name.
      host: <my_developer_hub_domain>
    
    route:
      enabled: false
    
    upstream:
      service:
        # NodePort is required for the ALB to route to the Service
        type: NodePort
    
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: alb
    
          alb.ingress.kubernetes.io/scheme: internet-facing
    
          # TODO: Using an ALB HTTPS Listener requires a certificate for your own domain. Fill in the ARN of your certificate, e.g.:
          alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:xxx:xxxx:certificate/xxxxxx
    
          alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    
          alb.ingress.kubernetes.io/ssl-redirect: '443'
    
          # TODO: Set your application domain name.
          external-dns.alpha.kubernetes.io/hostname: <your rhdh domain name>
    
      backstage:
        image:
          pullSecrets:
          - rhdh-pull-secret
        podSecurityContext:
          # you can assign any random value as fsGroup
          fsGroup: 2000
      postgresql:
        image:
          pullSecrets:
          - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            # you can assign any random value as fsGroup
            fsGroup: 3000
      volumePermissions:
        enabled: true
  12. For GKE, use the following values.yaml file template:

    global:
      host: <rhdh_domain_name>
    route:
      enabled: false
    upstream:
      service:
        type: NodePort
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: gce
          kubernetes.io/ingress.global-static-ip-name: <ADDRESS_NAME>
          networking.gke.io/managed-certificates: <rhdh_certificate_name>
          networking.gke.io/v1beta1.FrontendConfig: <ingress_security_config>
        className: gce
      backstage:
        image:
          pullSecrets:
          - rhdh-pull-secret
        podSecurityContext:
          fsGroup: 2000
      postgresql:
        image:
          pullSecrets:
          - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            fsGroup: 3000
      volumePermissions:
        enabled: true
  13. Install the Helm chart in the current namespace by running the following command:

    $ helm install rhdh ./<helm_chart_archive_file_name> -f values.yaml

    where

    <helm_chart_archive_file_name>
    Specifies the name of the Helm chart archive file, for example, redhat-developer-hub-1.4.0.tgz.
  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Export the plugin catalog index and all referenced plugin OCI artifacts to disk by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-dir <my_plugin_mirror_dir>

    where:

    <my_plugin_mirror_dir>

    Enter the absolute path to a directory where you want to export the plugin artifacts, for example, /home/user/rhdh-plugins-mirror.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  3. Transfer the directory specified by the --to-dir option to your disconnected environment.
  4. From a machine in your disconnected environment that has access to the target mirror registry, import the plugin artifacts by running the following command:

    $ bash mirror-plugins.sh \
      --from-dir <my_plugin_mirror_dir> \
      --to-registry <target_registry>

    where:

    <my_plugin_mirror_dir>
    Enter the path to the directory containing the exported plugin artifacts.
    <target_registry>
    Enter the URL of the target mirror registry, for example, registry.example.com.
  1. Create a config map containing a registries.conf file that redirects the install-dynamic-plugins init container to your mirror registry:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-plugin-mirror-conf
    data:
      rhdh-registries.conf: |
        [[registry]]
        prefix = "registry.access.redhat.com/rhdh"
        location = "<target_registry>/rhdh"
    
        [[registry]]
        prefix = "quay.io/rhdh"
        location = "<target_registry>/rhdh"

    where:

    <target_registry>
    Enter the URL of your mirror registry, for example, registry.example.com.
  2. Mount the config map in the install-dynamic-plugins init container by adding the following to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-plugin-mirror-conf
            configMap:
              name: rhdh-plugin-mirror-conf
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-plugin-mirror-conf
                mountPath: /etc/containers/registries.conf.d/rhdh-registries.conf
                subPath: rhdh-registries.conf
                readOnly: true
    Important

    Because of Helm merge limitations, you must include all existing default volumes, volume mounts, and init container fields from the Red Hat Developer Hub Helm chart alongside your additions. Omitting the defaults overwrites them and can break the deployment.

    Note

    Cluster-level mirroring resources, such as ImageDigestMirrorSet or ImageContentSourcePolicy, do not apply to the install-dynamic-plugins init container because it uses skopeo directly to pull plugin artifacts.

  3. Optional: To enforce signature verification in production environments, create a policy.json config map and mount it in the install-dynamic-plugins init container:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-mirror-policy
    data:
      policy.json: |
        {
          "transports": {
            "docker": {
              "<target_registry>/<namespace>": [
                {
                  "type": "signedBy",
                  "keyType": "GPGKeys",
                  "keyPath": "<path_to_gpg_key>"
                }
              ]
            }
          }
        }

    Then add the following volumes and volume mount entries to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-mirror-policy
            configMap:
              name: rhdh-mirror-policy
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-mirror-policy
                mountPath: /etc/containers/policy.json
                subPath: policy.json
                readOnly: true

4.4.5.3. Mirror Helm images to local registries for partially disconnected Kubernetes networks

Mirror Helm chart images directly to a target registry in a partially disconnected Kubernetes environment.

In a partially disconnected environment, the cluster cannot access external registries, for example, registry.redhat.io, but it can access an internal mirror registry. This method requires direct access to an internal mirror registry from the cluster.

Prerequisites

  • You have set up your workstation.

    • You have installed GNU tar 1.35 or later, Helm 3.13 or later, jq 1.7 or later, Skopeo 1.20 or later, and yq 4.4 or later.
    • You have an active Skopeo session against registry.redhat.io
    • You have an active Skopeo session against your target mirror registry, for example, registry.internal.example.com
    • You have access to the Kubernetes cluster with kubectl configured

Procedure

  1. In a terminal, download and extract the Helm chart by running the following commands:

    $ helm repo add <helm_chart_repo_name> https://charts.openshift.io/
    $ helm repo update
    $ helm pull <helm_chart_repo_name>/redhat-developer-hub --version <rhdh_version>
    $ helm show values <helm_chart_repo_name>/redhat-developer-hub --version <rhdh_version> > values.default.yaml

    where:

    <helm_chart_repo_name>
    Enter the name of the Helm chart repository, for example, openshift-helm-charts.
    <rhdh_version>
    Enter the Red Hat Developer Hub version that you want to use, for example, 1.10.1.
  2. Use yq to extract the image digests by running the following commands:

    RHDH_IMAGE=$(yq '.upstream.backstage.image | .registry + "/" + .repository' values.default.yaml)
    RHDH_DIGEST=$(yq '.upstream.backstage.image.tag' values.default.yaml)
    PG_IMAGE=$(yq '.upstream.postgresql.image | .registry + "/" + .repository' values.default.yaml)
    PG_DIGEST=$(yq '.upstream.postgresql.image.tag' values.default.yaml)
  3. Mirror the images to the internal mirror registry by entering the following commands:

    $ skopeo login registry.redhat.io
    
    $ skopeo login _<mirror_registry_name>_
    
    $ skopeo copy --remove-signatures \
      docker://${PG_IMAGE}@${PG_DIGEST} \
      docker://_<mirror_registry_name>_/_<postgresql_repo_name>_:${PG_DIGEST}
    
    $ skopeo copy --remove-signatures \
      docker://$RHDH_IMAGE}@$RHDH_DIGEST} \
      docker://_<mirror_registry_name>_/_<rhdh_repo_name>_$RHDH_DIGEST}

    where

    <mirror_registry_name>
    Specifies the name of the internal mirror registry, for example, registry.internal.example.com.
    <postgresql_repo_name>
    Specifies the name of the PostgreSQL repository, for example, rhdh/postgresql-15.
    <rhdh_repo_name>
    Specifies the name of the Red Hat Developer Hub repository, for example, rhdh/rhdh-hub-rhel9.
  4. Create a values.yaml file for the Kubernetes platform that you want to use and add the following image references to the file to reflect local use:

    upstream:
      backstage:
        image:
          registry: "_<mirror_registry_name>_"
          repository: _<rhdh_repo_name>_
          tag: "$RHDH_DIGEST}"
    
      postgresql:
        image:
          registry: "_<mirror_registry_name>_"
          repository: _<postgresql_repo_name>_
          tag: "${PG_DIGEST}"
  5. For AKS, use the following values.yaml file template:

    global:
      host: <app_address>
    route:
      enabled: false
    upstream:
      ingress:
        enabled: true
        className: webapprouting.kubernetes.azure.com
        host:
      backstage:
        image:
          pullSecrets:
            - rhdh-pull-secret
        podSecurityContext:
          fsGroup: 3000
      postgresql:
        image:
          pullSecrets:
            - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            fsGroup: 3000
      volumePermissions:
        enabled: true
  6. For EKS, use the following values.yaml file template:

    global:
      # TODO: Set your application domain name.
      host: <your Developer Hub domain name>
    
    route:
      enabled: false
    
    upstream:
      service:
        # NodePort is required for the ALB to route to the Service
        type: NodePort
    
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: alb
    
          alb.ingress.kubernetes.io/scheme: internet-facing
    
          # TODO: Using an ALB HTTPS Listener requires a certificate for your own domain. Fill in the ARN of your certificate, e.g.:
          alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:xxx:xxxx:certificate/xxxxxx
    
          alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    
          alb.ingress.kubernetes.io/ssl-redirect: '443'
    
          # TODO: Set your application domain name.
          external-dns.alpha.kubernetes.io/hostname: <your rhdh domain name>
    
      backstage:
        image:
          pullSecrets:
          - rhdh-pull-secret
        podSecurityContext:
          # you can assign any random value as fsGroup
          fsGroup: 2000
      postgresql:
        image:
          pullSecrets:
          - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            # you can assign any random value as fsGroup
            fsGroup: 3000
      volumePermissions:
        enabled: true
  7. For GKE, use the following values.yaml file template:

    global:
      host: <rhdh_domain_name>
    route:
      enabled: false
    upstream:
      service:
        type: NodePort
      ingress:
        enabled: true
        annotations:
          kubernetes.io/ingress.class: gce
          kubernetes.io/ingress.global-static-ip-name: <ADDRESS_NAME>
          networking.gke.io/managed-certificates: <rhdh_certificate_name>
          networking.gke.io/v1beta1.FrontendConfig: <ingress_security_config>
        className: gce
      backstage:
        image:
          pullSecrets:
          - rhdh-pull-secret
        podSecurityContext:
          fsGroup: 2000
      postgresql:
        image:
          pullSecrets:
          - rhdh-pull-secret
        primary:
          podSecurityContext:
            enabled: true
            fsGroup: 3000
      volumePermissions:
        enabled: true
  8. Install the Helm chart in the current namespace by running the following command:

    $ helm install rhdh ./_<helm_chart_archive_file_name>_ -f values.yaml

    where

    <helm_chart_archive_file_name>
    Specifies the name of the Helm chart archive file, for example, redhat-developer-hub-1.10.1.tgz.
  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Mirror the plugin catalog index and all referenced plugin OCI artifacts to your target registry by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-registry <target_registry>

    where:

    <target_registry>

    Enter the URL of the target mirror registry, such as, registry.example.com.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  1. Create a config map containing a registries.conf file that redirects the install-dynamic-plugins init container to your mirror registry:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-plugin-mirror-conf
    data:
      rhdh-registries.conf: |
        [[registry]]
        prefix = "registry.access.redhat.com/rhdh"
        location = "<target_registry>/rhdh"
    
        [[registry]]
        prefix = "quay.io/rhdh"
        location = "<target_registry>/rhdh"

    where:

    <target_registry>
    Enter the URL of your mirror registry, for example, registry.example.com.
  2. Mount the config map in the install-dynamic-plugins init container by adding the following to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-plugin-mirror-conf
            configMap:
              name: rhdh-plugin-mirror-conf
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-plugin-mirror-conf
                mountPath: /etc/containers/registries.conf.d/rhdh-registries.conf
                subPath: rhdh-registries.conf
                readOnly: true
    Important

    Because of Helm merge limitations, you must include all existing default volumes, volume mounts, and init container fields from the Red Hat Developer Hub Helm chart alongside your additions. Omitting the defaults overwrites them and can break the deployment.

    Note

    Cluster-level mirroring resources, such as ImageDigestMirrorSet or ImageContentSourcePolicy, do not apply to the install-dynamic-plugins init container because it uses skopeo directly to pull plugin artifacts.

  3. Optional: To enforce signature verification in production environments, create a policy.json config map and mount it in the install-dynamic-plugins init container:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rhdh-mirror-policy
    data:
      policy.json: |
        {
          "transports": {
            "docker": {
              "<target_registry>/<namespace>": [
                {
                  "type": "signedBy",
                  "keyType": "GPGKeys",
                  "keyPath": "<path_to_gpg_key>"
                }
              ]
            }
          }
        }

    Then add the following volumes and volume mount entries to your Helm values file:

    upstream:
      backstage:
        extraVolumes:
          - name: rhdh-mirror-policy
            configMap:
              name: rhdh-mirror-policy
        initContainers:
          - name: install-dynamic-plugins
            volumeMounts:
              - name: rhdh-mirror-policy
                mountPath: /etc/containers/policy.json
                subPath: policy.json
                readOnly: true

Chapter 5. Upgrade

5.1. Upgrade

Keep your Red Hat Developer Hub instance current by upgrading to the latest version to receive new features, security patches, and bug fixes.

5.2. Upgrade RHDH to apply the latest features and security patches

5.2.1. Upgrade RHDH to apply the latest features and security patches

Upgrade your Red Hat Developer Hub instance to a later version to apply the latest features, security patches, and bug fixes without disrupting your development teams.

Red Hat Developer Hub supports two upgrade paths depending on your deployment method:

  • Operator — An administrator can upgrade the Red Hat Developer Hub Operator by using the OpenShift Container Platform web console. After approval of the install plan, the Operator reconciles the deployment to the new version.
  • Helm chart — You can upgrade by using either the OpenShift Container Platform web console or the Helm CLI. Red Hat Developer Hub supports direct upgrades from any earlier version to the latest release without installing intermediate versions.

Before upgrading, review the release notes for every version between your current release and the target release to identify breaking changes, deprecations, or required migration steps. If your Helm chart deployment uses custom values.yaml files that override default configuration lists, you must manually merge new mandatory defaults before upgrading.

5.2.2. Upgrade the RHDH Operator

If you use the Operator to deploy your Red Hat Developer Hub instance, then an administrator can use the OpenShift Container Platform web console to upgrade the Operator to a later version.

OpenShift Container Platform is currently supported from version 4.18 to 4.21. See also the Red Hat Developer Hub Life Cycle.

Prerequisites

  • You have logged in as an administrator on the OpenShift Container Platform web console.
  • You have installed the Red Hat Developer Hub Operator.
  • You have configured the appropriate roles and permissions within your project to create or access an application. For more information, see the link:Building applications in the Red Hat OpenShift Container Platform documentation.

Procedure

  1. In the Administrator perspective of the OpenShift Container Platform web console, click Operators > Installed Operators.
  2. On the Installed Operators page, click Red Hat Developer Hub Operator.
  3. On the Red Hat Developer Hub Operator page, click the Subscription tab.
  4. From the Upgrade status field on the Subscription details page, click Upgrade available.

    Note

    If there is no upgrade available, the Upgrade status field value is Up to date.

  5. On the InstallPlan details page, click Preview InstallPlan > Approve.

    Important

    If you are on the Orchestrator plugin 1.7, you must manually update the plugin configuration after approval to avoid a failed deployment. For more information, see Upgrading the Orchestrator plugin from 1.7 to 1.10.

Verification

  • The Upgrade status field value on the Subscription details page is Up to date.

5.2.2.1. Approve the Operator InstallPlan

Approve the Operator InstallPlan to complete the upgrade to the latest version.

Procedure

  • TO DO: Update procedure steps

5.2.3. Upgrade the RHDH Helm chart

You can upgrade to a later version of Red Hat Developer Hub in OpenShift Container Platform by using either the web console or the CLI.

Prerequisites

  • You have deployed Developer Hub on OpenShift Container Platform by using the Helm chart.

Procedure

  1. OpenShift Container Platform web console

    Warning

    If you have installed Developer Hub manually using the Helm CLI, the Helm chart release upgrade in the OpenShift Container Platform web console is going to fail. The failure is due to the limitations when using the OpenShift Container Platform console to upgrade a Helm release that was initially deployed using the Helm CLI. You can bypass this limitation by using the Helm CLI to upgrade. However, if you still want to upgrade using the console, select the Helm Chart version from the drop-down list and select the Developer Hub version you want to upgrade to. Before performing this step, save your values.yaml configuration file in a different location.

    Important

    You can upgrade Red Hat Developer Hub directly from any earlier version to the latest release without installing intermediate versions. Before upgrading, you must review the release notes for every skipped version to identify breaking changes, deprecations, or required migration steps. For example, if upgrading from version 1.5 to 1.7, check the release notes for both 1.6 and 1.7.

  2. In the Developer perspective, click Helm to open the Helm Releases tab.
  3. Click the overflow menu on the Helm release that you want to use and select Upgrade.
  4. On the Upgrade Helm Release page, select the version of Developer Hub that you want to upgrade to from the chart version drop-down list.
  5. Click Upgrade.

    Note

    It might take a few minutes to delete the resources in the older versions and to start the newer versions of the Developer Hub pods.

  6. Close all open Developer Hub web pages, and log in again to verify that the upgrade was successful.
  7. OpenShift Container Platform CLI
  8. Log in to the OpenShift Container Platform cluster as the cluster administrator and switch to the project or namespace where you installed Developer Hub.

    $ oc login -u <user> -p <password> https://api.<HOSTNAME>:6443
    $ oc project my-rhdh-project
  9. For a new version of the Developer Hub Helm chart, run the following upgrade command:

    $ helm upgrade -i rhdh -f new-values.yml \
      openshift-helm-charts/redhat-developer-hub --version 1.10.1
    Note

    You can also give extra values to the chart by creating a new-values.yml file on your workstation with values that override the attributes in the installed chart or by adding new attributes.

5.2.3.1. Apply the new Helm chart version

Apply the new Helm chart version to upgrade your Red Hat Developer Hub instance.

Procedure

  • TO DO: Update procedure steps

5.2.3.2. Update custom Helm chart configurations

Update custom Helm chart configurations to ensure compatibility with the new version.

Procedure

  • TO DO: Update procedure steps

5.2.3.4. Update custom Helm configurations to safely upgrade from version 1.8 to 1.9

If you use custom values.yaml files that override default configuration lists, you must manually update the files to include new mandatory defaults before upgrading to 1.10.

Prerequisites

  • You have a running instance of Red Hat Developer Hub 1.8 deployed using the Helm chart.
  • Your custom values.yaml file overrides any of the following affected fields:

    • upstream.backstage.extraVolumeMounts
    • upstream.backstage.extraVolumes
    • upstream.backstage.initContainers

Procedure

  • Manually merge the new default items into your values.yaml file to include the following highlighted items within their lists and avoid configuration loss:

    upstream:
      backstage:
        extraVolumeMounts:
          # TODO: In addition to your custom mounts and the RHDH defaults, ensure this item is present (defined in the default RHDH chart):
          - name: extensions-catalog
            mountPath: /extensions
    
        extraVolumes:
          # TODO: In addition to your custom volumes and the RHDH defaults, ensure this item is present (defined in the default RHDH chart):
          - name: extensions-catalog
            emptyDir: {}
    
        initContainers:
          # TODO: Ensure the 'install-dynamic-plugins' container includes these environment variables and volume mounts:
          - name: install-dynamic-plugins
            env:
              # TODO: In addition to your custom env vars and the RHDH defaults for the install-dynamic-plugins init container,
              # ensure the following items are present (defined in the default RHDH chart):
              - name: CATALOG_INDEX_IMAGE
                value: '{{ .Values.global.catalogIndex.image.registry }}/{{ .Values.global.catalogIndex.image.repository }}:{{ .Values.global.catalogIndex.image.tag }}'
              - name: CATALOG_ENTITIES_EXTRACT_DIR
                value: '/extensions'
            volumeMounts:
              # TODO: In addition to your custom volume mounts and the RHDH defaults for the install-dynamic-plugins init container,
              # ensure the following item is present (defined in the default RHDH chart):
              - name: extensions-catalog
                mountPath: /extensions
            # ... other fields omitted for brevity
    Tip

    To view the full list of default values for 1.10, run the following command:

    helm show values redhat-developer-hub --repo https://charts.openshift.io --version 1.10.1

Verification

  • Verify that the Red Hat Developer Hub application successfully initializes.

5.2.3.5. Upgrade the OpenShift Serverless Logic Operator for Red Hat Developer Hub 1.9

Upgrade the OpenShift Serverless Logic (OSL) Operator to version 1.38.0 for compatibility with Red Hat Developer Hub 1.10.

See OpenShift Serverless Logic Operator documentation for the supported OpenShift Serverless Logic Operator versions and upgrade process.

Starting with OSL 1.37.0, the Operator subscription name and starting ClusterServiceVersion (CSV) no longer explicitly reference the operating system (OS) version.

In previous releases, the Operator subscription name and starting CSV explicitly included the OS version, such as logic-operator-rhel8 and logic-operator-rhel8.v1.36.0.

Important

Before performing the upgrade, make sure you do not delete the existing SonataflowPlatform operands during this process. When performing the upgrade, you must replace the logic-operator-rhel8 subscription with the logic-operator subscription.

Prerequisites

  • You have administrative access to the OpenShift cluster.

Procedure

  1. Delete the previous logic-operator-rhel8 subscription and apply the following configuration to install the logic-operator subscription:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: openshift-serverless-logic
    ---
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: openshift-serverless-logic
      namespace: openshift-serverless-logic
    spec:
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: logic-operator
      namespace: openshift-serverless-logic
    spec:
      channel: stable  #  channel of an operator package to subscribe to
      installPlanApproval: Automatic #  whether the update should be installed automatically
      name: logic-operator  #  name of the operator package
      source: redhat-operators  #  name of the catalog source
      sourceNamespace: openshift-marketplace
      startingCSV: logic-operator.v1.38.0  # The initial version of the operator
  2. Optional: If your configuration uses an external PostgreSQL database with SSL, add the required datasource environment variables to the jobService specification in the SonataflowPlatform custom resource as shown in the following configuration:

    jobService:
      enabled: true
      persistence:
        dbMigrationStrategy: service
        postgresql:
          # no additional url params here. We only have currentSchema=jobs-service.
          jdbcUrl: 'jdbc:postgresql://postgress-external-db-primary.postgress-external-db.svc.cluster.local:5432/sonataflow?currentSchema=jobs-service'
          secretRef:
            name: postgres-cred
            passwordKey: POSTGRES_PASSWORD
            userKey: POSTGRES_USER
      podTemplate:
        container:
          env:
            # only this two env vars
            - name: QUARKUS_DATASOURCE_REACTIVE_POSTGRESQL_SSL_MODE
              value: allow
            - name: QUARKUS_DATASOURCE_REACTIVE_TRUST_ALL
              value: 'true'

5.2.3.6. Upgrade the Orchestrator plugins for 1.9 Operator-backed instances

Update the dynamic-plugins ConfigMap to use Open Container Initiative (OCI) image references for Orchestrator plugins compatibility with Red Hat Developer Hub 1.10.

Important

If you do not update the dynamic-plugins ConfigMap after upgrading the RHDH Operator to 1.10, the Developer Hub instance fails to upgrade.

Prerequisites

  • You have a running instance of Red Hat Developer Hub with Orchestrator 1.8 backed by the Operator.
  • You have upgraded the Red Hat Developer Hub Operator to version 1.10.
  • You have administrative access to the OpenShift cluster.

Procedure

  1. Open your dynamic-plugins ConfigMap for editing.
  2. Update the package references for the Orchestrator plugins to use the 1.10 OCI registry paths as shown in the following example:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: 'oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{inherit}}'
            disabled: false
          - package: 'oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{inherit}}'
            disabled: false
            dependencies:
              - ref: sonataflow
          - package: 'oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{inherit}}'
            disabled: false
          - package: 'oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{inherit}}'
            disabled: false
    Note

    The {{inherit}} attribute in your configuration automatically resolves to the 1.10 version provided by the Operator.

  3. Save the configuration changes.

Verification

  1. Log in to your Red Hat Developer Hub instance.
  2. Confirm that the Orchestrator plugins display the version metadata for 1.10.

Chapter 6. Migrate

6.1. Migrate

Migrate your Red Hat Developer Hub data infrastructure to meet production requirements by moving from the default local database to an external PostgreSQL server to improve reliability, performance, and scalability.

6.2. Migrate from a local database to an external PostgreSQL server

6.2.1. Migrate from a local database to an external PostgreSQL server

When scaling your Red Hat Developer Hub deployment for production use, migrate from the default local database to an external PostgreSQL server to improve reliability, performance, and long-term maintainability of your data infrastructure.

By default, the Red Hat Developer Hub Operator and Helm chart create a local PostgreSQL instance for storing catalog data, user sessions, and plugin state. While this local database is suitable for evaluation and development, production environments require an external PostgreSQL server that supports high availability, automated backups, and independent scaling.

Migrating to an external PostgreSQL server provides the following benefits:

  • Reliability — External databases support replication, failover, and disaster recovery, reducing the risk of data loss.
  • Performance — Dedicated database resources prevent resource contention between the application and database layers.
  • Scalability — External databases scale independently, supporting larger catalogs and higher concurrency.
  • Maintainability — Database administrators can manage patching, monitoring, and tuning without affecting the RHDH deployment.
Important

Configure your database to use the date format of the International Organization for Standardization (ISO) through the DateStyle setting. Other formats are incompatible with the internal tracking of the software catalog, which causes scheduling tasks to fail and prevents your catalog items from refreshing.

6.2.2. Configure an external PostgreSQL database

Configure an external PostgreSQL database for production environments instead of using the default local database created by the Red Hat Developer Hub Operator or Helm chart.

Important

Configure your database to use the date format of the International Organization for Standardization (ISO) through the DateStyle setting. Other formats are incompatible with the internal tracking of the software catalog, which causes scheduling tasks to fail and prevents your catalog items from refreshing.

6.2.2.1. Configure an external PostgreSQL instance using the Operator

Configure an external PostgreSQL instance by using the Red Hat Developer Hub Operator instead of the default local PostgreSQL instance.

Prerequisites

  • You meet the Sizing requirements for external PostgreSQL deployments.
  • You are using a supported version of PostgreSQL. For more information, see the Product life cycle page.
  • You have the following details:

    • db_host: Denotes your PostgreSQL instance Domain Name System (DNS) or IP address
    • db_port: Denotes your PostgreSQL instance port number, such as 5432
    • username: Denotes the user name to connect to your PostgreSQL instance
    • password: Denotes the password to connect to your PostgreSQL instance
  • You have installed the Red Hat Developer Hub Operator.
  • Optional: You have a CA certificate, Transport Layer Security (TLS) private key, and TLS certificate so that you can secure your database connection by using the TLS protocol. For more information, refer to your PostgreSQL vendor documentation.
Note

By default, Developer Hub uses a database for each plugin and automatically creates it if none exists. You might need the Create Database privilege in addition to PostgreSQL Database privileges for configuring an external PostgreSQL instance.

Procedure

  1. Optional: Create a certificate secret to configure your PostgreSQL instance with a TLS connection:

    $ cat <<EOF | oc -n my-rhdh-project create -f -
    apiVersion: v1
    kind: Secret
    metadata:
     name: my-rhdh-database-certificates-secrets
    type: Opaque
    stringData:
     postgres-ca.pem: |-
      -----BEGIN CERTIFICATE-----
      <ca_certificate_key>
     postgres-key.key: |-
      -----BEGIN CERTIFICATE-----
      <tls_private_key>
     postgres-crt.pem: |-
      -----BEGIN CERTIFICATE-----
      <tls_certificate_key>
      # ...
    EOF

    Where:

    my-rhdh-database-certificates-secrets
    The certificate secret name.
    <ca_certificate_key>
    The CA certificate key.
    <tls_private_key>
    Optional: The TLS private key.
    <tls_certificate_key>
    Optional: The TLS certificate key.
  2. Create a credential secret to connect to the PostgreSQL instance:

    $ cat <<EOF | oc -n my-rhdh-project create -f -
    apiVersion: v1
    kind: Secret
    metadata:
     name: my-rhdh-database-secrets
    type: Opaque
    stringData:
     POSTGRES_PASSWORD: <password>
     POSTGRES_PORT: "<db_port>"
     POSTGRES_USER: <username>
     POSTGRES_HOST: <db_host>
     PGSSLMODE: <ssl_mode>
     NODE_EXTRA_CA_CERTS: <abs_path_to_pem_file>
    EOF

    Where:

    my-rhdh-database-secrets
    The credential secret name.
    <password>
    The password to connect to your PostgreSQL instance.
    <db_port>
    Your PostgreSQL instance port number, such as 5432.
    <username>
    The user name to connect to your PostgreSQL instance.
    <db_host>
    Your PostgreSQL instance DNS or IP address.
    <ssl_mode>
    Optional: For TLS connections, the required SSL mode.
    <abs_path_to_pem_file>
    Optional: For TLS connections, the absolute path to the Privacy-Enhanced Mail (PEM) file, for example /opt/app-root/src/postgres-crt.pem.
  3. Create a Kubernetes service that points to your external PostgreSQL database:

    apiVersion: v1
    kind: Service
    metadata:
      name: external-postgresql-service
    spec:
      type: ExternalName
      externalName: <your-external-db-host-name>
      ports:
        - port: 5432
          targetPort: 5432
          protocol: TCP

    Where:

    external-postgresql-service
    Name of the service to reference in plugin configurations.
    ExternalName
    Service type that creates a CNAME record to the external database host name.
    <your-external-db-host-name>

    FQDN of your external PostgreSQL server, for example, postgres.example.com.

    Note

    If your external database is outside the cluster or uses an IP address instead of a host name, create a service with endpoints:

    apiVersion: v1
    kind: Service
    metadata:
      name: external-postgresql-service
    spec:
      ports:
        - port: 5432
          targetPort: 5432
          protocol: TCP
    ---
    apiVersion: v1
    kind: Endpoints
    metadata:
      name: external-postgresql-service
    subsets:
      - addresses:
          - ip: <your-external-db-ip>
        ports:
          - port: 5432
            protocol: TCP

    Where:

    <your-external-db-ip>
    IP address of your external PostgreSQL server.
  4. Optional: Ensure your external PostgreSQL instance is configured with recommended performance tuning parameters.

    Set shared_buffers to approximately 1/4 and effective_cache_size to approximately 1/2 of the allocated database memory. For recommended values based on your deployment scale, see Sizing requirements for Red Hat Developer Hub.

  5. Create your Backstage custom resource (CR):

    cat <<EOF | oc -n my-rhdh-project create -f -
    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <backstage_instance_name>
    spec:
      database:
        enableLocalDb: false
      application:
        extraFiles:
          mountPath: <path>
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
        extraEnvs:
          secrets:
            - name: my-rhdh-database-secrets
            # ...

    Where:

    spec.database.enableLocalDb
    Set to false to disable creating local PostgreSQL instances.
    <path>
    The mount path for certificate files, for example /opt/app-root/src.
    my-rhdh-database-certificates-secrets
    The certificate secret name, required if you configure a TLS connection.
    key
    The key names as defined in the my-rhdh-database-certificates-secrets Secret.
    my-rhdh-database-secrets

    The credential secret name.

    Note

    The environment variables listed in the Backstage CR work with the Operator default configuration. If you have changed the Operator default configuration, you must reconfigure the Backstage CR accordingly.

  6. Apply the Backstage CR to the namespace where you have deployed the Developer Hub instance.

6.2.2.2. Configure an external PostgreSQL instance using the Helm chart

Configure an external PostgreSQL instance by using the Helm chart instead of the default local PostgreSQL instance.

Prerequisites

  • You meet the Sizing requirements for external PostgreSQL deployments.
  • You are using a supported version of PostgreSQL. For more information, see the Product life cycle page.
  • You have the following details:

    • db_host: Denotes your PostgreSQL instance Domain Name System (DNS) or IP address
    • db_port: Denotes your PostgreSQL instance port number, such as 5432
    • username: Denotes the user name to connect to your PostgreSQL instance
    • password: Denotes the password to connect to your PostgreSQL instance
  • You have installed the RHDH application by using the Helm chart.
  • Optional: You have a CA certificate, Transport Layer Security (TLS) private key, and TLS certificate so that you can secure your database connection by using the TLS protocol. For more information, refer to your PostgreSQL vendor documentation.
Note

By default, Developer Hub uses a database for each plugin and automatically creates it if none exists. You might need the Create Database privilege in addition to PostgreSQL Database privileges for configuring an external PostgreSQL instance.

Procedure

  1. Optional: Create a certificate secret to configure your PostgreSQL instance with a TLS connection:

    $ cat <<EOF | oc -n <your_namespace> create -f -
    apiVersion: v1
    kind: Secret
    metadata:
     name: my-rhdh-database-certificates-secrets
    type: Opaque
    stringData:
     postgres-ca.pem: |-
      -----BEGIN CERTIFICATE-----
      <ca_certificate_key>
     postgres-key.key: |-
      -----BEGIN CERTIFICATE-----
      <tls_private_key>
     postgres-crt.pem: |-
      -----BEGIN CERTIFICATE-----
      <tls_certificate_key>
      # ...
    EOF

    Where:

    my-rhdh-database-certificates-secrets
    The certificate secret name.
    <ca_certificate_key>
    The CA certificate key.
    <tls_private_key>
    Optional: The TLS private key.
    <tls_certificate_key>
    Optional: The TLS certificate key.
  2. Create a credential secret to connect to the PostgreSQL instance:

    $ cat <<EOF | oc -n <your_namespace> create -f -
    apiVersion: v1
    kind: Secret
    metadata:
     name: my-rhdh-database-secrets
    type: Opaque
    stringData:
     POSTGRES_PASSWORD: <password>
     POSTGRES_PORT: "<db_port>"
     POSTGRES_USER: <username>
     POSTGRES_HOST: <db_host>
     PGSSLMODE: <ssl_mode>
     NODE_EXTRA_CA_CERTS: <abs_path_to_pem_file>
    EOF

    Where:

    my-rhdh-database-secrets
    The credential secret name.
    <password>
    The password to connect to your PostgreSQL instance.
    <db_port>
    Your PostgreSQL instance port number, such as 5432.
    <username>
    The user name to connect to your PostgreSQL instance.
    <db_host>
    Your PostgreSQL instance DNS or IP address.
    <ssl_mode>
    Optional: For TLS connections, the required SSL mode.
    <abs_path_to_pem_file>
    Optional: For TLS connections, the absolute path to the Privacy-Enhanced Mail (PEM) file, for example /opt/app-root/src/postgres-crt.pem.
  3. Create a Kubernetes service that points to your external PostgreSQL database:

    apiVersion: v1
    kind: Service
    metadata:
      name: external-postgresql-service
    spec:
      type: ExternalName
      externalName: <your-external-db-host-name>
      ports:
        - port: 5432
          targetPort: 5432
          protocol: TCP

    Where:

    external-postgresql-service
    Name of the service to reference in plugin configurations.
    ExternalName
    Service type that creates a CNAME record to the external database host name.
    <your-external-db-host-name>

    FQDN of your external PostgreSQL server, for example, postgres.example.com.

    Note

    If your external database is outside the cluster or uses an IP address instead of a host name, create a service with endpoints:

    apiVersion: v1
    kind: Service
    metadata:
      name: external-postgresql-service
    spec:
      ports:
        - port: 5432
          targetPort: 5432
          protocol: TCP
    ---
    apiVersion: v1
    kind: Endpoints
    metadata:
      name: external-postgresql-service
    subsets:
      - addresses:
          - ip: <your-external-db-ip>
        ports:
          - port: 5432
            protocol: TCP

    Where:

    <your-external-db-ip>
    IP address of your external PostgreSQL server.
  4. Configure your PostgreSQL instance in the Helm configuration file named values.yaml:

    # ...
    upstream:
      postgresql:
        enabled: false
        auth:
          existingSecret: my-rhdh-database-secrets
      backstage:
        appConfig:
          backend:
            database:
              connection:
                host: ${POSTGRES_HOST}
                port: ${POSTGRES_PORT}
                user: ${POSTGRES_USER}
                password: ${POSTGRES_PASSWORD}
                ssl:
                  rejectUnauthorized: true,
                  ca:
                    $file: /opt/app-root/src/postgres-ca.pem
                  key:
                    $file: /opt/app-root/src/postgres-key.key
                  cert:
                    $file: /opt/app-root/src/postgres-crt.pem
      extraEnvVarsSecrets:
        - my-rhdh-database-secrets
      extraEnvVars:
        - name: BACKEND_SECRET
          valueFrom:
            secretKeyRef:
              key: backend-secret
              name: '{{ include "rhdh.backend-secret-name" $ }}'
      extraVolumeMounts:
        - mountPath: /opt/app-root/src/dynamic-plugins-root
          name: dynamic-plugins-root
        - mountPath: /opt/app-root/src/postgres-crt.pem
          name: postgres-crt
          subPath: postgres-crt.pem
        - mountPath: /opt/app-root/src/postgres-ca.pem
          name: postgres-ca
          subPath: postgres-ca.pem
        - mountPath: /opt/app-root/src/postgres-key.key
          name: postgres-key
          subPath: postgres-key.key
      extraVolumes:
        - ephemeral:
            volumeClaimTemplate:
              spec:
                accessModes:
                  - ReadWriteOnce
                resources:
                  requests:
                    storage: 1Gi
          name: dynamic-plugins-root
        - configMap:
            defaultMode: 420
            name: dynamic-plugins
            optional: true
          name: dynamic-plugins
        - name: dynamic-plugins-npmrc
          secret:
            defaultMode: 420
            optional: true
            secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}'
        - name: postgres-crt
          secret:
            secretName: my-rhdh-database-certificates-secrets
            # ...

    Where:

    upstream.postgresql.enabled
    Set to false to disable the local PostgreSQL instance creation.
    upstream.postgresql.auth.existingSecret
    The credentials secret to inject into Backstage.
    upstream.backstage.appConfig.backend.database.connection
    The Backstage database connection parameters.
    upstream.backstage.extraEnvVarsSecrets
    The credentials secret to inject as environment variables into Backstage.
    extraVolumeMounts (postgres-crt, postgres-ca, postgres-key)
    Optional: Inject TLS certificate, CA certificate, and TLS private key into the Backstage container.
    extraVolumes (postgres-crt)
    The certificate secret name, required if you configure TLS.
  5. Optional: Ensure your external PostgreSQL instance is configured with recommended performance tuning parameters.

    Set shared_buffers to approximately 1/4 and effective_cache_size to approximately 1/2 of the allocated database memory. For recommended values based on your deployment scale, see Sizing requirements for Red Hat Developer Hub.

  6. Apply the configuration changes in your Helm configuration file named values.yaml:

    $ helm upgrade -n <your_namespace> <your_deploy_name> openshift-helm-charts/redhat-developer-hub -f values.yaml --version 1.10.1

6.2.2.3. Migrate local databases to an external PostgreSQL server

Migrate data from a local PostgreSQL server to an external PostgreSQL service by using PostgreSQL utilities such as pg_dump and psql.

Note

The following procedure uses a database copy script to do a quick migration.

Prerequisites

  • You have installed the pg_dump and psql utilities on your local machine.
  • For data export, you have the PostgreSQL user privileges to make a full dump of local databases.
  • For data import, you have the PostgreSQL admin privileges to create an external database and populate it with database dumps.

Procedure

  1. Configure port forwarding for the local PostgreSQL database pod by running the following command on a terminal:

    $ oc port-forward -n <your_namespace> <pgsql_pod_name> <forward_to_port>:<forward_from_port>

    Where:

  2. The <pgsql_pod_name> variable denotes the name of a PostgreSQL pod with the format backstage-psql-<deployment_name>-<_index>.
  3. The <forward_to_port> variable denotes the port of your choice to forward PostgreSQL data to.
  4. The <forward_from_port> variable denotes the local PostgreSQL instance port, such as 5432.

    $ oc port-forward -n developer-hub backstage-psql-developer-hub-0 15432:5432
  5. Make a copy of the following db_copy.sh script and edit the details based on your configuration:

    #!/bin/bash
    
    to_host=<db_service_host>
    to_port=5432
    to_user=postgres
    
    from_host=127.0.0.1
    from_port=15432
    from_user=postgres
    
    allDB=("backstage_plugin_app" "backstage_plugin_auth" "backstage_plugin_catalog" "backstage_plugin_permission" "backstage_plugin_scaffolder" "backstage_plugin_search")
    
    for db in ${!allDB[@]};
    do
      db=${allDB[$db]}
      echo Copying database: $db
      PGPASSWORD=$TO_PSW psql -h $to_host -p $to_port -U $to_user -c "create database $db;"
      pg_dump -h $from_host -p $from_port -U $from_user -d $db | PGPASSWORD=$TO_PSW psql -h $to_host -p $to_port -U $to_user -d $db
    done

    Where:

    to_host
    The destination hostname, for example <db_instance_name>.rds.amazonaws.com.
    to_port
    The destination port, such as 5432.
    to_user
    The destination server username, for example postgres.
    from_host
    The source hostname, such as 127.0.0.1.
    from_port
    The source port number, such as the <forward_to_port> variable.
    from_user
    The source server username, for example postgres.
    allDB
    Database names to import, in double quotes separated by spaces.
  6. Create a destination database for copying the data:

    /bin/bash TO_PSW=<destination_db_password> /path/to/db_copy.sh

    Replace <destination_db_password> with the password to connect to the destination database.

    Note

    You can stop port forwarding when the copying of the data is complete. For more information about handling large databases and using the compression tools, see the Handling Large Databases section on the PostgreSQL website.

  7. Reconfigure your Backstage custom resource (CR). For more information, see Configure an external PostgreSQL instance using the Operator.
  8. Check that the following code is present at the end of your Backstage CR after reconfiguration:

    # ...
    spec:
      database:
        enableLocalDb: false
      application:
      # ...
        extraFiles:
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem
        extraEnvs:
          secrets:
            - name: my-rhdh-database-secrets
    # ...
    Note

    Reconfiguring the Backstage CR deletes the corresponding StatefulSet and Pod objects, but does not delete the PersistenceVolumeClaim object. Use the following command to delete the local PersistenceVolumeClaim object:

    oc -n developer-hub delete pvc <local_psql_pvc_name>

    where, the <local_psql_pvc_name> variable is in the data-<psql_pod_name> format.

  9. Apply the configuration changes.

Verification

  1. Verify that your RHDH instance is running with the migrated data and does not contain the local PostgreSQL database by running the following command:

    oc get pods -n <your_namespace>
  2. Check the output for the following details:
  3. The backstage-developer-hub-xxx pod is in running state.
  4. The backstage-psql-developer-hub-0 pod is not available.

    You can also verify these details by using the Topology view in the OpenShift Container Platform web console.

6.2.2.4. Configure schema-based plugin isolation to simplify single-database provisioning

Configure schema-based plugin isolation to support database users without CREATEDB privileges or to reduce database provisioning overhead. Each RHDH plugin uses its own PostgreSQL schema within a single shared database.

Prerequisites

  • An external PostgreSQL instance is configured using the Operator or the Helm chart.
  • Your database user has CREATE SCHEMA privileges on the target database, or your database administrator will create the required schemas.
Note

By default, when pluginDivisionMode is set to schema, RHDH automatically creates the required schemas because the ensureExists configuration defaults to true. The database user must have CREATE SCHEMA privileges on the target database.

Procedure

  1. Add pluginDivisionMode: schema to the backend.database section of your RHDH configuration in the app-config-rhdh ConfigMap:

    backend:
      database:
        client: pg
        pluginDivisionMode: schema
        connection:
          host: ${POSTGRES_HOST}
          port: ${POSTGRES_PORT}
          user: ${POSTGRES_USER}
          password: ${POSTGRES_PASSWORD}
  2. Save the configuration changes.
  3. Restart the Red Hat Developer Hub deployment to apply the new configuration.

6.2.3. Execute the database copy script

Run the database copy script to migrate data from the local PostgreSQL instance to your external PostgreSQL server.

Procedure

  • TO DO: Break apart existing topic

6.2.4. Create destination database on the external server

Create destination databases on the external PostgreSQL server to receive the migrated data.

Procedure

  • TO DO: Break apart existing topic

6.3. Migrate to the front-end system to use blueprint-based dynamic routing

6.3.1. Migrate to the front-end system to use blueprint-based dynamic routing

Migrate your Red Hat Developer Hub environment to the extension-based front-end system to use blueprint-based dynamic routing for improved extensibility and performance.

Important

Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

6.3.1.1. Additional resources

6.3.2. Customize platform appearance to reflect your brand identity

Apply custom color schemes, logos, and visual elements to the Red Hat Developer Hub interface so the platform reflects your organization’s brand identity.

Prerequisites

  • You have installed the @backstage/frontend-defaults package.
  • You have access to the packages/app/src/App.tsx file.
  • You have access to the app-config.yaml file.

Procedure

  1. To enable the custom theme, import the rhdhThemeModule from the theme plugin alpha module in your packages/app/src/App.tsx file:

    import { createApp } from '@backstage/frontend-defaults';
    import { rhdhThemeModule } from '@red-hat-developer-hub/backstage-plugin-theme/alpha';
    
    export default createApp({
      features: [
        rhdhThemeModule,
        // Additional features
      ],
    });
    Note

    For advanced customization beyond color schemes and branding, you can create a custom theme module that extends the base theme configuration. For a complete example of creating a custom theme module by overriding theme plugin extensions, see the theme plugin example in the rhdh-plugins repository.

  2. To set the application title and branding, configure extension settings in your app-config.yaml file:

    app:
      title: My Company Catalog
      baseUrl: http://localhost:3000
    
    organization:
      name: My Company
  3. Save the configuration file and restart your Red Hat Developer Hub instance to apply the theme changes.

Verification

  1. Open your Red Hat Developer Hub instance in a web browser.
  2. Verify that the interface displays your custom theme.
  3. Check that theme colors match your brand identity specifications.

6.3.3. Update Global Header mount points to integrate securely with the new Blueprint architecture

Update Global Header mount points to integrate securely with the new Blueprint architecture by installing and integrating the global header plugin into your Red Hat Developer Hub application as a prerequisite for adding custom buttons, menus, and navigation shortcuts to the header.

Procedure

  1. To enable custom navigation, install the global header plugin package.

    yarn --cwd packages/app add @red-hat-developer-hub/backstage-plugin-global-header
  2. To register the global header, import the plugin and modules in your packages/app/src/App.tsx file.

    import { createApp } from '@backstage/frontend-defaults';
    import globalHeaderPlugin, {
      globalHeaderModule,
      globalHeaderTranslationsModule,
    } from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
    
    export default createApp({
      features: [
        globalHeaderModule,
        globalHeaderTranslationsModule,  // Enables translation support
        globalHeaderPlugin,
      ],
    });
    Note

    You can omit the globalHeaderPlugin if your app-config.yaml file includes the following configuration:

    app:
      packages: all
  3. Restart your development server to load the plugin.

6.3.4. Add navigation shortcuts to reduce clicks to frequently used resources

Add custom toolbar buttons and drop-down menu items to the Red Hat Developer Hub global header to give you quick access to frequently used tools, documentation, and support resources.

You can add navigation shortcuts by using any of the following approaches:

  • Configuration-driven items through app-config.yaml without code
  • Extension blueprints for plugin contributions (GlobalHeaderComponentBlueprint for toolbar items, GlobalHeaderMenuItemBlueprint for drop-down menu entries)
  • Fully custom React components

Prerequisites

  • You have installed the @red-hat-developer-hub/backstage-plugin-global-header package.
  • You have access to the app-config.yaml file.
  • You have integrated the global header plugin into your application features.

Procedure

  1. To add navigation shortcuts, configure the globalHeader block in your app-config.yaml file with components for toolbar buttons and menuItems for dropdown entries:

    globalHeader:
      components:
        - title: Visualizer Dashboard
          titleKey: visualizer.dashboard.title  # Optional localization key for the title.
          icon: dashboard
          link: /visualizer/tree
          priority: 75  # Priority determines display order. Higher values appear first.
      menuItems:
        - target: help  # Target specifies which drop-down menu (`help`, `profile`, or `app-launcher`) receives this item.
          title: Internal Wiki
          titleKey: wiki.internal.title
          icon: article
          link: https://wiki.internal.example.com
          sectionLabel: resources  # Section groups related menu items together.
          priority: 80
  2. Save the configuration file.
  3. Restart your Red Hat Developer Hub instance to apply the changes.

Verification

  1. Open your Red Hat Developer Hub instance in a web browser.
  2. Verify that your custom toolbar button is displayed in the global header.
  3. Click the target drop-down menu to confirm your menu item is displayed in the correct section.

6.3.5. Add plugin-specific buttons to the toolbar for quick actions

Add custom buttons or interactive widgets to the global header toolbar that trigger your plugin’s functionality directly. Use GlobalHeaderComponentBlueprint to create these toolbar components programmatically.

Prerequisites

  • You have set up the global header plugin in your application.
  • You have access to your plugin source code.

Procedure

  1. To add a plugin button to the toolbar, create a custom toolbar component extension in your plugin code:

    import { GlobalHeaderComponentBlueprint } from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
    
    const myToolbarButton = GlobalHeaderComponentBlueprint.make({
      name: 'my-toolbar-item',
      params: {
        component: MyCustomComponent,  // React component to render in the toolbar.
        priority: 100,  // Higher priority values display first in the toolbar.
      },
    });
  2. To create icon buttons without custom components, you can provide data-driven configuration instead of a component:

    const dashboardButton = GlobalHeaderComponentBlueprint.make({
      name: 'dashboard-button',
      params: {
        icon: 'dashboard',
        title: 'Dashboard',
        link: '/dashboard',
        priority: 75,  // Higher priority values display first in the toolbar.
      },
    });
  3. To activate the toolbar button, register the extension in your plugin’s alpha exports:

    export default createPlugin({
      id: 'my-plugin',
      extensions: [myToolbarButton],
    });

6.3.7. Reorganize or remove header items to align with your team priorities

Adjust the display order of global header components by changing their priority values, replace default implementations with custom versions, or hide items that your team does not use to streamline the interface.

Procedure

  1. To reorder components, assign higher priority values to items that should appear first:

    globalHeader:
      components:
        - title: Priority Item
          icon: star
          link: /important
          priority: 200  # Higher values render before lower-priority defaults.
  2. To override a default component, create an extension with the same name but different configuration:

    const customSearch = GlobalHeaderComponentBlueprint.make({
      name: 'search',  // Matches the default search component to replace it.
      params: {
        component: MyCustomSearchComponent,
        priority: 150,
      },
    });
  3. To disable a default extension, configure it with disabled: true in your extension overrides:

    extensions:
      - global-header-component:search:
          disabled: true  # Disables the default search component.

6.3.8. Migrate the Homepage to function as a dynamic plugin loaded through blueprints

Migrate the dynamic homepage to function as a plugin loaded through blueprints to choose which templates and widgets appear when you log in. You can use customizable layouts to drag and resize cards, or fixed layouts with predefined positions.

Available widgets include:

  • Onboarding sections
  • Entity catalogs
  • Software templates
  • Quick access cards
  • Search bars
  • Recently visited items
  • Top visited resources

Prerequisites

  • You have installed the @red-hat-developer-hub/backstage-plugin-dynamic-home-page package.
  • You have access to the packages/app/src/App.tsx file.
  • You have access to the app-config.yaml file.

Procedure

  1. To enable the dynamic homepage, import and register the homepage modules in your packages/app/src/App.tsx file:

    import { createApp } from '@backstage/frontend-defaults';
    import {
      homePageDevModule,
      homepageTranslationsModule,
    } from '@red-hat-developer-hub/backstage-plugin-dynamic-home-page/alpha';
    
    export default createApp({
      features: [
        homePageDevModule,  // Enables the dynamic homepage plugin
        homepageTranslationsModule,  // Adds internationalization support
        // Additional features
      ],
    });
  2. To set the homepage route and visit tracking, configure them in your app-config.yaml file:

    app:
      extensions:
        - page:home:
            config:
              path: /  # Set to / to make the homepage your landing page
        - api:home/visits: true  # Enables visit tracking for recently visited and top visited widgets
        - app-root-element:home/visit-listener: true  # Activates the visit listener to record page visits
  3. Choose a layout mode by setting the customizable option. Set to true for a customizable grid where you can drag and resize cards, or set to false for a read-only grid with fixed card positions:

    app:
      extensions:
        - home-page-layout:home/dynamic-homepage-layout:
            config:
              customizable: true  # Set to false to prevent you from moving or resizing cards
  4. To control widget display order and sizing, configure widget sections with priority values and responsive breakpoints. Priority values determine display order in read-only layouts, with higher values appearing first.

    app:
      extensions:
        - home-page-layout:home/dynamic-homepage-layout:
            config:
              customizable: false
              widgetLayout:
                RhdhTemplateSection:  # Software templates widget section
                  priority: 300  # Priority applies only to read-only layouts. Higher values display first.
                  breakpoints:  # Card dimensions (width w and height h in grid units) across device sizes
                    xl: { w: 12, h: 5 }
                    lg: { w: 12, h: 5 }
                    md: { w: 12, h: 5 }
                    sm: { w: 12, h: 5 }
                    xs: { w: 12, h: 7.5 }
                    xxs: { w: 12, h: 13.5 }
                RhdhEntitySection:  # Entity catalog widget section showing registered components
                  priority: 200
                  breakpoints:
                    xl: { w: 12, h: 7 }
                    lg: { w: 12, h: 7 }
                    md: { w: 12, h: 7 }
                    sm: { w: 12, h: 7 }
                    xs: { w: 12, h: 9 }
                    xxs: { w: 12, h: 15 }
                RhdhOnboardingSection:  # Onboarding widget section with getting started guides
                  priority: 100
                  breakpoints:
                    xl: { w: 12, h: 6 }
                    lg: { w: 12, h: 6 }
                    md: { w: 12, h: 6 }
                    sm: { w: 12, h: 6 }
                    xs: { w: 12, h: 8 }
                    xxs: { w: 12, h: 12 }
  5. Save the configuration file.
  6. Restart your Red Hat Developer Hub instance to apply the homepage layout changes.

Verification

  1. Open your Red Hat Developer Hub instance in a web browser.
  2. Verify that the homepage displays at the configured path.
  3. Check that widget cards appear in the expected order and size.
  4. If customizable: true, confirm that you can drag and resize cards.
  5. Verify that visit tracking works by navigating to different pages and checking the recently visited widget.

6.3.9. Enable guided tutorials to learn platform features

Enable guided tutorials in Red Hat Developer Hub to learn platform features through interactive quick start walkthroughs. Tutorials automatically display on first visit and are accessible from a Quick start button in the global header.

Prerequisites

  • You have installed the @red-hat-developer-hub/backstage-plugin-quickstart package.
  • You have access to the packages/app/src/App.tsx file.

Procedure

  1. To enable guided tutorials, import the quick start modules in your packages/app/src/App.tsx file:

    import { createApp } from '@backstage/frontend-defaults';
    import {
      quickstartInitModule,
      quickstartTranslationsModule,
    } from '@red-hat-developer-hub/backstage-plugin-quickstart/alpha';
    
    export default createApp({
      features: [
        quickstartInitModule,  // Handles first-visit auto-open and notifications
        quickstartTranslationsModule,  // Provides internationalization support
        // Additional features
      ],
    });
  2. To make tutorials accessible, add the Quick start sidebar button to your navigation component:

    import { useAppDrawer } from '@backstage/frontend-plugin-api';
    import { WavingHandOutlinedIcon } from '@mui/icons-material';
    import { QUICKSTART_DRAWER_ID } from '@red-hat-developer-hub/backstage-plugin-quickstart';
    
    function QuickstartSidebarItem() {
      const { toggleDrawer } = useAppDrawer();
      return (
        <SidebarItem
          text="Quick start"
          icon={WavingHandOutlinedIcon}
          onClick={() => toggleDrawer(QUICKSTART_DRAWER_ID)}
        />
      );
    }
    Note

    If you have the global header plugin installed, a default menu item for opening and closing the Quick start drawer automatically appears in the Help menu. The custom sidebar button shown above is only necessary if the global header plugin is not installed.

Verification

  1. Open your Red Hat Developer Hub instance in a new browser window.
  2. Verify that the Quick start drawer opens automatically on first visit.
  3. Click the Quick start sidebar button to toggle the drawer.
  4. Confirm that tutorials display based on your role.

6.3.10. Preserve custom integrations when migrating to the front-end system

Migrate your mount points and custom components from the Scalprum-based system to Red Hat Developer Hub extension-based front-end system by converting YAML-based mount points to extension blueprints.

Your existing mount points for entity pages, application headers, search filters, and admin pages map to specific extension attachment points in the front-end system. The extension tree resolves attachments by matching extension outputs to parent inputs. Blueprints provide typed patterns for common extension types including pages, navigation items, and entity content.

Available entity page mount points:

  • overview
  • topology
  • issues
  • pull-requests
  • ci
  • cd
  • kubernetes
  • image-registry
  • monitoring
  • api
  • dependencies
  • docs
  • definition
  • diagram

Prerequisites

  • You have access to the packages/app/src/App.tsx file.
  • You have access to your app-config.yaml file.
  • You understand your current mount point configuration in the dynamicPlugins.frontend section.

Procedure

  1. To begin migration, identify your current mount points in the dynamicPlugins.frontend configuration:

    dynamicPlugins:
      frontend:
        my-plugin:
          mountPoints:
            - mountPoint: entity.page.overview/cards  # Current mount point
              importName: MyComponent
              config:
                if:
                  isKind: component
                layout:
                  xs: { w: 12, h: 4 }
  2. To understand the migration path, map your mount points to front-end system extension points:

    Previous mount pointCurrent extension attachmentBlueprint to use

    entity.page.overview/cards

    page:catalog/entity with input contents

    EntityContentBlueprint or EntityCardBlueprint

    entity.page.*/cards

    page:catalog/entity with input contents

    EntityContentBlueprint

    application/header

    app/root with custom attachment

    Custom extension with coreExtensionData.reactElement

    search.page.results

    page:search with input content

    Custom extension

    admin.page.plugins

    page:admin with input content

    Custom extension

  3. To migrate your configuration, convert your mount point configuration to extension blueprint code in your plugin’s /alpha export file:

    // For entity page cards
    import { EntityCardBlueprint } from '@backstage/plugin-catalog-react/alpha';
    
    const myEntityCard = EntityCardBlueprint.make({
      name: 'my-component',
      params: {
        filter: entity => entity.kind === 'Component',  // Replaces if.isKind condition
        loader: () => import('./MyComponent').then(m => <m.MyComponent />),
      },
    });
    
    export default createFrontendPlugin({
      pluginId: 'my-plugin',
      extensions: [myEntityCard],
    });
  4. To migrate entity tabs, convert entityTabs configuration to EntityContentBlueprint:

    // Old configuration
    dynamicPlugins:
      frontend:
        my-plugin:
          entityTabs:
            - path: /my-tab
              title: My Tab
              mountPoint: entity.page.my-tab
    
    // New extension blueprint
    import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
    
    const myTab = EntityContentBlueprint.make({
      name: 'my-tab',
      params: {
        defaultPath: '/my-tab',
        defaultTitle: 'My Tab',
        loader: () => import('./MyTabContent').then(m => <m.MyTabContent />),
      },
    });
  5. To activate the migrated plugin, update your packages/app/src/App.tsx file to import it:

    import { createApp } from '@backstage/frontend-defaults';
    import myPlugin from '@my-org/backstage-plugin-my-plugin/alpha';
    
    export default createApp({
      features: [
        myPlugin,
        // Additional plugins
      ],
    });
  6. To complete the migration, remove the previous mount point configuration from your app-config.yaml file after verifying the migration works.

Verification

  1. Open your Red Hat Developer Hub instance in a web browser.
  2. Navigate to an entity page where your component should appear.
  3. Verify that your custom component displays in the correct location.
  4. Check that conditional rendering based on entity kind or type works as expected.
  5. Verify that any custom layout configurations apply correctly.

Chapter 7. Administer

7.1. Administer

Measure component compliance, track portfolio health, and analyze platform adoption to maintain operational visibility across your Red Hat Developer Hub deployment. Administration tasks ensure software standards are met and platform investments deliver measurable value.

7.2. Evaluate component compliance using Scorecards

7.2.1. Component health and compliance monitoring using Scorecards

Important

This section describes Developer Preview features in the Scorecard plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

Use the Scorecard plugin to achieve the following goals:

  • Identify and prioritize risks: Use unified health data to make faster remediation decisions.
  • Maintain security standards: Automatically surface compliance gaps to enforce best practices.
  • Streamline workflows: Access all metrics in RHDH to reduce development overhead.
  • Standardize service quality: Define and measure consistent health criteria across the organization.
Scorecard plugin sample view showing component health metrics

7.2.2. Supported Scorecard metrics providers

The Scorecard plugin gathers data from third-party systems through metric providers. Use the following table to identify which metrics are available for each supported provider.

The following metric providers are supported:

ProviderMetric IDTitleDescriptionTypeThresholds

GitHub

github.open_prs

GitHub open PRs

Number of open pull requests in GitHub.

number

Configurable

Jira

jira.open_issues

Jira open issues

Number of open issues in Jira.

number

Configurable

OpenSSF

openssf.binary_artifacts

Binary Artifacts

Determines if the project has generated executable (binary) artifacts in the source repository.

score (0-10)

Fixed

OpenSSF

openssf.branch_protection

Branch Protection

Determines if the default and release branches are protected with branch protection settings.

score (0-10)

Fixed

OpenSSF

openssf.cii_best_practices

CII Best Practices

Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.

score (0-10)

Fixed

OpenSSF

openssf.ci_tests

CI Tests

Determines if the project runs tests before pull requests are merged.

score (0-10)

Fixed

OpenSSF

openssf.code_review

Code Review

Determines if the project requires human code review before pull requests are merged.

score (0-10)

Fixed

OpenSSF

openssf.contributors

Contributors

Determines if the project has a set of contributors from multiple organizations.

score (0-10)

Fixed

OpenSSF

openssf.dangerous_workflow

Dangerous Workflow

Determines if the project’s GitHub Action workflows avoid dangerous patterns.

score (0-10)

Fixed

OpenSSF

openssf.dependency_update_tool

Dependency Update Tool

Determines if the project uses a dependency update tool.

score (0-10)

Fixed

OpenSSF

openssf.fuzzing

Fuzzing

Determines if the project uses fuzzing.

score (0-10)

Fixed

OpenSSF

openssf.license

License

Determines if the project has defined a license.

score (0-10)

Fixed

OpenSSF

openssf.maintained

Maintained

Determines if the project is actively maintained.

score (0-10)

Fixed

OpenSSF

openssf.packaging

Packaging

Determines if the project is published as a package.

score (0-10)

Fixed

OpenSSF

openssf.pinned_dependencies

Pinned Dependencies

Determines if the project has declared and pinned the dependencies of its build process.

score (0-10)

Fixed

OpenSSF

openssf.sast

SAST (Static Analysis Security Testing)

Determines if the project uses static code analysis.

score (0-10)

Fixed

OpenSSF

openssf.security_policy

Security Policy

Determines if the project has published a security policy.

score (0-10)

Fixed

OpenSSF

openssf.signed_releases

Signed Releases

Determines if the project cryptographically signs release artifacts.

score (0-10)

Fixed

OpenSSF

openssf.token_permissions

Token Permissions

Determines if the project’s workflows follow the principle of least privilege.

score (0-10)

Fixed

OpenSSF

openssf.vulnerabilities

Vulnerabilities

Determines if the project has open, known unfixed vulnerabilities.

score (0-10)

Fixed

Filecheck

filecheck.<key>

<key>

Verifies that the configured file exists in the repository. The metric ID suffix and title are derived from the key you define in scorecard.plugins.filecheck.files. For more information, see Configure file-level checks to verify repositories contain required compliance documentation.

boolean

Fixed

For OpenSSF metrics, the fixed thresholds are: Error (score below 2), Warning (score between 2 and 7), Success (score above 7). For Filecheck metrics, the fixed thresholds are: exist (file present, success) and missing (file absent, error). For GitHub and Jira metrics, you can customize thresholds. For more information, see Scorecard metric thresholds.

7.2.3. Set up Scorecards

7.2.3.1. Set up Scorecards

Enable the Scorecards plugin and configure role-based access control to restrict metric visibility and administration. Initial setup establishes who can view compliance data and who can modify metric configurations.

7.2.3.2. Enable Scorecards

To monitor component health and quality in RHDH, you must enable the Scorecard plugin in your configuration.

Procedure

  • Add the following configuration in your RHDH dynamic-plugin-config.yaml file:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard:<tag>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-scorecard:
                entityTabs:
                  - path: '/scorecard'
                    title: Scorecard
                    mountPoint: entity.page.scorecard
                mountPoints:
                  - mountPoint: entity.page.scorecard/cards
                    importName: EntityScorecardContent
                    config:
                      layout:
                        gridColumn: 1 / -1
                      if:
                        allOf:
                          - isKind: component
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard-backend:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

7.2.3.3. Configure RBAC using the CSV file

You can grant read access to Scorecard metrics by adding permission policies to your RBAC CSV file.

Prerequisites

Procedure

  1. Add the following policy to your CSV file to allow users to view metrics:

    g, user:default/<YOUR_USERNAME>, role:default/scorecard-viewer
    p, role:default/scorecard-viewer, scorecard.metric.read, read, allow
    p, role:default/scorecard-viewer, catalog.entity.read, read, allow

    See Permission policies reference.

  2. Optional: Restrict access to specific metrics by defining a conditional policy in the rbac-conditional-policies.yaml file as described in Defining conditional policies:

    result: CONDITIONAL
    roleEntityRef: "role:default/scorecard-viewer"
    pluginId: scorecard
    resourceType: scorecard-metric
    permissionMapping:
      - read
    conditions:
      rule: HAS_METRIC_ID
      resourceType: scorecard-metric
      params:
        metricIds: [<your_metric_id>]

    where:

    metricIds

    Enter the metric ID for user access, such as github.open_prs.

    This policy allows users to read only the specified metrics and restricts access to all other metrics.

Verification

  • Verify that the user can view Scorecard metrics in RHDH.

7.2.3.4. Configure RBAC using the Web UI

You can grant read access to Scorecard metrics by using the RBAC Web UI in RHDH.

Prerequisites

Procedure

  1. In the Red Hat Developer Hub navigation menu, go to Administration > RBAC.
  2. Select or create the Role for Scorecard access.
  3. In the Add permission policies section, select Scorecard from the plugins list.
  4. Expand the Scorecard entry, select policy with the following details, and click Next:

    • Name: scorecard.metric.read
    • Permission: read

      The RBAC UI showing the scorecard.metric.read permission selected for a role
  5. Optional: Restrict access to specific metrics:

    1. In the Add permission policies step, select the following:

      • Name: scorecard.metrics.read
      • Permission: Read
    2. Click Use advanced customized permissions to allow access to specific parts of the selected resource type under Actions.
    3. Select the HAS_METRIC_ID rule and specify the plugin IDs, using commas to separate multiple IDs.

Verification

  • Verify that the user can view Scorecard metrics in RHDH.

7.2.4. Install and configure Scorecards

7.2.4.1. Install and configure Scorecards

Integrate external metric providers to populate Scorecard data from your existing development tools. Each provider connection enables specific health metrics that reflect real-time project activity.

7.2.4.2. Integrate GitHub health metrics

You can configure the GitHub Scorecard plugin to display repository metrics in your RHDH catalog. This integration allows you to monitor component health and security risks directly from Red Hat Developer Hub.

You can grant RHDH access to the GitHub API by using a GitHub App or a GitHub token.

Important

For long-lived integrations or organizational access, you must use a GitHub App.

Prerequisites

Procedure

  1. Grant GitHub API access: Create one of the following authentication methods:

    • Configure using a GitHub App.

      1. Create a GitHub App with the required permissions (Read-only for Contents to allow reading repositories).

        Note

        You must install the GitHub App on the organization (or user account) that owns repositories you want access to, granting it the necessary repository access permissions.

        1. In the General > Clients secrets section, click Generate a new client secret.
        2. In the General > Private keys section, click Generate a private key.
        3. In the Install App tab, choose an account to install your GitHub App on.
        4. Record the App ID, Client ID, Client Secret, and Private key values.
      2. Add secrets to RHDH by adding the following key/value pairs to your RHDH secrets. You can use these secrets in the RHDH configuration files by using the corresponding environment variable name for each secret.

        • GITHUB_INTEGRATION_APP_ID:: The saved App ID.
        • GITHUB_INTEGRATION_CLIENT_ID:: The saved Client ID.
        • GITHUB_INTEGRATION_CLIENT_SECRET:: The saved Client Secret.
        • GITHUB_INTEGRATION_HOST_DOMAIN:: The GitHub host domain: github.com.
        • GITHUB_INTEGRATION_ORGANIZATION:: Your GitHub organization name, such as <your_github_organization_name>.
        • GITHUB_INTEGRATION_PRIVATE_KEY_FILE:: The saved Private key content.
      3. Configure the GitHub integration in your RHDH app-config.yaml file by adding the authentication details to the integrations.github section:

        integrations:
          github:
            - host: ${GITHUB_INTEGRATION_HOST_DOMAIN}
              apps:
                - appId: ${GITHUB_INTEGRATION_APP_ID}
                  clientId: ${GITHUB_INTEGRATION_CLIENT_ID}
                  clientSecret: ${GITHUB_INTEGRATION_CLIENT_SECRET}
                  privateKey: |
                    ${GITHUB_INTEGRATION_PRIVATE_KEY_FILE}
    • Configure using a GitHub token.

      1. Create a GitHub token with the following permissions:

      2. Add the token to RHDH secrets by adding the following key/value pair to your RHDH secrets.

        where:

        GITHUB_TOKEN
        The generated GitHub token.
      3. Configure the GitHub integration in your RHDH app-config.yaml file by adding the authentication details to the integrations.github section:

        integrations:
          github:
            - host: github.com
              token: ${GITHUB_TOKEN}
  2. Enable the GitHub Scorecard plugin: Add the GitHub Scorecard module to your RHDH dynamic-plugins-config.yaml file:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard-backend-module-github:<tag>
        disabled: false

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  3. Find your Backstage version in the RHDH release notes preface.
  4. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  5. Annotate catalog entities: Link a component to the GitHub data source by editing the catalog-info.yaml file for your RHDH entity and adding the required annotations as shown in the following code:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: my-service
      annotations:
        # Required: GitHub project slug in format "owner/repository"
        github.com/project-slug: myorg/my-service
        # Required: Entity source location
        backstage.io/source-location: url:https://github.com/myorg/my-service
    spec:
      type: service
      lifecycle: production
      owner: _<your_team_name>_

    where:

    annotations:github.com/project-slug
    The GitHub repository format, for example, owner/repository.
    annotations:backstage.io/source-location
    The entity source location format, for example, url:https://github.com/owner/repository.
    spec:owner

    Your team name.

    Note

    You must add the team entity to the Catalog to ensure the provided permissions are applicable.

  6. Ingest the catalog entity: Add the location of your catalog-info.yaml to the catalog.locations section in your RHDH app-config.yaml file:

    catalog:
      locations:
        - type: url
          target: https://github.com/<owner>/<repository>/catalog-info.yaml
  7. Optional: Customize thresholds: Define custom roles for the GitHub Open Pull Requests (github.open_prs) metric in your RHDH app-config.yaml file:

    scorecard:
      plugins:
        github:
          open_prs:
            thresholds:
              rules:
                - key: success
                  expression: '<10'
                - key: warning
                  expression: '10-50'
                - key: error
                  expression: '>50'

    where:

    scorecard:plugins:github:open_prs:thresholds
    Lists the default threshold values for the GitHub open PRs metric.

7.2.4.3. Integrate Jira health metrics

You can configure the Jira Scorecard plugin to display project tracking and delivery velocity data in your RHDH instance. This integration centralizes development status and facilitates the evaluation of component readiness.

The plugin supports Jira Cloud (API v3) and Jira Data Center (API v2).

Prerequisites

Procedure

  1. Generate a Jira configuration token using one of the following methods, depending on your Jira product:

    • Jira Cloud: Create a personal token. You must create a Base64-encoded string using the following plain text format: your-atlassian-email:your-jira-api-token.

      $ echo -n 'your-atlassian-email:your-jira-api-token' | base64
    • Jira data center: Create a Personal Access Token (PAT) in your Jira data center account.
  2. Add Jira secrets: Define the following key/value pairs in your RHDH secrets:

    JIRA_TOKEN
    Enter your generated Jira token.
    JIRA_BASE_URL
    Enter your Jira base URL.
  3. Configure the plugin: In your RHDH dynamic-plugins-config.yaml file, enable the plugin using either a direct setup or a proxy setup.

    Note

    You must use the proxy setup to ensure configuration compatibility if you also use the Roadie Jira Frontend Plugin.

    • Use a direct setup:

      1. Add the following code to your RHDH dynamic-plugins-config.yaml file:

        plugins:
          - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard-backend-module-jira:<tag>
            disabled: false

        where:

        <tag>
        Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  4. Find your Backstage version in the RHDH release notes preface.
  5. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    1. In your RHDH app-config.yaml file, add the following direct setup settings:

      jira:
        baseUrl: ${JIRA_BASE_URL}
        token: ${JIRA_TOKEN}
        product: _<jira_product>_

      where:

      baseUrl
      The base URL of your Jira instance, configured under ${JIRA_BASE_URL} in your RHDH secrets.
      token
      The Jira token (Base64 string for Cloud, PAT for Data Center), configured under ${JIRA_TOKEN} in your RHDH secrets.
      product

      Enter the supported product: cloud or datacenter.

      • Use a proxy setup:
    2. In your RHDH dynamic-plugins-config.yaml file, add the following code:

      plugins:
        - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard-backend-module-jira:<tag>
          disabled: false

      where:

      <tag>
      Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  6. Find your Backstage version in the RHDH release notes preface.
  7. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    1. In your RHDH app-config.yaml file, add the following proxy settings:

      proxy:
        endpoints:
          '/jira/api':
            target: ${JIRA_BASE_URL}
            headers:
              Accept: 'application/json'
              Content-Type: 'application/json'
              X-Atlassian-Token: 'no-check'
              Authorization: ${JIRA_TOKEN} # Must be configured in your environment
      jira:
        proxyPath: /jira/api
        product: cloud # Change to 'datacenter' if using Jira Datacenter

      where:

      target
      The base URL of your Jira instance, configured under ${JIRA_BASE_URL} in your RHDH secrets.
      Authorization

      The Jira token, configured under ${JIRA_TOKEN} in your RHDH secrets. Set the token value as one of the following values:

      • For Cloud: Basic YourCreatedCloudToken
      • For Data Center: Bearer YourJiraToken
  8. Annotate catalog entities: Add the Jira project key to the metadata.annotations section of the catalog-info.yaml file for your component:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: my-service
      annotations:
        jira/project-key: PROJECT
        jira/component: Component
        jira/label: UI
        jira/team: 9d3ea319-fb5b-4621-9dab-05fe502283e
        jira/custom-filter: 'reporter = "abc@xyz.com" AND resolution is not EMPTY'
    spec:
      type: website
      lifecycle: experimental
      owner: guests
      system: examples
      providesApis: [example-grpc-api]

    where:

    jira/project-key
    Required: Enter the Jira project key.
    jira/component
    Optional: Enter the Jira component name.
    jira/label
    Optional: Enter the Jira label.
    jira/team
    Optional: Enter the Jira team ID (not the team title).
    jira/custom-filter
    Optional: Enter a custom Jira Query Language (JQL) filter.
  9. Ingest the catalog entity: Add the location of your catalog-info.yaml to the catalog.locations section in the RHDH app-config.yaml file:

    catalog:
      locations:
        - type: url
          target: https://github.com/<owner>/<repository>/catalog-info.yaml
  10. Optional: Define metric thresholds and filters: To customize health criteria or filter issues, add the Jira Open Issues metric thresholds to your RHDH app-config.yaml file:

    scorecard:
      plugins:
        jira:
          open_issues:
            thresholds:
              rules:
                - key: success
                  expression: '<10'
                - key: warning
                  expression: '10-50'
                - key: error
                  expression: '>50'

    where:

    scorecard:plugins:jira:open_issues:thresholds
    Lists the default threshold values for the Jira Open Issues metric.
  11. Optional: Define global or custom mandatory filters that entities can override by adding the following code to your RHDH app-config.yaml file:

    scorecard:
      plugins:
        jira:
          open_issues:
            options:
              mandatoryFilter: Type = Task AND Resolution = Unresolved
              customFilter: priority in ("Critical", "Blocker")

    where:

    mandatoryFilter
    Optional: Replaces the default filter (type = Bug and resolution = Unresolved).
    customFilter

    Optional: Specifies a global custom filter. The entity annotation jira/custom-filter overrides this value.

    For more information about how to customize the threshold values, see Thresholds in Scorecard plugins.

7.2.4.4. Integrate OpenSSF security metrics by using Scorecards

Important

This section describes Developer Preview features in the Scorecard plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

You can configure the OpenSSF Scorecard module to display security and compliance metrics from the OpenSSF Scorecard project in your RHDH catalog.

By default, the module fetches data from the public OpenSSF Scorecard API, which requires no authentication and supports public GitHub repositories. Alternatively, the annotation can point to any HTTPS endpoint that serves OpenSSF Scorecard JSON data, such as a self-hosted instance or a static file.

Prerequisites

Procedure

  1. Enable the OpenSSF Scorecard module: Add the following configuration to your RHDH dynamic-plugins-config.yaml file:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard-backend-module-openssf:<tag>
        disabled: false

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  2. Find your Backstage version in the RHDH release notes preface.
  3. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  4. Annotate catalog entities: Link a component to the OpenSSF Scorecard data source by editing the catalog-info.yaml file for your RHDH entity and adding the required annotation as shown in the following code:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: my-service
      annotations:
        openssf/scorecard-location: https://api.securityscorecards.dev/projects/github.com/_<owner>_/_<repository>_
    spec:
      type: service
      lifecycle: production
      owner: _<your_team_name>_

    where:

    annotations:openssf/scorecard-location
    Specifies the full URL to the OpenSSF Scorecard API endpoint for the repository. The URL must start with https://.
    spec:owner

    Specifies your team name.

    Note

    For organizations running a self-hosted OpenSSF Scorecard instance, replace api.securityscorecards.dev with the URL of your instance.

  5. Ingest the catalog entity: Add the location of your catalog-info.yaml to the catalog.locations section in your RHDH app-config.yaml file:

    catalog:
      locations:
        - type: url
          target: https://github.com/<owner>/<repository>/catalog-info.yaml
    Important

    OpenSSF metrics use fixed, non-configurable thresholds. Unlike GitHub and Jira metrics, you cannot customize these thresholds.

    Error
    Score below 2.
    Warning
    Score between 2 and 7.
    Success
    Score above 7.

7.2.4.5. Configure file-level checks to verify repositories contain required compliance documentation

Important

This section describes Developer Preview features in the Scorecard plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

You can configure the Scorecard filecheck module to verify that repositories contain required files such as LICENSE, CODEOWNERS, CONTRIBUTING.md, or any file that you have configured. Each configured file generates a boolean metric that reports whether the file is present or missing.

Prerequisites

Procedure

  1. Enable the filecheck module: Add the following configuration to your RHDH dynamic-plugins-config.yaml file:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard-backend-module-filecheck:<tag>
        disabled: false

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  2. Find your Backstage version in the RHDH release notes preface.
  3. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  4. Configure the files to check: Define which files to verify in your RHDH app-config.yaml file:

    scorecard:
      plugins:
        filecheck:
          files:
            license: LICENSE
            codeowners: CODEOWNERS
            contributing: CONTRIBUTING.md
            readme: README.md

    where:

    scorecard:plugins:filecheck:files

    A map of file checks. Each key becomes a metric ID suffix (for example, license produces the filecheck.license metric) and each value is the relative file path to check within the repository.

    Important

    File paths must be relative. Do not use a leading /, ./, or ../ prefix in the path. When no files are configured, no metrics are registered and the module is inactive.

  5. Optional: Customize the collection schedule: By default, the filecheck module collects metrics every hour. To override the schedule, add the following configuration to your RHDH app-config.yaml file:

    scorecard:
      plugins:
        filecheck:
          schedule:
            frequency:
              cron: '0 6 * * *'
            timeout:
              minutes: 5
            initialDelay:
              seconds: 5
    Note

    All configured file checks share one schedule. The module fetches each entity’s repository tree once per run and checks all configured paths in that single request.

  6. Verify the entity annotation: Confirm that your catalog entities have the backstage.io/source-location annotation set:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: my-service
      annotations:
        backstage.io/source-location: url:https://github.com/myorg/my-service
    spec:
      type: service
      lifecycle: production
      owner: _<your_team_name>_

    where:

    annotations:backstage.io/source-location
    The entity source location. The filecheck module uses this annotation to resolve the source repository and read its file tree.
    spec:owner

    Your team name.

    Note

    This annotation is usually added automatically during catalog ingestion. If your entities are already registered in the catalog, this annotation is likely already present.

    Important

    Filecheck metrics use fixed boolean thresholds. Unlike GitHub and Jira metrics, you cannot customize these thresholds.

    exist
    File is present (success).
    missing
    File is absent (error).

7.2.4.6. Disable specific scorecard metrics per entity

You can disable specific scorecard metrics for an individual catalog entity by adding an annotation to its catalog-info.yaml file. This applies to metrics from any provider, including GitHub, Jira, and OpenSSF. Disabled metrics are not calculated.

Procedure

  • Add the scorecard.io/disabled-metrics annotation to the catalog-info.yaml file for your RHDH entity:

    metadata:
      annotations:
        scorecard.io/disabled-metrics: openssf.maintained,filecheck.readme,filecheck.license

    where:

    scorecard.io/disabled-metrics
    Enter a comma-separated list of metric IDs to disable for this entity. You can use IDs from any provider. For available values, see Available scorecard metric providers and metric IDs.

7.2.4.7. Disable scorecard metrics globally

You can disable specific scorecard metrics globally across all catalog entities, and control whether entity owners can disable additional metrics by using annotations.

Procedure

  • Add the following configuration to your RHDH app-config.yaml file:

    scorecard:
      disabledMetrics:
        - openssf.packaging
      entityAnnotations:
        disabledMetrics:
          enabled: true
          except:
            - openssf.maintained

    where:

    disabledMetrics
    Enter a list of metric IDs to disable globally. Metrics in this list are always skipped and cannot be overridden by entity annotations. For available values, see Available scorecard metric providers and metric IDs.
    entityAnnotations.disabledMetrics.enabled
    Enter true to allow entity owners to disable metrics by using the scorecard.io/disabled-metrics annotation. Enter false to prevent entity owners from disabling metrics. Defaults to true.
    entityAnnotations.disabledMetrics.except
    Enter a list of metric IDs that entity owners cannot disable, even when enabled is true. Use this to ensure critical metrics always run.

7.2.5. Manage metric thresholds

7.2.5.1. Manage metric thresholds

Define threshold rules that categorize metric values into pass, warning, and fail states. Threshold management controls how Scorecards evaluate component health and flag noncompliant services.

7.2.5.2. Metric categorization criteria

A threshold defines conditions or expressions to assign metric values to specific visual categories.

To categorize metric values accurately, you must follow the following evaluation rules:

  • Sequential evaluation: The system processes threshold rules in the order you define them and applies only the first matching rule.
  • Restrictive ordering: You must sequence rules from the most restrictive range to the least restrictive range to verify that the system assigns categories correctly.
  • Supported categories: Use only the success, warning, and error keys to define thresholds.

7.2.5.3. Threshold expression syntax

Metric threshold expressions use mathematical and logical operators to evaluate data. Use the following operators to define health criteria based on the metric data type.

Metric TypeOperatorExample ExpressionJob Performed

Number

>, >=, <, , ==, !=

>40

The category applies if the value is greater than 40.

Number

- (Range)

80-100

The category applies if the value is between 80 and 100 (inclusive).

Boolean

==, !=

==true

The category applies if the value is exactly true.

7.2.5.4. Resolve configuration conflicts using threshold precedence

Threshold rules follow a specific order of precedence. Higher-priority configurations override lower-priority settings, allowing you to define global defaults with entity-specific exceptions.

PriorityConfiguration MethodLocationJob Performed

1 (Highest)

Entity Annotations

catalog-info.yaml

Overrides specific rules for a single component.

2 (Medium)

App Configuration

app-config.yaml

Sets global rules that override provider defaults.

3 (Lowest)

Provider Defaults

Backend Plugin Code

Baseline rules defined by the metric source.

7.2.5.5. Standardize metric thresholds across components

You can define global thresholds in your RHDH app-config.yaml file to standardize health indicators across all components. Global configurations replace the default thresholds provided by a metric source.

If you omit a threshold category, such as success, the Scorecard plugin does not assign that category to the metric.

The following example defines thresholds for the jira.open_issues metric. These settings apply to all components using this metric unless an entity annotation overrides them.

scorecard:
  plugins:
    jira:
      open_issues:
        thresholds:
          rules:
            - key: success
              expression: '<10'    # fewer than 10 open issues
            - key: warning
              expression: '10-50'    # Between 10 and 50 open issues
            - key: error
              expression: '>50'      # More than 50 open issues

7.2.5.6. Component-specific threshold rules

Use annotations in the catalog-info.yaml file of a component to override global threshold rules. These annotations merge with and take precedence over the global rules defined in your RHDH app-config.yaml file.

7.2.5.6.1. Annotation structure

The annotation key must use the following format: scorecard.io/{providerId}.thresholds.rules.{thresholdKey}: '{expression}'

ElementDescriptionExample AnnotationExample Value

{providerId}

Unique identifier of the metric

scorecard.io/jira.open_issues…​

jira.open_issues

{thresholdKey}

The overridden category

…​rules.warning

success, warning, or error

{expression}

The new condition for the rule

…​: '>15'

>15

7.2.5.6.2. Example: Override global Jira thresholds

In the following example, the component overrides the warning and error rules for the jira.open_issues metric. The success rule remains unchanged from the global configuration.

# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: critical-production-service
  annotations:
    # Changes global 'warning' from '10-50' to '10-15'
    scorecard.io/jira.open_issues.thresholds.rules.warning: '10-15'
    # Changes global 'error' from '>50' to '>15'
    scorecard.io/jira.open_issues.thresholds.rules.error: '>15'
spec:
  type: service

7.2.5.7. Logical flow verification

To ensure Scorecard assigns the correct health status, order rules carefully, because the evaluation stops at the first matching rule.

Evaluation order for rules
To ensure the system evaluates all values correctly, sequence rules from the most strict (smallest range) value to the least strict (largest range). If rules are ordered incorrectly, a broad rule can prevent the system from reaching stricter rules.
Problematic rule order example

If rules are ordered incorrectly, a less restrictive rule can prevent stricter rules from being evaluated:

  1. warning: <50: Any value less than 50 triggers the warning rule and stops evaluation.
  2. success: <10: This rule is not evaluated because all values less than 10 have already matched the preceding warning rule.
Correct ordering example
The following example demonstrates the correct sequence for successes, warnings, and errors:
rules:
  - key: success
    expression: '<10'     # Most restrictive: Only values below 10
  - key: warning
    expression: '10-50'   # Values between 10 and 50
  - key: error
    expression: '>50'     # Least restrictive: All values above 50

7.2.5.8. Configure custom severity levels and colors for Scorecard

Customizing severity thresholds and color mappings in your Scorecard configuration allows you to visualize platform metrics using your organization’s custom operational terminology.

Note

Each custom severity threshold key requires both a corresponding icon configuration value and a color parameter configuration value. The scorecard plugin validates the YAML configuration files during application startup. Omitting either property or providing an invalid value causes an initialization failure, and the Scorecard plugin fails to function.

Prerequisites

  • You have administrative access to the Red Hat Developer Hub configuration files.
  • You have added a custom application configuration file to your Red Hat Developer Hub deployment workspace.
  • You have installed Scorecard backend and frontend plugins, and at least one Scorecard plugin module.

Procedure

  1. Open the RHDH app-config.yaml file.
  2. Navigate to the scorecard.plugins backend threshold definition block.
  3. Define your custom severity threshold keys by adding a structured rule entry containing your custom key string, your boundary expression, your preferred color parameter format, and a supported icon string variable.

    scorecard:
      plugins:
        myDatasource:
          myMetric:
            thresholds:
              rules:
                - key: ideal
                  expression: '<10'
                  color: '#5CE65C'
                  icon: star
                - key: warning
                  expression: '10-50'
                  color: 'rgb(233, 213, 2)'
                  icon: monitor
                - key: critical
                  expression: '>50'
                  color: error.main
                  icon: scorecardErrorStatusIcon

    where:

    myDatasource
    represents your specific scorecard data source, such as jira
    myMetric

    represents the metric identifier, such as open_issues

    Note

    Custom severity thresholds and color configurations are only functional for scorecard plugin modules that support custom rules. At this time, the filecheck, openssf, and dependabot modules do not support custom thresholds.

  4. Save the changes to the configuration file.
  5. Restart your Red Hat Developer Hub instance to apply the new threshold rules.

Verification

  • Open the Red Hat Developer Hub UI, navigate to the Scorecard component, and verify that the custom severity levels display with the colors and icons you specified.

7.2.5.9. Scorecard color and icon configuration formats

Learn the supported color string formats and syntax rules required to map custom severity threshold keys in the configuration parser.

7.2.5.9.1. Threshold color mapping values
Color format typeConfiguration examples

Theme palette references

success.main, warning.main, error.main

HEX hexadecimal codes

'#5CE65C', '#FFA500'

RGB or RGBA functional strings

'rgb(233, 213, 2)', 'rgba(255, 0, 0, 0.8)'

Note

The default threshold rules use the built-in theme palette references: success.main for success states, warning.main for warning states, and error.main for error states. You can use these standard theme indicators for custom severity levels if desired.

7.2.5.9.2. Supported threshold icon configuration formats

To determine what graphic displays in the metrics matrix block, the Scorecard plugin uses standard frontend mapping components, allowing you to specify icons using any of the following parameters.

Note

When using Material Design strings, use only icons from the internal icon catalog, such as star or monitor. Standard upstream values that are not added, such as check, will not appear in the user interface. You can use default icons or extend the icon set with dynamic plugins.

7.2.5.9.3. Threshold icon component options
Icon syntax layoutValue definition format examples

Backstage system icons

'kind:component', 'kind:api'

Material Design icon strings

'home', 'star', 'monitor'

Inline SVG strings

Raw XML element blocks (for example, '<svg>…​</svg>')

External URLs

'https://example.com/icon.png', '/assets/icon.svg'

Data encoded URIs

'data:image/svg+xml;base64,…​'

Note

The default threshold rules use pre-configured icons: scorecardSuccessStatusIcon for success rule matches, scorecardWarningStatusIcon for warning rule matches, and scorecardErrorStatusIcon for error rule matches. You can use these pre-configured icons for custom severity levels if desired.

7.2.6. Monitor component health

You can view metrics to evaluate the health and security of your software components directly in the RHDH catalog.

Prerequisites

  • You have installed your RHDH instance.
  • You have configured the GitHub or Jira Scorecard (or both) plugin.
  • If RBAC is enabled, you have a role with the following permission: scorecard.metric.read.

Procedure

  1. In your RHDH navigation menu, go to Catalog.
  2. Select the software component (catalog entity) that has Scorecard metrics configured.
  3. On the component Service page, click the Scorecard tab.
  4. Select a metric tile to view detailed data.

7.3. Monitor portfolio health using aggregated Scorecard KPIs

7.3.1. Monitor portfolio health using aggregated Scorecard KPIs

Track compliance trends across your entire software portfolio by using aggregated Scorecard KPIs. Aggregated views surface systemic issues that individual component scores cannot reveal, enabling data-driven prioritization of remediation work.

7.3.2. Monitor collective health

7.3.2.1. Monitor collective health

View aggregated compliance metrics across all components owned by your team or organization. Collective health monitoring identifies portfolio-wide trends that require coordinated remediation.

7.3.2.2. Monitor portfolio health with aggregated KPIs

Use aggregated Key Performance Indicators (KPIs) to identify high-level health trends and technical risks across your portfolio. By consolidating metrics from multiple entities in the Software Catalog, you can assess the health of your entire team from a single dashboard.

To maintain RHDH performance, the Scorecard plugin fetches data from external sources on schedule and saves them to a database. Although the backend calculates KPIs in real time using this stored data, the synchronization of metrics for each entity occurs hourly by default. You have the option to customize the refresh schedule to balance your requirement for current data with the system processing load.

The aggregation endpoint (/metrics/:metricId/catalog/aggregations) summarizes metrics based on entity ownership. By default, the plugin only considers direct ownership, which includes the following entities:

  • Entities you own directly.
  • Entities owned by groups where you are a direct member.

The plug-in does not traverse nested group hierarchies unless you enable transitive parent group ownership.

The plugin supports simple aggregation logic, such as summing values (SUM) or calculating averages (AVERAGE) across entities.

7.3.2.3. Aggregated KPIs in the scorecard

Monitor the technical health and regulatory compliance of your infrastructure by using aggregated Key Performance Indicators (KPIs). These KPIs summarize complex data from multiple entities into a high-level overview, allowing you to identify system risks quickly.

Aggregated KPIs allow engineering and product managers to monitor the collective status of all entities the viewer owns in the Software Catalog. Instead of manually inspecting individual service scorecards, managers can use these metrics to identify broad trends or risks within their portfolio.

Aggregated metrics rely on the owner field defined in the Software Catalog entities to determine which data points to include. The scorecard plugin performs scheduled batch processing to calculate these values; therefore, aggregated data is not updated in real-time.

The plugin supports simple aggregation logic, such as summing values (SUM) or calculating averages (AVERAGE) across entities.

7.3.3. Configure aggregated Scorecard KPIs

7.3.3.1. Configure aggregated Scorecard KPIs

Configure home page cards, scheduling intervals, and retention policies for aggregated Scorecard KPIs. Aggregation settings control how frequently metrics refresh, how long historical data persists, and where summary dashboards appear.

7.3.3.2. Aggregated KPIs in the scorecard

Monitor the technical health and regulatory compliance of your infrastructure by using aggregated Key Performance Indicators (KPIs). These KPIs summarize complex data from multiple entities into a high-level overview, allowing you to identify system risks quickly.

Aggregated KPIs allow engineering and product managers to monitor the collective status of all entities the viewer owns in the Software Catalog. Instead of manually inspecting individual service scorecards, managers can use these metrics to identify broad trends or risks within their portfolio.

Aggregated metrics rely on the owner field defined in the Software Catalog entities to determine which data points to include. The scorecard plugin performs scheduled batch processing to calculate these values; therefore, aggregated data is not updated in real-time.

The plugin supports simple aggregation logic, such as summing values (SUM) or calculating averages (AVERAGE) across entities.

7.3.3.3. Configure a default scorecard aggregation card

Add a standard scorecard summary card to your homepage using default, out-of-the-box configurations.

Prerequisites

  • The scorecard plugin is installed and configured in your Red Hat Developer Hub instance.
  • You have administrator permissions to update application configuration files.

Procedure

  1. Open your dynamic plugin configuration file.
  2. Navigate to your scorecard card block under the home.page/cards mount point.
  3. Update the configuration to use the aggregationId property with an established system metric name:

    - mountPoint: home.page/cards
      importName: ScorecardHomepageCard
      config:
        props:
          aggregationId: "github.open_prs"
        layouts:
          xl: { w: 3, h: 6, x: 3 }
          lg: { w: 4, h: 6, x: 4 }
          md: { w: 6, h: 6, x: 6 }
          sm: { w: 12, h: 6 }
          xs: { w: 12, h: 6 }
          xxs: { w: 12, h: 6 }
  4. Save the modified configuration file and restart your Red Hat Developer Hub instance.

Verification

  1. Access your Developer Hub homepage interface.
  2. Verify that the standard scorecard summary card displays with default metrics.

7.3.3.4. Configure aggregated KPIs for the scorecard

Define aggregated Key Performance Indicators (KPIs) in your configuration to provide a consolidated view of team or group health. Aggregating KPIs allows you to summarize technical metrics into high-level insights for management and stakeholders.

Prerequisites

  • The scorecard plugin is installed and configured in your Red Hat Developer Hub instance.
  • You have identified the metricId you want to aggregate.

Procedure

  1. Access your app-config.yaml file.
  2. Navigate to the scorecard section and add an aggregationKPIs block.
  3. Update the configuration to create a homepage card that summarizes a specific metric for a team portfolio. The following example adds a Jira open issues card that groups counts by threshold status for the entities that the signed-in user owns:

    scorecard:
      aggregationKPIs:
        openIssuesKpi:
          title: 'Jira open issues KPI'
          description: 'Open issues across entities you own, grouped by status.'
          type: statusGrouped
          metricId: jira.open_issues

    where:

    scorecard.aggregationKPIs
    Map of KPI keys to KPI definitions. Each key is an aggregation ID. For example openIssuesKpi.
    title
    Title shown for the KPI.
    description
    Short description of the KPI.
    type
    Aggregation strategy. Use statusGrouped for counts per threshold status, or average for a weighted portfolio score.
    metricId
    Metric provider ID. For example jira.open_issues, github.open_prs.
  4. Save the configuration and restart your Red Hat Developer Hub instance.

Verification

  1. Navigate to the Developer Hub homepage.
  2. Verify that the new aggregated card is displayed with the defined name and calculated value.

7.3.3.5. Configure an aggregation card with a status-grouped tracking type

Configure a scorecard aggregation card to count entities based on status thresholds.

Prerequisites

  • The scorecard plugin is installed and configured in your Red Hat Developer Hub instance.

Procedure

  1. Open your app-config.yaml file.
  2. Navigate to the scorecard section and define your backend Key Performance Indicator (KPI) map within an aggregationKPIs block, setting the tracking type to statusGrouped:

    scorecard:
      aggregationKPIs:
        team-alpha-bugs:
          title: "Team Alpha Bug KPI"
          description: "Portfolio bug counts grouped by status threshold"
          type: statusGrouped
          metricId: jira.open_issues
  3. Open your dynamic plugin configuration file.
  4. Reference your custom aggregation ID inside the homepage card properties block under the home.page/cards mount point:

    - mountPoint: home.page/cards
      importName: ScorecardHomepageCard
      config:
        props:
          aggregationId: "team-alpha-bugs"
        layouts:
          xl: { w: 3, h: 6 }
          lg: { w: 4, h: 6 }
          md: { w: 6, h: 6 }
          sm: { w: 12, h: 6 }
          xs: { w: 12, h: 6 }
          xxs: { w: 12, h: 6 }
  5. Save the modified configuration files and restart your Red Hat Developer Hub instance.

Verification

  1. Access your Developer Hub homepage interface.
  2. Verify that the status-grouped scorecard summary card displays with your defined title and calculations.

7.3.3.6. Configure an aggregation card with an average tracking type

Configure a scorecard aggregation card to calculate a single weighted portfolio score across multiple components.

Prerequisites

  • The scorecard plugin is installed and configured in your Red Hat Developer Hub instance.

Procedure

  1. Open your app-config.yaml file.
  2. Navigate to the scorecard section and define your backend Key Performance Indicator (KPI) map within an aggregationKPIs block, setting the tracking type to average.
  3. Add the required statusScores map to bind numeric weights to your status rules:

    scorecard:
      aggregationKPIs:
        portfolio-average-health:
          title: "Portfolio Health KPI"
          description: "Weighted average score across portfolio components"
          type: average
          metricId: github.open_prs
          options:
            statusScores:
              success: 100
              warning: 50
              error: 0
  4. Optional: To override the built-in system defaults, add custom threshold parameters using a continuous, gapless number range evaluated on a scale of 0 to 100:

    options:
      statusScores:
        success: 100
        warning: 50
        error: 0
      thresholds:
        rules:
        - key: success
          expression: '>=80'
          color: '#6bb300'
        - key: warning
          expression: '51-80'
          color: 'rgb(224, 189, 108)'
        - key: error
          expression: '<51'
          color: '#be1ec7'
        - key: critical
          expression: '<10'
          color: '#ff0000'
  5. Open your dynamic plugin configuration file.
  6. Reference your average tracking aggregation ID inside the homepage card properties block under the home.page/cards mount point:

    - mountPoint: home.page/cards
      importName: ScorecardHomepageCard
      config:
        props:
          aggregationId: "portfolio-average-health"
        layouts:
          xl: { w: 3, h: 6 }
          lg: { w: 4, h: 6 }
          md: { w: 6, h: 6 }
          sm: { w: 12, h: 6 }
          xs: { w: 12, h: 6 }
          xxs: { w: 12, h: 6 }
  7. Save the modified configuration files and restart your Red Hat Developer Hub instance.

Verification

  1. Access your Developer Hub homepage interface.
  2. Verify that the weighted average scorecard summary card displays with your custom scores and thresholds.

7.3.3.7. Configure portfolio health

7.3.3.7.1. Configure portfolio health

Add portfolio health cards to the Red Hat Developer Hub home page to display aggregated compliance summaries. Card placement depends on whether you use a customizable or read-only home page layout.

7.3.3.7.2. Configure on a customizable home page

You can add the aggregated Scorecard widget to a customizable RHDH home page to monitor the collective technical health of your portfolio.

Prerequisites

Procedure

  1. Update your RHDH app-config.yaml with the following code:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard:<tag>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-scorecard:
                entityTabs:
                  - path: "/scorecard"
                    title: Scorecard
                    mountPoint: entity.page.scorecard
                mountPoints:
                  - mountPoint: entity.page.scorecard/cards
                    importName: EntityScorecardContent
                    config:
                      layout:
                        gridColumn: 1 / -1
                  - mountPoint: home.page/cards
                    importName: ScorecardHomepageCard
                    config:
                      id: "scorecard-jira.open_issues"
                      title: "Jira open blocking tickets"
                      props:
                        metricId: "jira.open_issues"
                  - mountPoint: home.page/cards
                    importName: ScorecardHomepageCard
                    config:
                      id: "scorecard-github.open_prs"
                      title: "GitHub open PRs"
                      props:
                        metricId: "github.open_prs"
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-dynamic-home-page:
                dynamicRoutes:
                  - path: /
                    importName: DynamicCustomizableHomePage

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  2. Find your Backstage version in the RHDH release notes preface.
  3. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    For more information, see Customizing Red Hat Developer Hub.

  4. Log in to the RHDH application.
  5. Enter the Edit mode on the home page.
  6. Click Add widget and select the metric to include.

    Note

    You can add only one metric at a time.

  7. Drag the widget to your preferred layout position.
  8. Click Save.

Verification

  1. Log in to RHDH.
  2. On the Home page, verify that the aggregated Scorecard widget appears with the name you provided.
  3. Confirm that the displayed KPIs reflect the status of your owned components, systems, and resources.
7.3.3.7.3. Configure on a read-only home page

You can add the aggregated Scorecard widget to a read-only RHDH home page to monitor the collective technical health of your portfolio.

Prerequisites

Procedure

  1. Open your RHDH app-config.yaml file. For more information, see Configuring Red Hat Developer Hub.
  2. Add the aggregated Scorecard mount points to the dynamic plugin configuration file:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard:<tag>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-scorecard:
                entityTabs:
                  - path: "/scorecard"
                    title: Scorecard
                    mountPoint: entity.page.scorecard
                mountPoints:
                  - mountPoint: entity.page.scorecard/cards
                    importName: EntityScorecardContent
                    config:
                      layout:
                        gridColumn: 1 / -1
                  - mountPoint: home.page/cards
                    importName: ScorecardHomepageCard
                    config:
                      props:
                        aggregationId: "jira.open_issues"
                      layouts:
                        xl: { w: 3, h: 6 }
                        lg: { w: 4, h: 6 }
                        md: { w: 6, h: 6 }
                        sm: { w: 12, h: 6 }
                        xs: { w: 12, h: 6 }
                        xxs: { w: 12, h: 6 }
                  - mountPoint: home.page/cards
                    importName: ScorecardHomepageCard
                    config:
                      props:
                        aggregationId: "github.open_prs"
                      layouts:
                        xl: { w: 3, h: 6, x: 3 }
                        lg: { w: 4, h: 6, x: 4 }
                        md: { w: 6, h: 6, x: 6 }
                        sm: { w: 12, h: 6 }
                        xs: { w: 12, h: 6 }
                        xxs: { w: 12, h: 6 }
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-dynamic-home-page:
                dynamicRoutes:
                  - path: /
                    importName: DynamicHomePage

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  3. Find your Backstage version in the RHDH release notes preface.
  4. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    Note

    The widget automatically calculates and displays aggregations for the entities you own. You do not have to manually configure filters or specify target owner groups in the widget settings.

Verification

  1. Log in to RHDH.
  2. On the Home page, verify that the aggregated Scorecard widget appears with the name you provided.
  3. Confirm that the displayed KPIs reflect the status of your owned components, systems, and resources.
7.3.3.7.4. Configure a default scorecard aggregation card

Add a standard scorecard summary card to your homepage using default, out-of-the-box configurations.

Prerequisites

  • The scorecard plugin is installed and configured in your Red Hat Developer Hub instance.
  • You have administrator permissions to update application configuration files.

Procedure

  1. Open your dynamic plugin configuration file.
  2. Navigate to your scorecard card block under the home.page/cards mount point.
  3. Update the configuration to use the aggregationId property with an established system metric name:

    - mountPoint: home.page/cards
      importName: ScorecardHomepageCard
      config:
        props:
          aggregationId: "github.open_prs"
        layouts:
          xl: { w: 3, h: 6, x: 3 }
          lg: { w: 4, h: 6, x: 4 }
          md: { w: 6, h: 6, x: 6 }
          sm: { w: 12, h: 6 }
          xs: { w: 12, h: 6 }
          xxs: { w: 12, h: 6 }
  4. Save the modified configuration file and restart your Red Hat Developer Hub instance.

Verification

  1. Access your Developer Hub homepage interface.
  2. Verify that the standard scorecard summary card displays with default metrics.

7.3.3.8. Schedule metrics

To balance data freshness with system performance and API rate limits, you can customize the collection frequency for Scorecard metrics. Scorecard uses the Backstage built-in scheduler service. The default refresh frequency is hourly, but you can adjust it for each metric.

Prerequisites

Procedure

  1. Open your RHDH app-config.yaml file.
  2. Navigate to the scorecard.plugins section.
  3. Add a schedule configuration for your specific data source and metric using the following structure:

    scorecard:
      plugins:
        my_datasource:
          example_metric:
            schedule:
              frequency:
                cron: '0 6 * * *'
              timeout:
                minutes: 5
              initialDelay:
                minutes: 1
  4. Define the schedule parameters based on the Backstage SchedulerServiceTaskScheduleDefinitionConfig schema.
  5. Save the file.
  6. Restart the RHDH backend to apply the changes.

    Important

    Constraints: You must make sure the configured frequency does not exceed the API rate limits of your metric provider.

Verification

  1. Review the backend logs to make sure the task is scheduled without errors.
  2. Verify that new metric data appears in the database according to the defined interval.

7.3.3.9. Adjust metric retention

To manage storage capacity and comply with data retention policies, adjust the number of days the Scorecard plugin retains metric data to align with your organization’s policies. By default, the system retains metrics for 365 days.

Procedure

  1. Open your RHDH app-config.yaml file.
  2. In the scorecard section, add or update the dataRetentionDays parameter with the desired number of days:

    scorecard:
      dataRetentionDays: 12
  3. Save the file.
  4. Restart the RHDH backend to apply the changes.

Verification

  1. Review the backend logs during the next scheduled cleanup cycle to make sure the job runs without errors.
  2. Query the database to confirm that records older than your specified limit are removed.

7.3.3.10. Establish ownership in the software catalog

To enable automatic metric aggregation in the Scorecard plugin, you must establish ownership relationships between users, groups, and components in the Software Catalog. The Scorecard plugin uses these definitions to calculate health trends based on who owns the entities.

When you implement the following examples, you must replace the placeholder values with your specific project details.

Group entity
The Group entity defines a team within a specific namespace.
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
  name: _<example_team>_
  namespace: _<your_namespace>_
spec:
  type: team
  children: [user:_<your_namespace>_/userName]
User entity
The User entity defines an individual and establishes their team membership by using the memberOf field.
apiVersion: backstage.io/v1alpha1
kind: User
metadata:
  name: userName
  title: Example User
spec:
  profile:
    displayName: Example User
  memberOf: [group:_<your_namespace>_/example-team]
Component entities
The Component specification defines the owner to include the component in a user’s or team’s aggregated metrics.
# Example of user ownership
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: _<user_owned_service>_
  annotations:
    github.com/_<your_project_name>_: example-org/example-repository
    jira/project-key: ET
spec:
  type: service
  owner: user:_<your_namespace>_/userName
  lifecycle: production
# Example of group ownership
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: _<group_owned_service>_
  annotations:
    github.com/_<your_project_name>_: example-org/example-repository
    jira/project-key: ET
spec:
  type: service
  owner: group:_<your_namespace>_/_<example_team>_
  lifecycle: production

7.3.3.11. View aggregated metrics for owned entities

View aggregated metrics for your owned entities in RHDH to monitor the collective health of your software portfolio. The Scorecard plugin consolidates these metrics based on your ownership definitions in the Software Catalog.

Prerequisites

  • (To view aggregated KPIs) You have established owner group relationships in the Software Catalog.
  • You have added a custom Developer Hub application configuration.
  • You have the catalog.entity.read permission for the entities included in the aggregation.
  • You have the scorecard.metric.read permission to view aggregated metrics on the home page.

Procedure

  1. Navigate to your RHDH home page.
  2. Locate the Scorecard dashboard to view the aggregated metrics for your owned entities.
  3. Optional: To include entities from a nested group hierarchy in the aggregation, you must enable transitive parent group ownership.

Verification

  • Confirm that the displayed Key Performance Indicators (KPIs) reflect the status of all components, systems, and resources defined under your ownership in the Software Catalog.

7.3.3.12. Scorecard card configuration parameters

Parameters for application settings and dynamic plugin files used to manage homepage visualizations and portfolio data logic.

7.3.3.12.1. Dynamic plugin properties
PropertyDescription

aggregationId

The target identifier for the homepage visualization block. Accepts a default system metric name string or a custom KPI key mapped in your core settings.

metricId

[Deprecated] Legacy identifier for the source metric string. Supported for backwards compatibility but scheduled for removal in a future release. Replace with aggregationId.

7.3.3.12.2. Application configuration properties (scorecard.aggregationKPIs)
PropertyDescription

title

The primary textual label rendered on the header block of the homepage card.

description

A brief text string summarizing the target scope of the KPI.

type

The structural tracking strategy. Specify statusGrouped to return independent numerical entity counts per threshold status layer, or specify average to calculate a single weighted portfolio score.

metricId

The unique provider identifier mapping to the individual source plugin collection layer.

7.3.3.12.3. Options parameters for the average tracking type
options.statusScores
Map of threshold status rule keys (success, warning, error) to numeric weight integers. This parameter is required for the average type and must be non-empty; missing or empty maps cause application startup failures.
options.thresholds
Optional numeric value array tracking custom status levels evaluated against the averageScore output value on a scale from 0 to 100 with one decimal place. If omitted, the system falls back to default values: less than 30 indicates an error, 30 to 79 indicates a warning, and 80 or higher indicates a success. Custom configurations must provide full real-line range coverage with no numeric gaps.

7.3.4. Identify services impacting team compliance KPIs

7.3.4.1. Identify services impacting team compliance KPIs

Query the Scorecard REST API to retrieve metric data and identify which services drive down team compliance scores. Programmatic access enables integration with external dashboards, alerting systems, and automated remediation workflows.

7.3.4.2. View detailed metrics from aggregated scorecard KPIs

Configure the Red Hat Developer Hub Scorecard plugin to enable drill-down capabilities. This allows you to investigate the specific catalog entities and metrics that contribute to aggregated KPI scores, helping to identify and troubleshoot failing applications across a portfolio.

Prerequisites

  • You have installed Red Hat Developer Hub.
  • You have configured at least one Scorecard metric provider, such as GitHub or Jira.
  • You have configured aggregated KPIs.

Procedure

  1. Define the metric ID for drill-down in your app-config.yaml file.

    Drill-downs are metric-scoped. Even when you click an aggregated KPI, the system requires the underlying metricId to query the catalog for related entities.

    jira:
      product: cloud
      baseUrl: ${JIRA_URL}
      token: ${JIRA_TOKEN}
    scorecard:
      plugins:
        jira:
          open_issues:
            schedule:
              frequency: { minutes: 5 }
              timeout: { minutes: 10 }
              initialDelay: { seconds: 10 }
  2. Configure Role-Based Access Control (RBAC) permissions for the relevant user roles to enable scorecard access.

    1. Open your RBAC policy file, typically rbac-policy.csv.
    2. Add the following permission to read both scorecard metrics and catalog entities.

      p, role:default/team_lead, scorecard.metric.read, read, allow
      p, role:default/team_lead, catalog.entity.read, read, allow

Verification

  1. Navigate to the Red Hat Developer Hub Home Page.
  2. Click an aggregated KPI tile, such as Critical Jira Issues.
  3. Verify that a list of individual catalog entities appears, showing the components contributing to that aggregate score.

    If the list does not appear, ensure you are using the latest version of the RHDH plugins.

7.3.4.3. API endpoints and parameter details

REST API endpoints for the scorecard plugin used to fetch portfolio evaluations and component summaries.

7.3.4.3.1. Required permissions

To use these endpoints, make sure your account has the following permissions:

  • scorecard.metric.read
  • catalog.entity.read (for the specific entities you intend to query)
7.3.4.3.2. Supported REST API endpoints
Method and endpointDescriptionStatus

GET /metrics

Retrieves all base metrics collected by the plugin environment.

Active

GET /metrics/catalog/:kind/:namespace/:name

Retrieves the latest metric values for a specific catalog entity.

Active

GET /aggregations/:aggregationId

Retrieves calculated summary parameters for a targeted portfolio grouping definition.

Active

GET /metrics/:metricId/catalog/aggregations

Retrieves aggregated summary parameters for a specified entity grouping path.

Deprecated

Important

The endpoint GET /metrics/:metricId/catalog/aggregations is deprecated. Update your platform integrations to use the new route path structure: GET /aggregations/:aggregationId.

7.3.4.3.3. API parameter definitions
aggregationId
The unique identification key tracking a targeted scorecard summary layout block.
metricId
The unique provider key tracking an individual metrics collection channel source layer.
7.3.4.3.4. Filtering metrics (GET /metrics)

Use these parameters to refine the list of metrics.

Note

You must not use both parameters in the same request.

ParameterTypeRequiredDescription

metricIds

String

No

A comma-separated list of IDs (for example, github.open_prs).

datasource

String

No

Filter by the source ID (for example, github or jira).

7.3.4.3.5. Identifying entities (GET /metrics/catalog/…​)

Use path parameters to specify an entity in the Software Catalog.

ParameterTypeRequiredDescription

kind

String

Yes

The entity type (for example, component).

namespace

String

Yes

The entity namespace (for example, default).

name

String

Yes

The specific name of the entity.

7.3.4.3.6. Troubleshooting API errors

If a request fails, the API returns a status code and a message. Use the following table to resolve common issues.

Status codeError messageResolution

400 Bad Request

Validation error

Make sure you are not using metricIds and datasource in the same request.

403 Forbidden

Permission denied

Verify that you have both scorecard.metric.read and catalog.entity.read permissions.

404 Not Found

User entity reference not found

Verify that your user account has a defined entity reference in the Software Catalog.

7.3.4.4. Available metric data for entities

Use the Scorecard API endpoints to list available metrics, retrieve values for specific catalog entities, and analyze performance trends for entities or aggregated groups.

7.3.4.4.1. Required permissions

To use these endpoints, make sure your account has the following permissions:

  • scorecard.metric.read
  • catalog.entity.read (for the specific entities you intend to query)
7.3.4.4.2. API overview

The following table summarizes the available endpoints and their primary functions.

EndpointDescriptionQuery parameters

GET /metrics

Retrieves a list of all available metrics.

metricIds, datasource

GET /metrics/catalog/:kind/:namespace/:name

Retrieves the latest metric values for a specific catalog entity.

metricIds

GET /metrics/:metricId/catalog/aggregations

Retrieves status counts (success, warning, error) for entities you own.

None

7.3.4.4.3. API parameter details
Filtering metrics (GET /metrics)
Use these parameters to refine the list of metrics.
Note

You must not use both parameters in the same request.

ParameterTypeRequiredDescription

metricIds

String

No

A comma-separated list of IDs (for example, github.open_prs).

datasource

String

No

Filter by the source ID (for example, github or jira).

Identifying entities (GET /metrics/catalog/…​)
Use path parameters to specify an entity in the Software Catalog.
ParameterTypeRequiredDescription

kind

String

Yes

The entity type (for example, component).

namespace

String

Yes

The entity namespace (for example, default).

name

String

Yes

The specific name of the entity.

7.3.4.4.4. Troubleshooting API errors

If a request fails, the API returns a status code and a message. Use the following table to resolve common issues.

Status codeError messageResolution

400 Bad Request

Validation error

Make sure you are not using metricIds and datasource in the same request.

403 Forbidden

Permission denied

Verify that you have both scorecard.metric.read and catalog.entity.read permissions.

404 Not Found

User entity reference not found

Verify that your user account has a defined entity reference in the Software Catalog.

Chapter 8. Develop

8.1. Develop

Register software components, use templates to standardize projects, automate repository onboarding, and orchestrate workflows to streamline development processes.

8.2. Register and update software components to maintain a unified service inventory

8.2.1. Register and update software components to maintain a unified service inventory

The Red Hat Developer Hub Software Catalog is a centralized system that gives you visibility into all the software across your ecosystem, including services, websites, libraries, and data pipelines.

The metadata for the components in your Software Catalog is stored as YAML files that live alongside your code in your version control system. The version control repositories can include one or many metadata files. Software Catalog organizes items as entities, which include Components, Resources, and APIs, and other related types. Each entity includes associated metadata such as its owner, type, and other relevant details.

By storing metadata in YAML files alongside the code, you allow Red Hat Developer Hub to process and display this information through a clear, visual interface. With the Software Catalog, you can manage and maintain your software, stay aware of all software available in your ecosystem, and take ownership of your services and tools.

The Overview page for a component provides key information such as links to the source code, documentation, dependencies, and ownership details. You can customize this page with plugins to suit specific needs.

8.2.2. Manage your software components

8.2.2.1. Manage your software components

The Red Hat Developer Hub Software Catalog is a centralized system that gives you visibility into all the software across your ecosystem, including services, websites, libraries, and data pipelines.

The metadata for the components in your Software Catalog is stored as YAML files that live alongside your code in your version control system. The version control repositories can include one or many metadata files. Software Catalog organizes items as entities, which include Components, Resources, and APIs, and other related types. Each entity includes associated metadata such as its owner, type, and other relevant details.

By storing metadata in YAML files alongside the code, you allow Red Hat Developer Hub to process and display this information through a clear, visual interface. With the Software Catalog, you can manage and maintain your software, stay aware of all software available in your ecosystem, and take ownership of your services and tools.

The Overview page for a component provides key information such as links to the source code, documentation, dependencies, and ownership details. You can customize this page with plugins to suit specific needs.

8.2.2.2. Register new software components

8.2.2.2.1. Register new software components

You can add new components to your Red Hat Developer Hub catalog by either generating new components from software templates or registering existing repositories manually.

8.2.2.2.2. Create new components in your Red Hat Developer Hub instance

You can create new components in the Software Catalog in your RHDH instance. Red Hat Developer Hub automatically registers all components that developers or platform engineers create using Templates in the Software Catalog.

Prerequisites

  • You have installed and configured the Red Hat Developer Hub instance.
  • If RBAC is enabled, you have a role with the following permissions: catalog.entity.create, scaffolder.template.parameter.read, scaffolder.template.step.read, scaffolder.task.create.

Procedure

  1. In your Red Hat Developer Hub navigation menu, click Catalog.
  2. On the Catalog page, click Self-service.
8.2.2.2.3. Register components manually in your RHDH instance

To manually register components in your RHDH instance, create a catalog-info.yaml file and register it with your Red Hat Developer Hub instance.

Prerequisites

  • You have installed and configured the Red Hat Developer Hub instance.
  • If RBAC is enabled, you have a role with the following permissions: catalog.entity.create, catalog.location.create.

Procedure

  1. In the root directory of your software project, create a file named catalog-info.yaml.

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
        name: _<your_software_component>_
        description: _<software_component_brief_description>_
        tags:
             - example
             - service
        annotations:
             github.com/project-slug: _<repo_link_of_your_component_to_register>_
    spec:
        type: _<your_service>_
        owner: _<your_team_name>_
        lifecycle: _<your_lifecycle>_
  2. Commit the catalog-info.yaml file to the root of your project source code repository.
  3. In your Red Hat Developer Hub navigation menu, go to Catalog > Self-service.
  4. On the Self-service page, click Register Existing Component.
  5. On the Register an existing component page, enter the full URL of the catalog-info.yaml file in your repository. For example: Artist lookup component.
  6. Complete the wizard instructions.

Verification

  • Your software component is listed in the Software Catalog. You can view its details and ensure all the metadata is accurate.
8.2.2.2.4. Add new components to your Red Hat Developer Hub instance

You can add new components to expand your Developer Hub Software Catalog by registering them manually, creating them from Software Templates, or using bulk import.

Prerequisites

  • You have installed and configured the Red Hat Developer Hub instance.
  • If RBAC is enabled, you have a role with the following permissions: catalog.entity.create, catalog.location.create, bulk.import.

Procedure

  • Add components to your RHDH instance using the following methods:

    • Register components manually using the GUI or by using your app-config.yaml with the required permissions.
    • Create new components by using Software Templates.
  • Use the bulk import plugin with the required permissions. For more information, see Bulk importing GitHub repositories.

8.2.2.3. Update existing components in your Red Hat Developer Hub catalog

You can update components in the Software Catalog in your Red Hat Developer Hub instance.

Prerequisites

  • You have installed and configured the Red Hat Developer Hub instance.
  • If RBAC is enabled, you have a role with the following permission: catalog.entity.refresh.

Procedure

  1. In your Red Hat Developer Hub navigation menu, click Catalog.
  2. Find the software component that you want to edit, under Actions, click the Edit icon.

    Note

    This action redirects you to the YAML file on GitHub.

  3. On your remote repository UI, update your YAML file.

    Note

    After you merge your changes, the updated metadata in the Software Catalog is displayed after some time.

8.2.2.4. Find components by Kind in the Red Hat Developer Hub catalog

Filter the Software Catalog to display components by their type, such as Component, API, or Template.

Prerequisites

  • You are logged in to the RHDH instance.

Procedure

  1. In your Red Hat Developer Hub navigation menu, click Catalog.
  2. On the Catalog page, click the Kind drop-down list.
  3. Select the Kind you want to filter by, such as Component, API, or Template.

    Note

    The available filter lists change based on the Kind you select, showing options relevant to that entity type.

Verification

  • The Catalog updates to list only the components matching the selected Kind.

8.2.2.5. Filter components by text in the Red Hat Developer Hub catalog

Search and filter components by text in the Software Catalog to quickly locate specific services, libraries, or other entities.

Procedure

  1. In your Red Hat Developer Hub navigation menu, click Catalog.
  2. In the Search field, enter a component name, description, or keyword that you are looking for.

Verification

  • The Catalog list updates to display only components matching your search criteria.

8.2.2.6. Review the YAML configuration of your Red Hat Developer Hub Software Catalog

You can view the Software Catalog YAML file in your Red Hat Developer Hub instance to review the metadata for the components in your Software Catalog.

Procedure

  1. In your Red Hat Developer Hub navigation menu, click Catalog.
  2. Find the software component that you want to view, under Actions, click the View icon.

    Note

    These steps redirect you to the YAML file on your remote repository.

8.2.2.7. Star key components in the Software Catalog

You can add commonly used components to the Your Starred Entities card for quick access.

Procedure

  1. In the Red Hat Developer Hub navigation menu, select Catalog.
  2. Locate the components you want to add as a favorite.
  3. In the Actions column for that component, click the Add to favorites (star) icon.

Verification

  • Navigate to the Home page and verify that the Your Starred Entities card lists the component.

8.2.3. Define software components in the catalog

Populate your software catalog by creating and configuring a YAML descriptor file that defines your application or service.

Prerequisites

  • You have access to a Git repository to host your catalog files.

Procedure

  1. Create a YAML file named catalog-info.yaml in the root directory of your repository.
  2. Add the following component configuration to the file:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: example-service
    spec:
      type: service
      lifecycle: production
      owner: group:example-team
  3. Save and commit the file to your Git repository.

Verification

  • Navigate to the Catalog page in the UI, filter by Component, and verify your service is visible.

8.2.4. Define APIs in the catalog

Expose your interfaces for consumption within the hub by registering an API entity.

Procedure

  1. Create a YAML file named catalog-info.yaml in your repository.
  2. Add the following API schema configuration to the file:

    apiVersion: backstage.io/v1alpha1
    kind: API
    metadata:
      name: example-api
    spec:
      type: openapi
      lifecycle: production
      owner: group:example-team
      definition: |
        openapi: "3.0.0"
        info:
          title: Example API
          version: "1.0.0"
        paths: {}
  3. Save and commit the file to your Git repository.

Verification

  • Navigate to the Catalog page in the UI, filter by API, and verify your endpoint definition is visible.

8.2.5. Define resources in the catalog

Track infrastructure dependencies by creating a YAML descriptor file to register a resource entity in the software catalog.

Prerequisites

  • You have an active {product-title} instance.
  • You have access to a Git repository to host your catalog descriptor files.

Procedure

  1. Create a YAML file named catalog-info.yaml in your project or infrastructure repository directory.
  2. Add the following resource configuration to the file:

    apiVersion: backstage.io/v1alpha1
    kind: Resource
    metadata:
      name: example-database
    spec:
      type: database
      owner: group:example-team
  3. Save the file and commit it to your Git repository.

Verification

  1. Log in to your {product-title} instance web console.
  2. Navigate to the Catalog page using the left sidebar menu.
  3. Locate the Filters panel on the left side of the catalog view and click Resource.
  4. Confirm that your newly defined resource appears in the filtered list.

8.2.6. Define locations in the catalog

Import multiple entity descriptors into the software catalog by creating a YAML descriptor file that defines a location entity.

Prerequisites

  • You have an active {product-title} instance.
  • You have access to a Git repository to host your catalog descriptor files.

Procedure

  1. Create a YAML file named catalog-info.yaml in your centralized repository folder.
  2. Add the location configuration to the file, using the spec.targets array to point to your individual target configurations:

    apiVersion: backstage.io/v1alpha1
    kind: Location
    metadata:
      name: example-location
    spec:
      type: url
      targets:
        - https://github.com/example-org/example-repo/blob/main/catalog-info.yaml
  3. Save the file and commit it to your Git repository.

Verification

  1. Log in to your {product-title} instance web console.
  2. Navigate to the Catalog page using the left sidebar menu.
  3. Locate the Filters panel on the left side of the catalog view and click Location.
  4. Confirm that your newly defined location entity appears in the list and that the target data components are successfully discovered without validation errors.

8.2.7. Catalog entity descriptor reference

Use these reference tables to identify required YAML attributes and mandatory fields for registering components in the Red Hat Developer Hub catalog.

8.2.7.1. Mandatory fields for catalog entities

The following table lists the fields required for each entity kind supported by {product-title}. If you do not provide a mandatory field, the catalog processor fails to validate the entity and throws a TypeError.

8.2.7.2. Mandatory fields by entity kind

Entity KindMandatory FieldsPractical Usage and Optional Fields

Component

apiVersion, kind, metadata.name, spec.type, spec.lifecycle, spec.owner

Template

apiVersion, kind, metadata.name, spec.type, spec.parameters, spec.steps

API

apiVersion, kind, metadata.name, spec.type, spec.lifecycle, spec.owner, spec.definition

Group

apiVersion, kind, metadata.name, spec.type, spec.children (can be empty)

User

apiVersion, kind, metadata.name, spec.memberOf (can be empty)

Resource

apiVersion, kind, metadata.name, spec.type, spec.owner

System

apiVersion, kind, metadata.name, spec.owner

Domain

apiVersion, kind, metadata.name, spec.owner

Location

apiVersion, kind, metadata.name, spec

While spec can technically be empty ({}), practical usage requires pointing to target definitions using these optional fields:

* spec.type: The location type, such as url or file. * spec.target: A single string pointer to a target configuration. * spec.targets: An array of one or more string pointers to target configurations. * spec.presence: Specifies whether the target must exist (required) or can be missing (optional).

8.2.7.3. Conditional UI behavior for component entities

The visibility of navigation tabs in the {product-title} interface is determined by the spec.type attribute or specific metadata annotations within the component descriptor.

8.2.7.4. Component UI behavior mapping

Field or AnnotationSettingUI Change

spec.type

service

The API tab is visible in the component interface.

spec.type

website or library

The API tab is hidden, but provided and consumed APIs remain visible under the Dependencies tab.

metadata.annotations

backstage.io/techdocs-ref

The Docs tab is visible, providing access to TechDocs documentation.

Note

For the Docs tab to successfully render technical documentation, the TechDocs plugin must be configured correctly in your instance.

8.3. Project standardization with software templates

8.3.1. Project standardization with software templates

Use Software Templates in Red Hat Developer Hub to provide standardized project starter kits that improve developer productivity and ensure that new projects follow organizational standards.

8.3.2. Create new Software Templates

To automate the setup of standardized environments for your developers, you must create a template definition. This definition allows RHDH to automate the repetitive tasks of repository creation and initial configuration.

Prerequisites

Procedure

  1. Create a directory in your Git repository for the Software Template.
  2. Create a file named template.yaml in that directory.
  3. In the template.yaml file, define the apiVersion, kind, and metadata to identify the starter kit in the software catalog.
  4. Add a spec section to define the parameters that a developer must provide when they use the Software Template.
  5. Define the steps required to generate the project, which can include fetch:template to retrieve the skeleton and publish:github to create the new repository.

    Important

    You must include TechDocs in your Software Templates to ensure that documentation is automatically generated for every new project created from the Software Template.

Verification

  1. Inspect the template.yaml file to ensure the YAML syntax is valid.
  2. Confirm that the name and action fields are defined so the template is correctly recognized as a Scaffolder task.
  3. Check that the defined parameters match the variables used in your Software Template skeleton files.
  4. Navigate to the form playground at <instance_url>/create/template-form and test the Software Template configuration to confirm the fields and logic render as intended.

8.3.3. Use sample templates

The scaffolder supports a defaultEnvironment configuration that provides default parameters and secrets to all templates. Use this configuration in your app-config.yaml file to reduce template complexity and improve security by centralizing common values.

Example of an app-config.yaml configured for default parameters and secrets
scaffolder:
  defaultEnvironment:
    parameters:
      githubOrg: my-org
      defaultOwner: platform-team
    secrets:
      GITHUB_TOKEN: ${GITHUB_TOKEN}
Note

Default parameters are isolated in their own context to avoid naming conflicts.

Default parameters are accessible via ${{ environment.parameters.* }} in templates.

Example of default parameters configuration for application deployment
spec:
  parameters:
    - title: Project details
      required:
        - name
      properties:
        name:
          title: Name
          type: string
          description: Unique name for the new repository.

  steps:
    - id: fetch-base
      name: Fetch skeleton
      action: fetch:template
      input:
        url: ./skeleton
        values:
          name: ${{ parameters.name }} # Resolves to frontend input value
          owner: ${{ environment.parameters.defaultOwner }} # Resolves to defaultEnvironment.parameters.defaultOwner

Default secrets are resolved from environment variables and accessible via ${{ environment.secrets.* }} in template actions.

Example of a default secret configuration
spec:
  parameters:
    - title: Project details
      required:
        - name
      properties:
        name:
          title: Name
          type: string
          description: Unique name for the new repository.

  steps:
    - id: publish
      name: Publish to GitHub
      action: publish:github
      input:
        allowedHosts: ['github.com']
        description: ${{ parameters.name }}
        repoUrl: github.com?owner=${{ environment.parameters.githubOrg }}&repo=${{ parameters.name }}
        token: ${{ environment.secrets.GITHUB_TOKEN }} # Resolves to defaultEnvironment.secrets.GITHUB_TOKEN
Important

Secrets are automatically masked in logs. They are only available to backend actions, never exposed to the frontend.

8.3.4. Publish template definitions to the catalog

To allow developers to create new projects independently using your standards, you must publish the Software Template definition to the RHDH catalog. This registration makes the template a selectable option in the software creator interface.

Prerequisites

  • If RBAC is enabled, you have a role with the following permissions: catalog.entity.create, catalog.location.create.
  • You have a Git repository to store Software Template files.

Procedure

  1. Navigate to the Create page in the RHDH interface.
  2. Select Register Component.
  3. Enter the full URL to your template.yaml file in the Repository URL field.
  4. Click Analyze and then Import.

Verification

  1. Navigate to the Create page.
  2. Confirm that your new template is displayed in the list of available options.

8.3.5. Extend templates using conditional logic and external fetch capabilities

Use advanced logic to create Software Templates that adapt to specific project requirements and user inputs. Advanced templating includes parameterization, conditional logic, and fetch-and-run capabilities.

FeatureDescription

Parameterization

Use variables to inject user-provided data into project files.

Conditional Logic

Perform specific automation steps only when certain conditions are met.

Fetch and Run

Retrieve remote files and run commands during the setup process.

8.3.6. Version Software Templates to track template updates and dependencies

8.3.6.1. Version Software Templates to track template updates and dependencies

Software Templates in Red Hat Developer Hub provide a streamlined way to create software components and publish them to different version control repositories such as Git. Platform engineers create and maintain Software Templates in Red Hat Developer Hub.

8.3.6.2. Version Software Templates

Version Software Templates by using the catalog:scaffolded-from and catalog:template:version custom actions to track template versions and the entities created from them.

Prerequisites

  • You have added a custom Developer Hub application configuration.
  • The following dynamic plugins are enabled in your Backstage or my-rhdh-app-config file:

    • backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic
    • backstage-plugin-notifications
    • backstage-plugin-notifications-backend-dynamic

Procedure

  1. Make sure the required plugins are enabled in your RHDH my-rhdh-app-config file or the Backstage custom resource (CR):

    global:
      dynamic:
        plugins:
          - package: ./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic
            disabled: false
          - package: ./dynamic-plugins/dist/backstage-plugin-notifications
            disabled: false
          - package: ./dynamic-plugins/dist/backstage-plugin-notifications-backend-dynamic
            disabled: false
  2. Modify the Software Template that you want to update.
  3. Complete one or both of the following tasks:
  4. Include the annotation in your template: Add the backstage.io/template-version annotation in your template metadata. When this annotation is present, it is automatically used to annotate your catalog entity and display a default version value.
  5. Pass the annotation as input to the action: This method takes precedence over the annotation in the template itself and allows the user running the template to specify the version.

    # ...
    - id: version-templateRef
      name: Append the version of this template to the entityRef
      action: catalog:template:version
      input:
        annotations:
          backstage.io/template-version: ${{ parameters.version }}
    # ...

Verification

  1. Create a catalog component using the updated Software Template. This step creates a new component in Backstage and optionally, pushes files to an external repository (for example, GitHub, GitLab).
  2. Check the component in the Catalog UI.

    1. On the Catalog page, locate the newly created catalog component.
    2. Verify that the backstage.io/template-version annotation is present in the entity. You can use INSPECT ENTITY and select YAML Raw or JSON Raw view to find the annotation in the component definition.
  3. Only if you have published the catalog component: Check the component file in the repository.

    1. If VIEW SOURCE is present in your UI: Click VIEW SOURCE to open the stored component file in the repository.
    2. Locate the file manually and verify that the backstage.io/template-version annotation is present.

8.3.6.3. Enable update notifications

Enable notification alerts for template version updates so that component owners are automatically notified when the Software Template used to generate their components is updated to a new version.

Prerequisites

  • You have installed and configured the RHDH notification plugins:

    • backend: @backstage/plugin-notifications-backend
    • front-end: @backstage/plugin-notifications

Procedure

  1. Open your RHDH app-config.yaml file.
  2. Add the following configuration to the scaffolder section to enable Software Template update notifications
  3. Optional: To customize the notification title and description, add the message block:

    scaffolder:
      notifications:
        templateUpdate:
          enabled: true
          message:
            title: 'Custom title for $ENTITY_DISPLAY_NAME'
            description: 'Custom description'

    where:

    enabled
    Set to true to enable the notification. Default value is false.
    message:title
    Enter the notification title.
    message:description

    Enter the notification description.

    Note

    The message:title and message:description fields support the $ENTITY_DISPLAY_NAME variable. The system replaces this variable with the title (or the name, if the title is missing) of the scaffolded entity.

Verification

  1. Log in to your Red Hat Developer Hub instance.
  2. In the left navigation menu, verify that the Notifications item is displayed.
  3. Update the version of a Software Template and verify that the owner of a component scaffolded from that template receives a notification.

8.3.7. Track component provenance to map dependencies back to source templates

8.3.7.1. Track component provenance to map dependencies back to source templates

Track the dependency link between a generated entity and its source template to simplify lifecycle management.

Platform engineers use custom actions within the Software Template scaffolding process to establish and track the dependency link between a generated entity (Component or Resource) and its source template. This relationship is called scaffolding provenance.

Platform administrators use custom actions such as catalog:scaffolded-from and catalog:template:version in the Scaffolder backend module to track the template version and the corresponding entity version, which simplifies lifecycle management.

8.3.7.2. Configure provenance annotations

Modify the Software Template YAML definition to add provenance information during the scaffolding process.

As a platform engineer, you must modify the Software Template YAML definition to ensure the required provenance information is added during the scaffolding process.

Procedure

  1. Locate the Software Template object YAML file where you want to add the provenance information and add a step that uses the catalog:scaffolded-from action. This action links the resulting catalog entity back to the source template.
  2. Optional: To track the template version (for example, v1.0 versus v1.5), include the catalog:template:version action in the steps section. The following code block is an example to adding versioning action to the steps section:

    steps:
      - id: create-provenance-annotation
        name: Append the entityRef of this template to the entityRef
        action: catalog:scaffolded-from
      - id: create-version-annotation
        name: Create Template Version Annotation
        action: catalog:template:version
        input:
          templateVersion: ${{ parameters.version }}
      - ... other steps ...

    where:

    steps:input:templateVersion

    Reads the version parameter

    Note

    The catalog:template:version action reads a version parameter defined in the template and applies it as an annotation to the resulting catalog entity.

  3. In your Red Hat Developer Hub app-config.yaml file, configure the catalog.locations section to point to the Software Template that you want to add. You might need to add Template to the global catalog.rules.allow list or add a granular rule to the location to allow for Software Templates ingestion, as shown in the following example:

    # ...
    catalog:
      locations:
        - type: url
          target: https://<repository_url>/example-template.yaml
          rules:
            - allow: [Template]
    # ...

    where:

    catalog.locations.type
    Enter the url type if you are importing templates from a repository, such as GitHub or GitLab.
    catalog.locations.target
    Enter the URL for the template.
    catalog.locations.rules.allow
    Enter the Template rule to allow new Software Templates to be added to the catalog.

Verification

After creating a component with the updated template, verify the provenance annotations in the resulting Catalog Entity YAML.

  1. In the Red Hat Developer Hub navigation menu, go to Catalog and locate the newly created catalog component.
  2. To view the underlying data that links the entity to the template, select the INSPECT ENTITY option.
  3. To verify provenance annotations, complete the following steps:

    1. Select the YAML Raw or JSON Raw view and verify the presence of the data item for the scaffoldedFrom link.
    2. Optional: If versioning was included, verify the presence of the backstage.io/template-version annotation.

      Note

      If you publish the catalog component to an external repository (such as Git), the component file in that repository must also contain the backstage.io/template-version annotation.

8.3.7.3. View template dependencies in the catalog

View all entities created from a specific Software Template to identify the complete dependency and impact map.

As a developer, you can track which entities were created from a specific Software Template. When a platform engineer configures provenance on a template, you can quickly identify the complete dependency and impact map of that template by viewing all linked components and resources in the Catalog.

Procedure

  1. In the Red Hat Developer Hub navigation menu, click Catalog, use the filters to find and select the Software Template you want to inspect.
  2. In the Software Template detail page, click the Dependencies tab. This view lists all catalog entities such as components, resources, and systems that reference this template, including any version information if configured.

8.3.8. Automate template lifecycle management

8.3.8.1. Automate template lifecycle management

Automatically apply template updates to all downstream repositories to maintain compliance without manual file comparisons.

When Software Templates receive security updates or configuration changes, you can apply those updates to all downstream repositories automatically so that your applications remain compliant without manual file comparisons.

Automated template lifecycle management maintains consistency by monitoring your source templates. When a template version changes, the scaffolder-relation-processor plugin identifies all entities provisioned from that template and creates a pull request (PR) or merge request (MR) containing the necessary file updates, additions, or deletions.

8.3.8.2. Enable the scaffolder-relation-processor

Configure the scaffolder-relation-processor plugin to synchronize Software Template changes to downstream repositories.

To automate the synchronization of changes from Software Templates to your repositories, you must configure the plugin in your backend settings and ensure that your entities contain the required metadata.

Prerequisites

  • You have added a custom Developer Hub application configuration.
  • You have configured GitHub or GitLab integrations in your RHDH app-config.yaml file.
  • Your scaffolded entities include the spec.scaffoldedFrom field referencing the source template.
  • Your entities include the backstage.io/managed-by-location annotation pointing to a valid GitHub or GitLab URL.

Procedure

  1. Enable the template sync and notification plugins in your RHDH dynamic-plugins.yaml file:

    plugins:
    # Enables the core template synchronization logic
      - package: './dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-scaffolder-relation-processor'
        disabled: false
    # Required only if you want to receive notifications for new pull requests
      - package: './dynamic-plugins/dist/backstage-plugin-notifications'
        disabled: false
  2. Open your RHDH app-config.yaml file.
  3. Configure the pull request (PR) feature by adding the following configuration:

    scaffolder:
      pullRequests:
        templateUpdate:
          enabled: true
  4. Optional: Enable notifications to alert entity owners when a PR is created:

    scaffolder:
      notifications:
        templateUpdate:
          enabled: true
  5. Restart the Red Hat Developer Hub instance to apply the changes.

Verification

  1. Update the version of a source template in its repository.
  2. Navigate to a repository scaffolded from that template.
  3. Confirm that a new pull request named [component-name]/template-upgrade-v[version] exists.

8.3.8.3. Template sync limitations

Review reviewer assignment, variable resolution limitations, and other details to troubleshoot the synchronization process.

Review the following details to troubleshoot or refine the synchronization process.

Reviewer assignment

The plugin automatically assigns a reviewer if the entity owner is a User entity with a defined VCS login.

  • GitHub: Requires the github.com/user-login annotation.
  • GitLab: Requires the gitlab.com/user-login annotation.

    If the owner is a Group, the plugin creates the PR without an assigned reviewer.

Variable resolution limitations

The synchronization engine uses regex matching to resolve template variables such as ${{ values.name }}. You must manually review PRs because:

  • Variables that do not match keys in the scaffolded repository remain in raw template syntax.
  • Conditional Jinja2 blocks ({% if %}) are stripped, which might cause unexpected formatting.
  • Complex nested structures might not resolve correctly.
Error handling

If a PR fails to create due to credential issues or network errors, the plugin:

  • Logs the error in the backend.
  • Sends a failure notification to the entity owner (if notifications are enabled).
  • Skips the sync if no file differences are detected between the template and the repository.

8.3.8.4. Template synchronization and notification outcomes

Review the behavior for each combination of pull request creation and notification settings.

You can enable pull requests and notifications independently. The following table describes the behavior for each configuration combination:

PR CreationNotificationsOutcome

Disabled

Disabled

No action occurs when a template updates.

Disabled

Enabled

The plugin sends a notification to the entity owner with a link to the catalog.

Enabled

Disabled

The plugin creates a PR but sends no notification.

Enabled

Enabled

The plugin creates a PR and sends a notification to the owner with a link to the PR.

Note

If PR creation fails, the plugin sends a notification containing error details instead of the custom message.

8.3.9. Standardized project generation with software templates

8.3.9.1. Standardized project generation with software templates

Use Software Templates in Red Hat Developer Hub to provide standardized project starter kits that improve developer productivity and ensure that new projects follow organizational standards.

8.3.9.2. Run Software Templates from the UI

You can use Software Templates in RHDH to automate the project setup process to reduce manual configuration and errors for developers. These Software Templates are part of the Backstage Scaffolder system.

A Software Template consists of a YAML file with the following elements:

Metadata
Names and describes the template so developers can find the correct starter kit in the catalog.
Parameters
Define the specific information developers must provide, such as the project name or owner.
Steps
Sequence of steps that the system performs to build the project, which can include fetching a repository skeleton, injecting parameters, and publishing the code to a Git provider.

8.3.9.3. Browse available templates

This sample Software Template defines project parameters and publishes the generated code to a GitHub repository.

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: basic-node-service
  title: Basic Node.js Service
  description: A starter kit for a standardized Node.js microservice.
  tags:
    - nodejs
    - recommended
spec:
  owner: platform-team
  type: service
  parameters:
    - title: ProjectDetails
      required:
        - name
        - owner
      properties:
        name:
          title: Name
          type: string
          description: Unique name for the new repository.
        owner:
          title: Owner
          type: string
          description: The group responsible for this component.
          ui:field: OwnerPicker
          ui:options:
            allowedKinds:
              - Group
  steps:
    - id: fetch-base
      name: Fetch Skeleton
      action: fetch:template
      input:
        url: ./skeleton
        values:
          name: ${{ parameters.name }}
          owner: ${{ parameters.owner }}
    - id: publish
      name: Publish to GitHub
      action: publish:github
      input:
        allowedHosts: ['github.com']
        description: This is ${{ parameters.name }}
        repoUrl: github.com?owner=my-org&repo=${{ parameters.name }}
  output:
    links:
      - title: Repository
        url: ${{ steps['publish'].output.remoteUrl }}

8.3.9.4. Publish template definitions to the catalog

To allow developers to create new projects independently using your standards, you must publish the Software Template definition to the RHDH catalog. This registration makes the template a selectable option in the software creator interface.

Prerequisites

  • If RBAC is enabled, you have a role with the following permissions: catalog.entity.create, catalog.location.create.
  • You have a Git repository to store Software Template files.

Procedure

  1. Navigate to the Create page in the RHDH interface.
  2. Select Register Component.
  3. Enter the full URL to your template.yaml file in the Repository URL field.
  4. Click Analyze and then Import.

Verification

  1. Navigate to the Create page.
  2. Confirm that your new template is displayed in the list of available options.

8.4. Automate repository onboarding to the catalog

8.4.1. Automate repository onboarding to the catalog

Automate onboarding of GitHub repositories and GitLab projects to Red Hat Developer Hub catalog, and monitor import status by using bulk import capabilities.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

8.4.2. Import source code repositories in bulk

8.4.2.1. Import source code repositories in bulk

Automate onboarding of GitHub repositories to the Red Hat Developer Hub catalog, and monitor import status by using bulk import capabilities.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

8.4.2.2. Repository visibility in Bulk Import

View and bulk-import only the repositories you have permission to access and have not yet added to your catalog.

8.4.2.2.1. User-scoped repository access

When you use Bulk Import, Red Hat Developer Hub retrieves the list of available repositories using your authenticated user credentials through OAuth. Repository and organization listing API calls use your OAuth token for each configured source code management (SCM) host, ensuring that results match your personal access permissions rather than server-wide integration credentials.

This approach provides several benefits:

User-scoped access
You see only repositories you can access in GitHub or GitLab, matching your experience in those platforms.
Enhanced security
Import operations use your personal access token, maintaining audit trails tied to your user account.
Permission alignment
Repository visibility respects your organizational access policies and role-based permissions.

This differs from catalog discovery providers, which use service account credentials to automatically discover and import repositories containing catalog-info.yaml files across an entire organization.

8.4.2.2.2. Technical implementation

Bulk Import requires user authentication for all repository and organization listing operations. The following API endpoints require a valid OAuth token:

  • GET /repositories - List all accessible repositories
  • GET /organizations/{org}/repositories - List repositories in a specific organization

These endpoints use the X-SCM-Tokens header to pass user OAuth tokens for GitHub and GitLab hosts. There is no fallback to server-wide integration credentials (GitHub App, PAT, or GitLab token) for these listing operations. Requests without valid user OAuth tokens are rejected with HTTP 401 Unauthorized.

Important

Deployments that previously relied on integration-only listing must configure SCM authentication providers for user authentication. See the Bulk Import plugin documentation for configuration details.

8.4.2.2.3. Automatic filtering of imported repositories

The Bulk Import interface automatically excludes repositories that are already present in your Developer Hub catalog, showing only repositories that have not yet been imported. This filtering helps you:

  • Avoid duplicate catalog entries.
  • Focus on new repositories that need onboarding.
  • Identify which repositories remain to be imported from your Git provider.
Note

If a repository is removed from the catalog, it will reappear in the Bulk Import repository list and can be imported again.

8.4.2.2.4. Prerequisites for repository visibility

User authentication with OAuth is a mandatory requirement for the Bulk Import feature. To view and import repositories through Bulk Import, you must:

  • Configure GitHub or GitLab authentication using one of the following approaches:

    • As your primary authentication provider for Developer Hub.
    • As an auxiliary authentication provider if you use another primary provider, for example, OIDC or Red Hat build of Keycloak.
  • Configure SCM authentication providers with OAuth support for your Git hosts
  • Have the bulk.import permission configured in RBAC policies.
  • Maintain an active OAuth session with your Git provider.
Warning

Repository and organization listing operations require user OAuth tokens. There is no fallback to server-wide integration credentials. Deployments without user authentication configured will receive HTTP 401 errors when accessing Bulk Import.

8.4.2.2.5. Troubleshooting repository visibility

If you cannot see expected repositories in the Bulk Import interface, verify the following:

User access
Your user account has access to those repositories in GitHub or GitLab
Catalog status
The repositories are not already imported into the Developer Hub catalog
Session validity
Your Developer Hub OAuth session has not expired
Authentication configuration
GitHub or GitLab authentication provider is correctly configured
ScmAuthApi registration
The ScmAuthApi is properly registered for your SCM hosts

If you receive HTTP 401 Unauthorized errors when accessing the Bulk Import page, this indicates that user OAuth tokens are not available. Verify that:

  • You have authenticated to Developer Hub using GitHub or GitLab as your authentication provider
  • Your authentication provider includes OAuth scopes required for repository access
  • The SCM authentication provider is configured and registered in your Developer Hub deployment

8.4.2.3. Enable and authorize Bulk Import capabilities in Red Hat Developer Hub

Enable Bulk Import plugins and configure RBAC permissions to allow users to import multiple GitHub repositories and GitLab projects into the catalog.

Prerequisites

Important

Bulk Import requires user OAuth tokens for all repository and organization listing operations. Deployments without user authentication configured will receive HTTP 401 Unauthorized errors when accessing the Bulk Import feature.

Procedure

  1. The Bulk Import plugins are installed but disabled by default. To enable the ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic and ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import plugins, edit your dynamic-plugins.yaml with the following content:

    plugins:
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic
        disabled: false
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
        disabled: false

    See Installing and viewing plugins in Red Hat Developer Hub.

  2. Configure the required bulk.import RBAC permission for the users who are not administrators as shown in the following code:

    rbac-policy.csv fragment

    p, role:default/bulk-import, bulk.import, use, allow
    g, user:default/<your_user>, role:default/bulk-import

    Note that only Developer Hub administrators or users with the bulk.import permission can use the Bulk Import feature. See Permission policies in Red Hat Developer Hub.

Verification

  1. The sidebar displays a Bulk Import option.
  2. The Bulk Import page shows a list of added GitHub repositories and GitLab projects.

8.4.2.4. Import multiple GitHub repositories

Select and import multiple GitHub repositories that you can access into the Red Hat Developer Hub catalog, automatically creating pull requests with required catalog-info.yaml files.

Note

The Bulk Import feature displays only repositories that your GitHub user account can access and that are not already imported into the Developer Hub catalog. Repository visibility is determined by your GitHub permissions, not the Developer Hub GitHub App configuration.

Procedure

  1. Click Bulk Import in the Developer Hub left sidebar.
  2. If your RHDH instance has multiple source control tools configured, select GitHub from the Source control tool list.

    The interface displays GitHub repositories that your authenticated user account can access, excluding repositories already present in the catalog.

  3. Select the repositories to import, and click Add.

    Developer Hub creates a pull request in each selected repository to add the required catalog-info.yaml file using your GitHub credentials.

  4. For each repository to import, click PR to review and merge the changes in GitHub.

Verification

  1. Click Bulk Import in the Developer Hub left sidebar.
  2. Verify that each imported GitHub repository in the Selected repositories list has the status Waiting for approval or Imported.
  3. For each Waiting for approval repository, click the pull request link to review and merge the catalog-info.yaml file in the corresponding repository.

    The pull request is created using your GitHub user account, ensuring proper attribution in the repository history.

8.4.2.5. Import multiple GitLab repositories

Select and import multiple GitLab projects that you can access into the Red Hat Developer Hub catalog, automatically creating merge requests with required catalog-info.yaml files.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

Prerequisites

Note

The Bulk Import feature displays only projects that your GitLab user account can access and that are not already imported into the Developer Hub catalog. Project visibility is determined by your GitLab permissions, not the Developer Hub GitLab integration token configuration.

Procedure

  1. In the Developer Hub left sidebar, click Bulk Import.
  2. If your RHDH instance has multiple source control tools configured, select GitLab from the Source control tool list.

    The interface displays GitLab projects that your authenticated user account can access, excluding projects already present in the catalog.

  3. Select the projects to import, and click Add.

    Developer Hub creates a merge request in each selected project to add the required catalog-info.yaml file using your GitLab credentials.

  4. For each project to import, click MR to review and merge the changes in GitLab.

Verification

  1. Click Bulk Import in the Developer Hub left sidebar.
  2. Verify that each imported GitLab project in the Selected projects list has the status Waiting for approval or Imported.
  3. For projects with the Waiting for approval status, click the merge request link to review and add the catalog-info.yaml file to the project repository.

    The merge request is created using your GitLab user account, ensuring proper attribution in the project history.

8.4.2.6. Manage imported repositories

You can oversee and manage the Git repositories that are imported to Developer Hub.

Prerequisites

Procedure

  • Click Bulk Import in the left sidebar to display all the current GitHub repositories and GitLab projects that are being tracked as Import jobs, along with their status.

    Added
    The Git repository is added to the Developer Hub catalog after the import pull request is merged or if the Git repository already contained a catalog-info.yaml file during the bulk import. It can take a few minutes for the entities to be available in the catalog.
    Waiting for approval
    There is an open pull request or merge request adding a catalog-info.yaml file to the GitHub repository or GitLab project. You can:
  • Click pencil icon on the right to see details about the pull request or merge request. You can use the detailed view to edit the request content right from Developer Hub.
  • Delete the Import job, this action closes the import pull request or merge request as well.
  • To move the Import job to the Added state, merge the import pull request or merge request from the Git repository.

    Empty

    Developer Hub is unable to determine the import job status because the Git repository is imported from other sources but does not have a catalog-info.yaml file and lacks any import pull or merge request adding it.

    Note
    • After an import pull request or merge request is merged, the import status is marked as Added in the list of Added entities, but it might take a few seconds for the corresponding entities to appear in the Developer Hub Catalog.
    • A location added through other sources (for example, statically in an app-config.yaml file, dynamically when enabling GitHub discovery, or registered manually using the "Register an existing component" page) might show up in the Bulk Import list of Added Repositories if the following conditions are met:

      • The location URL points to a catalog-info.yaml file at the root of the Git repository default branch.
      • For GitHub only: The target repository is accessible from the configured GitHub integrations.

8.4.2.7. Monitor Bulk Import actions using audit logs

Review Bulk Import backend plugin audit log events to monitor repository import operations, track API requests, and troubleshoot import issues.

Procedure

  1. Access your Developer Hub backend logs where audit log events are recorded.
  2. Review the following Bulk Import audit log events to monitor repository operations:

    BulkImportUnknownEndpoint
    Tracks requests to unknown endpoints.
    BulkImportPing
    Tracks GET requests to the /ping endpoint, which allows us to make sure the bulk import backend is up and running.
    BulkImportFindAllOrganizations
    Tracks GET requests to the /organizations endpoint, which returns the list of organizations accessible from all configured GitHub Integrations.
    BulkImportFindRepositoriesByOrganization
    Tracks GET requests to the /organizations/:orgName/repositories endpoint, which returns the list of repositories for the specified organization (accessible from any of the configured GitHub Integrations).
    BulkImportFindAllRepositories
    Tracks GET requests to the /repositories endpoint, which returns the list of repositories accessible from all configured GitHub Integrations.
    BulkImportFindAllImports
    Tracks GET requests to the /imports endpoint, which returns the list of existing import jobs along with their statuses.
    BulkImportCreateImportJobs
    Tracks POST requests to the /imports endpoint, which allows to submit requests to bulk-import one or many repositories into the Developer Hub catalog, by eventually creating import pull requests in the target repositories.
    BulkImportFindImportStatusByRepo
    Tracks GET requests to the /import/by-repo endpoint, which fetches details about the import job for the specified repository.
    BulkImportDeleteImportByRepo

    Tracks DELETE requests to the /import/by-repo endpoint, which deletes any existing import job for the specified repository, by closing any open import pull request that could have been created.

    Example audit log output:

    {
      "actor": {
        "actorId": "user:default/myuser",
        "hostname": "localhost",
        "ip": "::1",
        "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
      },
      "eventName": "BulkImportFindAllOrganizations",
      "isAuditLog": true,
      "level": "info",
      "message": "'get /organizations' endpoint hit by user:default/myuser",
      "meta": {},
      "plugin": "bulk-import",
      "request": {
        "body": {},
        "method": "GET",
        "params": {},
        "query": {
          "pagePerIntegration": "1",
          "sizePerIntegration": "5"
        },
        "url": "/api/bulk-import/organizations?pagePerIntegration=1&sizePerIntegration=5"
      },
      "response": {
        "status": 200
      },
      "service": "backstage",
      "stage": "completion",
      "status": "succeeded",
      "timestamp": "2024-08-26 16:41:02"
    }

8.4.3. Configure bulk import capabilities

8.4.3.1. Configure bulk import capabilities

Configure custom Scaffolder workflows and register repository lists with the orchestrator for advanced bulk import operations.

8.4.3.2. Input parameters for Bulk Import Scaffolder template

Define Scaffolder template parameters such as repository URL, name, organization, and branch details to customize bulk import automation workflows for your repositories.

As an administrator, you can use the Bulk Import plugin to run a Scaffolder template task with specified parameters, which you must define within the template.

The Bulk Import plugin analyzes Git repository information and provides the following parameters for the Scaffolder template task:

repoUrl

Normalized repository URL in the following format:

  ${gitProviderHost}?owner=${owner}&repo=${repository-name}
name
The repository name.
organization
The repository owner, which can be a user nickname or organization name.
branchName
The proposed repository branch. By default, the proposed repository branch is bulk-import-catalog-entity.
targetBranchName
The default branch of the Git repository.
gitProviderHost
The Git provider host parsed from the repository URL. You can use this parameter to write Git-provider-agnostic templates.

Example of a Scaffolder template:

parameters:
  - title: Repository details
    required:
      - repoUrl
      - branchName
      - targetBranchName
      - name
      - organization
    properties:
      repoUrl:
        type: string
        title: Repository URL ({product-short} format)
        description: github.com?owner=Org&repo=repoName
      organization:
        type: string
        title: Owner of the repository
      name:
        type: string
        title: Name of the repository
      branchName:
        type: string
        title: Branch to add the catalog entity to
      targetBranchName:
        type: string
        title: Branch to target the PR/MR to
      gitProviderHost:
        type: string
        title: Git provider host

8.4.3.3. Set up a custom Scaffolder workflow for Bulk Import

Create custom Scaffolder templates aligned with your organization’s repository conventions to automate bulk import tasks such as entity imports, pull request creation, and webhook integration.

As an administrator, you can create a custom Scaffolder template inline with the repository conventions of your organization and add the template into the Red Hat Developer Hub catalog for use by the Bulk Import plugin on many selected repositories.

You can define various custom tasks, including, but not limited to the following:

  • Importing existing catalog entities from a repository
  • Creating pull requests for cleanup
  • Calling webhooks for external system integration

Prerequisites

  • You created a custom Scaffolder template for the Bulk Import plugin.
  • You have run your RHDH instance with the following environment variable enabled to allow the use of the Scaffolder functionality:

    export NODE_OPTIONS=--no-node-snapshot

Procedure

  • Configure your app-config.yaml configuration to instruct the Bulk Import plugin to use your custom template as shown in the following example:

    bulkImport:
      importTemplate: <your_template_entity_reference_or_template_name>
      importAPI: `open-pull-requests` | `scaffolder`;

    where:

    importTemplate:
    Enter your Scaffolder template entity reference.
    importAPI
    Set the API to 'scaffolder' to trigger the defined workflow for high-fidelity automation. This field defines the import workflow and currently supports two following options:
    open-pull-requests
    This is the default import workflow, which includes the logic for creating pull requests for every selected repository.
    scaffolder

    This workflow uses an import scenario defined in the Scaffolder template to create import jobs. Select this option to use the custom import scenario defined in your Scaffolder template.

    Optional: You can direct the Bulk Import plugin to hand off the entire list of selected repositories to a custom Orchestrator workflow.

    Important

    The Scaffolder template must be generic and not specific to a single repository if you want your custom Scaffolder template to run successfully for every repository in the bulk list.

Verification

  • The Bulk Import plugin runs the custom Scaffolder template for the list of repositories using the /task-imports API endpoint.

8.4.3.4. Register repository lists with the orchestrator

8.4.3.4.1. Register repository lists with the orchestrator

Run orchestrator workflows for bulk imports and design custom workflows for data handoff.

8.4.3.4.2. Run Orchestrator workflows for bulk imports

Configure Bulk Import to use Orchestrator workflows for advanced bulk operations across multiple repositories, enabling automated pull request creation and configuration publishing at scale.

As a platform engineer, you can configure the Bulk Import plugin to run Orchestrator workflows for bulk import operations. This mode uses the Orchestrator engine to provide advanced capabilities, such as creating pull requests or publishing configurations across multiple repositories.

Prerequisites

Procedure

  1. Configure the Bulk Import plugin by editing your app-config.yaml file to enable Orchestrator mode.

    bulkImport:
      orchestratorWorkflow: your_workflow_id
      importAPI: 'orchestrator'

    where:

    orchestratorWorkflow
    The ID of the workflow to run for each repository.
    importAPI
    The execution mode for the workflow. Enter orchestrator to enable workflow execution.
  2. Verify that the Orchestrator workflow receives the following input:

    {
      "inputData": {
        "owner": "redhat-developer",
        "repo": "rhdh-plugins",
        "baseBranch": "main",
        "targetBranch": "bulk-import-orchestrator"
      },
      "authTokens": [
        {
          "token": "<github_token>",
          "provider": "github"
        }
      ]
    }

    where:

    owner
    Specifies the repository owner (organization or user name).
    repo
    Specifies the repository name.
    baseBranch
    Specifies the default branch of the Git repository (for example, main).
    targetBranch
    Specifies the target branch for the import operation. By default, this is set to bulk-import-orchestrator.
    authTokens
    Specifies the authentication tokens for the Git provider:
  3. For GitHub: { token: <github_token>, provider: github }
  4. For GitLab: { token: <gitlab_token>, provider: gitlab }
  5. Navigate to the Bulk Import page in the sidebar and complete the following steps:

    1. Select your Git provider (for example, GitHub or GitLab).
    2. Select the projects you want to import.
  6. Click import to run the workflow.

Verification

  • Locate your repository and confirm status is COMPLETED.
8.4.3.4.3. Data handoff and custom workflow design

Design Scaffolder templates to receive repository data as parameters and automate repository-specific tasks when using Scaffolder mode for bulk imports.

When you configure the Bulk Import plugin by setting the importAPI field to scaffolder, the Bulk Import Backend passes all necessary context directly to the Scaffolder API.

As an administrator, you can define the Scaffolder template workflow and structure the workflow to do the following:

Define template parameters to consume input
Structure the Scaffolder template to receive the repository data as template parameters for the current workflow run. The template must be generic, and not specific to a single repository, so that it can successfully run for every repository in the bulk list.
Automate processing for each repository
Implement the custom logic needed for a single repository within the template. The Orchestrator iterates through the repository list, launching the template once for each repository and passes only the data for that single repository to the template run. This allows you to automate tasks such as creating the catalog-info.yaml, running compliance checks, or registering the entity with the catalog.

8.4.4. Enable GitHub repository discovery

Configure automatic GitHub repository discovery to import repositories containing catalog-info.yaml files into the Red Hat Developer Hub catalog without manual registration.

Prerequisites

Procedure

  1. Create a GitHub App to allow Developer Hub to access the GitHub API. Opt for a GitHub App instead of an OAuth app to use fine-grained permissions, gain more control over which repositories the application can access, and use short-lived tokens.

    1. Register a GitHub App with the following configuration:

      GitHub App name
      Enter a unique name identifying your GitHub App, such as integrating-with-rhdh-<GUID>.
      Homepage URL
      Enter your Developer Hub URL: https://<my_developer_hub_domain>.
      Authorization callback URL
      Enter your Developer Hub authentication backend URL: https://<my_developer_hub_domain>/api/auth/github/handler/frame.
      Webhook
      Clear "Active", as this is not needed for authentication and catalog providers.
      App permissions

      Select permissions to define the level of access for the app. Adapt permissions to your needs:

      Reading software components
      Contents
      Read-only
      Commit statuses
      Read-only
      Reading organization data
      Members
      Read-only
      Publishing software templates

      Set permissions if you intend to use the same GitHub App for software templates.

      Administration
      Read & write (for creating repositories)
      Contents
      Read & write
      Metadata
      Read-only
      Pull requests
      Read & write
      Issues
      Read & write
      Workflows
      Read & write (if templates include GitHub workflows)
      Variables
      Read & write (if templates include GitHub Action Repository Variables)
      Secrets
      Read & write (if templates include GitHub Action Repository Secrets)
      Environments
      Read & write (if templates include GitHub Environments)
      Organization permissions
      Members
      Read-only
      Where can this GitHub App be installed?
      Select Only on this account.
    2. In the GeneralClients secrets section, click Generate a new client secret.
    3. In the GeneralPrivate keys section, click Generate a private key.
    4. In the Install App tab, choose an account to install your GitHub App on.
    5. Save the following values for the next step:
  2. App ID
  3. Client ID
  4. Client secret
  5. Private key
  6. Add your GitHub credentials to Developer Hub by adding the following key/value pairs to your Developer Hub secrets. You can use these secrets in the Developer Hub configuration files by using the corresponding environment variable name for each secret.

    GITHUB_APP_APP_ID
    Enter the saved App ID.
    GITHUB_APP_CLIENT_ID_INTEGRATION
    Enter the saved Client ID.
    GITHUB_APP_CLIENT_SECRET_INTEGRATION
    Enter the saved Client Secret.
    GITHUB_APP_PRIVATE_KEY
    Enter the saved Private key.
    GITHUB_URL
    Enter the GitHub host domain: https://github.com.
    GITHUB_ORG
    Enter your GitHub organization name, such as <your_github_organization_name>.
  7. Enable the plugin-catalog-backend-module-github plugin in your dynamic-plugins.yaml file.

    This plugin discovers catalog entities by scanning repositories within a GitHub organization for catalog-info.yaml files. It provides an automated alternative to manually registering components via catalog.locations. When a repository contains a catalog-info.yaml file, the entity is ingested into the catalog as a component.

    dynamic-plugins.yaml file fragment

    plugins:
      - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github'
        disabled: false

  8. Configure the GitHub integration, by adding the catalog.providers.github and the integrations.github sections to your custom Developer Hub app-config.yaml configuration file:

    app-config.yaml file fragment with mandatory fields to enable GitHub integration

    catalog:
      providers:
        github:
          providerId:
            organization: "${GITHUB_ORG}"
            schedule:
              frequency:
                minutes: 30
              initialDelay:
                seconds: 15
              timeout:
                minutes: 15
    integrations:
      github:
        - host: ${GITHUB_URL}
          apps:
            - appId: ${GITHUB_APP_APP_ID}
              clientId: ${GITHUB_APP_CLIENT_ID_INTEGRATION}
              clientSecret: ${GITHUB_APP_CLIENT_SECRET_INTEGRATION}
              privateKey: |
                ${GITHUB_APP_PRIVATE_KEY}

8.5. Orchestrate infrastructure tasks using workflows

8.5.1. Orchestrate infrastructure tasks using workflows

You can streamline and automate your work by using the Orchestrator in Red Hat Developer Hub to design, run, and monitor workflows across applications and services.

  • Design, run, and monitor workflows to simplify multi-step processes across applications and services.
  • Standardize onboarding, migration, and integration workflows to reduce manual effort and improve consistency.
  • Extend RHDH with enterprise-grade Orchestration features to support collaboration and scalability.
Note

Orchestrator currently supports only Red Hat OpenShift Container Platform (OpenShift Container Platform); it is not available on Microsoft Azure Kubernetes Service (AKS), Amazon Elastic Kubernetes Service (EKS), or Google Kubernetes Engine (GKE).

8.5.2. Orchestrator process automation architecture

8.5.2.1. Orchestrator process automation architecture

You can streamline and automate your work by using the Orchestrator in Red Hat Developer Hub to design, run, and monitor workflows across applications and services.

  • Design, run, and monitor workflows to simplify multi-step processes across applications and services.
  • Standardize onboarding, migration, and integration workflows to reduce manual effort and improve consistency.
  • Extend RHDH with enterprise-grade Orchestration features to support collaboration and scalability.
Note

Orchestrator currently supports only Red Hat OpenShift Container Platform (OpenShift Container Platform); it is not available on Microsoft Azure Kubernetes Service (AKS), Amazon Elastic Kubernetes Service (EKS), or Google Kubernetes Engine (GKE).

8.5.3. Build serverless workflows

8.5.3.1. Build serverless workflows

Deploy a workflow and make it available in the Orchestrator plugin by building workflow images, generating workflow manifests, and deploying workflows to a cluster.

  • Building workflow images
  • Generating workflow manifests
  • Deploying workflows to a cluster

This process moves the workflow from your local machine to deployment on a cluster.

8.5.3.2. Pre-built workflow container image capabilities

8.5.3.2.1. Pre-built workflow container image capabilities

Pre-built workflow container images provide capabilities for building and deploying workflow projects.

8.5.3.2.2. Project structure overview

The project utilizes Quarkus project layout (Maven project structure), as illustrated by the 01_basic workflow example.

01_basic
├── pom.xml
├── README.md
└── src
    └── main
        ├── docker
        │   ├── Dockerfile.jvm
        │   ├── Dockerfile.legacy-jar
        │   ├── Dockerfile.native
        │   └── Dockerfile.native-micro
        └── resources
            ├── application.properties
            ├── basic.svg
            ├── basic.sw.yaml
            ├── schemas
            │   ├── basic__main-schema.json
            │   └── workflow-output-schema.json
            └── secret.properties

The main workflow resources are located under the src/main/resources/ directory.

The kn-workflow CLI generated this project structure. You can try generating the structure yourself by following the Getting Started guide.

8.5.3.2.3. Benefits of workflow images

While the OpenShift Serverless Logic Operator supports the building of workflows dynamically, this approach is primarily for experimentation. For production deployments, building images is the preferred method due to the following reasons:

  • Production readiness: Prebuilt images can be scanned, secured, and tested before going live.
  • GitOps compatibility: The Orchestrator relies on a central OpenShift Serverless Logic Operator instance to track workflows and their state. To use this tracking service, you must deploy workflows with the gitops profile, which expects a prebuilt image.
  • Testing and quality: Building an image gives you more control over the testing process.
8.5.3.2.4. Create and run your serverless workflow project locally

Use the kn-workflow CLI to generate workflow manifests and project structures, enabling you to develop and test a new serverless workflow locally.

Procedure

  1. Use the kn-workflow CLI to create a new workflow project, which adheres to the Quarkus structure as shown in the following example:

    $ kn-workflow quarkus create --name <specify project name, for example ,00_new_project>
  2. Edit the workflow, add schema and specific files, and run it locally from project folder as shown in the following example:

    $ kn-workflow quarkus run
  3. Run the workflow locally using the kn-workflow run which pulls the following image:

    registry.redhat.io/openshift-serverless-1/logic-swf-devmode-rhel9:1.38.0
  4. For building the workflow image, the kn-workflow CLI pulls the following images:

    registry.redhat.io/openshift-serverless-1/logic-swf-builder-rhel9:1.38.0
    registry.access.redhat.com/ubi9/openjdk-17:1.21-2

8.5.3.3. Build workflow container images locally using the build.sh script

8.5.3.3.1. Build workflow container images locally using the build.sh script

Build workflow images locally using the provided build.sh script with support for various configuration flags and environment variables.

8.5.3.3.2. The build-sh script functionality and important flags

The build-sh script generates workflow manifests, builds workflow images, and optionally pushes images and deploys workflows.

  • Generates workflow manifests using the kn-workflow CLI.
  • Builds the workflow image using podman or docker.
  • Optional: The script pushes the images to an image registry and deploys the workflow using kubectl.

You can review the script configuration options and see available flags and their functions by accessing the help menu:

./scripts/build.sh [flags]

The following flags are essential for running the script:

FlagDescription

-i, --image

Required: Full image path, for example, quay.io/orchestrator/demo:latest

-w, --workflow-directory

Workflow source directory (default is the current directory)

-m, --manifests-directory

Where to save generated manifests

--push

Push the image to the registry

--deploy

Deploy the workflow

-h, --help

Show the help message

Tip

The script also supports builder and runtime image overrides, namespace targeting, and persistence flags.

8.5.3.3.3. Environment variables supported by the build script

The build-sh script supports environment variables that customize the workflow build process without modifying the script itself.

QUARKUS_EXTENSIONS

The QUARKUS_EXTENSIONS variable specifies additional Quarkus extensions required by the workflow. This variable takes the format of a comma-separated list of fully qualified extension IDs as shown in the following example:

export QUARKUS_EXTENSIONS="io.quarkus:quarkus-smallrye-reactive-messaging-kafka"

Add Kafka messaging support or other integrations at build time.

MAVEN_ARGS_APPEND

The MAVEN_ARGS_APPEND variable appends additional arguments to the Maven build command. This variable takes the format of a string of Maven CLI arguments as shown in the following example:

export MAVEN_ARGS_APPEND="-DmaxYamlCodePoints=35000000"

Control build behavior. For example, set maxYamlCodePoints parameter that controls the maximum input size for YAML input files to 35000000 characters (~33MB in UTF-8).

Additional resources

8.5.3.3.4. Required tools

To run the build-sh script locally and manage the workflow lifecycle, you must install several command-line tools.

ToolConceptual Purpose.

podman or docker

Container runtime required for building the workflow images.

kubectl

Kubernetes CLI.

yq

YAML processor.

jq

JSON processor.

curl, git, find, which

Shell utilities.

kn-workflow

CLI for generating workflow manifests.

8.5.3.3.5. Build the 01_basic workflow

To run the script from the root directory of the repository, you must use the -w flag to point to the workflow directory. Additionally, specify the output directory with the -m flag.

Prerequisites

  • You have specified the target image using a tag.

Procedure

  1. Run the following command:

    $ ./scripts/build.sh --image=quay.io/orchestrator/demo-basic:test -w 01_basic/ -m 01_basic/manifests

    This build command produces the following two artifacts:

  2. A workflow image and Kubernetes manifests: quay.io/orchestrator/demo-basic:test and tagged as latest.
  3. Kubernetes manifests under: 01_basic/manifests/
  4. Optional: You can add the --push flag to automatically push the image after building. Otherwise, pushing manually is mandatory before deploying.
8.5.3.3.6. Build workflow images locally

Build workflow images locally by using the build script (build.sh) to prepare container images for deployment.

Procedure

  1. Clone the project as shown in the following example:

    git clone git@github.com:rhdhorchestrator/orchestrator-demo.git
    cd orchestrator-demo
  2. Check the help menu of the script:

    ./scripts/build.sh --help
  3. Run the build.sh script, providing the required flags, for example, the image path (-i), workflow source directory (-w), and manifests output directory (-m).

    Important

    You must specify the full target image path with a tag as shown in the following example:

    ./scripts/build.sh --image=quay.io/orchestrator/demo-basic:test -w 01_basic/ -m 01_basic/manifests

8.5.3.4. Generated workflow manifests

Review the structure and content of workflow manifests generated under the 01_basic/manifests directory.

01_basic/manifests
├── 00-secret_basic-secrets.yaml
├── 01-configmap_basic-props.yaml
├── 02-configmap_01-basic-resources-schemas.yaml
└── 03-sonataflow_basic.yaml
00-secret_basic-secrets.yaml
Contains secrets from 01_basic/src/main/resources/secret.properties. Values are not required at this stage as you can set them later after applying CRs or when using GitOps.
Important

In OpenShift Serverless Logic 1.38.0, after updating a secret, you must manually restart the workflow Pod for changes to apply.

01-configmap_basic-props.yaml
Holds application properties from application.properties. Any change to this ConfigMap triggers an automatic Pod restart.
02-configmap_01-basic-resources-schemas.yaml

Contains JSON schemas from src/main/resources/schemas.

Note

You do not need to deploy certain configuration resources when using the GitOps profile.

03-sonataflow_basic.yaml

The SonataFlow custom resource (CR) that defines the workflow.

podTemplate:
  container:
    image: quay.io/orchestrator/demo-basic
    resources: {}
    envFrom:
      - secretRef:
          name: basic-secrets
persistence:
  postgresql:
    secretRef:
      name: sonataflow-psql-postgresql
      userKey: <your_postgres_username>
      passwordKey: <your_postgres_password>
    serviceRef:
      name: sonataflow-psql-postgresql
      port: 5432
      databaseName: sonataflow
      databaseSchema: basic

where:

postgresql:secretRef:name
Enter the Secret name for your deployment.
postgresql:secretRef:userKey
Enter the key for your deployment.
postgresql:secretRef:passwordKey
Enter the password for your deployment.
postgresql:serviceRef:name

Enter the Service name for your deployment.

If you must connect to an external database, replace serviceRef with jdbcUrl. See Managing workflow persistence.

By default, the script generates all the manifests without a namespace. You can specify a namespace to the script by using the --namespace flag if you know the target namespace in advance. Otherwise, you must provide the namespace when applying the manifests to the cluster. See Configuring workflow services.

8.5.3.5. Deploy workflows on a cluster

You can deploy the workflow on a cluster, because the image is pushed to the image registry and the deployment manifests are available.

Prerequisites

  • You have an OpenShift Container Platform cluster with the following versions of components installed:

  • You must apply the workflow manifests in a namespace that contains a SonataflowPlatform custom resource (CR), which manages the supporting services.

Procedure

  1. Use the kubectl create command specifying the target namespace to apply the Kubernetes manifests as shown in the following example:

    $ kubectl create -n <your_namespace> -f ./01_basic/manifests/.
  2. After deployment, monitor the status of the workflow pods as shown in the following example:

    $ kubectl get pods -n <your_namespace> -l app=basic

    The pod may initially appear in an Error state because of missing or incomplete configuration in the Secret or ConfigMap.

  3. Inspect the Pod logs as shown in the following example:

    $ oc logs -n <your_namespace> basic-f7c6ff455-vwl56

    The following code is an example of the output:

    SRCFG00040: The config property quarkus.openapi-generator.notifications.auth.BearerToken.bearer-token is defined as the empty String ("") which the following Converter considered to be null: io.smallrye.config.Converters$BuiltInConverter
    java.lang.RuntimeException: Failed to start quarkus
    ...
    Caused by: io.quarkus.runtime.configuration.ConfigurationException: Failed to read configuration properties

    The error indicates a missing property: quarkus.openapi-generator.notifications.auth.BearerToken.bearer-token.

  4. In such a case where the logs show the ConfigurationException: Failed to read configuration properties error or indicate a missing value, retrieve the ConfigMap as shown in the following example:

    $ oc get -n <your_namespace> configmaps basic-props -o yaml

    The following code is an example of the sample output:

    apiVersion: v1
    data:
      application.properties: |
        # Backstage notifications service
        quarkus.rest-client.notifications.url=${BACKSTAGE_NOTIFICATIONS_URL}
        quarkus.openapi-generator.notifications.auth.BearerToken.bearer-token=${NOTIFICATIONS_BEARER_TOKEN}
    ...

    Resolve the placeholders using values provided using a Secret.

  5. You must edit the corresponding Secret and provide appropriate base64-encoded values to resolve the placeholders in application.properties as shown in the following example:

    $ kubectl edit secrets -n <your_namespace> basic-secrets
  6. Restart the workflow Pod for Secret changes to take effect in OpenShift Serverless Logic 1.38.0.

Verification

  1. Verify the deployment status by checking the Pods again as shown in the following example:

    $ oc get pods -n <your_namespace> -l app=basic

    The expected status for a successfully deployed workflow Pod is as shown in the following example:

    NAME                    READY   STATUS    RESTARTS   AGE
    basic-f7c6ff455-grkxd   1/1     Running   0          47s
  2. Once the Pod is in the Running state, the workflow now appears in the Orchestrator plugin inside the Red Hat Developer Hub.

Next steps

  • Inspect the provided build script to extract the actual steps and implement them in your preferred CI/CD tool, for example, GitHub Actions, GitLab CI, Jenkins, and Tekton.

8.5.3.6. Workflow design best practices

8.5.3.6.1. Workflow design best practices

Follow best practices when creating serverless workflows, including maintaining unique workflow IDs to prevent duplicates.

8.5.3.6.2. Best practices when creating serverless workflows

Create effective serverless workflows using thoughtful approaches to design, handle data, and manage error by following these best practices based on the Serverless Workflow Domain Specific Language (DSL) principles. These principles help you to build robust workflows.

Workflow design principles

The Serverless Workflow DSL prioritizes clarity and ease of use when writing workflows.

Priority of constituencies
When developing workflows or APIs, ensure the needs of the author (workflow writer) come first. The constituencies are prioritized in the following order: Authors > Operators > Implementers > Specifications writers.
Linguistic fluency and clarity
  • Use imperative verbs such as Call, Emit, For, Fork, Raise, Run, Set, Switch, and Wait. These simple, universally understood terms make your workflow simple to read and understand.
Structure and extensibility
  • Use implicit default behaviors to reduce redundancy.
  • Declare components inline if they are not reusable to keep the definition self-contained.
  • Use external references to import and reuse shared components, which promotes a modular design.
  • Prioritize flexibility over strict enumerations to ensure extensibility and adaptability across different runtime environments.
Data flow and runtime management
Controlling data flow is critical for efficient workflows. Tasks are the fundamental computing units of a workflow. The Domain Specific Language (DSL) defines several default task types that runtimes must do. These include Do, Listen, Raise, Run, Try, and Wait.
Security and error handling
Secrets
Use Secrets with caution. Avoid passing them directly in call inputs as this might expose sensitive information.
Fault tolerance and error handling
Serverless Workflow is designed with resilience in mind to recover from failures.
Orchestrator UI integration best practices

For your workflow results to be effectively displayed in the Orchestrator UI and to facilitate chaining of workflows, you must structure the output data according to the WorkflowResult schema. Additionally, include any error information as part of the workflow output so the UI and subsequent workflows can handle them accordingly.

Workflow output schema
Results placement
The primary output intended for subsequent processing must be placed under the data.result property.
Schema reference
Your output schema file (schemas/workflow-output-schema.json) must reference the WorkflowResult schema.
Outputs definition

Include an outputs section in your workflow definition. This section contains human-readable key/value pairs that the UI will display.

Structure of workflow:

id: my-workflow
version: "0.8"
specVersion: "0.8"
name: My Workflow
start: ImmediatelyEnd
dataInputSchema: schemas/basic__main-schema.json
extensions:
  - extensionid: workflow-output-schema
    outputSchema: schemas/workflow-output-schema.json
functions:
  - name: print
    type: custom
    operation: sysout
  - name: successResult
    type: expression
    operation: '{
      "result": {
      "message": "Project " + .projectName + " active",
      "outputs":[]
      }
      }'
start: "successResult"
states:
  - name: successResult
    type: operation
    actions:
      - name: setOutput
        functionRef:
          refName: successResult
    end: true
8.5.3.6.3. Unique workflow ID requirements to prevent duplicates

Unique workflow IDs prevent duplicate entries in RHDH. You must use distinct IDs for each deployment to avoid tracking conflicts and maintain clear workflow visibility.

Understand how RHDH identifies workflows
RHDH identifies each workflow by using its unique ID. When you deploy or update workflows, the system uses this ID to track, display, and manage workflow instances. If multiple workflows share the same ID, RHDH cannot distinguish between them, resulting in unexpected behavior.
Follow workflow ID format requirements

Workflow identifiers must comply with RFC 1123 DNS label standards to function correctly across all deployment configurations. Your workflow IDs must meet these format requirements:

  • Contain only lowercase letters (a-z), digits (0-9), and hyphens (-)
  • Start and end with a lowercase letter or digit
  • Not contain underscores, uppercase letters, or leading or trailing hyphens

    Valid workflow ID examples:

  • order-processing
  • invoice123
  • customer-onboarding-flow
  • flow-01

    Invalid workflow ID examples:

  • OrderProcessing (contains uppercase letters)
  • order_processing (contains underscore)
  • -orderflow (starts with hyphen)
  • orderflow- (ends with hyphen)
Maintain workflow ID consistency across configurations

You must use the same workflow identifier consistently across all configurations when you build and deploy your workflow. This requirement proves essential for operator-driven deployments that use the gitops profile.

For gitops profile deployments, the Kubernetes resource name must match the workflow ID field in your workflow definition file (.sw.yaml or .sw.json). This consistency prevents deployment failures and maintains proper workflow tracking in RHDH.

Recognize version field limitations

Although the Serverless workflow specification allows you to define a workflow version attribute in your workflow definition, the current SonataFlow and RHDH ecosystem does not support multiple versions of a workflow that share the same ID.

Important

Deploying multiple workflows with the same ID and different versions is not supported and results in unexpected behavior. Each workflow ID must be unique across all deployments.

The version field serves as metadata and appears in the RHDH UI for informational purposes to help you identify workflow definitions. The backend retrieves version information from the Data Index GraphQL schema and displays it in both the workflow list view and on individual workflow details pages. If you do not specify a version in your workflow definition, the field appears empty in the UI.

The system does not use the version field to differentiate between workflows or manage workflow versions. All workflow operations, including execution, deletion, and API calls, rely solely on the workflow ID.

Avoid deploying workflows with duplicate IDs

Each workflow ID must be unique across all deployments, regardless of the configured version attribute. Deploying multiple workflows with the same ID and different versions is not supported and can result in the following issues:

  • Duplicate workflow entries appear in the RHDH Orchestrator UI.
  • Workflow deletion operations become unpredictable.
  • Historical workflow data becomes difficult to interpret.
  • Workflow instance tracking becomes unreliable.

    Duplicate entries can occur when you deploy workflows with the same ID to different runtime servers over time, or when you redeploy a workflow with a new version by using the same ID. Because the Data Index records all workflow executions regardless of which runtime server executed them, historical records from multiple deployments with the same ID appear as duplicate entries in the RHDH UI.

Apply workflow version management best practices

To maintain different versions of a workflow, assign a new workflow ID for each version. Incorporate the version identifier into the workflow ID itself using a consistent naming convention.

Recommended naming pattern: Use a naming convention that clearly links related versions of the same workflow:

  • workflow-name-v1 implements and deploys version 1
  • workflow-name-v2 implements and deploys version 2
  • workflow-name-v3 implements and deploys version 3

    Example workflow ID evolution:

    id: customer-onboarding-v1
    version: "1.0"
    name: Customer Onboarding Workflow

    When you need to deploy an updated version:

    id: customer-onboarding-v2
    version: "2.0"
    name: Customer Onboarding Workflow

    This approach provides clarity and prevents conflicts when you manage multiple iterations of a workflow.

Manage workflow transitions between versions

When you transition from one workflow version to another:

  • Deploy the new workflow version with a unique ID (for example, workflow-name-v2).
  • Verify the new workflow operates correctly.
  • Monitor running instances of the old workflow version.
  • After all instances of the old workflow complete, remove the old workflow deployment.

    This process helps you maintain workflow history and prevents disruption to running workflow instances.

8.5.4. Deploy Red Hat Developer Hub for workflow automation

To automate CI/CD pipeline setup, deploy Red Hat Developer Hub with workflow orchestration by using predefined Operator configurations.

Prerequisites

Procedure

  1. Create a namespace for your Red Hat Developer Hub instance or use an existing namespace:

    $ oc new-project my-rhdh-project
  2. Create a Backstage CR with the Orchestrator deployment configuration:

    $ cat <<EOF | oc -n my-rhdh-project create -f -
    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <backstage_instance_name>
    spec:
      flavours:
        - name: orchestrator
          enabled: true
    EOF

    Where:

    <backstage_instance_name>
    A name for your Red Hat Developer Hub instance, for example developer-hub-orchestrator.
    spec.flavours
    The pre-configured settings array. Set name: orchestrator with enabled: true to automatically configure workflow orchestration capabilities.
    Note

    This example uses the default local PostgreSQL database. For production deployments, Red Hat recommends using an external PostgreSQL database. If you configured an external database in the prerequisites, add the database configuration to the CR as shown in Configure external PostgreSQL databases.

  3. Wait for the Operator to reconcile the Backstage CR:

    $ oc get backstage <backstage_instance_name> -n my-rhdh-project -w

    The deployment is ready when the PHASE column shows Deployed.

Verification

  1. Verify that the Data Index service pod is running:

    $ oc get pods -n my-rhdh-project | grep sonataflow

    You should see the Data Index service pod. The Orchestrator backend plugin runs within the main Red Hat Developer Hub pod.

  2. Access the Red Hat Developer Hub UI:

    $ oc get route backstage-<backstage_instance_name> -n my-rhdh-project -o jsonpath='{.spec.host}'

    Go to the URL in your browser.

  3. Verify the Orchestrator plugin is displayed in the Red Hat Developer Hub navigation menu. Look for the Orchestrator option in the left navigation panel.
  4. Optional: Test workflow deployment by creating a sample workflow. For detailed workflow examples, see Orchestrator in Red Hat Developer Hub.

Troubleshooting

If workflow pods fail to start

Verify the PostgreSQL connection by checking the Operator logs:

$ oc logs -n openshift-operators deployment/rhdh-operator -c manager

Ensure the database credentials in the Secret are correct and the database is accessible from the cluster.

If the Data Index service fails
Verify that the PostgreSQL user has permissions to create schemas and tables. The Orchestrator deployment configuration automatically initializes required database schemas.

8.5.5. Automate workflow deployments

8.5.5.1. Automate workflow deployments

Automate the software development lifecycle for serverless workflows by using Orchestrator software templates to bootstrap complete workflow projects with Git repositories, deployment configurations, and CI/CD pipelines.

8.5.5.2. Orchestrator workflow deployment components

The Orchestrator plugin integrates several components to automate the software development lifecycle for serverless workflows.

Note

Use the rhdh namespace where the RHDH chart is installed.

The Orchestrator plugin integrates these components:

RHDH Helm chart
Installs the RHDH Orchestrator.
Tekton or Red Hat OpenShift Pipelines
Manages the Kubernetes-native CI pipeline to build images.
ArgoCD or Red Hat OpenShift GitOps
Manages the CD pipeline to deploy the workflow on the RHDH instance.
Quay.io
Stores the container images generated by the pipelines.
OpenShift Serverless Logic operator
Implements serverless workflow specifications

8.5.5.3. Install Orchestrator Helm charts

8.5.5.3.1. Install Orchestrator Helm charts

Install Orchestrator software templates using Helm charts to enable workflow automation capabilities.

8.5.5.3.2. Install the Orchestrator Software Templates Infra chart

The orchestrator-software-templates-infra chart installs the Custom Resource Definitions (CRDs) and operators for Tekton (Red Hat OpenShift Pipelines) and Argo CD (Red Hat OpenShift GitOps). These are required to handle the CI/CD automation for serverless workflows.

Prerequisites

  • You have cluster-admin privileges.
  • You have installed the Helm CLI.
  • You have added the following plugins to the RHDH chart values.yaml file to include the following dynamic plugins:

    • backstage-plugin-scaffolder-backend-module-github-dynamic
    • backstage-plugin-scaffolder-backend-module-gitlab-dynamic
    • backstage-plugin-kubernetes-backend-dynamic
    • backstage-plugin-kubernetes
    • backstage-community-plugin-tekton
    • backstage-community-plugin-redhat-argocd
    • backstage-community-plugin-argocd-backend
    • roadiehq-scaffolder-backend-argocd-dynamic

      Edit the values.yaml and upgrade the chart.

Procedure

  • Install the infrastructure chart:

    $ helm install <release_name> redhat-developer/redhat-developer-hub-orchestrator-infra

Verification

  • Verify the installation by running the following command:

    $ helm test redhat-developer-hub-orchestrator-infra
8.5.5.3.3. Install the Orchestrator Software Templates chart

The orchestrator-software-templates chart loads the actual software templates into your RHDH instance. This allows users to select workflow templates from the RHDH Catalog.

Prerequisites

  • You have installed the orchestrator-software-templates-infra chart to deploy OpenShift Pipelines (Tekton) operator and OpenShift GitOps (ArgoCD) operator in the same namespace as RHDH.
  • You have labeled the rhdh namespace to enable GitOps sync:

    $ oc label ns rhdh rhdh.redhat.com/argocd-namespace=true
  • You have created a secret named orchestrator-auth-secret in the rhdh namespace containing the following keys:

    • BACKEND_SECRET: Backend authentication secret
    • K8S_CLUSTER_TOKEN: Kubernetes cluster token
    • K8S_CLUSTER_URL: Kubernetes cluster URL
    • GITHUB_TOKEN: GitHub access token (optional)
    • GITHUB_CLIENT_ID: GitHub OAuth client ID (optional)
    • GITHUB_CLIENT_SECRET: GitHub OAuth client secret (optional)
    • GITLAB_HOST: GitLab host URL (optional)
    • GITLAB_TOKEN: GitLab access token (optional)
    • ARGOCD_URL: ArgoCD server URL (optional)
    • ARGOCD_USERNAME: ArgoCD username (optional)
    • ARGOCD_PASSWORD: ArgoCD password (optional)

Procedure

  1. Install the software templates chart:

    $ helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart
    $ helm install my-orchestrator-templates redhat-developer/orchestrator-software-templates --version 0.2.0
  2. Create your environment-specific values file:

    1. Retrieve your RHDH route URL:

      RHDH_ROUTE="https://$(oc get route -n {{ .Values.orchestratorTemplates.rhdhChartNamespace }} -o jsonpath='{.items[0].spec.host}')"
    2. Copy the template and replace placeholders

      cp charts/orchestrator-software-templates/orchestrator-templates-values.yaml.template orchestrator-templates-values.yaml
      sed -i "s|RHDH_BASE_URL|$RHDH_ROUTE|g" orchestrator-templates-values.yaml
  3. Backup your RHDH configuration:

    helm show values charts/backstage \
         -n {{ .Values.orchestratorTemplates.rhdhChartNamespace }} > current-backstage-values.yaml
  4. Upgrade the RHDH chart with both value files:

     helm upgrade {{ .Values.orchestratorTemplates.rhdhChartReleaseName }} charts/backstage \
         -n {{ .Values.orchestratorTemplates.rhdhChartNamespace }} \
         -f current-backstage-values.yaml \
         -f orchestrator-templates-values.yaml

Verification

  1. Wait for the deployment to complete.
  2. Open your RHDH instance and verify the new software templates appear in the Create menu.
8.5.5.3.4. Install Red Hat Developer Hub (RHDH) on OpenShift Container Platform with the Orchestrator using the Helm CLI

You can install Red Hat Developer Hub (RHDH) on OpenShift Container Platform with the Orchestrator by using the Helm CLI. The installation automatically enables the required dynamic plugins and integrates workflow infrastructure.

Prerequisites

  • You are logged in as an administrator and have access to the Red Hat Developer Hub Helm chart repository.
  • You can install the necessary infrastructures resources, such as other OpenShift operators (OpenShift Serverless and OpenShift Serverless Logic), alongside RHDH in the same namespace.

    This is a one-off requirement and must be completed before enabling the Orchestrator plugin.

Procedure

  1. Manually approve the install plans for the Operators. You must run the oc patch installplan commands provided in the output to approve their installation.

    Important

    By default, Orchestrator Infrastructure for Red Hat Developer Hub Helm chart does not auto-approve the required Serverless Operators. You must manually approve the install plans.

  2. As an administrator, install relevant cluster-wide resources.

    $ helm repo add openshift-helm-charts https://charts.openshift.io/
    $ helm install <release_name> openshift-helm-charts/redhat-developer-hub-orchestrator-infra
    Important

    You must be an administrator to install the redhat-developer-hub-orchestrator-infra Helm chart because it deploys additional cluster-scoped OpenShift Serverless and OpenShift Serverless Logic Operators. As an administrator, you must manually approve the install plans for OpenShift Serverless and Serverless Logic Operators.

  3. Install the Backstage chart with the orchestrator enabled as shown in the following example:

    $ helm install <release_name> openshift-helm-charts/redhat-developer-hub --version 1.10.1 \
      --set orchestrator.enabled=true
  4. (Optional) Enable Notifications and Signals plugins by adding them to the global.dynamic.plugins list in your values.yaml file as shown in the following example:

    global:
      dynamic:
        plugins:
          - disabled: false
            package: "./dynamic-plugins/dist/backstage-plugin-notifications"
          - disabled: false
            package: "./dynamic-plugins/dist/backstage-plugin-signals"
          - disabled: false
            package: "./dynamic-plugins/dist/backstage-plugin-notifications-backend-dynamic"
          - disabled: false
            package: "./dynamic-plugins/dist/backstage-plugin-signals-backend-dynamic"
  5. (Optional) You can disable the Serverless Logic and Serverless Operators individually or together by setting their values to false, as shown in the following example:

    $ helm install <release_name> openshift-helm-charts/redhat-developer-hub \
      --version 1.10.1 \
      --set orchestrator.enabled=true \
      --set orchestrator.serverlessOperator=false \
      --set orchestrator.serverlessLogicOperator=false
  6. (Optional) To configure Orchestrator to use an external PostgreSQL database, follow the detailed instructions in Configure Orchestrator to connect to existing PostgreSQL infrastructure using Helm.

    Note

    Configuring an external database for Orchestrator requires additional steps beyond standard RHDH external database configuration. You must create the backstage_plugin_orchestrator database, configure the orchestrator.sonataflowPlatform values, and ensure proper service connectivity. See the detailed procedure for complete instructions.

Verification

  1. Verify that the Orchestrator plugin is visible in the Red Hat Developer Hub UI.
  2. Create and run sample workflows to confirm the orchestration is functioning correctly.
8.5.5.3.5. Install Red Hat Developer Hub (RHDH) using Helm from the OpenShift Container Platform web console

You can install Red Hat Developer Hub (RHDH) with the Orchestrator by using the (OpenShift Container Platform) web console. This method is useful if you prefer a graphical interface or want to deploy cluster-wide resources without using the Helm CLI.

Prerequisites

  • You are logged in to the OpenShift Container Platform web console as an administrator.
  • You have access to the Red Hat Developer Hub Helm chart repository.
  • Your cluster has internet access or the Helm charts are mirrored in a disconnected environment.

Procedure

  1. In the OpenShift Container Platform web console, go to the Helm Charts and verify that the Red Hat Developer Hub Helm chart repository is available.
  2. Search for the Orchestrator infrastructure for Red Hat Developer Hub and select Install.

    Important

    You must be an administrator to install the Orchestrator Infrastructure for Red Hat Developer Hub Helm chart because it deploys cluster-scoped resources. As an administrator, you must manually approve the install plans for OpenShift Serverless and Serverless Logic Operators.

    As a regular user, search for the Red Hat Developer Hub chart and install it by setting the value of orchestrator.enabled to true. Otherwise, the Orchestrator will not be deployed.

  3. Wait until they are successfully deployed.
  4. Monitor the deployment status by navigating to Pods or releases.

Verification

After deployment completes:

  1. The orchestrator-related pods are running in the selected namespace.
  2. Cluster-wide resources are present.
  3. You can start connecting the orchestrator to your Red Hat Developer Hub UI.

8.5.5.4. Install Orchestrator in an air-gapped environment

8.5.5.4.1. Install Orchestrator in an air-gapped environment

You can configure Red Hat Developer Hub (RHDH) with the Orchestrator plugin in a fully disconnected or partially disconnected environment by using the Operator or Helm chart.

8.5.5.4.2. Install Red Hat Developer Hub with Orchestrator in a fully disconnected OpenShift Container Platform environment using the Operator

You can install Red Hat Developer Hub with Orchestrator plugin in a fully air-gapped environment using the Operator.

A disconnected installation prevents unauthorized access, data transfer, or communication with external sources.

You can use the helper script to install Red Hat Developer Hub by mirroring the Operator-related images to disk and transferring them to your disconnected environment without any connection to the internet.

Prerequisites

  • You have set up your disconnected environment using a local registry.
  • You have permissions to push OCI images to your internal container registry.
  • You have installed the oc mirror tool, with a version corresponding to the version of your OpenShift Container Platform cluster.

Procedure

  1. Create an ImageSetConfiguration file for oc mirror. You must include the images and operators required by the Serverless Logic Operator in the ImageSetConfiguration file, as shown in the following example:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      additionalimages:
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@<digest>
    
      operators:
        - catalog: registry.redhat.io/redhat/redhat-operator-index:v<ocp-version>
         # For example: registry.redhat.io/redhat/redhat-operator-index:v4.21
          packages:
          - name: logic-operator
            channels:
            - name: stable
              minVersion: 1.38.0
              maxVersion: 1.38.0
          - name: serverless-operator
            channels:
            - name: stable
              minVersion: 1.37.1
              maxVersion: 1.37.1

    where:

    <digest>

    Locate the image digests for your version of RHDH in the dynamic-plugins.default.yaml file. You can extract this file from the plugin catalog index image to verify the default settings for your specific release:

    #!/bin/bash
    
    unpack () {
      local IMAGE="$1"
      DIR="${IMAGE//:/}" DIR="/tmp/${DIR//\//-}" rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}") podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/"; podman rm $container_id; rm -f /tmp/image.tar echo "Unpacked $IMAGE into $DIR" cd $DIR; tree -d -L 3 -I "usr|root|buildinfo" } unpack "registry.access.redhat.com/rhdh/plugin-catalog-index:{product-version)" # you can then find the dynamic-plugins.default.yaml under /tmp/registry.access.redhat.com/rhdh/plugin-catalog-index{product-version)/dynamic-plugins.default.yaml
  2. Mirror the images in the ImageSetConfiguration.yaml file by running the oc mirror command. For example:

    $ oc mirror --config=ImageSetConfiguration.yaml file:///path/to/mirror-archive --authfile /path/to/authfile --v2
    Note
    1. The --v2 flag is required for OpenShift Container Platform 4.21 and later.
    2. The oc mirror command generates a local workspace containing the mirror archive files and the required cluster manifests.
  3. Transfer the directory specified by /path/to/mirror-archive to a bastion host within your disconnected environment.
  4. From the bastion host which has access to the mirror registry, mirror the images from the disk directory to your target registry. For example:

    $ oc mirror --v2 --from <mirror-archive-file> docker://<target-registry-url:port> --workspace file://<workspace folder> --authfile /path/to/authfile

    where:

    <mirror-archive-file>
    Enter the name of the transferred tar file.
    <target-registry-url:port>
    Enter your local registry, for example, registry.localhost:5000.
  5. Apply the cluster-wide resources generated during the push step to redirect all image pulls to your local registry, as shown in the following example:

    $ cd <workspace folder>/working-dir/cluster-resources/
    $ oc apply -f .
  6. Install the OpenShift Serverless Operator and OpenShift Serverless Logic Operators using OperatorHub.
  7. Create a Backstage custom resource (CR).
  8. Configure the Backstage CR for the Orchestrator as described in the Orchestrator plugin dependencies for Operator installation.

    Create all the resources and configure the Backstage instance accordingly.

Verification

  1. Restart the RHDH pod and wait for the components to deploy properly.
  2. Once stable, go to the RHDH UI, and confirm that the Orchestrator UI is accessible and functioning correctly.
Note

The successful accessibility of the Orchestrator UI confirms that the underlying components are running and the cluster recognizes the plugin.

8.5.5.4.3. Install Red Hat Developer Hub with Orchestrator in a partially disconnected OpenShift Container Platform environment using the Operator

You can install Red Hat Developer Hub with Orchestrator plugin in a partial air-gapped environment using the Operator.

A disconnected installation prevents unauthorized access, data transfer, or communication with external sources.

You can use the oc mirror command to mirror resources directly to your accessible local mirror registry and apply the generated cluster resources.

Prerequisites

  • You have set up your disconnected environment using a local registry.
  • You have permissions to push OCI images to your internal container registry.
  • You have installed the oc mirror tool, with a version corresponding to the version of your OpenShift Container Platform cluster.

Procedure

  1. Create an ImageSetConfiguration file for oc mirror. You must include the images and operators required by the Serverless Logic Operator in the ImageSetConfiguration file, as shown in the following example:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      additionalimages:
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@<digest>
    
      operators:
        - catalog: registry.redhat.io/redhat/redhat-operator-index:v<ocp-version>
         # For example: registry.redhat.io/redhat/redhat-operator-index:v4.21
          packages:
          - name: logic-operator
            channels:
            - name: stable
              minVersion: 1.38.0
              maxVersion: 1.38.0
          - name: serverless-operator
            channels:
            - name: stable
              minVersion: 1.37.1
              maxVersion: 1.37.1

    Where:

    <digest>

    Locate the image digests for your version of RHDH in the dynamic-plugins.default.yaml file. You can extract this file from the plugin catalog index image to verify the default settings for your specific release:

    #!/bin/bash
    
    unpack () {
      local IMAGE="$1"
      DIR="${IMAGE//:/}" DIR="/tmp/${DIR//\//-}" rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}") podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/"; podman rm $container_id; rm -f /tmp/image.tar echo "Unpacked $IMAGE into $DIR" cd $DIR; tree -d -L 3 -I "usr|root|buildinfo" } unpack "registry.access.redhat.com/rhdh/plugin-catalog-index:{product-version)" # you can then find the dynamic-plugins.default.yaml under /tmp/registry.access.redhat.com/rhdh/plugin-catalog-index{product-version)/dynamic-plugins.default.yaml
  2. Mirror the images in the ImageSetConfiguration.yaml file by running the oc mirror command. For example:

    $ oc mirror --config=imagesetconfiguration.yaml docker://<registry URL:port> --workspace file://<workspace folder> --authfile /path/to/authfile --v2
    $ cd <workspace folder>/working-dir/cluster-resources/
    $ oc apply -f .
    Note

    The --v2 flag is required for OpenShift Container Platform 4.21 and later.

  3. Install the OpenShift Serverless Operator and OpenShift Serverless Logic Operators using OperatorHub.
  4. Create a Backstage custom resource (CR).
  5. Configure the Backstage CR for the Orchestrator as described in the Orchestrator plugin dependencies for Operator installation.

    Create all the resources and configure the Backstage instance accordingly.

Verification

  1. Restart the RHDH pod and wait for the components to deploy properly.
  2. Once stable, go to the RHDH UI, and confirm that the Orchestrator UI is accessible and functioning correctly.
Note

The successful accessibility of the Orchestrator UI confirms that the underlying components are running and the cluster recognizes the plugin.

8.5.5.4.4. Install Red Hat Developer Hub with Orchestrator in a fully disconnected OpenShift Container Platform environment using the Helm chart

You can install Red Hat Developer Hub (RHDH) with the Orchestrator plugin in a fully air-gapped OpenShift Container Platform environment using the Helm chart.

You can mirror images to an intermediary disk, and then mirror from the disk to your target local registry and apply the generated cluster resources.

Prerequisites

  • You have set up your disconnected environment using a local registry.
  • You have permissions to push OCI images to your internal container registry.
  • You have installed the oc mirror tool, with a version corresponding to the version of your OpenShift Container Platform cluster.

Procedure

  1. Create an ImageSetConfiguration.yaml file for oc mirror. You must use an ImageSetConfiguration file to include all mirrored images required, as shown in the following example:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      additionalimages:
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@<digest>
    
      helm:
        repositories:
          - name: openshift-charts
            url: https://charts.openshift.io
            charts:
              - name: redhat-developer-hub
                version: "1.10.1"
              - name: redhat-developer-hub-orchestrator-infra
                version: "1.10.1"
      operators:
        - catalog: registry.redhat.io/redhat/redhat-operator-index:v<ocp-version>
         # For example: registry.redhat.io/redhat/redhat-operator-index:v4.21
          packages:
          - name: logic-operator
            channels:
            - name: stable
              minVersion: 1.38.0
              maxVersion: 1.38.0
          - name: serverless-operator
            channels:
            - name: stable
              minVersion: 1.37.1
              maxVersion: 1.37.1

    where:

    <digest>

    Locate the image digests for your version of RHDH in the dynamic-plugins.default.yaml file. You can extract this file from the plugin catalog index image to verify the default settings for your specific release:

    #!/bin/bash
    
    unpack () {
      local IMAGE="$1"
      DIR="${IMAGE//:/_}"
      DIR="/tmp/${DIR//\//-}"
      rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}")
      podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/"; podman rm $container_id; rm -f /tmp/image.tar
      echo "Unpacked $IMAGE into $DIR"
      cd $DIR; tree -d -L 3 -I "usr|root|buildinfo"
    }
    
    unpack "registry.access.redhat.com/rhdh/plugin-catalog-index:1.10"
    
    # you can then find the dynamic-plugins.default.yaml under /tmp/registry.access.redhat.com/rhdh/plugin-catalog-index_1.10/dynamic-plugins.default.yaml
  2. Mirror the images in the ImageSetConfiguration.yaml file by running the oc mirror command. For example:

    $ oc mirror --config=ImageSetConfiguration.yaml file:///path/to/mirror-archive --authfile /path/to/authfile --v2
    Note
    1. The --v2 flag is required for OpenShift Container Platform 4.21 and later.
    2. The oc mirror command pulls the charts listed in the ImageSetConfiguration file and makes them available as tgz archives under the /path/to/mirror-archive directory.
  3. Apply the cluster-wide resources generated during the push step to redirect all image pulls to your local registry, as shown in the following example:

    $ cd <workspace folder>/working-dir/cluster-resources/
    $ oc apply -f .
  4. Transfer the generated mirror archive file, for example, /path/to/mirror-archive/mirror_000001.tar, to a bastion host within your disconnected environment.
  5. From the bastion host in your disconnected environment, which has access to the mirror registry, mirror the images from the archive file to your target registry. For example:

    $ oc mirror --v2 --from <mirror-archive-file> docker://<target-registry-url:port> --workspace file://<workspace folder> --authfile /path/to/authfile

    where:

    <mirror-archive-file>
    Enter the name of the transferred tar file.
    <target-registry-url:port>
    Enter your local registry, for example, registry.localhost:5000.
  6. Apply the redhat-developer-hub-orchestrator-infra Helm chart and approve the install plans. See Air-gapped installation with Helm chart instructions for details.
  7. Apply the RHDH 1.10 Helm chart. Include the version 1.10.1 and enable the Orchestrator plugin, as shown in the following example:

    orchestrator.enabled=true
  8. The RHDH 1.10 Helm chart defaults to pulling Orchestrator plugins from the official Red Hat OCI registry using full URL references. Override this default behavior to point the chart to your local registry.

    To configure the Orchestrator plugins to use a custom registry, complete the following steps:

  9. Open your values.yaml file.
  10. List the Orchestrator plugin packages under the orchestrator.plugins section. You must replace the simplified package references with the full URLs that point to your custom OCI registry.

    Important

    You must explicitly include the pluginConfig configuration for each plugin as shown in the following example:

    orchestrator:
      plugins:
        - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@_<digest>_
          disabled: true
          pluginConfig:
            orchestrator:
              dataIndexService:
                url: http://sonataflow-platform-data-index-service
        - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@_<digest>_
          disabled: true
          pluginConfig:
            dynamicPlugins:
              frontend:
                red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {}
        - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@_<digest>_
          disabled: true
          pluginConfig:
            dynamicPlugins:
              frontend:
                red-hat-developer-hub.backstage-plugin-orchestrator:
                  appIcons:
                  - importName: OrchestratorIcon
                    name: orchestratorIcon
                  dynamicRoutes:
                  - importName: OrchestratorPage
                    menuItem:
                      icon: orchestratorIcon
                      text: Orchestrator
                      textKey: menuItem.orchestrator
                    path: /orchestrator
                  entityTabs:
                  - path: /workflows
                    title: Workflows
                    titleKey: catalog.entityPage.workflows.title
                    mountPoint: entity.page.workflows
                  mountPoints:
                  - mountPoint: entity.page.workflows/cards
                    importName: OrchestratorCatalogTab
                    config:
                      layout:
                        gridColumn: 1 / -1
                      if:
                        anyOf:
                          - IsOrchestratorCatalogTabAvailable
        - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator@_<digest>_
          disabled: true
          pluginConfig:
            orchestrator:
              dataIndexService:
                url: http://sonataflow-platform-data-index-service

    where:

    <custom_registry_url>
    Enter the address of your custom registry where the OCI images have been mirrored.
    <digest>

    Locate the image digests for your version of RHDH in the dynamic-plugins.default.yaml file. You can extract this file from the plugin catalog index image to verify the default settings for your specific release:

    #!/bin/bash
    
    unpack () {
      local IMAGE="$1"
      DIR="${IMAGE//:/}" DIR="/tmp/${DIR//\//-}" rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}") podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/"; podman rm $container_id; rm -f /tmp/image.tar echo "Unpacked $IMAGE into $DIR" cd $DIR; tree -d -L 3 -I "usr|root|buildinfo" } unpack "registry.access.redhat.com/rhdh/plugin-catalog-index:{product-version)" # you can then find the dynamic-plugins.default.yaml under /tmp/registry.access.redhat.com/rhdh/plugin-catalog-index{product-version)/dynamic-plugins.default.yaml

Verification

  1. Restart the RHDH Pod and wait for the components to deploy properly.
  2. After deployment is complete, go to the RHDH UI and confirm that the Orchestrator UI is accessible and functioning correctly.
Note

The successful accessibility of the Orchestrator UI confirms that the underlying components are running and the cluster recognizes the plugin.

8.5.5.4.5. Install Red Hat Developer Hub with Orchestrator in a partially disconnected OpenShift Container Platform environment using the Helm chart

You can install Red Hat Developer Hub (RHDH) with the Orchestrator plugin in a partial OpenShift Container Platform environment using the Helm chart.

A disconnected installation prevents unauthorized access, data transfer, or communication with external sources.

You can use the oc mirror command to mirror resources directly to your accessible local registry and apply the generated cluster resources.

Prerequisites

  • You have set up your disconnected environment using a local registry.
  • You have permissions to push OCI images to your internal container registry.
  • You have installed the oc mirror tool, with a version corresponding to the version of your OpenShift Container Platform cluster.

Procedure

  1. Create an ImageSetConfiguration.yaml file for oc mirror. You must use an ImageSetConfiguration file to include all mirrored images required, as shown in the following example:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      additionalimages:
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator@<digest>
      - name: registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@<digest>
    
      helm:
        repositories:
          - name: openshift-charts
            url: https://charts.openshift.io
            charts:
              - name: redhat-developer-hub
                version: "1.10.1"
              - name: redhat-developer-hub-orchestrator-infra
                version: "1.10.1"
      operators:
        - catalog: registry.redhat.io/redhat/redhat-operator-index:v<ocp-version>
         # For example: registry.redhat.io/redhat/redhat-operator-index:v4.21
          packages:
          - name: logic-operator
            channels:
            - name: stable
              minVersion: 1.38.0
              maxVersion: 1.38.0
          - name: serverless-operator
            channels:
            - name: stable
              minVersion: 1.37.1
              maxVersion: 1.37.1
  2. Mirror the images in the ImageSetConfiguration.yaml file by running the oc mirror command to pull images and charts, and push the images directly to the target registry. For example:

    $ oc mirror --config=imagesetconfiguration.yaml docker://<registry URL:port> --workspace file://<workspace folder> --authfile /path/to/authfile --v2
    Note
    1. The --v2 flag is required for OpenShift Container Platform 4.21 and later.
    2. The oc mirror command pulls the charts listed in the ImageSetConfiguration file and makes them available as tgz archives under the <workspace folder> directory.
  3. Apply the generated cluster resources to the disconnected cluster. For example:

    $ cd <workspace folder>/working-dir/cluster-resources/
    $ oc apply -f .
  4. Apply the redhat-developer-hub-orchestrator-infra Helm chart and approve the install plans. See Air-gapped installation with Helm chart instructions for details.
  5. Apply the RHDH 1.10 Helm chart. Include the version 1.10.1 and enable the Orchestrator plugin, as shown in the following example:

    orchestrator.enabled=true
  6. The RHDH 1.10 Helm chart defaults to pulling Orchestrator plugins from the official Red Hat OCI registry using full URL references. You must override this behavior to point to your local registry.

    To configure the Orchestrator plugins to use a custom registry, complete the following steps:

    • Open your values.yaml file.
    • Explicitly list the Orchestrator plugin packages under the orchestrator.plugins section.

      You must replace the simplified package references with the full URLs that point to your custom OCI registry. You must explicitly include the pluginConfig configuration for each plugin as shown in the following example:

      orchestrator:
        plugins:
          - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@_<digest>_
            disabled: true
            pluginConfig:
              orchestrator:
                dataIndexService:
                  url: http://sonataflow-platform-data-index-service
          - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@_<digest>_
            disabled: true
            pluginConfig:
              dynamicPlugins:
                frontend:
                  red-hat-developer-hub.backstage-plugin-orchestrator-form-widgets: {}
          - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@_<digest>_
            disabled: true
            pluginConfig:
              dynamicPlugins:
                frontend:
                  red-hat-developer-hub.backstage-plugin-orchestrator:
                    appIcons:
                    - importName: OrchestratorIcon
                      name: orchestratorIcon
                    dynamicRoutes:
                    - importName: OrchestratorPage
                      menuItem:
                        icon: orchestratorIcon
                        text: Orchestrator
                        textKey: menuItem.orchestrator
                      path: /orchestrator
                    entityTabs:
                    - path: /workflows
                      title: Workflows
                      titleKey: catalog.entityPage.workflows.title
                      mountPoint: entity.page.workflows
                    mountPoints:
                    - mountPoint: entity.page.workflows/cards
                      importName: OrchestratorCatalogTab
                      config:
                        layout:
                          gridColumn: 1 / -1
                        if:
                          anyOf:
                            - IsOrchestratorCatalogTabAvailable
          - - package: oci://<custom_registry_url>/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator@_<digest>_
            disabled: true
            pluginConfig:
              orchestrator:
                dataIndexService:
                  url: http://sonataflow-platform-data-index-service

      Where:

      <custom_registry_url>
      Enter the address of your custom registry where the OCI images have been mirrored.
      <digest>

      Locate the image digests for your version of RHDH in the dynamic-plugins.default.yaml file. You can extract this file from the plugin catalog index image to verify the default settings for your specific release:

      #!/bin/bash
      
      unpack () {
        local IMAGE="$1"
        DIR="${IMAGE//:/}" DIR="/tmp/${DIR//\//-}" rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}") podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/"; podman rm $container_id; rm -f /tmp/image.tar echo "Unpacked $IMAGE into $DIR" cd $DIR; tree -d -L 3 -I "usr|root|buildinfo" } unpack "registry.access.redhat.com/rhdh/plugin-catalog-index:{product-version)" # you can then find the dynamic-plugins.default.yaml under /tmp/registry.access.redhat.com/rhdh/plugin-catalog-index{product-version)/dynamic-plugins.default.yaml

Verification

  1. Restart the RHDH pod and wait for the components to deploy properly.
  2. After deployment is complete, go to the RHDH UI and confirm that the Orchestrator UI is accessible and functioning correctly.
Note

The successful accessibility of the Orchestrator UI confirms that the underlying components are running and the cluster recognizes the plugin.

8.5.5.5. Create a serverless workflow project

Use the Orchestrator software templates to generate a project that includes workflow definitions, Kustomize configurations, and CI/CD pipelines.

Prerequisites

  • You have installed orchestrator-software-templates-infra and orchestrator-software-templates Helm charts to enable templates.
  • You have installed RHDH and the Orchestrator plugin by using the Helm chart.
  • You have a Quay.io organization and repository for storing the workflow images.
  • You have a GitHub or Gitlab personal access token with repository creation permissions.
  • You have configured a GitOps secret for the target cluster.
  • You have set the target namespace for both the pipeline and the workflow to the rhdh namespace.

Procedure

  1. Prepare the image registry. Before creating the template, configure the target repository in Quay.io.

    1. Log in to your Quay.io organization (for example, orchestrator-testing).
    2. Create a new repository (for example, serverless-workflow-demo).
    3. Add robot account permissions to the repository settings.
  2. Open the Red Hat Developer Hub Catalog.

    Product catalog
  3. Select the Basic workflow bootstrap project template and click Launch Template.
  4. Follow the template form to enter required details, including the GitHub organization, source code repository name, and a unique Workflow ID.
  5. For the CI/CD method, select Tekton with Argo CD to generate GitOps resources.
  6. Set the Workflow Namespace to rhdh and the GitOps Namespace to orchestrator-gitops.
  7. Enter your Quay.io registry details.
  8. Click Review, then click Create.

    Basic workflow bootstrap template form
  9. Optional: Enable persistence and provide database connection details if the workflow requires a database schema.

Verification

  • The system creates the following repositories:

    • Source code repository: Contains the serverless workflow project.
    • GitOps repository: Contains GitOps configurations, Tekton pipeline templates, and bootstrap instructions.

8.5.5.6. Bootstrap GitOps resources and trigger pipelines

You must manually bootstrap the GitOps resources to trigger the continuous integration (CI) pipeline.

Procedure

  1. Open the generated GitOps repository.
  2. Clone the repository and navigate to the bootstrap directory:

    $ git clone https://token:<PAT>@${{ values.gitHost }}/${{ values.orgName }}/${{ values.repoName }}.git
    cd <repo_name>/bootstrap
    Note

    If you are not authenticated, you must use a personal access token (PAT) in the clone URL. Make sure the PAT has repository access permissions.

  3. Open ${{values.workflowId}}-argocd-repo.yaml and replace the REPLACE_SSH_PRIVATE_KEY string with your SSH private key.
  4. Apply the manifests to the cluster:

    $ kubectl apply -f .

    Applying these manifests triggers the following automated sequence:

    1. CI Pipeline (Tekton): Builds the workflow image and pushes it to your Quay.io registry.
    2. CD Pipeline (Argo CD): Deploys the serverless workflow manifests to the cluster.

8.5.5.7. Verify the deployment

Verify the status of your continuous integration (CI) and continuous deployment (CD) pipelines in the RHDH component catalog.

Procedure

  1. For CI:

    1. In the RHDH Catalog, select your source code repository component (for example, onboardings).
    2. Click the CI tab and verify that the pipeline run status is Succeeded.
    3. If the pipeline status does not appear in the Red Hat Developer Hub console, verify the CI status directly in your Git provider (GitHub or GitLab).
    4. If the pipeline fails, click the run name to view the logs and identify build errors.
  2. For CD:

    1. Open the GitOps Resources Repository component in the Catalog (for example, onboarding-gitops).
    2. Click the CD tab and make sure the Kubernetes resources are synced and healthy. This confirms that ArgoCD deployed the workflow to the cluster.

      Workflow deployment successful with synced and healthy status

8.5.5.8. Event-driven workflow execution for enterprise messaging integration

Event-driven workflows enable RHDH Orchestrator to respond to business events from existing messaging systems. This architecture maintains loose coupling and integrates workflows into established enterprise event streams.

8.5.5.8.1. Why CloudEvents matter for workflow integration

When you integrate workflows with message-driven systems, you need a common event format that works across different platforms and services without custom adapters for each system.

CloudEvents is a Cloud Native Computing Foundation (CNCF) specification that standardizes how to describe event data across services, platforms, and systems. This common envelope format ensures that systems can produce and consume events without custom integration code for each platform.

A CloudEvent includes required metadata fields such as the event type, source, unique identifier, and specification version. Optional fields provide additional context such as content type, data schema, subject, and timestamp. The data field contains the event payload itself, which can include structured data relevant to the event type.

For example, a CloudEvent might describe a deployment request, a compliance check trigger, or a customer order placement. Because CloudEvents standardizes the event format, multiple systems can process these events by using common libraries and tools, reducing integration complexity.

8.5.5.8.2. How your workflows respond to CloudEvents

When you configure a workflow for event-driven execution, RHDH Orchestrator processes incoming CloudEvents sourced from Apache Kafka that match specific event types. The underlying SonataFlow engine natively supports CloudEvents, which means your workflows can consume events without additional transformation or middleware.

When a CloudEvent arrives:

  1. The workflow engine validates the CloudEvent structure and extracts the event metadata.
  2. The engine matches the event type to registered workflows configured to handle that event type.
  3. The workflow instance starts automatically, with the CloudEvent data available as workflow input.
  4. The workflow runs its defined steps, which can include calling APIs, orchestrating services, or emitting additional CloudEvents.

This event-driven model differs from HTTP-triggered workflows, where you explicitly call a workflow endpoint to start the workflow.

8.5.5.8.3. Event-driven versus HTTP-triggered workflow execution

Event-driven and HTTP-triggered workflows serve different integration patterns:

HTTP-triggered workflows
This approach is appropriate for synchronous operations where the caller needs immediate feedback or must wait for workflow completion. The caller sends an HTTP request to a specific workflow endpoint and receives a response indicating the workflow status. This pattern works well for user-initiated actions in web applications or API integrations that require request-response semantics.
Event-driven workflows
Use this approach when your event producers need to continue working immediately without waiting for workflow completion. Your producers publish CloudEvents to Apache Kafka, and workflows start automatically when events arrive, without blocking the producer. This pattern supports fire-and-forget semantics, enabling the producer to continue processing without blocking on the workflow. Event-driven workflows also provide better scalability for high-volume workloads and support complex event routing and filtering capabilities that the message broker provides.
8.5.5.8.4. Benefits of event-driven workflows

Integrating workflows with CloudEvents and message brokers provides several architectural advantages:

Loose coupling
Event producers do not need direct knowledge of workflow endpoints or RHDH infrastructure. They publish standardized CloudEvents to a message broker, and the workflow engine consumes events independently. This separation allows services to evolve independently without tight coupling.
Asynchronous execution
Event producers do not block waiting for workflows to complete. This improves system responsiveness and allows workflows to handle long-running operations without impacting the producing system.
Architectural consistency
Organizations that have standardized on message-oriented middleware can integrate RHDH workflows into existing event-driven architectures without creating HTTP-based exceptions. This maintains architectural consistency across the enterprise.
Enterprise messaging standards
CloudEvents specification provides a vendor-neutral event format that major cloud providers and messaging platforms support. This ensures portability and reduces vendor lock-in.
8.5.5.8.5. CloudEvent type to Kafka topic mapping

When you configure workflows to consume CloudEvents from Kafka, you decide how CloudEvent types map to Kafka topics based on your workflow design and organizational standards.

A common pattern maps each workflow to a specific Kafka topic, where the topic name corresponds to the CloudEvent type that triggers the workflow. For example, a workflow that processes deployment requests might subscribe to a deployment.request topic, and producers would publish CloudEvents with type: deployment.request to that topic.

You can organize workflows by business capability and route events to the appropriate workflow by using Kafka topic-based routing. You can also use Kafka consumer groups to scale workflow processing across multiple RHDH instances.

8.5.5.8.6. When to use CloudEvent triggering

Choose CloudEvent-based workflow triggering when:

  • Your organization has standardized on message brokers such as Apache Kafka for system-to-system communication.
  • Your workflows respond to business events produced by other systems in your architecture.
  • You need asynchronous, fire-and-forget workflow execution.
  • You want to decouple workflow callers from RHDH infrastructure.
  • Your workflows integrate into existing event-driven architectural patterns.

Use HTTP-triggered workflows when:

  • Your users need immediate workflow feedback or synchronous responses.
  • Your workflows serve as APIs for external systems that expect request-response patterns.
  • Your organization has not deployed message broker infrastructure.
  • Your workflow execution is strictly on-demand rather than event-driven.

8.5.5.9. Enable event-driven workflows by configuring Kafka connectivity

Configure Apache Kafka connectivity in the Orchestrator backend to enable workflows triggered by CloudEvents. This configuration allows workflows to respond asynchronously to business events from your messaging infrastructure.

Prerequisites

  • You have enabled Orchestrator plugins.
  • You have deployed Apache Kafka broker infrastructure and ensured it is accessible from RHDH.
  • You have Kafka broker URLs and connection credentials.
  • You have verified network connectivity between RHDH and Kafka brokers.

Procedure

  1. Locate your Developer Hub application configuration file.

    The location depends on your deployment method:

    • For Operator deployments: The configuration is in a ConfigMap, typically named my-rhdh-app-config.
    • For Helm deployments: The configuration is in the values.yaml file or a custom configuration file referenced in your Helm values.
  2. Add the orchestrator.kafka configuration section to your app-config.yaml file.

    orchestrator:
      kafka:
        clientId: my-rhdh-orchestrator
        brokers:
          - kafka-broker-1.example.com:9092
          - kafka-broker-2.example.com:9092
          - kafka-broker-3.example.com:9092
        # logLevel override for the orchestrator kafka services. Defaults to INFO which is 4
        # logLevel values based on KafkaJS values https://kafka.js.org/docs/configuration#logging
        # logLevel: 5 // DEBUG
        logLevel: 4

    where:

    clientId
    Unique identifier for the RHDH Kafka client. This identifier is displayed in Kafka broker logs and metrics.
    brokers
    Array of Kafka broker URLs. Include multiple brokers for high availability.
    logLevel
    Optional. Kafka client logging level. Valid numeric values based on KafkaJS values are 0 (NOTHING), 1 (ERROR), 2 (WARN), 4 (INFO), or 5 (DEBUG). Default is 4 (INFO).
  3. Apply the configuration changes.

    • For Operator deployments: Update the ConfigMap and restart the RHDH instance by scaling the deployment to zero and back to the target replica count, or by deleting the pod to trigger a restart.

      Replace <my_deployment_name> with the name of your deployment:

      $ oc rollout restart deployment/<my_deployment_name>
    • For Helm deployments: Upgrade the Helm release with the updated configuration.

      $ helm upgrade my-rhdh-custom-resource redhat-developer/backstage -f values.yaml -n my-rhdh-project

Verification

  1. Check the orchestrator-backend plugin logs for Kafka connection messages.

    Replace <my_deployment_name> with the name of your deployment:

    $ oc logs deployment/<my_deployment_name> | grep -i kafka

    Successful connection logs include messages indicating the Kafka client has connected to the broker cluster.

  2. Navigate to the Orchestrator plugin in the RHDH UI.
  3. Verify that the Run as Event button is displayed next to workflows.

    The button is only visible when Kafka connectivity is successfully configured.

Troubleshooting

If the Run as Event button does not appear:

  • Verify that the Kafka broker URLs are correct and accessible from the RHDH pod.
  • Check the orchestrator-backend logs for connection errors or authentication failures.
  • Confirm that network policies allow traffic between RHDH and the Kafka brokers.
  • Verify that the orchestrator.kafka configuration section is correctly formatted in the configuration file.

8.5.5.10. Run workflows asynchronously through the UI with CloudEvents

Publish CloudEvents to Apache Kafka from the RHDH UI to trigger workflows asynchronously. This method enables fire-and-forget operation without blocking on workflow completion.

Prerequisites

  • You have configured Kafka connectivity for the Orchestrator.
  • You have deployed an event-type workflow that appears in the Orchestrator plugin.

Procedure

  1. In the RHDH UI, navigate to the Orchestrator plugin.
  2. In the workflows list, locate the workflow you want to trigger.
  3. Click the Run as Event button next to the workflow.

    Note

    The Run as Event button appears only when you have configured Kafka connectivity and the workflow supports event-driven execution.

  4. If the workflow requires input data, complete the workflow input form.

    The form fields correspond to the workflow’s input schema. The CloudEvent data payload includes the values you provide.

  5. Click Submit to send the CloudEvent to Kafka.

    The RHDH UI transmits a CloudEvent to the configured Kafka broker with the workflow input data. The workflow starts when the Kafka broker delivers the event to the SonataFlow engine.

  6. Monitor the workflow status.

    After submitting the CloudEvent, one of two outcomes occurs:

    Immediate start
    If the workflow starts before the UI timeout period, the UI navigates to the workflow instance detail page, where you can monitor progress.
    Delayed start
    If the workflow has not started when the UI timeout expires, the UI displays an informational message indicating that it sent the event to Kafka as a kafkaEvent. The UI navigates to the workflow runs list, where the workflow instance appears when the workflow starts.
  7. If the workflow does not start immediately, locate the workflow in the workflow runs list.

    The workflow instance appears in the list when the Kafka broker delivers the CloudEvent and the workflow engine starts the workflow. Depending on Kafka broker latency and workflow engine processing time, this can take several seconds.

Troubleshooting

If the workflow does not appear in the workflow runs list after several minutes:

  • Verify that the Kafka broker is running and accessible.
  • Check the orchestrator-backend logs for errors related to Kafka message publishing.
  • Confirm that you configured the workflow to consume CloudEvents from the correct Kafka topic.
  • Verify that the CloudEvent type matches the workflow’s event type configuration.

8.5.5.11. CloudEvent structure reference for workflow design and troubleshooting

CloudEvent attribute specifications and Kafka topic mapping patterns help you design workflows that consume events from external systems. Understanding this structure is essential for troubleshooting event-driven workflow integration.

8.5.5.11.1. CloudEvent specification structure

CloudEvents use a standardized JSON structure with required and optional attributes.

AttributeDescriptionRequired

specversion

CloudEvents specification version. RHDH uses version 1.0.

Yes

type

Event type identifier. This typically corresponds to the Kafka topic name and the workflow event type.

Yes

source

URI identifying the context in which the event occurred. For example, the service or system that produced the event.

Yes

id

Unique identifier for the event instance. Each CloudEvent must have a unique ID.

Yes

datacontenttype

Content type of the data value. Common values are application/json or application/xml.

No

dataschema

URI of the schema that the data adheres to.

No

subject

Subject of the event in the context of the event producer. For example, a resource identifier or entity name.

No

time

Timestamp when the event occurred, in RFC3339 format.

No

data

Event payload containing domain-specific data. This is where workflow input parameters are included.

No

8.5.5.11.2. Example CloudEvent payload

An example of a CloudEvent that triggers a deployment workflow:

{
  "specversion": "1.0",
  "type": "deployment.request",
  "source": "/api/deployments",
  "id": "a234-5678-9abc-def0",
  "datacontenttype": "application/json",
  "time": "2025-08-15T14:30:00Z",
  "data": {
    "applicationName": "my-application",
    "environment": "production",
    "version": "2.1.0",
    "approver": "jane.doe@example.com"
  }
}

In this example:

  • The type field (deployment.request) identifies the event type and typically matches the Kafka topic name.
  • The source field indicates the API endpoint that produced the event.
  • The id field provides a unique identifier for this specific deployment request.
  • The data field contains the workflow input parameters required to run the deployment.
8.5.5.11.3. How RHDH constructs CloudEvents

When you use the Run as Event button in the RHDH UI, the Orchestrator backend plugin constructs a CloudEvent automatically:

  1. The plugin generates a unique event ID by using UUID format.
  2. The plugin sets the type field based on the workflow’s event type configuration.
  3. The plugin sets the source field to identify RHDH as the event producer.
  4. The plugin sets specversion to 1.0.
  5. The plugin includes the workflow input form data in the data field.
  6. The plugin publishes the CloudEvent to the configured Kafka broker.
8.5.5.11.4. Workflow input data structure

When you design workflows that consume CloudEvents, the workflow input schema should match the structure of the CloudEvent data field.

For example, if your workflow requires the following input:

{
  "applicationName": "string",
  "environment": "string",
  "version": "string"
}

The CloudEvent data field must provide these properties. When you trigger the workflow from the RHDH UI, the workflow input form collects these values and includes them in the data field of the published CloudEvent.

8.5.5.11.5. CloudEvent type and Kafka topic mapping

The mapping between CloudEvent types and Kafka topics depends on your workflow configuration and Kafka topic design:

Single topic per workflow type
Each workflow subscribes to a dedicated Kafka topic, where the topic name matches the CloudEvent type field. For example, a workflow handling deployment.request events subscribes to the deployment.request topic. This pattern provides clear separation between workflow types and simplifies event routing.
Shared topic with event filtering
Multiple workflow types subscribe to a shared Kafka topic, and each workflow filters events based on the type field. This pattern reduces the number of Kafka topics but requires workflows to include event filtering logic.

The SonataFlow workflow definition specifies which event types the workflow consumes, and the Kafka topic configuration determines where the workflow engine listens for events.

8.6. Write and publish documentation as code to keep knowledge synchronized

8.6.1. Write and publish documentation as code to keep knowledge synchronized

After an administrator configures TechDocs, a developer can add documentation by importing from a remote repository, creating standalone docs, or enabling docs for an existing catalog entity.

8.6.2. About TechDocs

Your organization can use the TechDocs plugin to create, find, and manage documentation in a central location and in a standardized way.

The Red Hat Developer Hub instance includes the TechDocs plugin preinstalled and enabled by default. You can also enhance your technical documentation experience with built-in TechDocs features and add-ons. For example:

Docs-like-code approach
Write your technical documentation in Markdown files that are stored inside your project repository along with your code.
Documentation site generation
Use MkDocs to create a full-featured, Markdown-based, static HTML site for your documentation that is rendered centrally in Developer Hub.
Documentation site metadata and integrations
See additional metadata about the documentation site alongside the static documentation, such as the date of the last update, the site owner, top contributors, open GitHub issues, Slack support channels, and Stack Overflow Enterprise tags.
Built-in navigation and search
Locate the information that you need within a document quickly and easily.
Add-ons
Make your documentation more functional and interactive with supported TechDocs add-ons. Some add-ons are preinstalled and enabled by default. To extend the default functionality, you can dynamically load external and third-party add-ons into your Red Hat Developer Hub instance. If you want to further customize your TechDocs experience, you can create add-ons that meet specific documentation needs for your organization.

8.6.3. Import documentation into TechDocs from a remote repository

Teams can store their documentation files in the same remote repository where they store their code files. You can import documentation into your TechDocs plugin from a remote repository that contains the documentation files that your team uses.

Prerequisites

  • Your organization has documentation files stored in a remote repository.
  • You have a mkdocs.yaml file in the root directory of your repository.
  • You have the catalog.entity.create and catalog.location.create permissions to import documentation into TechDocs from a remote repository.

Procedure

  1. In your Red Hat Developer Hub instance, click Catalog > Self-service > Register Existing Component.
  2. In the Select URL box, enter the URL to the catalog-info.yaml file that you want to import from your repository using the following format:

    https://github.com/<project_name>/<repo_name>/blob/<branch_name>/<file_directory>/catalog-info.yaml

  3. Click Analyze
  4. Click Finish

Verification

  1. In the Developer Hub navigation menu, click Docs.
  2. Verify that the documentation that you imported is listed in the table on the Documentation page.

8.6.4. Search for relevant content

To quickly find the information needed for your services, search or filter the TechDocs catalog. Narrowing your search helps you find relevant resources without browsing many repositories.

Procedure

  1. In the Red Hat Developer Hub navigation menu, click Docs.
  2. On the Documentation page, use the Search bar or filters to locate your document:

    • Search: Enter keywords to find specific terms within documents.
    • Filter by Owner: View documents owned by specific users or groups.
    • Filter by Tags: Narrow results by specific labels or categories.
    • Filter by Owned: View documents belonging to you or your group.
    • Filter by Starred: View your bookmarked favorites.

      The results update automatically to show the number of documents that meet your criteria.

8.6.5. Access and navigate documentation

Use the built-in navigation tools to move between related documents within a book. This ensures you can easily reference implementation details and requirements in a logical sequence.

Procedure

  1. In the Red Hat Developer Hub navigation menu, click Docs.
  2. In the Documentation table, click the name of the document you want to view.
  3. Navigate the content using the following on-screen tools:

    • Search bar: Find keywords within the current document.
    • Table of contents: Jump to specific sections.
    • Navigation menu: Switch between different documents in the same book.
    • Next: Proceed to the next sequential document.
    • Add-ons: Perform additional actions if the system configures plugins, such as setting the text size.

8.6.6. Make changes to project documentation in TechDocs

You can edit a document in your TechDocs plugin directly from the document book page. Any authorized user in your organization can edit a document regardless of whether or not they are the owner of the document.

Procedure

  1. In the Red Hat Developer Hub navigation menu, click Docs.
  2. In the Documentation table, click the name of the document that you want to edit.
  3. In the document, click the Edit this page icon to open the document in your remote repository.
  4. In your remote repository, edit the document as needed.
  5. Use the repository provider UI and your usual team processes to commit and merge your changes.

8.6.7. Add video content to enhance TechDocs

You can use <iframe> elements to add video content to enhance your experience with TechDocs.

Prerequisites

  • An administrator has configured your AWS S3 bucket to store TechDocs sites.
  • An administrator has configured the appropriate techdocs.sanitizer.allowedIframeHosts and backend.csp settings in your app-config.yaml file.

Procedure

  1. In the section of the TechDocs file that you want to embed a video into, add the following configuration:

    <iframe
      width="<video_width>"
      height="<video_height>"
      src="<video_url>"
      title="<video_title>"
      frameborder="<frame_border>"
      allow="picture-in-picture"
      allowfullscreen>
    </iframe>

    where

    <video_width>
    Specifies the width of the video in number of pixels, for example, 672.
    <video_height>
    Specifies the height of the video in number of pixels, for example, 378.
    <video_url>
    Specifies the url of the video, for example, https://www.youtube.com/watch?v=LB1w8hjBt5k.
    <video_title>
    Specifies the title of the video, for example, Red Hat Developer Hub Overview Video.
    <frame_border>

    Specifies the size of the frame border in number of pixels, for example, 0. Use a value of 0 for no border.

    Note

    TechDocs uses DOMPurify to sanitize HTML. To prevent DOMPurify from removing the <iframe> elements, you must list every permitted video host, such as www.youtube.com, under the techdocs.sanitizer.allowedIframeHosts section of your app-config.yaml file. You must also add the video host to the backend.csp section of your app-config.yaml file.

  2. In the frame-src and allowedIframeHosts fields of your app-config.yaml file, add any video hosts that you want to use. You can add multiple hosts. For example:

    backend:
            csp:
    connect-src: ['https:']
    frame-src: ['https://www.youtube.com/']
    techdocs:
      builder: external
      sanitizer:
        allowedIframeHosts:
          - www.youtube.com
          - <additional_video_host_url>
      publisher:
        type: awsS3
        awsS3:
          bucketName: $AWS_S3_BUCKET_NAME}
          accountId: $AWS_ACCOUNT_ID}
          region: $AWS_REGION}

8.6.8. Configure TechDocs storage and CI/CD pipelines

8.6.8.1. Configure TechDocs storage and CI/CD pipelines

Configure storage and CI/CD pipelines for TechDocs to enable documentation publishing.

8.6.8.2. Create standalone documentation in TechDocs

You can create standalone documentation in TechDocs for content that is not tied to a specific codebase, such as onboarding guides, architecture overviews, or team runbooks.

Prerequisites

  • An administrator has configured the TechDocs plugin.
  • You have the catalog.entity.create and catalog.location.create permissions.

Procedure

  1. Create a directory for your documentation project with the following structure:

    my-documentation/
      catalog-info.yaml
      mkdocs.yml
      docs/
        index.md
  2. Create a catalog-info.yaml file that defines a documentation entity:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: my-documentation
      description: Onboarding guide for new team members
      annotations:
        backstage.io/techdocs-ref: dir:.
    spec:
      type: documentation
      lifecycle: production
      owner: group:default/my-team
  3. Create an mkdocs.yml file to configure the documentation site:

    site_name: My Documentation
    nav:
      - Home: index.md
    plugins:
      - techdocs-core
  4. Create a docs/ directory containing at least an index.md file with your documentation content in Markdown.
  5. Commit and push the directory to a Git repository.
  6. In your Developer Hub instance, register the documentation entity:

    1. Click Catalog > Self-service > Register Existing Component.
    2. In the Select URL box, enter the URL to the catalog-info.yaml file in your repository.
    3. Click Analyze, then click Finish.

Verification

  1. In the Developer Hub navigation menu, click Docs.
  2. Verify that your standalone documentation appears in the table on the Documentation page.

    Note

    The documentation might not appear immediately. Developer Hub refreshes catalog entities periodically, which can take up to 45 minutes. To trigger a refresh sooner, navigate to the entity in the software catalog and click the refresh button on the Overview tab.

8.6.8.3. Enable documentation for an existing entity

You can add TechDocs documentation to a component that is already registered in the Developer Hub software catalog but does not yet have documentation configured.

Prerequisites

  • An existing entity is registered in the Developer Hub software catalog.
  • You have write access to the entity’s source repository.

Procedure

  1. Add the backstage.io/techdocs-ref annotation to the catalog-info.yaml file in your repository:

    apiVersion: backstage.io/v1alpha1
    kind: Component
    metadata:
      name: my-component
      annotations:
        backstage.io/techdocs-ref: dir:.
    spec:
      type: service
      lifecycle: production
      owner: group:default/my-team
  2. Create an mkdocs.yml file in the repository root:

    site_name: My Component Documentation
    nav:
      - Home: index.md
    Note

    Developer Hub automatically adds the techdocs-core plugin to mkdocs.yml if it is missing.

  3. Create a docs/ directory in the repository root containing at least an index.md file with your documentation content in Markdown.
  4. Commit, push, and merge the changes.

Verification

  1. In the Developer Hub software catalog, navigate to your component.
  2. Verify that a Docs tab appears with your documentation.

    Note

    The Docs tab might not appear immediately. Developer Hub refreshes catalog entities periodically, which can take up to 45 minutes. To trigger a refresh sooner, click the refresh button on the entity’s Overview tab.

8.6.8.4. Configuring storage for TechDocs files

The TechDocs publisher stores generated files in local storage or in cloud storage, such as AWS S3 or OpenShift Data Foundation.

8.6.8.5. Configure Amazon S3 or OpenShift Data Foundation buckets

8.6.8.5.1. Configure Amazon S3 or OpenShift Data Foundation buckets

Configure Amazon S3 or OpenShift Data Foundation for TechDocs file storage and make object storage accessible to containers.

8.6.8.5.2. Configure Amazon S3 for file storage

You can create a dedicated Amazon S3 bucket to store TechDocs sites. Red Hat Developer Hub uploads TechDocs to this bucket and serves them from the same location.

Prerequisites

  • You are logged in to your AWS account as an administrator.

Procedure

  1. On the AWS console, create an AWS S3 bucket.

    1. On the Create bucket page, enter a Bucket name and use the default selections for all other settings.
    2. Create an IAM policy to give authorized users permissions to generate and publish TechDocs for your organization.
    3. On the Create policy > Specify permissions page, in the Policy editor, enter the following JSON content:

      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Sid": "TechDocsList",
                  "Effect": "Allow",
                  "Action": "s3:ListBucket",
                  "Resource": "arn:aws:s3:::_<bucket_name>_"
              },
              {
                  "Sid": "TechDocsObjects",
                  "Effect": "Allow",
                  "Action": [
                      "s3:GetObject",
                      "s3:PutObject",
                      "s3:DeleteObject",
                      "s3:DeleteObjectVersion"
                  ],
                  "Resource": "arn:aws:s3:::_<bucket_name>_/*"
              }
          ]
      }

      where

      <bucket_name>
      Specifies the name of your Amazon S3 bucket.
    4. On the Create policy > Specify permissions page, enter a Policy name.
  2. Assign the IAM policy to a new or existing user.
  3. Generate a new access key and a new secret access key.

    Note

    You can use the newly created access keys to generate a TechDocs pipeline with GitHub Actions.

  4. From the OpenShift Container Platform web console, click Topology > Actions > Restart rollout to restart the pod.

    Note

    You must restart the pod to apply the configuration changes.

Verification

  • Go to your Amazon S3 bucket to see a set of static site files in your Objects list.
8.6.8.5.3. Configure OpenShift Data Foundation for file storage

You can configure OpenShift Data Foundation to store the files that TechDocs generates instead of relying on other cloud storage solutions.

OpenShift Data Foundation provides an ObjectBucketClaim custom resource (CR) that you can use to request an S3-compatible bucket backend. You must install the OpenShift Data Foundation Operator to use this feature.

Note

For air-gapped environments, using OpenShift Data Foundation is the recommended storage for TechDocs.

Prerequisites

  • An OpenShift Container Platform administrator has installed the OpenShift Data Foundation Operator in Red Hat OpenShift Container Platform, created an OpenShift Data Foundation cluster and configured the StorageSystem schema. For more information, see Deploying OpenShift Data Foundation using Amazon Web Services.

Procedure

  • Create an ObjectBucketClaim CR where the generated TechDocs files are stored. For example:

    apiVersion: objectbucket.io/v1alpha1
    kind: ObjectBucketClaim
    metadata:
      name: <rhdh_bucket_claim_name>
    spec:
      generateBucketName: <rhdh_bucket_claim_name>
      storageClassName: openshift-storage.noobaa.io
    Note

    Creating the Developer Hub ObjectBucketClaim CR automatically creates both the Developer Hub ObjectBucketClaim config map and secret. The config map and secret have the same name as the ObjectBucketClaim CR.

    After you create the ObjectBucketClaim CR, you can use the information stored in the config map and secret to make the information accessible to the Developer Hub container as environment variables. Depending on the method that you used to install Developer Hub, you add the access information to either the Red Hat Developer Hub Helm chart or Operator configuration.

8.6.8.5.3.1. Make object storage accessible to containers by using the Helm chart

Add ObjectBucketClaim access information to the Helm chart configuration to make it accessible to the Developer Hub container as environment variables.

Creating an ObjectBucketClaim custom resource (CR) automatically generates both the Developer Hub ObjectBucketClaim config map and secret. The config map and secret contain ObjectBucket access information. The Helm chart uses the following environment variables:

  • BUCKET_NAME
  • BUCKET_HOST
  • BUCKET_PORT
  • BUCKET_REGION
  • BUCKET_SUBREGION
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

These variables are then used in the TechDocs plugin configuration.

Prerequisites

  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Helm chart.
  • You have created an ObjectBucketClaim CR for storing files generated by TechDocs. For more information see Using OpenShift Data Foundation for file storage

Procedure

  • In the upstream.backstage key in the Helm chart values, enter the name of the Developer Hub ObjectBucketClaim secret as the value for the extraEnvVarsSecrets field and the extraEnvVarsCM field. For example:

    upstream:
      backstage:
        extraEnvVarsSecrets:
          - <rhdh_bucket_claim_name>
        extraEnvVarsCM:
          - <rhdh_bucket_claim_name>
8.6.8.5.3.1.1. Example TechDocs Plugin configuration for the Helm chart

The following example shows a Developer Hub Helm chart configuration for the TechDocs plugin.

global:
  dynamic:
    includes:
      - 'dynamic-plugins.default.yaml'
  plugins:
    - disabled: false
      package: ./dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic
      pluginConfig:
        techdocs:
          builder: external
          generator:
            runIn: local
          publisher:
            awsS3:
              bucketName: '${BUCKET_NAME}'
              credentials:
                accessKeyId: '$AWS_ACCESS_KEY_ID}'
                secretAccessKey: '$AWS_SECRET_ACCESS_KEY}'
              endpoint: 'https://${BUCKET_HOST}'
              region: '${BUCKET_REGION}'
              s3ForcePathStyle: true
            type: awsS3
8.6.8.5.3.2. Make object storage accessible to containers by using the Operator

Add ObjectBucketClaim access information to the Operator configuration to make it accessible to the Developer Hub container as environment variables.

Creating an ObjectBucketClaim custom resource (CR) automatically generates both the Developer Hub ObjectBucketClaim config map and secret. The config map and secret contain ObjectBucket access information. The Operator uses the following environment variables:

  • BUCKET_NAME
  • BUCKET_HOST
  • BUCKET_PORT
  • BUCKET_REGION
  • BUCKET_SUBREGION
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

These variables are then used in the TechDocs plugin configuration.

Prerequisites

  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Operator.
  • You have created an ObjectBucketClaim CR for storing files generated by TechDocs.

Procedure

  • In your Backstage CR, enter the name of the Developer Hub ObjectBucketClaim config map as the value for the spec.application.extraEnvs.configMaps field and enter the Developer Hub ObjectBucketClaim secret name as the value for the spec.application.extraEnvs.secrets field. For example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: {backstage}
    metadata:
     name: <name>
    spec:
      application:
        extraEnvs:
          configMaps:
            - name: <rhdh_bucket_claim_name>
          secrets:
            - name: <rhdh_bucket_claim_name>
8.6.8.5.3.2.1. Example TechDocs Plugin configuration for the Operator

The following example shows a Red Hat Developer Hub Operator config map configuration for the TechDocs plugin.

kind: ConfigMap
apiVersion: v1
metadata:
  name: dynamic-plugins-rhdh
data:
  dynamic-plugins.yaml: |
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - disabled: false
        package: ./dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic
        pluginConfig:
          techdocs:
            builder: external
            generator:
              runIn: local
            publisher:
              awsS3:
                bucketName: '${BUCKET_NAME}'
                credentials:
                  accessKeyId: '$AWS_ACCESS_KEY_ID}'
                  secretAccessKey: '$AWS_SECRET_ACCESS_KEY}'
                endpoint: 'https://${BUCKET_HOST}'
                region: '${BUCKET_REGION}'
                s3ForcePathStyle: true
              type: awsS3

8.6.8.6. Streamline documentation builds using GitHub Actions

For production use, deploy TechDocs by building documentation in CI/CD, publishing to external storage such as AWS S3, and configuring read-only mode. You can automate this workflow using GitHub Actions to generate and publish TechDocs when users update documentation files.

Prerequisites

  • The TechDocs plugin is enabled and configured on your Red Hat Developer Hub instance.
  • Your organization has documentation files stored in a remote repository.
  • You have an mkdocs.yaml file located in the root directory of your repository.
  • You have the catalog.entity.create and catalog.location.create permissions to import documentation into TechDocs from a remote repository.
  • You have an AWS S3 bucket to store your TechDocs sites.
  • Minimal IAM Policies are configured for your S3 bucket, granting both Write and Read access.
  • An administrator has created an IAM User, attached the necessary policy, and generated an access key in the AWS console.

Procedure

  1. Set up the GitHub Actions workflow.

    1. On GitHub, create a fork of the RHDH TechDocs Pipeline repository.

      Note

      The rhdh-techdocs-pipeline repository contains a generate-and-publish-techdocs.yaml workflow that automatically generates TechDocs from the docs folder and publishes them to an Amazon S3 bucket.

    2. Use the GitHub GUI to make sure that all of the permissions required to run the workflow are enabled.
    3. Add the Repository secrets required to connect the workflow to your AWS account, for example, TECHDOCS_S3_BUCKET_NAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION.

      Note

      The default mkdocs.yaml file in the rhdh-techdocs-pipeline workflow installs the techdocs-core and minify plugins.

    4. Optional: Customize the default structure or files of the rhdh-techdocs-pipeline repository to meet the needs of your organization.
    5. Optional: Add other mkdocs plugins that you want to use by adding the name of the plugins to the plugins section of the mkdocs.yaml file and to the steps.name: install mkdocs and mkdocs plugins section of the generate-and-publish-techdocs.yaml file.
  2. . In the navigation menu of the OpenShift Container Platform console, click ConfigMaps and select your RHDH app-config.yaml file.
  3. Update the app-config.yaml file to enable your Amazon S3 bucket to serve TechDocs to your RHDH instance. For example:

    techdocs:
      builder: external
      publisher:
        type: awsS3
        awsS3:
          bucketName: $AWS_S3_BUCKET_NAME}
          accountId: $AWS_ACCOUNT_ID}
          region: $AWS_REGION}
    
    aws:
      accounts:
        - accountId: $AWS_ACCOUNT_ID}
          accessKeyId: $AWS_ACCESS_KEY_ID}
          secretAccessKey: $AWS_SECRET_ACCESS_KEY}
    
    catalog:
         locations:
            - type: url
              target: https://github.com/<your_org>/rhdh-techdocs-pipeline/blob/main/catalog-info.yaml
  4. Click Save.
  5. In the navigation menu of the OpenShift Container Platform console, click Topology and restart the pod.

    Note

    Changes to the docs folder or the mkdocs.yaml file trigger the rhdh-techdocs-pipeline workflow to run. After the rhdh-techdocs-pipeline workflow runs successfully, the generated TechDocs are uploaded to your Amazon S3 bucket.

Verification

  • Go to your RHDH instance and click Docs to see the TechDocs served from your Amazon S3 bucket.

8.6.9. Configuring CI/CD to generate and publish TechDocs sites

You can generate documentation on CI/CD and publish to cloud storage by using the techdocs-cli CLI tool.

TechDocs reads the static generated documentation files from a cloud storage bucket, such as OpenShift Data Foundation. The documentation site is generated on the CI/CD workflow associated with the repository that has the documentation files.

You can use the following example to create a script for TechDocs publication:

# Prepare
REPOSITORY_URL='https://github.com/org/repo'
git clone $REPOSITORY_URL
cd repo

# Install @techdocs/cli, mkdocs and mkdocs plugins
npm install -g @techdocs/cli
pip install "mkdocs-techdocs-core==1.*"

# Generate
techdocs-cli generate --no-docker

# Publish
techdocs-cli publish --publisher-type awsS3 --storage-name <bucket/container> --entity <Namespace/Kind/Name>

The TechDocs workflow starts the CI when a user makes changes in the repository containing the documentation files. You can configure the workflow to start only when files inside the docs/ directory or mkdocs.yml are changed.

8.6.10. Install TechDocs add-ons

8.6.10.1. Install TechDocs add-ons

Install and configure TechDocs add-ons to extend the functionality of the TechDocs plugin in Red Hat Developer Hub.

TechDocs add-ons supported by Red Hat are exported to the TechDocs plugin by the backstage-plugin-techdocs-module-addons-contrib plugin package, which is preinstalled on Red Hat Developer Hub and enabled by default. The <ReportIssue /> add-on is part of the default configuration of this plugin package and comes ready to use in the TechDocs plugin.

You can install other supported TechDocs add-ons by configuring the backstage-plugin-techdocs-module-addons-contrib plugin package in the Red Hat Developer Hub ConfigMap or Helm chart, depending on whether you use the Operator or Helm chart for installation. If you want to customize your TechDocs experience beyond the functions of the supported add-ons, you can install third-party add-ons on your TechDocs plugin, including add-ons that you create yourself.

8.6.10.2. Install external or third-party add-ons

8.6.10.2.1. Install external or third-party add-ons

Install external or third-party TechDocs add-ons using the Operator or Helm Chart.

8.6.10.2.2. Install and configure an external TechDocs add-on using the Operator

You can use a dynamic plugin to import TechDocs add-ons into your TechDocs plugin. If you use the Red Hat Developer Hub Operator to install the dynamic plugin, you can add TechDocs add-ons to the plugin package in your ConfigMap.

Preinstalled add-ons, such as ReportIssue, are included in the default backstage-plugin-techdocs-module-addons-contrib package configuration. External add-ons that are supported by Red Hat are installed by manually adding them to the techdocsAddons section of the configuration file.

Procedure

  1. From the Developer perspective in the OpenShift Container Platform web console, click ConfigMaps > Create ConfigMap.
  2. From the Create ConfigMap page, select the YAML view option in the Configure via field.
  3. In the newly created ConfigMap, add the default backstage-plugin-techdocs-module-addons-contrib package configuration. For example:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
            disabled: false
            pluginConfig:
              dynamicPlugins:
                frontend:
                  backstage.plugin-techdocs-module-addons-contrib:
                    techdocsAddons:
                      - importName: ReportIssue
  4. In the techdocsAddons section of the ConfigMap, add importName: <external_techdocs_add-on> for each external TechDocs add-on that you want to add from the specified plugin package. For example:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
            disabled: false
            pluginConfig:
              dynamicPlugins:
                frontend:
                  backstage.plugin-techdocs-module-addons-contrib:
                    techdocsAddons:
                      - importName: ReportIssue
                      - importName: <external_techdocs_add-on>

    where:

    <external_techdocs_add-on>
    Specifies the external TechDocs add-on that you want to install, for example, TextSize or LightBox.
  5. Click Create.
  6. In the web console navigation menu, click Topology.
  7. Click the overflow menu for the Red Hat Developer Hub instance that you want to use and select Edit Backstage to load the YAML view of the Red Hat Developer Hub instance.
  8. In your Backstage CR, add the dynamicPluginsConfigMapName: <dynamic_plugins_configmap> key-value pair. For example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh
    spec:
      application:
    # ...
        dynamicPluginsConfigMapName: <dynamic_plugins_configmap>
    # ...

    where:

    <dynamic_plugins_configmap>
    Specifies the name of your dynamic plugins ConfigMap for your Red Hat Developer Hub instance, for example, dynamic-plugins-rhdh.
  9. Click Save.
  10. In the web console navigation menu, click Topology and wait for the Red Hat Developer Hub pod to start.
  11. Click the Open URL icon to start using the Red Hat Developer Hub platform with the new configuration changes.
8.6.10.2.3. Install and configure an external TechDocs add-on using the Helm chart

You can use a dynamic plugin to import TechDocs add-ons into your TechDocs plugin. If you use the Red Hat Developer Hub Helm chart to install the dynamic plugin, you can add TechDocs add-ons to the plugin package in your Helm chart.

Preinstalled add-ons, such as ReportIssue, are included in the default backstage-plugin-techdocs-module-addons-contrib package configuration. External add-ons that are supported by Red Hat are installed by manually adding them to the techdocsAddons section of the configuration file.

Prerequisites

  • The TechDocs plugin is installed and enabled.

Procedure

  1. In your Helm chart, add the global.dynamic parameters required to install a dynamic plugin, as shown in Installing dynamic plugins using the Helm chart

    Note

    The default configuration includes the dynamic-plugins.default.yaml file, which contains all of the dynamic plugins, including TechDocs add-ons, that are preinstalled in Red Hat Developer Hub, whether they are enabled or disabled by default.

  2. In your Helm chart, add the default backstage-plugin-techdocs-module-addons-contrib package configuration. For example:

    global:
      dynamic:
        plugins:
          - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
            disabled: false
            pluginConfig:
              dynamicPlugins:
                frontend:
                  backstage.plugin-techdocs-module-addons-contrib:
                    techdocsAddons:
                      - importName: ReportIssue
  3. In the techdocsAddons section of the Helm chart, add importName: <external_techdocs_add-on> for each external TechDocs add-on that you want to add from the specified plugin package. For example:

    global:
      dynamic:
        plugins:
          - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
            disabled: false
            pluginConfig:
              dynamicPlugins:
                frontend:
                  backstage.plugin-techdocs-module-addons-contrib:
                    techdocsAddons:
                      - importName: ReportIssue
                      - importName: <external_techdocs_add-on>

    where:

    <external_techdocs_add-on>
    Specifies the external TechDocs add-on that you want to install, for example, TextSize or LightBox.
8.6.10.2.4. Install and configure a third-party TechDocs add-on

You can install a compatible third-party TechDocs add-on on your Red Hat Developer Hub instance as a front-end dynamic plugin.

Prerequisites

  • The third-party TechDocs add-on has a valid package.json file in its root directory, containing all required metadata and dependencies.
  • The third-party plugin is packaged as a dynamic plugin in an OCI image. For alternative package types, see link:Installing third-party plugins in Red Hat Developer Hub.
  • You have installed the yarn package manager.
  • The third-party plugin is packaged as a dynamic plugin in an OCI image.* You have installed and configured Node.js and NPM.

Procedure

  1. Install the third-party plugin that you want to use to import your third-party add-on by entering the following command:

    $ yarn install
  2. Obtain the source code for the third-party TechDocs add-on that you want to use.
  3. Export the TechDocs add-on as a dynamic plugin using the following command:

    $ npx @red-hat-developer-hub/cli@latest plugin export
    Note

    The @latest tag pulls the latest version of the @red-hat-developer-hub/cli package, which is compatible with the most recent features and fixes. Use a version that is compatible with your Red Hat Developer Hub version.

  4. To package the third-party TechDocs add-on as a dynamic plugin, navigate to the root directory where the plugin is stored (not the dist-dynamic directory) and run the npx command with the --tag option to specify the image name and tag. For example:

    $ npx @red-hat-developer-hub/cli@latest plugin package --tag quay.io/<user_name>/<techdocs_add-on_image>:latest
    Note

    The output of the package-dynamic-plugins command provides the file path to the plugin for use in the dynamic-plugin-config.yaml file.

  5. To publish the third-party TechDocs add-on to a Quay repository, push the image to a registry using one of the following commands, depending on your virtualization tool:
  6. To use podman, enter the following command:

    $ podman push quay.io/<user_name>/<techdocs_add-on_image>:latest
  7. To use docker, enter the following command:

    $ docker push quay.io/<user_name>/<techdocs_add-on_image>:latest
  8. Open your dynamic-plugins.yaml file to view or modify the configuration for the third-party TechDocs add-on. For example:

    plugins:
          - package: oci://quay.io/<user_name>/<techdocs_add-on_image>:latest
            disabled: false
            pluginConfig:
              dynamicPlugins:
                frontend:
                 <techdocs_add-on_package>
                    techdocsAddons:
                      - importName: <third-party_add-on_name>
                       config:
                          props:
                           <techdocs_add-on_property_key>: <techdocs_add-on_property_value>

    where

    <user_name>
    Specifies your Quay user name or organization name.
    <techdocs_add-on_image>
    Specifies the name of the image for the third-party add-on that you want to use, for example, mermaid.
    <techdocs_add-on_package>
    Specifies the , for example, backstage-plugin-techdocs-addon-mermaid.
    <third-party_add-on_name>
    Specifies the name of the third-party add-on that you want to use, for example, Mermaid.
    <techdocs_add-on_property_key>
    Specifies the name of the custom property that can be passed to the third-party add-on, for example, themeVariables. Properties are specific to each add-on. You can list multiple properties for an add-on.
    <techdocs_add-on_property_value>
    Specifies the value of a property key for the third-party add-on, for example, lineColor: #000000.

8.6.10.3. Disable or remove TechDocs add-ons

8.6.10.3.1. Disable or remove TechDocs add-ons

Remove or disable installed TechDocs add-ons from your Red Hat Developer Hub instance by using the Operator or the Helm chart.

Administrators can remove installed TechDocs add-ons by using either the Operator or Helm chart, depending on the method used to install the add-on. If you used the Operator to install the add-on, remove it from the ConfigMap. If you used the Helm chart to install the add-on, remove it from the Helm chart.

If you want to disable a plugin instead of removing it from your Red Hat Developer Hub instance, you can disable the plugin that you are using to import the TechDocs add-on. Since the disabled status is controlled at the plugin level, disabling the plugin disables all of the TechDocs add-ons in the specified plugin package.

8.6.10.3.2. Remove an external TechDocs add-on from your ConfigMap

Disable or permanently remove an external TechDocs add-on from your Red Hat Developer Hub ConfigMap when you no longer need it.

The disabled status is controlled at the plugin level, therefore, disabling the plugin disables all of the TechDocs add-ons in the disabled plugin package.

Procedure

  1. From the Developer perspective in the OpenShift Container Platform web console, click ConfigMaps.
  2. From the ConfigMaps page, click the ConfigMap that contains the TechDocs add-on that you want to remove.
  3. Select the YAML view option in the Configure via field.
  4. In the plugins section of the ConfigMap, do one of the following actions based on whether you want to disable or remove a TechDocs add-on:

    • To temporarily disable all of the TechDocs add-ons in a particular plugin package, change the value of the disabled field to true. For example:

      kind: ConfigMap
      apiVersion: v1
      metadata:
        name: dynamic-plugins-rhdh
      data:
        dynamic-plugins.yaml: |
          includes:
            - dynamic-plugins.default.yaml
          plugins:
            - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
              disabled: true
              pluginConfig:
                dynamicPlugins:
                  frontend:
                    backstage.plugin-techdocs-module-addons-contrib:
                      techdocsAddons:
                        - importName: ReportIssue
                        - importName: <external_techdocs_add-on>

      where:

      <external_techdocs_add-on>
      Specifies the external TechDocs add-on that you want to remove, for example, TextSize.
    • To remove one or more TechDocs add-ons from your Red Hat Developer Hub instance, delete importName: <external_techdocs_add-on> for each external TechDocs add-on that you want to remove from the techdocsAddons section of your ConfigMap. For example:

      kind: ConfigMap
      apiVersion: v1
      metadata:
        name: dynamic-plugins-rhdh
      data:
        dynamic-plugins.yaml: |
          includes:
            - dynamic-plugins.default.yaml
          plugins:
            - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
              disabled: false
              pluginConfig:
                dynamicPlugins:
                  frontend:
                    backstage.plugin-techdocs-module-addons-contrib:
                      techdocsAddons:
                        - importName: ReportIssue
                        - importName: <external_techdocs_add-on>

      where:

      <external_techdocs_add-on>
      Specifies the external TechDocs add-on that you want to remove, for example, TextSize.
  5. Click Save.
  6. In the web console navigation menu, click Topology and wait for the Red Hat Developer Hub pod to start.
  7. Click the Open URL icon to start using the Red Hat Developer Hub platform with the new configuration changes.
8.6.10.3.3. Remove an external TechDocs add-on from your Helm chart

Disable or permanently remove an external TechDocs add-on from your Red Hat Developer Hub Helm chart when you no longer need it.

The disabled status is controlled at the plugin level, therefore, disabling the plugin disables all of the TechDocs add-ons in the disabled plugin package.

Procedure

  • In the plugins section of the Helm chart, do one of the following actions based on whether you want to disable or remove a TechDocs add-on:

    • To temporarily disable all of the TechDocs add-ons in a particular plugin package, change the value of the disabled field to true. For example:

      global:
        dynamic:
          plugins:
            - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
              disabled: true
              pluginConfig:
                dynamicPlugins:
                  frontend:
                    backstage.plugin-techdocs-module-addons-contrib:
                      techdocsAddons:
                        - importName: ReportIssue
                        - importName: <external_techdocs_add-on>

      where:

      <external_techdocs_add-on>
      Specifies the external TechDocs add-on that you want to remove, for example, TextSize.
    • To remove one or more TechDocs add-ons from your Red Hat Developer Hub instance, delete importName: <external_techdocs_add-on> for each external TechDocs add-on that you want to remove from the techdocsAddons section of your Helm chart. For example:

      global:
        dynamic:
          plugins:
            - package: ./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib
              disabled: false
              pluginConfig:
                dynamicPlugins:
                  frontend:
                    backstage.plugin-techdocs-module-addons-contrib:
                      techdocsAddons:
                        - importName: ReportIssue
                        - importName: <external_techdocs_add-on>

      where:

      <external_techdocs_add-on>
      Specifies the external TechDocs add-on that you want to remove, for example, TextSize.

8.6.10.4. Use enabled add-ons

8.6.10.4.1. Use enabled add-ons

After an administrator installs a TechDocs add-on in your Red Hat Developer Hub instance, you can use it to extend the functionality of the TechDocs plugin and enhance your documentation experience.

8.6.10.4.2. Use the ReportIssue TechDocs add-on

If you find an error in your organization’s TechDocs documentation, you can use the ReportIssue add-on to open a new GitHub or GitLab issue directly from the documentation. ReportIssue automatically imports the text that you highlight in the document into a new issue template in your repository.

Prerequisites

  • The ReportIssue add-on is installed and enabled in your TechDocs plugin.
  • You have permissions to create issues in the repository where documentation issues are reported.

Procedure

  1. In your TechDocs documentation, highlight the text that you want to report an issue for.
  2. Click the text in the ReportIssue box, for example, Open new GitHub issue.
  3. From the new issue page in your repository, use the template to create the issue that you want to report.

    Note

    The default issue title is Documentation feedback: <highlighted_text>, where <highlighted_text> is the text that you highlighted in your TechDocs documentation.

    In the issue description, <highlighted_text> is the default value for the The highlighted text field.

Verification

  • The issue that you created is listed on the issues page in your repository.
8.6.10.4.3. Use the TextSize TechDocs add-on

You can use the TextSize add-on to change the size of the text on either the TechDocs Reader page or an Entity page.

Prerequisites

  • The TextSize add-on is installed and enabled in your TechDocs plugin.

Procedure

  1. In your TechDocs header, click the Settings icon.
  2. Use the sliding scale to adjust the size of your documentation text.

    Note
    1. The default text size is 100%
    2. The minimize text size is 90%
    3. The maximum text size is 150%
8.6.10.4.4. Use the LightBox TechDocs add-on

Use the LightBox add-on to view enlarged images in a lightbox overlay window and navigate between images on a single documentation page.

Prerequisites

  • The LightBox add-on is installed and enabled in your TechDocs plugin.

Procedure

  1. In your TechDocs documentation, click the image that you want to view in a lightbox.
  2. In the lightbox, you can do any of the following actions:
  3. Click the image or scroll to zoom in or zoom out.
  4. Click the arrow to navigate between images.

8.6.11. TechDocs add-ons

TechDocs add-ons are dynamic plugins that extend the functionality of the built-in TechDocs plugin. For example, you can use add-ons to report documentation issues, change text size, or view images in overlay in either the TechDocs Reader page or an Entity page.

The following table describes the TechDocs add-ons that are available for Red Hat Developer Hub 1.10:

TechDocs Add-onPackage/PluginDescriptionType

<ReportIssue />

backstage-plugin-techdocs-module-addons-contrib

Select a portion of text on a TechDocs page and open an issue against the repository that contains the documentation. The issue template is automatically populated with the selected text.

Preinstalled

<TextSize />

backstage-plugin-techdocs-module-addons-contrib

Customize text size on documentation pages by increasing or decreasing the font size with a slider or buttons. The default value for font size is 100% and this setting is kept in the browser’s local storage whenever it is changed.

External

<LightBox />

backstage-plugin-techdocs-module-addons-contrib

Open images in a light-box on documentation pages, to navigate to multiple images on a single page. The image size of the light-box image is the same as the image size on the document page. Clicking the zoom icon increases the image size to fit the screen.

External

The backstage-plugin-techdocs-module-addons-contrib plugin package exports both preinstalled and external add-ons supported by Red Hat to the TechDocs plugin. This plugin package is preinstalled on Red Hat Developer Hub and is enabled by default. If the plugin package is disabled, all of the TechDocs add-ons exported by the package as also disabled.

8.6.12. Create a TechDocs add-on

If your organization has documentation needs that are not met by the functions of existing TechDocs add-ons, developers can create a new add-on for your TechDocs plugin.

A TechDocs add-on is a React component that is imported from a front-end plugin. If you do not have an existing plugin that you can use to export your TechDocs add-on, you can create a new plugin by using backstage-cli to generate a default front-end plugin structure that you can customize.

The folder structure of a new plugin that can be used to import TechDocs add-ons into the TechDocs plugin looks similar to the following example:

<new_plugin_for_techdocs_add-on>/
   dev/
       index.ts
   src/
       components/
         <new_techdocs_add-on_component>/
              <new_techdocs_add-on_component>.test.tsx
              <new_techdocs_add-on_component>.tsx
               index.ts
         <new_techdocs_add-on_fetch-component>/
              <new_techdocs_add-on_fetch-component>.test.tsx
              <new_techdocs_add-on_fetch-component>.tsx
               index.ts
       index.ts
       plugin.test.ts
       plugin.ts
       routes.ts
       setupTests.ts
   .eslintrc.js
   package.json
   README.md

Prerequisites

  • The yarn package manager is installed.
  • Docker v3.2.0 or later or Podman v3.2.0 or later is installed and running.

Procedure

  1. In the terminal, navigate to the root folder of the repository where you want to create your new plugin.
  2. To create a new front-end plugin, run the following command:

    $ yarn new

    Example output:

    ? What do you want to create? plugin - A new frontend plugin
    ? Enter the ID of the plugin [required]
  3. In the terminal prompt, type a name for the new plugin. For example:

    ? Enter the ID of the plugin [required] <new_plugin_for_techdocs_add-on>

    Example output:

    Successfully created plugin

    Upon completion of this action, a sub-directory with the same name that you gave to your plugin is automatically generated inside the plugins directory. The directory contains all of the files that you need to configure to create your new plugin.

  4. In the terminal, navigate to your new plugin directory. For example:

    $ cd plugins/<new_techdocs_add-on_directory>
  5. Add the`@backstage/plugin-techdocs-react` package to get frontend utilities for TechDocs add-ons. For example:

    $ yarn add @backstage/plugin-techdocs-react
  6. In the directory containing the components of your custom TechDocs add-on, delete any default files or file components that are not required for your add-on, such as the routes.ts file or components of the index.tsx and plugins.ts files.
  7. In the plugins.ts file, add the following code:

    $ import { createPlugin } from '@backstage/core-plugin-api';
    $ import { createTechDocsAddonExtension } from '@backstage/plugin-techdocs-react';
    
    $ export const <new_plugin_for_techdocs_add-on> = createPlugin({
      id: '<new_techdocs_add-on>',
     });
    
     /*
     *
     * @public
     */
    $ export const <new_techdocs_add-on> = <new_plugin_for_techdocs_add-on>.provide(
     createTechDocsAddonExtension<_<new_techdocs_addon_props>_>({
        name: '<new_techdocs_add-on>',
        location: TechDocsAddonLocations.Content,
        component: <new_techdocs_add-on_component>,
      }),
    );

    where

    <new_plugin_for_techdocs_add-on>
    Specifies the new plugin that you use to import the TechDocs add-on to your Red Hat Developer Hub instance.
    <new_techdocs_add-on>
    Specifies the custom TechDocs add-on that you want to create.
    <new_techdocs_addon_props> (Optional)
    Specifies the props for your new TechDocs add-on, as specified in your <new_techdocs_add-on>.tsx file, if applicable.
    <new_techdocs_add-on_component>
    Specifies the React component for the custom TechDocs add-on that you want to create. You will create this component in a .tsx file in a later step.
  8. In the index.ts file, export the custom TechDocs add-on that you want to create by adding the following code:

    $ export { <new_plugin_for_techdocs_add-on>, <new_techdocs_add-on> } from './plugin';
  9. Create a new <new_techdocs_add-on>.tsx file and add the code for your new TechDocs add-on component.
  10. Create a new index.tsx file and use it to export your new TechDocs add-on component by adding the following code:

    $ export { <new_techdocs_add-on>, type <new_techdocs_addon_props>} from './<new_techdocs_add-on_directory>'

    where

    <new_techdocs_addon_props> (Optional)
    Specifies the props for your new TechDocs add-on, as specified in your <new_techdocs_add-on>.tsx file, if applicable.
  11. In the plugins.ts file, import your new TechDocs add-on component.
  12. Install and configure your new TechDocs add-on by following the steps in Install and configure a TechDocs add-on

Verification

  1. Restart the RHDH application and verify that the plugin is successfully activated and configured.
  2. Verify the application logs for confirmation and ensure the plugin is functioning as expected.

Chapter 9. Configure

9.1. Configure

Configure Red Hat Developer Hub to meet your infrastructure requirements, customize the user interface to reflect your organizational branding, and set up language localization for global accessibility.

9.2. Configure core parameters to meet infrastructure requirements

9.2.1. Configure core parameters to meet infrastructure requirements

Configure the core parameters of your Developer Hub deployment, including default configurations, custom config maps and secrets, routes, TLS connections, and corporate proxy settings.

9.2.2. Default configurations to establish a deployment foundation

9.2.2.1. Default configurations to establish a deployment foundation

Deploy a standard Red Hat Developer Hub instance, understand its structure, and tailor the instance to meet your needs.

9.2.2.2. Red Hat Developer Hub configuration files overview

Overview of the configuration files and Kubernetes resources used to manage Red Hat Developer Hub instances across different deployment methods.

Developer Hub configuration files fall into two categories based on how they are consumed:

Cluster-provisioned files
Provisioned as Kubernetes resources, such as config maps or secrets, on the target cluster, typically by platform engineers. These files control the runtime behavior and deployment of your RHDH instance. While the source files can be stored in a Git repository, they must be applied to the cluster to take effect.
Application-consumed files
Authored by developers and committed to source repositories. RHDH reads these files directly from Git at runtime to populate the software catalog, execute templates, and build documentation.
9.2.2.2.1. Cluster-provisioned files

The following table lists configuration files that platform engineers create and provision as Kubernetes resources on the target cluster.

FilePurposeFormatOperator provisioningHelm chart provisioning

app-config.yaml

Main application configuration, including URLs, auth, catalog, database, plugin settings.

YAML

Config map referenced in the spec.application.appConfig.configMaps field in the Backstage custom resource.

Inline through upstream.backstage.appConfig values, or external config map through upstream.backstage.extraAppConfig.

Secrets, such as, my-rhdh-secrets)

Authentication credentials, backend secret, database passwords, and other sensitive values.

Kubernetes secret

Secret referenced in the spec.application.extraEnvs.secrets field in the Backstage custom resource.

Referenced through upstream.backstage.extraEnvVarsSecrets or upstream.backstage.extraEnvVars using a secretKeyRef.

dynamic-plugins.yaml

Enable, disable, and configure dynamic plugins.

YAML

Config map referenced in the spec.application.dynamicPluginsConfigMapName field in the Backstage custom resource.

Inline through global.dynamic.plugins Helm values.

rbac-policy.csv

RBAC permission policies and role assignments (Casbin format).

CSV

Config map mounted as file, path configured in app-config.yaml under permission.rbac.policies-csv-file.

Same.

rbac-conditional-policies.yaml

RBAC conditional policies with criteria-based filtering.

YAML

Config map mounted as file, path configured in app-config.yaml under permission.rbac.conditionalPoliciesFile.

Same.

Backstage custom resource

Operator-side deployment configuration that references config files, routes, database, replicas.

YAML Kubernetes custom resource

Applied directly as a Backstage custom resource.

N/A

Helm values.yaml

Helm-side deployment configuration, including image, replicas, resources, routes.

YAML

N/A

Passed by using helm install -f values.yaml or the --set option.

9.2.2.2.2. Application-consumed files

The following table lists configuration files that developers author and store in Git repositories. RHDH reads these files directly from Git at runtime.

FilePurposeFormatStored inConsumed by

catalog-info.yaml

Entity descriptor that defines components, APIs, systems, and their metadata and annotations.

YAML

Root of a source repository.

Software Catalog through catalog locations or discovery providers.

template.yaml

Software template definition with scaffolding steps for creating new components.

YAML

Template repository.

Software Templates (registered through catalog.locations URL in app-config.yaml).

mkdocs.yml

TechDocs configuration that controls how documentation is built from Markdown.

YAML

Alongside source repository docs.

TechDocs plugin.

9.2.2.3. Application configuration file

The app-config.yaml file is the main Developer Hub configuration file. It controls application behavior including URLs, authentication, catalog sources, database connections, and plugin settings.

The following are key sections in app-config.yaml:

app
Frontend settings such as the application title and base URL.
backend
Backend settings including the base URL, CORS origin, database connection, authentication, and cache.
auth
Authentication provider configuration.
catalog
Software Catalog locations and entity providers.
techdocs
TechDocs builder and storage configuration.
proxy
Proxy endpoints for external services.
permission
RBAC permission framework configuration.

The app-config.yaml file supports ${VAR_NAME} syntax that resolves at runtime from environment variables. You can inject environment variables through Kubernetes secrets or config maps, which allows you to keep sensitive values such as credentials and tokens out of your configuration files.

You can provision the app-config.yaml file by using either the Operator or the Helm chart:

  • With the Operator: on OpenShift Container Platform, the Operator might automatically set app.baseUrl, backend.baseUrl, and backend.cors.origin from the route in the default application configuration. Create a config map containing your app-config.yaml and reference it in the Backstage custom resource.
  • With the Helm chart: set the base URL fields manually. You can inline your configuration in the Helm chart values at upstream.backstage.appConfig, or reference external config maps through upstream.backstage.extraAppConfig.

9.2.2.4. Backstage custom resource

When you use the Red Hat Developer Hub Operator, the Backstage custom resource is the central deployment configuration. It defines how the Operator creates and manages the Developer Hub instance, and references the config maps and secrets that contain your configuration files.

The following fields control key aspects of the deployment:

spec.application.appConfig.configMaps
References config maps containing your app-config.yaml files.
spec.application.dynamicPluginsConfigMapName
References the config map containing the dynamic-plugins.yaml file.
spec.application.extraFiles
Mounts additional config maps, secrets, or PVCs as files in the Developer Hub container.
spec.application.extraEnvs
Injects environment variables from config maps, secrets, or inline values.
spec.application.route
Controls route or ingress configuration.
spec.database
Controls whether the built-in PostgreSQL database is enabled or disabled.
spec.deployment.patch
Applies a strategic merge patch to the Deployment resource for advanced customization.

9.2.2.5. Helm chart values file

When you deploy Developer Hub by using the Helm chart, the values.yaml file is the central deployment configuration. It controls how the Helm chart creates Kubernetes resources and can embed application configuration inline.

The following value paths control key aspects of the deployment:

upstream.backstage.appConfig
Generates a config map with your application configuration. The Helm chart renders these values into an app-config.yaml config map automatically.
upstream.backstage.extraAppConfig
References external config maps containing additional app-config.yaml files.
global.dynamic.plugins
Configures the dynamic plugins to enable, disable, or customize.
Note

Use Helm values for deployment-level concerns, such as images, replicas, resources, and routes. Use app-config.yaml for application behavior, such as authentication, catalogs, and plugins.

9.2.2.6. Dynamic plugins configuration file

The dynamic-plugins.yaml file controls which dynamic plugins are enabled in your Developer Hub instance. It defines a list of plugins to install, disable, or configure.

The file contains the following two main sections:

includes
References a base configuration file (dynamic-plugins.default.yaml) that is included with Developer Hub. This file contains the default plugin configuration.
plugins
A list of plugin entries that override or extend the base configuration. Each entry specifies a package (the plugin path), a disabled field (boolean), and an optional pluginConfig section with plugin-specific YAML that is merged into the application configuration.

You can provision the dynamic-plugins.yaml file in different ways depending on your deployment method:

With the Operator
Create a config map containing the dynamic-plugins.yaml data and reference it in the Backstage custom resource by using spec.application.dynamicPluginsConfigMapName.
With the Helm chart
Configure plugins inline by using the global.dynamic.plugins Helm values.

9.2.2.7. Configuration precedence

When multiple configuration sources are available, Developer Hub merges them following specific precedence rules. Understanding these rules helps you predict how your configuration files interact.

Review these configuration precedence behaviors:

Application configuration layering
When you provide multiple app-config.yaml files (for example, through multiple config maps), Developer Hub deep-merges them. Later files override earlier files for the same keys. For object values, the merge is recursive. For array values, the later array replaces the earlier array entirely.
Dynamic plugins merge behavior
The plugins list from your configuration merges with the plugins list from the includes file. If both lists contain an entry for the same plugin package, the fields in your configuration override the fields in the includes file.
Environment variable resolution
References using the ${VAR_NAME} syntax in any YAML configuration file resolve at runtime from environment variables. If a referenced environment variable is not set, Developer Hub fails to start.
Operator flavor merging
When you enable multiple pre-configured settings (for example, Orchestrator and Lightspeed), the Operator merges their configurations automatically. Settings from both configurations merge without manual intervention.

9.2.2.8. Catalog entity descriptor file

The catalog-info.yaml file is a YAML descriptor that defines catalog entities such as components, APIs, systems, and resources. Developers author this file and commit it to their source repository.

The Software Catalog consumes catalog-info.yaml files through catalog.locations entries in app-config.yaml or through discovery providers (for example, GitHub or GitLab discovery).

Key annotations in catalog-info.yaml control how plugins interact with the entity (for example, backstage.io/techdocs-ref for TechDocs, argocd/app-name for Argo CD).

9.2.2.9. Software template definition file

The template.yaml file defines a software template that scaffolds new components, repositories, or infrastructure. Developers author this file and store it in a template repository.

Software templates are registered in Developer Hub by adding the template.yaml URL to the catalog.locations section of app-config.yaml.

A template defines input parameters, scaffolding steps, and output actions such as creating a repository or registering a catalog entity.

Additional resources

9.2.2.10. TechDocs configuration file

The mkdocs.yml file configures how TechDocs builds documentation from Markdown source files. Developers store this file alongside the docs/ directory in their component repository.

The mkdocs.yml file controls the documentation site structure, navigation, theme, and MkDocs plugins.

The TechDocs plugin in Developer Hub reads this file when building or serving documentation for a catalog entity.

9.2.2.11. Dynamic plugins cache

The dynamic plugins cache reduces platform boot time by storing already-installed plugins and skipping redundant downloads when the configuration does not change.

When you enable dynamic plugins cache:

  • The system calculates a checksum of each plugin’s YAML configuration (excluding pluginConfig).
  • The system stores the checksum in a file named dynamic-plugin-config.hash within the plugin’s directory.
  • During boot, if a plugin’s package reference matches the earlier installation and the checksum does not change, the system skips the download.
  • The system automatically removes plugins that you disabled since the earlier boot.
Note

To enable the dynamic plugins cache in RHDH, the plugins directory dynamic-plugins-root must be a persistent volume.

9.2.2.12. Default configurations

The Operator creates Kubernetes resources with default configuration that you can customize using the Backstage Custom Resource.

The Operator stores the default configuration in a ConfigMap named rhdh-default-config in the rhdh-operator namespace on OpenShift. This ConfigMap has the YAML manifests that define the foundational structure of the RHDH instance.

You can create a basic RHDH instance by applying an empty Backstage Custom Resource as follows:

apiVersion: backstage.redhat.com/v1alpha4
kind: Backstage
metadata:
name: my-rhdh-instance
namespace: rhdh

The Operator automatically creates the following resources in the specified RHDH namespace by default based on the default configuration:

File NameResource Group/Version/Kind (GVK)Resource NameDescription

deployment.yaml

apps/v1/Deployment

backstage-{cr-name}

(Mandatory) The main Backstage application deployment.

service.yaml

v1/Service

backstage-{cr-name}

(Mandatory) The Backstage application service.

db-statefulset.yaml

apps/v1/StatefulSet

backstage-psql-{cr-name}

The PostgreSQL database stateful set. Needed if spec.enabledDb=true.

db-service.yaml

v1/Service

backstage-psql-{cr-name}

The PostgreSQL database service. Needed if spec.enabledDb=true.

db-secret.yaml

v1/Secret

backstage-psql-{cr-name}

The PostgreSQL database credentials secret. Needed if spec.enabledDb=true.

route.yaml

route.openshift.io/v1

backstage-{cr-name}

The OpenShift Route to expose Backstage externally. (Optional) Applied to OpenShift only.

app-config.yaml

v1/ConfigMap

backstage-config-{cr-name}

(Optional) Specifies one or more Backstage app-config.yaml files.

configmap-files.yaml

v1/ConfigMap

backstage-files-{cr-name}

(Optional) Specifies additional ConfigMaps to mount as files into the Backstage Pod.

configmap-envs.yaml

v1/ConfigMap

backstage-envs-{cr-name}

(Optional) Specifies additional ConfigMaps to expose as environment variables in the Backstage Pod.

secret-files.yaml

v1/Secret or list of v1/Secret

backstage-files-{cr-name}-{secret-name}

(Optional) Specifies additional Secrets to mount as files into the Backstage Pod.

secret-envs.yaml

v1/Secret or list of v1/Secret

backstage-envs-{cr-name}

(Optional) Specifies additional Secrets to expose as environment variables in the Backstage Pod.

dynamic-plugins.yaml

v1/ConfigMap

backstage-dynamic-plugins-{cr-name}

(Optional) Specifies the dynamic plugins that the Operator installs into the Backstage instance.

pvcs.yaml

list of v1/PersistentVolumeClaim

backstage-{cr-name}-{pvc-name}

(Optional) The Persistent Volume Claim for PostgreSQL database.

Note

{cr-name} is the name of the Backstage Custom Resource, for example 'my-rhdh-instance' in the above example.

9.2.2.13. Automated Operator features

Use the Operator to automate key configuration processes for your Backstage application.

9.2.2.13.1. Metadata generation

The Operator automatically generates metadata values for default resources at runtime to ensure proper application function.

For all the default resources, the Operator generates metadata.name according to the rules defined in the Default Configuration files, particularly the Resource name column. For example, a Backstage Custom Resource (CR) named mybackstage creates a Kubernetes Deployment resource called backstage-mybackstage.

The Operator generates the following metadata for each resource:

  • deployment.yaml

    • spec.selector.matchLabels[rhdh.redhat.com/app] = backstage-{cr-name}
    • spec.template.metadata.labels[rhdh.redhat.com/app] = backstage-{cr-name}
  • service.yaml

    • spec.selector[rhdh.redhat.com/app] = backstage-{cr-name}
  • db-statefulset.yaml

    • spec.selector.matchLabels[rhdh.redhat.com/app] = backstage-psql-{cr-name}
    • spec.template.metadata.labels[rhdh.redhat.com/app] = backstage-psql-{cr-name}
  • db-service.yaml

    • spec.selector[rhdh.redhat.com/app] = backstage-psql-{cr-name}
9.2.2.13.2. Many resources

Define and create many resources of the same type in a single YAML file by using the --- delimiter to separate resource definitions.

For example, adding the following code snip to pvcs.yaml creates two PersistentVolumeClaims (PVCs) called backstage-{cr-name}-myclaim1 and backstage-{cr-name}-myclaim2 and mounts them to the Backstage container.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim1
...
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim2
...
9.2.2.13.3. Default base URLs

The Operator automatically sets base URLs for your application based on route parameters and OpenShift cluster ingress domain.

The Operator follows these rules to set the base URLs for your application:

  • If the cluster is not OpenShift, the Operator makes no changes.
  • If you explicitly set the spec.application.route.enabled field in your Custom Resource (CR) to false, the Operator makes no changes.
  • If you define spec.application.route.host in the Backstage CR, the Operator sets the base URLs to https&#58;//<spec.application.route.host>.
  • If you specify the spec.application.route.subdomain in the Backstage CR, the Operator sets the base URLs to https&#58;//<spec.application.route.subdomain>.<cluster_ingress_domain>.
  • If you do not set a custom host or subdomain, the Operator sets the base URLs to https&#58;//backstage-<cr_name>-<namespace>.<cluster_ingress_domain>, which is the default domain for the created Route resource.

The Operator updates the following base URLs in the default app-config config map:

  • app.baseUrl
  • backend.baseUrl
  • backend.cors.origin
Note

You can perform these actions on a best-effort basis and only on OpenShift. During an error or on non-OpenShift clusters, you can still override these defaults by providing a custom app-config config map.

9.2.2.14. Time syntax

Use supported time duration formats in Red Hat Developer Hub, including human-readable strings, duration objects, ISO 8601 strings, and cron expressions.

Format

Description

Example

Compound values

Human-readable strings

Simple strings compatible with the ms library.

30m

No

Duration objects

A structured object specifying time units. Matches the HumanDuration TypeScript interface.

  timeout:
    minutes: 30

Yes

ISO 8601 duration strings

Standard ISO 8601 duration strings.

PT30M

Yes

Format

Description

Example

Cron

An object containing a cron key with a crontab-style string. Used primarily by Scheduler services for tasks such as frequency).

  frequency:
    cron: '*/30 * * * *'
Warning

RHDH configuration reader readDurationFromConfig explicitly disallows plain numbers to prevent ambiguity.

However, specific raw configuration fields, such as direct Node.js HTTP server settings, might strictly require numbers. Always check the specific documentation for the field you are configuring.

9.2.2.15. Pre-configured settings for common use cases

To choose the appropriate configuration for your use case, review the available predefined settings, their infrastructure prerequisites, and minimal Custom Resource examples.

Red Hat Developer Hub Operator 1.10.0 and later includes pre-configured settings for common use cases. Each configuration automatically applies required plugins, dependencies, and app-config settings.

NamePurposeInfrastructure prerequisitesDefault status

orchestrator

Workflow automation for CI/CD pipelines

OpenShift Serverless Operator, Knative Serving, Knative Eventing, OpenShift Serverless Logic Operator, PostgreSQL database, optional AMQ Streams

Disabled by default - enable explicitly

lightspeed

AI chat assistance for developers

External LLM provider (OpenAI-compatible API)

Enabled by default - disable to turn off

9.2.2.15.1. Orchestrator

Enable workflow automation with automatic plugin configuration.

Automatically configured components:

  • Orchestrator front-end plugin (red-hat-developer-hub-backstage-plugin-orchestrator)
  • Orchestrator backend plugin (red-hat-developer-hub-backstage-plugin-orchestrator-backend)
  • Orchestrator backend module for Scaffolder (red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator)
  • Orchestrator form widgets plugin (red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets)
  • SonataFlow Operator integration
  • Data Index service
  • Job service

Minimal CR example:

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub-orchestrator
spec:
  flavours:
    - name: orchestrator
      enabled: true
Note

This example uses the default local PostgreSQL database. For production deployments, Red Hat recommends using an external PostgreSQL database. For configuration details, see Configure external PostgreSQL databases.

Prerequisites:

  • OpenShift Serverless Operator, Knative Serving, Knative Eventing, and OpenShift Serverless Logic Operator
  • PostgreSQL database (external database recommended for production)
  • Optional: AMQ Streams (Kafka) for event-driven workflows

    For detailed steps, see Deploy Red Hat Developer Hub for workflow automation.

9.2.2.15.2. Developer Lightspeed for RHDH

Developer Lightspeed for RHDH is enabled by default in Red Hat Developer Hub 1.10.0 and later. Connect your LLM provider to use AI chat assistance.

Automatically configured components:

  • Developer Lightspeed for RHDH front-end plugin
  • Developer Lightspeed for RHDH backend plugin
  • Lightspeed Core Service sidecar

Minimal CR example:

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  application:
    extraEnvs:
      secrets:
        - name: lightspeed-secrets
          containers:
            - lightspeed-core
Note

Developer Lightspeed for RHDH is enabled by default. You do not need to set spec.flavours to enable AI assistance. To disable, set spec.flavours: [{name: lightspeed, enabled: false}].

Prerequisites:

9.2.2.15.3. Multiple pre-configured settings

Enable both Orchestrator and Developer Lightspeed for RHDH in a single deployment:

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub-full
spec:
  flavours:
    - name: orchestrator
      enabled: true
  application:
    extraEnvs:
      secrets:
        - name: lightspeed-secrets
          containers:
            - lightspeed-core
Note

Developer Lightspeed for RHDH is enabled by default, so you only need to explicitly enable Orchestrator. Settings from both configurations merge automatically. For production deployments with external PostgreSQL database, add the database configuration as shown in Configure external PostgreSQL databases.

You must meet prerequisites for both: OpenShift Serverless components for Orchestrator and external LLM provider for Developer Lightspeed for RHDH.

9.2.3. Provision custom config maps and secrets to define platform behavior

9.2.3.1. Provision custom config maps and secrets to define platform behavior

Configure Red Hat Developer Hub by using config maps to mount files and directories and secrets to inject environment variables into your Red Hat OpenShift Container Platform application.

9.2.3.2. Provision your custom configuration

Provision custom config maps and secrets on Red Hat OpenShift Container Platform (RHOCP) to configure Red Hat Developer Hub before running the application.

Tip

On Red Hat OpenShift Container Platform, you can skip this step to run Developer Hub with the default config map and secret. Your changes on this configuration might get reverted on Developer Hub restart.

Prerequisites

  • By using the OpenShift CLI (oc), you have access, with developer permissions, to the OpenShift cluster aimed at containing your Developer Hub instance.

Procedure

  1. For security, store your secrets as environment variables values in an OpenShift Container Platform secret, rather than in plain text in your configuration files. Collect all your secrets in the secrets.txt file, with one secret per line in KEY=value form.

    Enter your authentication secrets.

  2. Author your custom app-config.yaml file. This is the main Developer Hub configuration file. You need a custom app-config.yaml file to avoid the Developer Hub installer to revert user edits during upgrades. When your custom app-config.yaml file is empty, Developer Hub is using default values.

    • To prepare a deployment with the Red Hat Developer Hub Operator on OpenShift Container Platform, you can start with an empty file.
    • To prepare a deployment with the Red Hat Developer Hub Helm chart, or on Kubernetes, enter the Developer Hub base URL in the relevant fields in your app-config.yaml file to ensure proper functionality of Developer Hub. The base URL is what a Developer Hub user sees in their browser when accessing Developer Hub. The relevant fields are baseUrl in the app and backend sections, and origin in the backend.cors subsection:

      Configuring the baseUrl in app-config.yaml:

      app:
        title: Red Hat Developer Hub
        baseUrl: https://<my_developer_hub_domain>
      
      backend:
        auth:
          externalAccess:
            - type: legacy
              options:
                subject: legacy-default-config
                secret: "${BACKEND_SECRET}"
        baseUrl: https://<my_developer_hub_domain>
        cors:
          origin: https://<my_developer_hub_domain>
    • Optionally, enter your configuration such as:

  3. Author your custom dynamic-plugins.yaml file to enable plugins. By default, Developer Hub enables a minimal plugin set, and disables plugins that require configuration or secrets, such as the GitHub repository discovery plugin and the Role-based access control (RBAC) plugin.

    Enable the GitHub repository discovery and the RBAC features:

    dynamic.plugins.yaml

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github
        disabled: false
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

  4. Provision your custom configuration files to your OpenShift Container Platform cluster.

    1. Create the <my-rhdh-project> project aimed at containing your Developer Hub instance.

      $ oc create namespace my-rhdh-project
    2. Create config maps for your app-config.yaml and dynamic-plugins.yaml files in the <my-rhdh-project> project.

      $ oc create configmap my-rhdh-app-config --from-file=app-config.yaml --namespace=my-rhdh-project
      $ oc create configmap dynamic-plugins-rhdh --from-file=dynamic-plugins.yaml --namespace=my-rhdh-project

      You can also create the config maps by using the web console.

    3. Provision your secrets.txt file to the my-rhdh-secrets secret in the <my-rhdh-project> project.

      $ oc create secret generic my-rhdh-secrets --from-file=secrets.txt --namespace=my-rhdh-project

      You can also create the secret by using the web console.

9.2.3.3. Deploy a custom configuration using an Operator

Use the Red Hat Developer Hub Operator to deploy Developer Hub with custom configuration by creating a custom resource that mounts config maps and injects secrets.

Prerequisites

  • By using the OpenShift CLI (oc), you have access, with developer permissions, to the OpenShift Container Platform cluster aimed at containing your Developer Hub instance.
  • Your administrator has installed the Red Hat Developer Hub Operator in the cluster.
  • You have provisioned your custom config maps and secrets in your <my-rhdh-project> project.
  • You have a working default storage class, such as the Elastic Block Store (EBS) storage add-on, configured in your EKS cluster.

Procedure

  1. Author your Backstage CR in a my-rhdh-custom-resource.yaml file to use your custom config maps and secrets.

    Minimal my-rhdh-custom-resource.yaml custom resource example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh-custom-resource
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
        extraFiles:
          mountPath: /opt/app-root/src
        route:
          enabled: true
      database:
        enableLocalDb: true

    my-rhdh-custom-resource.yaml custom resource example with dynamic plugins and RBAC policies config maps, and external PostgreSQL database secrets:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <my-rhdh-custom-resource>
    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
        route:
          enabled: true
      database:
        enableLocalDb: false
    Mandatory fields
    No fields are mandatory. You can create an empty Backstage CR and run Developer Hub with the default configuration.
    Optional fields
    spec.application.appConfig.configMaps
    Enter your config map name list.

    Mount files in the my-rhdh-app-config config map:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config

    Mount files in the my-rhdh-app-config and rbac-policies config maps:

    spec:
      application:
        appConfig:
          mountPath: /opt/app-root/src
          configMaps:
             - name: my-rhdh-app-config
             - name: rbac-policies
    spec.application.extraEnvs.envs

    Optionally, enter your additional environment variables that are not secrets, such as your proxy environment variables.

    Inject your HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables:

    spec:
      application:
        extraEnvs:
          envs:
            - name: HTTP_PROXY
              value: 'http://10.10.10.105:3128'
            - name: HTTPS_PROXY
              value: 'http://10.10.10.106:3128'
            - name: NO_PROXY
              value: 'localhost,example.org'
    spec.application.extraEnvs.secrets

    Enter your environment variables secret name list.

    Inject the environment variables in your Red Hat Developer Hub secret:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>

    Inject the environment variables in the Red Hat Developer Hub and my-rhdh-database-secrets secrets:

    spec:
      application:
        extraEnvs:
          secrets:
             - name: <my_product_secrets>
             - name: my-rhdh-database-secrets
    Note

    <my_product_secrets> is your preferred Developer Hub secret name, specifying the identifier for your secret configuration within Developer Hub.

    spec.application.extraFiles.secrets

    Enter your certificates files secret name and files list.

    Mount the postgres-crt.pem, postgres-ca.pem, and postgres-key.key files contained in the my-rhdh-database-certificates-secrets secret:

    spec:
      application:
        extraFiles:
          mountPath: /opt/app-root/src
          secrets:
            - name: my-rhdh-database-certificates-secrets
              key: postgres-crt.pem, postgres-ca.pem, postgres-key.key
    spec.database.enableLocalDb

    Enable or disable the local PostgreSQL database.

    Disable the local PostgreSQL database generation to use an external postgreSQL database:

    spec:
      database:
        enableLocalDb: false

    On a development environment, use the local PostgreSQL database:

    spec:
      database:
        enableLocalDb: true
    spec.deployment
    Optionally, enter your deployment configuration.
  2. Apply your Backstage CR to start or update your Developer Hub instance:

    $ oc apply --filename=my-rhdh-custom-resource.yaml --namespace=my-rhdh-project

9.2.3.4. Deploy a custom configuration using Helm Chart

Use the Red Hat Developer Hub Helm chart to deploy Developer Hub with a custom application configuration file on OpenShift Container Platform.

Prerequisites

Procedure

  1. Configure Helm to use your custom configuration files in Developer Hub.

    1. Go to the Helm tab to see the list of Helm releases.
    2. Click the overflow menu on the Helm release that you want to use and select Upgrade.
    3. Use the YAML view to edit the Helm configuration.
    4. Set the value of the upstream.backstage.extraAppConfig.configMapRef and upstream.backstage.extraAppConfig.filename parameters as follows:

      upstream:
        backstage:
          extraAppConfig:
            - configMapRef: my-rhdh-app-config
              filename: app-config.yaml
    5. Click Upgrade.

Next steps

  • Install Developer Hub by using Helm.

9.2.4. Customize your Red Hat Developer Hub base URL

Change the default Red Hat Developer Hub base URL to match your organization’s DNS configuration.

Prerequisites

  • You know your required Developer Hub external URL: https://<my_developer_hub_domain>, and have configured DNS to point to your Red Hat OpenShift Container Platform cluster.
  • Custom Developer Hub configuration.

Procedure

  • In your custom app-config.yaml file, enter your Developer Hub external URL, such as https://<my_developer_hub_domain>.

    app-config.yaml excerpt

    app:
      baseUrl: https://<my_developer_hub_domain>
    backend:
      baseUrl: https://<my_developer_hub_domain>
      cors:
        origin: https://<my_developer_hub_domain>

9.2.5. Configure backend secrets to secure service-to-service communication

Developer Hub uses Kubernetes secrets to store sensitive values such as authentication credentials, backend secrets, and database passwords. The app-config.yaml file references these values through ${VAR_NAME} environment variable substitution.

The following are common secrets used by Developer Hub:

my-rhdh-secrets
The main Developer Hub secrets containing authentication provider client IDs and secrets, the BACKEND_SECRET, and other sensitive credentials.
my-rhdh-database-certificates-secrets
Optional. Contains external PostgreSQL TLS certificates such as postgres-crt.pem, postgres-ca.pem, and postgres-key.key.

To create secrets, author the secret values in a local file (for example, my-rhdh-secrets.txt), then create a Kubernetes secret by running oc create secret generic.

You can provision secrets using either of the following methods:

  • With the Operator: Reference secrets in the Backstage custom resource by using the spec.application.extraEnvs.secrets field to inject secrets as environment variables, or the spec.application.extraFiles.secrets field to mount secrets as files, such as, TLS certificates.
  • With the Helm chart: Reference secrets by using the upstream.backstage.extraEnvVarsSecrets or upstream.backstage.extraEnvVars field with a secretKeyRef. You can also mount secrets as files by using both the upstream.backstage.extraVolumes and upstream.backstage.extraVolumeMounts values.

9.2.6. Customize Red Hat Developer Hub backend secret

The default Red Hat Developer Hub configuration defines the Developer Hub backend secret for service to service authentication.

You can define your custom Developer Hub backend secret.

Procedure

  1. To define the Developer Hub backend secret, add to your custom <my_product_secrets>.txt file the BACKEND_SECRET environment variable with a base64 encoded string. Use a unique value for each Developer Hub instance.

    $ echo > <my_product_secrets>.txt "BACKEND_SECRET=$(node -p 'require("crypto").randomBytes(24).toString("base64")')"

    <my_product_secrets>.txt example

    BACKEND_SECRET=3E2/rIPuZNFCtYHoxVP8wjriffnN1q/z

  2. Add your backend secret to your custom app-config.yaml file.

    app-config.yaml excerpt defining the backend secret

    backend:
      auth:
        externalAccess:
          - type: legacy
            options:
              subject: legacy-default-config
              secret: "${BACKEND_SECRET}"

9.2.7. Inject extra files and variables to secure external service connections

Inject extra files and environment variables into Backstage containers by mounting ConfigMaps and Secrets by using the mountPath field.

  • If you do not specify key and mountPath: The system mounts each key or value as a filename or content with a subPath.
  • If you specify key with or without mountPath: The system mounts the specified key or value with a subPath.
  • If you specify only mountPath: The system mounts a directory containing all the keys or values without a subPath.
  • If you do not specify the containers field: The volume mounts only to the backstage-backend container. By default, files mount only to the backstage-backend container. You can also specify other targets, including a list of containers by name (such as dynamic-plugin-install or selectcustom sidecars) or select all containers in the Backstage Pod.

    Note
    • OpenShift Container Platform does not automatically update a volume mounted with subPath. By default, the RHDH Operator monitors these ConfigMaps or Secrets and refreshes the RHDH Pod when changes occur.
    • For security purposes, Red Hat Developer Hub does not give the Operator Service Account read access to Secrets. As a result, mounting files from Secrets without specifying both mountPath and key is not supported.

Procedure

  1. Apply the configuration to your Backstage custom resource (CR). The following code block is an example:

    spec:
      application:
        extraFiles:
          mountPath: _<default_mount_path>_
          configMaps:
            - name: _<configmap_name_all_entries>_
            - name: _<configmap_name_single_key>_
              key: _<specific_file_key>_
              containers:
                - "*"
            - name: _<configmap_name_custom_path>_
              mountPath: _<custom_cm_mount_path>_
              containers:
                - backstage-backend
                - install-dynamic-plugins
          secrets:
            - name: _<secret_name_single_key>_
              key: _<specific_secret_key>_
              containers:
                - install-dynamic-plugins
            - name: _<secret_name_custom_path>_
              mountPath: _<custom_secret_mount_path>_
          pvcs:
            - name: _<pvc_name_default_path>_
            - name: _<pvc_name_custom_path>_
              mountPath: _<custom_pvc_mount_path>_
        extraEnvs:
          configMaps:
            - name: _<configmap_name_env_var>_
              key: _<env_var_key>_
              containers:
                - "*"
          secrets:
            - name: _<secret_name_all_envs>_
          envs:
            - name: _<static_env_var_name>_
              value: "_<static_env_var_value>_"
              containers:
               - install-dynamic-plugins

    where:

    spec.application.extraFiles.mountPath
    Specifies the default base mount path for files if you do not set a specific mountPath for a resource (for example, /<default_mount_path>).
    spec.application.extraFiles.configMaps.name
    Mounts all entries from <configmap_name_all_entries> to the default mount path.
    spec.application.extraFiles.configMaps.key
    Mounts **only the specified key (for example, <specific_file_key>.txt) from the ConfigMap.
    spec.application.extraFiles.configMaps.containers
    Targets all containers ("*") for mounting.
    spec.application.extraFiles.configMaps.mountPath
    Overrides the default and mounts all ConfigMap entries as a directory at the specified path (for example, /<custom_cm_mount_path>).
    spec.application.extraFiles.secrets.key
    Mounts only a specific key from the Secret.
    spec.application.extraFiles.secrets.mountPath
    Overrides the default and mounts all Secret entries as a directory at the specified path (for example, /<custom_secret_mount_path>).
    spec.application.extraFiles.pvcs.name
    Mounts the PVC to the default mount path, appending the PVC name (for example, /<default_mount_path>/<pvc_name_default_path>).
    spec.application.extraFiles.pvcs.mountPath
    Overrides the default and mounts the PVC to the specified path (for example, /<custom_pvc_mount_path>).
    spec.application.extraEnvs.configMaps.containers
    Injects the specified ConfigMap key as an environment variable into all containers ("*").
    spec.application.extraEnvs.secrets.name
    Injects all keys from the Secret as environment variables into the default container.
    spec.application.envs.containers

    Targets only the listed container for the static environment variable injection.

    Note

    The following explicit options are supported:

    1. No or an empty field: Mounts only to the backstage-backend container.
    2. * (asterisk) as the first and only array element: Mounts to all containers.
    3. Explicit container names, for example, install-dynamic-plugins: Mounts only to the listed containers.

Verification

Verify the files mount with the following correct paths and container targets:

ResourceTarget typePath(s) or name(s)Container(s)

ConfigMap (<configmap_name_all_entries>)

File

/<default_mount_path>/<file_1_key>, /<default_mount_path>/<file_2_key>

backstage-backend

ConfigMap (<configmap_name_single_key>)

File

/<default_mount_path>/<specific_file_key>.txt

All

ConfigMap (<configmap_name_custom_path>)

Directory

/<custom_cm_mount_path>/

backstage-backend, install-dynamic-plugins

Secret (<secret_name_single_key>)

File

/<default_mount_path>/<specific_secret_key>.txt

install-dynamic-plugins

Secret (<secret_name_custom_path>)

Directory

/<custom_secret_mount_path>/

backstage-backend

PVC (<pvc_name_default_path>)

Directory

/<default_mount_path>/<pvc_name_default_path>

backstage-backend

ConfigMap (<configmap_name_env_var>)

Environment variable

<env_var_key>

All

Secret (<secret_name_all_envs>)

Environment variable

<secret_key_a>, <secret_key_b>

backstage-backend

Custom Resource Definition (CRD) (envs)

Environment variable

<static_env_var_name> = <static_env_var_value>

install-dynamic-plugins

9.2.8. Configure mount paths to safely attach default secrets and storage

Configure custom mount paths for Secrets and PVCs by adding the rhdh.redhat.com/mount-path annotation to your resource.

Procedure

  1. To specify a PVC mount path, add the rhdh.redhat.com/mount-path annotation to your configuration file as shown in the following example:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: <my_claim>
      annotations:
        rhdh.redhat.com/mount-path: /mount/path/from/annotation

    Where:

    <my_claim>
    The PVC to mount.
    rhdh.redhat.com/mount-path
    The mount path for the PVC, in this case the /mount/path/from/annotation directory.
  2. To specify a Secret mount path, add the rhdh.redhat.com/mount-path annotation to your configuration file as shown in the following example:

    apiVersion: v1
    kind: Secret
    metadata:
      name: <my_secret>
      annotations:
        rhdh.redhat.com/mount-path: /mount/path/from/annotation

9.2.9. Mount secrets to specific containers to isolate sensitive data

Mount secrets and PVCs to specific containers by adding the rhdh.redhat.com/containers annotation to your configuration file.

Procedure

  1. To mount Secrets to all containers, set the rhdh.redhat.com/containers annotation to * in your configuration file:

    apiVersion: v1
    kind: Secret
    metadata:
      name: <my_secret>
      annotations:
        rhdh.redhat.com/containers: *
    Important

    Set rhdh.redhat.com/containers to * to mount it to all containers in the deployment.

  2. To mount to specific containers, separate the names with commas:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: <my_claim>
      annotations:
        rhdh.redhat.com/containers: "init-dynamic-plugins,backstage-backend"
    Note

    This configuration mounts the <my_claim> PVC to the init-dynamic-plugins and backstage-backend containers.

9.2.10. Patch deployment resources to customize Operator pod specifications

Configure Red Hat Developer Hub deployment by using the spec.deployment.patch field in the Red Hat Developer Hub Operator custom resource to control the Deployment resource.

Create a Backstage CR with the following fields:

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  deployment:
    patch:
      spec:
        template:
labels

Add labels to the Developer Hub pod.

For example, to add the label my=true:

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  deployment:
    patch:
      spec:
        template:
          metadata:
            labels:
              my: true
volumes

Add an additional volume named my-volume and mount it under /my/path in the Developer Hub application container.

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  deployment:
    patch:
      spec:
        template:
          spec:
            containers:
              - name: backstage-backend
                volumeMounts:
                  - mountPath: /my/path
                    name: my-volume
            volumes:
              - ephemeral:
                  volumeClaimTemplate:
                    spec:
                      storageClassName: "special"
                name: my-volume

Replace the default dynamic-plugins-root volume with a persistent volume claim (PVC) named dynamic-plugins-root. Note the $patch: replace directive, otherwise the system adds a new volume.

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  deployment:
    patch:
      spec:
        template:
          spec:
            volumes:
              - $patch: replace
                name: dynamic-plugins-root
                persistentVolumeClaim:
                  claimName: dynamic-plugins-root
cpu request

Set the CPU request for the Developer Hub application container to 250m.

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  deployment:
    patch:
      spec:
        template:
          spec:
            containers:
              - name: backstage-backend
                resources:
                  requests:
                    cpu: 250m
my-sidecar container

Add a new my-sidecar sidecar container into the Developer Hub Pod.

apiVersion: rhdh.redhat.com/v1alpha5
kind: Backstage
metadata:
  name: developer-hub
spec:
  deployment:
    patch:
      spec:
        template:
          spec:
            containers:
              - name: my-sidecar
                image: quay.io/my-org/my-sidecar:latest

Additional resources

9.2.11. Configure TLS connections to encrypt external platform traffic

Configure RHDH with a TLS connection in Kubernetes to ensure secure connections with third-party applications and external databases.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

Prerequisites

  • You have set up an Azure Red Hat OpenShift (ARO) cluster with a public CA-signed certificate. For more information about obtaining CA certificates, refer to your vendor documentation.
  • You have created a namespace and setup a service account with proper read permissions on resources.

    For example, you can use the following Kubernetes manifest for role-based access control:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: backstage-read-only
    rules:
      - apiGroups:
          - '*'
        resources:
          - pods
          - configmaps
          - services
          - deployments
          - replicasets
          - horizontalpodautoscalers
          - ingresses
          - statefulsets
          - limitranges
          - resourcequotas
          - daemonsets
        verbs:
          - get
          - list
          - watch
    #...
  • You have obtained the secret and the service CA certificate associated with your service account.
  • You have created some resources and added annotations to them so the Kubernetes plugin can discover them. You can apply these Kubernetes annotations:

    • backstage.io/kubernetes-id to label components
    • backstage.io/kubernetes-namespace to label namespaces

Procedure

  1. Enable the Kubernetes plugins in the dynamic-plugins-rhdh.yaml file by setting disabled to false:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic
            disabled: false
          - package: ./dynamic-plugins/dist/backstage-plugin-kubernetes
            disabled: false
            # ...
    Note

    The backstage-plugin-kubernetes plugin is currently in Technology Preview. As an alternative, you can use the ./dynamic-plugins/dist/backstage-plugin-topology-dynamic plugin, which is Generally Available (GA).

  2. Set the Kubernetes cluster details and configure the catalog sync options in the app-config.yaml configuration file:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: my-rhdh-app-config
    data:
      "app-config.yaml": |
      # ...
      catalog:
        rules:
          - allow: [Component, System, API, Resource, Location]
        providers:
          kubernetes:
            openshift:
              cluster: openshift
              processor:
                namespaceOverride: default
                defaultOwner: guests
              schedule:
                frequency:
                  seconds: 30
                timeout:
                  seconds: 5
      kubernetes:
        serviceLocatorMethod:
          type: 'multiTenant'
        clusterLocatorMethods:
          - type: 'config'
            clusters:
              - url: <target_cluster_api_server_url>
                name: openshift
                authProvider: 'serviceAccount'
                skipTLSVerify: false
                skipMetricsLookup: true
                dashboardUrl: <target_cluster_console_url>
                dashboardApp: openshift
                serviceAccountToken: ${K8S_SERVICE_ACCOUNT_TOKEN}
                caData: ${K8S_CONFIG_CA_DATA}
                # ...
    url
    The base URL to the Kubernetes control plane. You can run the kubectl cluster-info command to get the base URL.
    skipTLSVerify
    Set the value of this parameter to false to enable the verification of the TLS certificate.
    dashboardUrl
    (Optional) The link to the Kubernetes dashboard managing the ARO cluster.
    serviceAccountToken
    (Optional) Pass the service account token by using a K8S_SERVICE_ACCOUNT_TOKEN environment variable that you define in your <my_product_secrets> secret.
    caData
    Pass the CA data by using a K8S_CONFIG_CA_DATA environment variable that you define in your <my_product_secrets> secret.
  3. Save the configuration changes.

Verification

  1. Run the RHDH application to import your catalog:

    $ kubectl -n rhdh-operator get pods -w
  2. Verify that the pod log shows no errors for your configuration.
  3. Go to Catalog and check the component page in the Developer Hub instance to verify the cluster connection and the presence of your created resources.
Note

If you meet connection errors, such as certificate issues or permissions, check the message box in the component page or view the logs of the pod.

9.2.12. Configure the base URL to route frontend and backend traffic

To secure application traffic with your own certificate, configure the Developer Hub route to use a TLS certificate stored in a Kubernetes secret.

Important

On Red Hat OpenShift Container Platform 4.18 and earlier, securing a route with an external certificate is a Technology Preview feature that requires enabling the RouteExternalCertificate Feature Gate. On Red Hat OpenShift Container Platform 4.19 and later, this feature is Generally Available and does not require a Feature Gate.

For more information, see Securing routes with external certificates in TLS secrets.

Prerequisites

  • An OpenShift Container Platform administrator has installed the Red Hat Developer Hub Operator.
  • You have a TLS certificate stored in a Kubernetes secret of type kubernetes.io/tls in the same namespace as your Developer Hub instance, and the certificate is valid for the route host configured in your Backstage custom resource, for example my-rhdh.apps.example.com.

Procedure

  1. Add the spec.application.route.tls.externalCertificateSecretName field to your Backstage custom resource, referencing the name of the secret that contains your TLS certificate:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh
    spec:
      application:
        route:
          enabled: true
          host: my-rhdh.apps.example.com
          tls:
            externalCertificateSecretName: my-rhdh-tls-cert
  2. Apply the updated custom resource:

    $ oc apply -f my-rhdh.yaml

Verification

  • Verify that the route uses your external certificate:

    $ oc get route backstage-$cr_name -o jsonpath='{.spec.tls}' | jq .

9.2.13. Configure HTTP server timeouts

Adjust HTTP server timeouts to prevent connection drops behind load balancers or when handling long-running API requests.

If your Red Hat Developer Hub (RHDH) instance is deployed behind a load balancer or reverse proxy, you might need to adjust the backend HTTP server timeouts. For example, if the load balancer closes idle connections before the RHDH backend does, clients might experience unexpected disconnects. Similarly, long-running operations such as large catalog imports or slow upstream API calls might require longer request timeouts.

Procedure

  • In your app-config.yaml configuration file, add or update the backend.server section:

    backend:
      server:
        keepAliveTimeout:
          minutes: 1
        headersTimeout:
          minutes: 2
        requestTimeout:
          minutes: 1
        timeout:
          minutes: 5
        maxHeadersCount: 2000
        maxRequestsPerSocket: 100

    Where:

    keepAliveTimeout
    Maximum time an idle keep-alive connection stays open before the server closes it. Set this higher than your load balancer’s idle timeout to avoid premature disconnects.
    headersTimeout
    Maximum time allowed to receive the complete HTTP request headers. Must be greater than keepAliveTimeout.
    requestTimeout
    Maximum time allowed for the entire HTTP request, including headers and body.
    timeout
    Socket inactivity timeout. Maximum time a socket can remain idle before being closed.
    maxHeadersCount
    Maximum number of incoming HTTP headers allowed per request.
    maxRequestsPerSocket

    Maximum number of requests a socket can handle before the connection is closed.

    When these settings are not configured, the Node.js defaults apply. Timeout values support multiple formats, including human-readable strings, duration objects, and ISO 8601 duration strings. For more information, see Time syntax in Red Hat Developer Hub.

Verification

  • Verify that long-running requests or idle connections behave as expected with the new timeout values.

9.2.14. Configure the dynamic plugins cache

Configure the dynamic plugins cache by setting pull policy and download parameters in the dynamic-plugins.yaml file.

Procedure

  • To configure the dynamic plugins cache, set the following optional dynamic plugin cache parameters in your dynamic-plugins.yaml file:

    pullPolicy: IfNotPresent (default)
    Download the artifact if it is not already present in the dynamic-plugins-root folder, without checking image digests.
    pullPolicy: Always

    Compare the image digest in the remote registry and downloads the artifact if it has changed, even if Developer Hub has already downloaded the plugin before.

    When applied to the Node Package Manager (NPM) downloading method, download the remote artifact without a digest check.

    Example dynamic-plugins.yaml file configuration to download the remote artifact without a digest check:

    plugins:
      - disabled: false
        pullPolicy: Always
        package: 'oci://quay.io/example-org/example-plugin:v1.0.0'
    forceDownload: false (default)
    Older option to download the artifact if it is not already present in the dynamic-plugins-root folder, without checking image digests.
    forceDownload: true

    Older option to force a reinstall of the plugin, bypassing the cache.

    Note

    The pullPolicy option takes precedence over the forceDownload option.

    The forceDownload option might become deprecated in a future Developer Hub release.

9.2.15. Optimize Operator memory usage for large clusters

In large clusters, the Red Hat Developer Hub Operator can consume substantial memory because the cache loads metadata for all Secrets and ConfigMaps cluster-wide. You can enable cache-level label filtering to restrict caching to only relevant resources.

Important

Enabling cache label filtering is a breaking change. After activation, every Secret and ConfigMap that the Operator manages must carry the rhdh.redhat.com/external-config: "true" label. Any existing Developer Hub instances that reference unlabeled resources stop working until you add the required label to those resources.

Prerequisites

  • An OpenShift Container Platform administrator has installed the Red Hat Developer Hub Operator.
  • You have identified the secrets and config maps that your Developer Hub instances reference.

Procedure

  1. To enable cache-level label filtering, edit the Operator subscription and add the ENABLE_CACHE_LABEL_FILTER environment variable.

    spec:
      config:
        env:
          - name: "ENABLE_CACHE_LABEL_FILTER"
            value: "true"

    Alternatively, edit the ClusterServiceVersion (CSV) resource to add the --enable-cache-label-filter command-line flag to the manager container:

    spec:
      template:
        spec:
          containers:
          - name: manager
            args:
            - --enable-cache-label-filter
  2. Label every secret and config map that your Developer Hub instances reference. This includes all resources listed in your Backstage custom resource under spec.application.

    $ oc label secret <secret_name> rhdh.redhat.com/external-config=true -n <namespace>
    $ oc label configmap <configmap_name> rhdh.redhat.com/external-config=true -n <namespace>

    Alternatively, add the label directly in the resource YAML:

    metadata:
      name: <resource_name>
      labels:
        rhdh.redhat.com/external-config: "true"

Verification

  • Verify that the Operator pod restarts and that your Developer Hub instances are running after enabling cache label filtering:

    $ oc get pods -n rhdh-operator

9.2.16. Fix 404 error after cached dynamic plugins configuration change

When many Developer Hub replicas share a single dynamic plugins cache PVC, updating configurations with the Operator can trigger temporary 404 errors. This occurs because the replicas might access inconsistent cache states during the update process, before all replicas have synchronized.

The solution is to use an individual cache per pod.

Prerequisites

  • Your API version is v1alpha5 or later.

Procedure

  1. In the Backstage Custom Resource (CR) file, set spec.deployment to use the optional StatefulSet as a resource kind. For example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <CR_name>
    ...
    spec:
     deployment:
      kind: StatefulSet
      patch:
       spec:
         replicas: 2
         template:
           spec:
             volumes:
               - $patch: replace
                 name: dynamic-plugins-root
                 persistentVolumeClaim:
                   claimName: dynamic-plugins-root
         volumeClaimTemplates:
           - apiVersion: v1
             kind: PersistentVolumeClaim
             metadata:
               name: dynamic-plugins-root
             spec:
               accessModes:
                 - ReadWriteOnce
               resources:
                 requests:
                   storage: 1Gi
    Note

    Using StatefulSet with a single replica can lead to downtime, while the application deletes the old pod and creates a new pod.

  2. Wait a few minutes until the Operator reconciles the CR and the StatefulSet resource is ready.
  3. If you are updating an existing CR, remove the earlier Deployment resource from the cluster:

    oc delete deployment -l app.kubernetes.io/instance=<CR_name>
    Note

    The same requirement applies for changing the resource kind from StatefulSet to Deployment. You must manually delete the resource created before from the cluster, because the Operator does not automatically remove the legacy resource.

9.2.17. Configure corporate proxy settings to enable external network access

9.2.17.1. Configure corporate proxy settings to enable external network access

In a network restricted environment, configure Red Hat Developer Hub to use your proxy to access remote network resources.

You can run the Developer Hub application behind a corporate proxy by setting any of the following environment variables before starting the application:

HTTP_PROXY
Denotes the proxy to use for HTTP requests.
HTTPS_PROXY
Denotes the proxy to use for HTTPS requests.
NO_PROXY
Set the environment variable to bypass the proxy for certain domains. The variable value is a comma-separated list of hostnames or IP addresses that do not require the proxy, even if you specify one.

9.2.17.2. The NO_PROXY exclusion rules

Configure NO_PROXY to bypass the proxy for specific hostnames, IP addresses, and port numbers when using Developer Hub.

Note

The default value for NO_PROXY in RHDH is localhost,127.0.0.1. If you want to override it, include at least localhost or localhost:7007 in the list. Otherwise, the RHDH backend might fail.

Matching follows these rules:

  • NO_PROXY=* will bypass the proxy for all requests.
  • Space and commas might separate the entries in the NO_PROXY list. For example, NO_PROXY="localhost,example.com", or NO_PROXY="localhost example.com", or NO_PROXY="localhost, example.com" would have the same effect.
  • If NO_PROXY has no entries, configuring the HTTP(S)_PROXY settings makes the backend send all requests through the proxy.
  • The backend does not perform a DNS lookup to decide if a request should bypass the proxy or not. For example, if DNS resolves example.com to 1.2.3.4, setting NO_PROXY=1.2.3.4 has no effect on requests sent to example.com. Only requests sent to the IP address 1.2.3.4 bypass the proxy.
  • If you add a port after the hostname or IP address, the request must match both the host/IP and port to bypass the proxy. For example, NO_PROXY=example.com:1234 would bypass the proxy for requests to http(s)://example.com:1234, but not for requests on other ports, such as http(s)://example.com.
  • If you do not specify a port after the hostname or IP address, all requests to that host/IP address will bypass the proxy regardless of the port. For example, NO_PROXY=localhost would bypass the proxy for requests sent to URLs such as http(s)://localhost:7077 and http(s)://localhost:8888.
  • IP Address blocks in CIDR notation will not work. So setting NO_PROXY=10.11.0.0/16 will not have any effect, even if the backend sends a request to an IP address in that block.
  • Supports only IPv4 addresses. IPv6 addresses such as ::1 will not work.
  • Generally, the proxy is only bypassed if the hostname is an exact match for an entry in the NO_PROXY list. The only exceptions are entries that start with a dot (.) or with a wildcard (*). In such a case, bypass the proxy if the hostname ends with the entry.
Note

List the domain and the wildcard domain if you want to exclude a given domain and all its subdomains. For example, you would set NO_PROXY=example.com,.example.com to bypass the proxy for requests sent to http(s)://example.com and http(s)://subdomain.example.com.

9.2.17.3. Configure proxy settings in Operator deployment

Configure proxy settings for Operator-based deployments by setting environment variables in the ConfigMap or custom resource file.

  • As a cluster administrator with access to the Operator namespace, you can configure the proxy variables in the Operator’s default ConfigMap file. This configuration applies the proxy settings to all the users of the Operator.
  • As a developer, you can configure the proxy variables in a custom resource (CR) file. This configuration applies the proxy settings to the RHDH application created from that CR.

Prerequisites

  • You have installed the Red Hat Developer Hub application.

Procedure

  1. Perform one of the following steps based on your role:
  2. As an administrator, set the proxy information in the Operator’s default ConfigMap file:

    1. Search for a ConfigMap file named backstage-default-config in the default namespace rhdh-operator and open it.
    2. Find the deployment.yaml key.
    3. Set the value of the HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables in the Deployment spec as shown in the following example:

      # ...
        deployment.yaml: |-
          apiVersion: apps/v1
          kind: Deployment
          spec:
            template:
              spec:
                # ...
                initContainers:
                  - name: install-dynamic-plugins
                    # ...
                    env:
                      - name: NPM_CONFIG_USERCONFIG
                        value: /opt/app-root/src/.npmrc.dynamic-plugins
                      - name: HTTP_PROXY
                        value: 'http://10.10.10.105:3128'
                      - name: HTTPS_PROXY
                        value: 'http://10.10.10.106:3128'
                      - name: NO_PROXY
                        value: 'localhost,example.org'
                    # ...
                containers:
                  - name: backstage-backend
                    # ...
                    env:
                      - name: APP_CONFIG_backend_listen_port
                        value: "7007"
                      - name: HTTP_PROXY
                        value: 'http://10.10.10.105:3128'
                      - name: HTTPS_PROXY
                        value: 'http://10.10.10.106:3128'
                      - name: NO_PROXY
                        value: 'localhost,example.org'
  3. As a developer, set the proxy information in your Backstage CR file as shown in the following example:

    spec:
      # ...
      application:
        extraEnvs:
          envs:
            - name: HTTP_PROXY
              value: 'http://10.10.10.105:3128'
            - name: HTTPS_PROXY
              value: 'http://10.10.10.106:3128'
            - name: NO_PROXY
              value: 'localhost,example.org'
  4. Save the configuration changes.

9.2.17.4. Configure proxy settings in Helm deployment

Configure proxy settings for Helm-based deployments by setting environment variables in the Helm configuration file.

Prerequisites

  • You have installed the Red Hat Developer Hub application.

Procedure

  1. Set the proxy information in your Helm configuration file:

    upstream:
      backstage:
        extraEnvVars:
          - name: HTTP_PROXY
            value: '<http_proxy_url>'
          - name: HTTPS_PROXY
            value: '<https_proxy_url>'
          - name: NO_PROXY
            value: '<no_proxy_settings>'

    Where,

    <http_proxy_url>
    Denotes a variable that you must replace with the HTTP proxy URL.
    <https_proxy_url>
    Denotes a variable that you must replace with the HTTPS proxy URL.
    <no_proxy_settings>

    Denotes a variable that you must replace with comma-separated URLs, which you want to exclude from proxying, for example, <example1>.com,<example2>.com.

    For example:

    upstream:
      backstage:
        extraEnvVars:
          - name: HTTP_PROXY
            value: 'http://10.10.10.105:3128'
          - name: HTTPS_PROXY
            value: 'http://10.10.10.106:3128'
          - name: NO_PROXY
            value: 'localhost,example.org'
  2. Save the configuration changes.

9.3. Customize the user interface to reflect organizational branding

9.3.1. Customize the user interface to reflect organizational branding

Customize the Developer Hub user interface by configuring themes and branding, the global header, floating action buttons, quick starts, tech radar, learning paths, sidebar navigation, home page layout, and quick access cards.

9.3.2. Customize your Red Hat Developer Hub title

You can change the default Red Hat Developer Hub display name.

Procedure

  • In your custom app-config.yaml file, enter your Developer Hub instance display name, such as <Red Hat Developer Hub>.

    app-config.yaml excerpt

    app:
      title: My custom Red Hat Developer Hub title

9.3.3. Customize Learning Paths to integrate tailored e-learning content

9.3.3.1. Customize Learning Paths to integrate tailored e-learning content

In Red Hat Developer Hub, you can configure Learning Paths by hosting the required data externally and by using the built-in proxy to deliver this data. You can provide Learning Paths data from a JSON file hosted on a web server or from a dedicated service that provides the data in JSON format by using an API.

9.3.3.2. Structured learning paths for developers onboarding

The Learning Paths plugin in Red Hat Developer Hub integrates customized e-learning content into developer workflows to accelerate onboarding, address skill gaps, and ensure that teams stay updated with best practices.

9.3.3.3. Customize by using a hosted JSON file

For ease of use and simplicity, you can configure the Learning Paths by using a hosted JSON file.

Procedure

  1. Publish the JSON file containing your Learning Paths data to a web server, such as GitHub or GitLab. You can find an example at https://raw.githubusercontent.com/redhat-developer/rhdh/release-1.10/packages/app/public/learning-paths/data.json.
  2. Configure the Developer Hub proxy to access the Learning Paths data from the hosted JSON file, by adding the following to the app-config.yaml file:

    proxy:
      endpoints:
        '/developer-hub':
          target: <target>
          pathRewrite:
            '^/api/proxy/developer-hub/learning-paths': '<learning_path.json>'
          changeOrigin: true
          secure: true
    <target>
    Enter the hosted JSON file base URL, such as https://raw.githubusercontent.com.
    <learning_path.json>

    Enter the hosted JSON file path without the base URL, such as '/redhat-developer/rhdh/main/packages/app/public/learning-paths/data.json'

    Tip

    When also configuring the home page, due to the use of overlapping pathRewrites for both the learning-path and homepage quick access proxies, create the learning-paths configuration (^api/proxy/developer-hub/learning-paths) before you create the homepage configuration (^/api/proxy/developer-hub). For example:

    proxy:
      endpoints:
        '/developer-hub':
          target: https://raw.githubusercontent.com/
          pathRewrite:
            '^/api/proxy/developer-hub/learning-paths': '/redhat-developer/rhdh/main/packages/app/public/learning-paths/data.json'
            '^/api/proxy/developer-hub': '/redhat-developer/rhdh/main/packages/app/public/homepage/data.json'
          changeOrigin: true
          secure: true

9.3.3.4. Customize by using a customization service

For advanced scenarios, you can host your Red Hat Developer Hub customization service to provide data to all configurable Developer Hub pages, such as the Learning Paths. You can even use a different service for each page.

Procedure

  1. Deploy your Developer Hub customization service on the same OpenShift Container Platform cluster as your Developer Hub instance. You can find an example at red-hat-developer-hub-customization-provider, that provides the same data as default Developer Hub data. The customization service provides a Learning Paths data URL such as: http://<rhdh-customization-provider>/learning-paths.
  2. Configure the Developer Hub proxy to use your dedicated service to provide the Learning Path data, add the following to the app-config.yaml file:

    proxy:
      endpoints:
        '/developer-hub/learning-paths':
          target: <learning_path_data_url>
          changeOrigin: true
          qsecure: true # Change to "false" in case of using self hosted cluster with a self-signed certificate

9.3.3.5. Start and complete lessons

As a developer, you can start a course and complete the lessons at your own pace.

Prerequisites

  • You can log in to developers.redhat.com
  • If RBAC is enabled, you have a role with the following permission: catalog.entity.read.

Procedure

  1. In your Red Hat Developer Hub navigation menu, click Learning Paths.
  2. Select the tile for the course you want to begin.

    Note

    This action redirects you to the main page of the course in the Red Hat Developers site.

9.3.4. Configure the global header for consistent top-level navigation

9.3.4.1. Configure the global header for consistent top-level navigation

As an administrator, you can configure the Red Hat Developer Hub global header to create a consistent and flexible navigation bar across your Developer Hub instance. By default, the Developer Hub global header includes the following components:

  • Self-service button provides quick access to a variety of templates, enabling users to efficiently set up services, backend and front-end plugins within Developer Hub
  • Support button that can link an internal or external support page
  • Notifications button displays alerts and updates from plugins and external services
  • Search input field allows users to find services, components, documentation, and other resources within Developer Hub
  • Plugin extension capabilities provide a preinstalled and enabled catalog of available plugins in Developer Hub
  • User profile drop-down menu provides access to profile settings, appearance customization, Developer Hub metadata, and a logout button

9.3.4.2. Customize your Red Hat Developer Hub global header

Extend the global header with additional buttons and customize the order and position of icons and features by using the red-hat-developer-hub.backstage-plugin-global-header dynamic plugin.

  - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-header
    disabled: false
    pluginConfig:
      app:
        sidebar:
          search: false
          settings: false
      dynamicPlugins:
        frontend:
          default.main-menu-items:
            menuItems:
              default.create:
                title: ''
          red-hat-developer-hub.backstage-plugin-global-header: # the default enabled dynamic header plugin
            mountPoints:
              - mountPoint: application/header
                importName: GlobalHeader
                config:
                  position: above-main-content 1
              - mountPoint: global.header/component
                importName: SearchComponent
                config:
                  priority: 100
              - mountPoint: global.header/component
                importName: Spacer
                config:
                  priority: 99
                  props:
                    growFactor: 0
              - mountPoint: global.header/component
                importName: HeaderIconButton
                config:
                  priority: 90
                  props:
                    title: Self-service
                    icon: add
                    to: create
              - mountPoint: global.header/component
                importName: SupportButton
                config:
                  priority: 80
              - mountPoint: global.header/component
                importName: NotificationButton
                config:
                  priority: 70
              - mountPoint: global.header/component
                importName: Divider
                config:
                  priority: 50
              - mountPoint: global.header/component
                importName: ProfileDropdown
                config:
                  priority: 10
              - mountPoint: global.header/profile
                importName: MenuItemLink
                config:
                  priority: 100
                  props:
                    title: Settings
                    link: /settings
                    icon: manageAccounts
              - mountPoint: global.header/profile
                importName: LogoutButton
                config:
                  priority: 10

where:

search
Enter false to hide the Search modal in the sidebar menu. Enter true to display the Search modal in the sidebar menu.
settings
Enter false to hides the Settings button in the sidebar menu. Enter true to display the Settings button in the sidebar menu.
default.main-menu-items
Enter this field to hide the Self-service button from the sidebar menu. Remove this field to display the Self-service button in the sidebar menu.
position
Enter above-main-content to position the header above the main content. Enter above-sidebar to position the header above the sidebar.

To extend the functionality of the default global header, include any of the following attributes in your global header entry:

mountPoint
Specifies the location of the header. Use application/header to specify it as a global header. You can configure several global headers at different positions by adding entries to the mountPoints field.
importName

Specifies the component exported by the global header plugin.

The red-hat-developer-hub.backstage-plugin-global-header package (enabled by default) offers the following header components as possible mount point values:

  • SearchComponent: Adds a search bar (enabled by default).
  • Spacer: Adds spacing in the header to position buttons at the end. Useful when you disable SearchComponent.
  • HeaderIconButton: Adds an icon button. By default, the Self-service icon button remains enabled.
  • SupportButton: Adds a Support icon button, allowing users to configure a link to an internal or external page. Enabled by default but requires additional configuration to display.
  • NotificationButton: Adds a Notifications icon button to display unread notifications in real time and navigate to the Notifications page. Enabled by default (requires the notifications plugin).
  • Divider: Adds a vertical divider. By default, a divider is displayed between the profile dropdown and other header components.
  • ProfileDropdown: Adds a profile dropdown showing the logged-in user’s name. By default, it contains two menu items.
  • MenuItemLink: Adds a link item in a dropdown menu. By default, the profile dropdown includes a link to the Settings page.
  • LogoutButton: Adds a logout button in the profile dropdown (enabled by default).
  • CreateDropdown: Adds a Self-service dropdown button (disabled by default). The menu items are configurable.
  • SoftwareTemplatesSection: Adds a list of software template links to the Self-service dropdown menu (disabled by default). You must enable CreateDropdown.
  • RegisterAComponentSection: Adds a link to the Register a Component page in the Self-service dropdown menu (disabled by default). You must enable CreateDropdown.
config.position
Specifies the position of the header. Supported values are above-main-content and above-sidebar.

Prerequisites

  • You must install the notifications plugin to display the Notifications button in the header.

Procedure

  1. Copy the default configuration and modify the field values to suit your needs. You can adjust the priority value of each header component to control its position. Additionally, you can enable or disable components by adding or removing them from the configuration. To ensure that the remaining header buttons align with the end of the header before the profile dropdown button, set config.props.growFactor to 1 in the Spacer mount point to enable the Spacer component. For example:

    - mountPoint: global.header/component
      importName: Spacer
      config:
        priority: 100
        props:
          growFactor: 1
  2. To use your custom header, you must install it as a dynamic plugin by adding your plugin configuration to your app-config-dynamic.yaml file. For example:

    - package: <npm_or_oci_package_reference>
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            <package_name>:
              mountPoints:
                - mountPoint: application/header
                  importName: <application_header_name>
                  config:
                    position: above-main-content
                - mountPoint: global.header/component
                  importName: <header_component_name>
                  config:
                    priority: 100
                - mountPoint: global.header/component
                  importName: <header_component_name>
                  config:
                    priority: 90

    where:

    <npm_or_oci_package_reference>
    Specifies the package name.
    <application_header_name>
    Specifies the name of the application header. For example: MyHeader
    <header_component_name>

    Specifies the name of the header component. For example: MyHeaderComponent

    Note

    importName is an optional name referencing the value returned by the scaffolder field extension API.

  3. Optional: To disable the global header, set the value of the disabled field to true in your dynamic-plugins.yaml file. For example:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-header
      disabled: true
  4. Optional: To display the Support button in the header, configure the app.support.url and app.support.items fields in your app-config.yaml file. For example:

    app:
      support:
        url: https://support.example.com
        items:
          - title: Support
            links:
              - url: https://support.example.com
                title: Open a support case

9.3.4.3. Mount points for dynamic plugin integration

You can customize the application header in Developer Hub using mount points for dynamic plugins. These mount points give flexibility in configuring the position of the header, its components, and dropdown menus.

application/header
Controls the header position. Use config.position to set placement as either above-main-content or above-sidebar.
global.header/component
Configures header components. Use config.priority to set the order of components, and pass properties (including CSS styles) via config.props.
Self-service button
- mountPoint: global.header/component
  importName: HeaderIconButton
  config:
    priority: 80
    props:
      title: Self-service
      icon: add
      to: create
Spacer element
- mountPoint: global.header/component
  importName: Spacer
  config:
    priority: 99
    props:
      growFactor: 0
Divider element
mountPoints:
  - mountPoint: global.header/component
    importName: Divider
    config:
      priority: 150
global.header/profile

Configures the profile dropdown list when the ProfileDropdown component is enabled.

  • To add a settings link to the profile dropdown, use the following code:

    - mountPoint: global.header/profile
      importName: MenuItemLink
      config:
        priority: 100
        props:
          title: Settings
          link: /settings
          icon: manageAccounts
global.header/create

Configures the create dropdown list when the CreateDropdown component is enabled.

  • To add a section for registering a component, use the following code:

    - mountPoint: global.header/create
      importName: RegisterAComponentSection
      config:
        props:
          growFactor: 0

9.3.4.4. Add custom branding logos

You can configure a company logo in the global header of the Red Hat Developer Hub (RHDH) to reflect your company’s branding. CompanyLogo is part of the global header by default and offers full control over the theming, navigation behavior, sizing, and fallback options.

When you define menu items or links in the global header, you must specify an icon identifier.

For the full list of available icon identifiers, see Common icons for customization.

This component supports the following props, which are provided through configuration:

  • logo: The base64 encoded logo image.
  • to: The redirect path for when users click the logo is '/catalog'.
  • width: The logo width is optional and defaults to 150px.
  • height: The logo height is optional and defaults to 40px.

Procedure

  1. To display a custom company logo in the global header, update the configuration with a mount point for CompanyLogo:

    # ...rest of the global header configuration
    red-hat-developer-hub.backstage-plugin-global-header:
      mountPoints:
        - mountPoint: application/header
          importName: GlobalHeader
          config:
            # Supported values: above-main-content | above-sidebar
            position: above-main-content
    
        - mountPoint: global.header/component
          importName: CompanyLogo
          config:
            priority: 200
            props:
              # Path to navigate when users click the logo:
              to: '/catalog'
              width: 300
              height: 200
              logo: <string> or <object> # Logo can be a base64 string or theme-specific object
                # Example 1: Single logo for all themes
                # logo: "<base64_encoded_images>"
    
                # Example 2: Theme-specific logos
                # logo:
                    dark: 'data:image/png;base64,...' # Used in dark theme
                    light: 'data:image/png;base64,...' # Used in light theme
  2. (Optional) If you do not provide logo props to the CompanyLogo component, the component instead uses values defined under app.branding in your app-config.yaml file. You can configure the CompanyLogo as shown in the following configuration:

    app:
      branding:
        fullLogoWidth: 220  # Fallback width
        fullLogo: <string> or <object> #fullLogo can be a base64 string or theme-specific object
    
        # Example 1: Single logo for all themes
        #fullLogo: "<base64_encoded_image>
        # Example 2: Theme-specific logos
        #fullLogo:
            dark: 'data:image/png;base64,...' # Used in dark theme
            light: 'data:image/png;base64,...' # Used in light theme

    CompanyLogo uses the following configuration elements to control fallback and sizing behavior:

    • Logo source priority

      • The component selects the logo source in the following order:

        First, CompanyLogo props (logo, logo.light, logo.dark), then, app.branding.fullLogo. If you do not provide a logo through either, the component displays the default Developer Hub theme-specific logo.

    • Logo width priority

      • The component applies the first available value from props.width, then app.branding.fullLogoWidth from app-config.yaml. If you do not specify the width using either, the component applies a default width (150px).

        Note

        CompanyLogo preserves the images aspect ratio and never crops or distorts it. If the configured width results in a height greater than the maximum allowed (default: 40px), the image is automatically scaled down. As a result, adjusting only the width might not visibly change the logo unless the height is also configured.

        Increasing the logo height increases the height of the global header. The component first applies the value from props.height. If you do not specify the height, the component applies a default height (40px).

Verification

  1. The logo is displayed correctly in the global header.
  2. Click the logo to confirm it redirects to the path you defined in props.to.
  3. Toggle between light and dark themes to ensure the correct logo loads in each.
  4. (Optional) Temporarily remove the CompanyLogo props to test the fallback to app.branding.fullLogo.

9.3.4.5. Enable logo in the sidebar

You can configure a logo in the sidebar of the Red Hat Developer Hub (RHDH).

Procedure

  1. To display the logo exclusively in the sidebar, set the value of the app.sidebar.logo parameter to true as shown in the following example:

    app:
      sidebar:
        logo: true
    Note

    To display the logo in only the sidebar, remove the CompanyLogo component from the configuration.

  2. To display the same logo in the sidebar for all themes, update the configuration as shown in the following configuration:

    app:
      sidebar:
        logo: true
      branding:
        fullLogoWidth: 220
        fullLogo: 'data:image/svg+xml;base64,...'
  3. For theme-specific logos, you can configure the sidebar logo as shown in the following configuration:

    app:
      sidebar:
        logo: true
      branding:
        fullLogoWidth: 220
        fullLogo:
          light: 'data:image/svg+xml;base64,...'
          dark: 'data:image/svg+xml;base64,...'

Verification

  1. The logo is displayed correctly in the sidebar.
  2. Toggle between light and dark themes to ensure the correct logo loads in each.

9.3.4.6. Configure display names

Display the preferred username in the global header profile drop-down list by configuring spec.profile.displayName in the user entity.

Procedure

  1. To configure spec.profile.displayName, use the following code:

    apiVersion: backstage.io/v1alpha1
    kind: User
    metadata:
      # Required unique username
      name: <my_display_name>
      # Optional preferred title
      title: <display_name_title>
    spec:
      profile:
        # Optional preferred display name (highest priority)
        displayName: <my_display_name>
      memberOf: [janus-authors]
  2. To configure metadata.title rather than spec.profile.displayname, use the following code:

    apiVersion: backstage.io/v1alpha1
    kind: User
    metadata:
      # Required unique username
      name: <my_display_name>
      # Optional preferred title
      title: <display_name_title>
    spec:
      memberOf: [janus-authors]
  3. To configure neither spec.profile.displayname or metadata.title, use the following code:

    apiVersion: backstage.io/v1alpha1
    kind: User
    metadata:
      # Required unique username
      name: <my_display_name>
    spec:
      memberOf: [janus-authors]
    Note

    The application falls back to metadata.name when you do not register the user entity.

9.3.5. Configure floating action buttons for quick access to workflows

9.3.5.1. Configure floating action buttons for quick access to workflows

Configure any action as a floating button in the Developer Hub instance by using the floating action button plugin.

Important

RHDH 1.10 disables the Global Floating Action Button plugin by default. For new deployments, use the Global Header plugin, which uses quick links and starred items to improve navigation.

Existing deployments that explicitly enable the Global Floating Action Button remain functional. However, as the plugin is deprecated, it will be removed in a future RHDH version, and you must eventually adjust your configuration.

9.3.5.1.1. Additional resources

9.3.5.2. Configure a floating action button as a dynamic plugin

You can configure the floating action button as a dynamic plugin to perform actions or open an internal or external link.

Procedure

  1. Specify the global.floatingactionbutton/config mount point in your app-config-dynamic.yaml file. For example:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-bulk-import:
              # Start of the floating action button configuration
              mountPoints:
                - mountPoint: global.floatingactionbutton/config
                  importName: BulkImportPage
                  config:
                    slot: 'page-end'
                    icon: <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#e8eaed"><g><rect fill="none" height="24" width="24"/></g><g><path d="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5-5L11,7z M20,19h-8v2h8c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-8v2h8V19z"/></g></svg>
                    label: 'Bulk import'
                    toolTip: 'Register multiple repositories in bulk'
                    to: /bulk-import/repositories
              # End of the floating action button configuration
              appIcons:
                - name: bulkImportIcon
                  importName: BulkImportIcon
              dynamicRoutes:
                - path: /bulk-import/repositories
                  importName: BulkImportPage
                  menuItem:
                    icon: bulkImportIcon
                    text: Bulk import
    frontend:mountPoints:importName
    (Required) The import name with an associated component to the mount point.
    frontend:mountPoints:importName:icon
    Use the svg value to display a black BulkImportPage icon.
  2. To configure an action as a floating action button that opens an external link, specify the global.floatingactionbutton/config mount point in your dynamic-plugins.yaml file within the backstage-plugin-global-floating-action-button plugin. For example:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-floating-action-button
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-global-floating-action-button:
              mountPoints:
                  - mountPoint: application/listener
                    importName: DynamicGlobalFloatingActionButton
                  - mountPoint: global.floatingactionbutton/config
                    importName: NullComponent
                    config:
                      icon: '<svg viewBox="0 0 250 300" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path d="M200.134 0l55.555 117.514-55.555 117.518h-47.295l55.555-117.518L152.84 0h47.295zM110.08 99.836l20.056-38.092-2.29-8.868L102.847 0H55.552l48.647 102.898 5.881-3.062zm17.766 74.433l-17.333-39.034-6.314-3.101-48.647 102.898h47.295l25-52.88v-7.883z" fill="#40B4E5"/><path d="M152.842 235.032L97.287 117.514 152.842 0h47.295l-55.555 117.514 55.555 117.518h-47.295zm-97.287 0L0 117.514 55.555 0h47.296L47.295 117.514l55.556 117.518H55.555z" fill="#003764"/></svg>'
                      label: 'Quay'
                      showLabel: true
                      toolTip: 'Quay'
                      to: 'https://quay.io'
                  - mountPoint: global.floatingactionbutton/config
                    importName: NullComponent
                    config:
                      icon: github
                      label: 'Git'
                      toolTip: 'Github'
                      to: https://github.com/redhat-developer/rhdh-plugins
    frontend:mountPoints:importName
    Enter the import name with an associated component to the mount point.
    frontend:mountPoints:importName:icon
    (Optional) Enter the icon in Scalable Vector Graphics (SVG) format to display the Quay icon.
  3. To configure a floating action button that contains a submenu, define the global.floatingactionbutton/config mount point in the same slot field in your dynamic-plugins.yaml file for multiple actions. The default slot is page-end when not specified. For example:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-bulk-import:
              # Start of fab config
              mountPoints:
                - mountPoint: global.floatingactionbutton/config
                  importName: BulkImportPage
                  config:
                    slot: 'page-end'
                    icon: <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#e8eaed"><g><rect fill="none" height="24" width="24"/></g><g><path d="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5-5L11,7z M20,19h-8v2h8c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-8v2h8V19z"/></g></svg>
                    label: 'Bulk import'
                    toolTip: 'Register multiple repositories in bulk'
                    to: /bulk-import/repositories
              # end of fab config
              appIcons:
                - name: bulkImportIcon
                  importName: BulkImportIcon
              dynamicRoutes:
                - path: /bulk-import/repositories
                  importName: BulkImportPage
                  menuItem:
                    icon: bulkImportIcon
                    text: Bulk import
    
    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-floating-action-button
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-global-floating-action-button:
              mountPoints:
                - mountPoint: application/listener
                  importName: DynamicGlobalFloatingActionButton
                - mountPoint: global.floatingactionbutton/config
                  importName: NullComponent
                  config:
                    icon: github
                    label: 'Git'
                    toolTip: 'Github'
                    to: https://github.com/redhat-developer/rhdh-plugins
                - mountPoint: global.floatingactionbutton/config
                  importName: NullComponent
                  config:
                    icon: '<svg viewBox="0 0 250 300" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path d="M200.134 0l55.555 117.514-55.555 117.518h-47.295l55.555-117.518L152.84 0h47.295zM110.08 99.836l20.056-38.092-2.29-8.868L102.847 0H55.552l48.647 102.898 5.881-3.062zm17.766 74.433l-17.333-39.034-6.314-3.101-48.647 102.898h47.295l25-52.88v-7.883z" fill="#40B4E5"/><path d="M152.842 235.032L97.287 117.514 152.842 0h47.295l-55.555 117.514 55.555 117.518h-47.295zm-97.287 0L0 117.514 55.555 0h47.296L47.295 117.514l55.556 117.518H55.555z" fill="#003764"/></svg>'
                    label: 'Quay'
                    showLabel: true
                    toolTip: 'Quay'
                    to: 'https://quay.io'
    frontend:mountPoints:importName
    (Required) The import name with an associated component to the mount point.
  4. To configure a floating action button to display only on specific pages, configure the global.floatingactionbutton/config mount point in the backstage-plugin-global-floating-action-button plugin and set the visibleOnPaths property as shown in the following example:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-bulk-import:
              # start of fab config
              mountPoints:
                - mountPoint: global.floatingactionbutton/config
                  importName: BulkImportPage 1
                  config:
                    slot: 'page-end'
                    icon: <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#e8eaed"><g><rect fill="none" height="24" width="24"/></g><g><path d="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5-5L11,7z M20,19h-8v2h8c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-8v2h8V19z"/></g></svg>
                    label: 'Bulk import'
                    toolTip: 'Register multiple repositories in bulk'
                    to: /bulk-import/repositories
                    visibleOnPaths: ['/catalog', '/settings']
              # end of fab config
              appIcons:
                - name: bulkImportIcon
                  importName: BulkImportIcon
              dynamicRoutes:
                - path: /bulk-import/repositories
                  importName: BulkImportPage
                  menuItem:
                    icon: bulkImportIcon
                    text: Bulk import
    frontend:mountPoints:importName
    Enter the import name with an associated component to the mount point.
  5. To hide a floating action button on specific pages, configure the global.floatingactionbutton/config mount point in the backstage-plugin-global-floating-action-button plugin and set the excludeOnPaths property as shown in the following example:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-bulk-import:
              # start of fab config
              mountPoints:
                - mountPoint: global.floatingactionbutton/config
                  importName: BulkImportPage 1
                  config:
                    slot: 'page-end'
                    icon: <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#e8eaed"><g><rect fill="none" height="24" width="24"/></g><g><path d="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5-5L11,7z M20,19h-8v2h8c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-8v2h8V19z"/></g></svg>
                    label: 'Bulk import'
                    toolTip: 'Register multiple repositories in bulk'
                    to: /bulk-import/repositories
                    excludeOnPaths: ['/bulk-import']
              # end of fab config
              appIcons:
                - name: bulkImportIcon
                  importName: BulkImportIcon
              dynamicRoutes:
                - path: /bulk-import/repositories
                  importName: BulkImportPage
                  menuItem:
                    icon: bulkImportIcon
                    text: Bulk import
    frontend:mountPoints:importName
    Enter the import name with an associated component to the mount point.
  6. To configure translation support for the floating action button, use translation keys instead of static text. The Global Floating Action Button plugin supports internationalization (i18n) through the labelKey and toolTipKey properties.

    Example for using translation keys in dynamic configuration:

    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-floating-action-button
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-global-floating-action-button:
              translationResources:
                - importName: globalFloatingActionButtonTranslations
                  ref: globalFloatingActionButtonTranslationRef
              mountPoints:
                - mountPoint: application/listener
                  importName: DynamicGlobalFloatingActionButton
                - mountPoint: global.floatingactionbutton/config
                  importName: NullComponent
                  config:
                    icon: github
                    label: 'GitHub' # Fallback text
                    labelKey: 'fab.github.label' # Translation key
                    toolTip: 'GitHub Repository' # Fallback text
                    toolTipKey: 'fab.github.tooltip' # Translation key
                    to: https://github.com/redhat-developer/rhdh-plugins
                - mountPoint: global.floatingactionbutton/config
                  importName: NullComponent
                  config:
                    color: 'success'
                    icon: search
                    label: 'Create' # Fallback text
                    labelKey: 'fab.create.label' # Translation key
                    toolTip: 'Create entity' # Fallback text
                    toolTipKey: 'fab.create.tooltip' # Translation key
                    to: '/create'
                    showLabel: true

9.3.5.3. Interface translation options

You can enable translation key support for floating action buttons, so that users can onboard in their preferred language. In Developer Hub, all existing and newly created floating action buttons support localization by using dedicated translation keys.

The Global Floating Action Button plugin supports internationalization (i18n) through translation keys. You can use labelKey and toolTipKey properties to provide translation keys instead of static text.

The plugin provides the following built-in translation keys organized under the fab namespace:

  • fab.create.label - "Create"
  • fab.create.tooltip - "Create entity"
  • fab.docs.label - "Docs"
  • fab.docs.tooltip - "Documentation"
  • fab.apis.label - "APIs"
  • fab.apis.tooltip - "API Documentation"
  • fab.github.label - "GitHub"
  • fab.github.tooltip - "GitHub Repository"
  • fab.bulkImport.label - "Bulk Import"
  • fab.bulkImport.tooltip - "Register multiple repositories in bulk"
  • fab.quay.label - "Quay"
  • fab.quay.tooltip - "Quay Container Registry"

The plugin includes translations for the following supported languages:

  • English (default)
  • French (fr)
  • German (de)
  • Italian (it)
  • Japanese (ja)
  • Spanish (es)

To ensure backward compatibility while providing translation support when available, the following order is used to resolve string translations:

  1. If the labelKey is provided, the plugin will attempt to resolve the translation key
  2. If the translation key is found, it will be used as the label
  3. If the translation key is not found, the plugin will fall back to the label property
Note

The same logic applies to toolTipKey and toolTip.

9.3.5.4. Internal translation implementation

The plugin uses a centralized translation system where:

  • The useTranslation() hook is called in components that render floating action buttons to ensure proper translation context initialization
  • The translation function (t) is passed down to child components that need to resolve translation keys
  • This internal architecture prevents infinite re-render loops and ensures stable component rendering
  • All components that use CustomFab must provide the translation function as a prop
Note

When extending or modifying the plugin components, ensure that the useTranslation() hook is called in parent components and the t prop is passed to CustomFab instances to maintain proper translation functionality and prevent rendering issues.

9.3.5.5. Floating action button parameters

The floating action button plugin supports various parameters for configuring label, icon, size, color, actions, tooltips, priority, and visibility.

NameDescriptionTypeDefault valueRequired

slot

Position of the floating action button. Valid values: PAGE_END, BOTTOM_LEFT

enum

PAGE_END

No

label

Name of the floating action button

String

Not applicable

Yes

labelKey

Translation key for the label. If provided, will be used instead of label when translations are available.

String

Not applicable

No

icon

Icon of the floating action button. Recommended to use filled icons from the Material Design library. You can also use an SVG icon. For example: <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#e8eaed"><g><rect fill="none" height="24" width="24"/></g><g><path d="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5-5L11,7z M20,19h-8v2h8c1.1,0,2-0.9,2-2V5c0-1.1-0.9-2-2-2h-8v2h8V19z"/></g></svg>

String, React.ReactElement, SVG image icon, HTML image icon

Not applicable

No

showLabel

Display of the label next to your icon

Boolean

Not applicable

No

size

Size of the floating action button

small, medium, large

medium

No

color

Color of the component. It supports both default and custom theme colors, that are added from the Palette Getting started guide.

default, error, info, inherit, primary, secondary, success, warning

default

No

onClick

Performed action when selecting a floating action button

React.MouseEventHandler

Not applicable

No

to

Link that opens when selecting a floating action button

String

Not applicable

No

toolTip

Text that is displayed when hovering over a floating action button

String

Not applicable

No

toolTipKey

Translation key for the tooltip. If provided, will be used instead of toolTip when translations are available.

String

Not applicable

No

priority

Order of the floating action buttons displayed in the submenu. A larger value means higher priority.

number

Not applicable

No

visibleOnPaths

Display floating action button on the specified paths

string[]

Display floating action button on all paths

No

excludeOnPaths

Hide floating action button on the specified paths

string[]

Display floating action button on all paths

No

Note

If multiple floating button actions are assigned to the same slot value, the floating buttons are displayed as submenu options within the main floating action button.

9.3.6. Customize the Quick Start to guide user onboarding

9.3.6.1. Customize the Quick Start to guide user onboarding

The quick start plugin provides guided onboarding for Red Hat Developer Hub users through customizable, interactive steps that help users get familiar with the platform.

9.3.6.2. About quick starts

The quick start plugin provides guided onboarding for users of Red Hat Developer Hub. It displays a customizable drawer interface with interactive quick start steps that help users get familiar with the platform.

Note

If RBAC is not enabled, quick start is only accessible to users with administrator permissions.

The quick start plugin is enabled by default and includes the following components:

Set up authentication
Set up secure login credentials to protect your account from unauthorized access.
Configure RBAC
Assign roles and permissions to control who can view, create, or edit resources, ensuring secure and efficient collaboration.
Configure Git
Connect your Git providers, such as GitHub to manage code, automate workflows, and integrate with platform features.
Manage plugins
Browse and install extensions to add features, connect to external tools, and customize your experience.

9.3.6.3. Configure role-based access control for quick starts

You can control which users see specific quick start guides by configuring role-based access control (RBAC) for quick starts in your app-config.yaml file.

Prerequisites

  • You have configured RBAC in RHDH.

Procedure

  1. Enable RBAC in your app-config.yaml file:

    permission:
      enabled: true

    When RBAC is enabled, the system determines user roles based on permissions:

    • Users with policy.entity.create permission are assigned the admin role.
    • Users without this permission are assigned the developer role.

      Note

      If RBAC is disabled (permission.enabled: false) or not configured, users are assumed to be platform engineers setting up Red Hat Developer Hub (RHDH) and are assigned the admin role.

  2. Configure quick start items with role assignments in your app-config.yaml file:

    app:
      quickstart:
        - title: 'Platform Configuration'
          titleKey: steps.platformConfiguration.title
          roles: ['admin']
          # Only admins see this
        - title: 'Getting Started as Developer'
          titleKey: steps.gettingStarted.title
          roles: ['developer']
          # Only developers see this
        - title: 'Universal Welcome Guide'
          titleKey: steps.universalWelcome.title
          roles: ['admin', 'developer']
          # Both user roles see this

    The following roles are supported:

    admin
    Platform engineers, administrators, and users with elevated permissions
    developer

    Regular developers and users with standard permissions

    Note

    Quick start items without a roles property default to the admin role. Items can specify multiple roles, and users see quick start items that match their assigned role.

9.3.6.4. Customize your quick start

As an administrator, you can configure the Red Hat Developer Hub quick start plugin to create customized onboarding for your Developer Hub users.

Procedure

  • Update your app-config.yaml with the following code:

    app:
      quickstart:
        - title: 'Welcome to Developer Hub'
          description: 'Learn the basics of navigating the Developer Hub interface'
          icon: 'home'
          roles: ['admin', 'developer'] # Show to both roles
          cta:
            text: 'Get Started'
            link: '/catalog'
        - title: 'Create Your First Component'
          description: 'Follow our guide to register your first software component'
          icon: 'code'
          roles: ['admin', 'developer'] # Show to both roles
          cta:
            text: 'Create Component'
            link: '/catalog-import'
        - title: 'Explore Templates'
          description: 'Discover available software templates to bootstrap new projects'
          icon: 'template'
          roles: ['admin', 'developer'] # Show to both roles
          cta:
            text: 'Browse Templates'
            link: '/create'

    where:

    title
    Enter the display title for the quick start step.
    description
    Enter the brief description of what the step covers.
    icon

    (Optional) Enter the icon identifier. You can use a full image URL, a valid SVG path, or one of the following common keys:

    For a list of supported icons you can use in your quick start definitions, see Common icons for customization.

9.3.6.5. Disable the quick start

You can disable the quick start plugin if you do not want to use guided onboarding steps in your Developer Hub instance.

Procedure

  • To disable the quick start plugin, set the disabled property to true as shown in the following code:

    global:
      dynamic:
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-quickstart
            disabled: true

9.3.6.6. Explore quick start onboarding steps

You can use the quick start onboarding steps to learn more about the administrator features of RHDH.

Prerequisites

  • (Optional) If RBAC is enabled, you must have administrator permissions to access to the quick start feature.

Procedure

  1. In your RHDH navigation menu, click the Help (?) icon.
  2. In the dropdown menu, click Quick start.
  3. Select the quick start step that you want to begin.
  4. To close the quick start drawer, click Hide.

    About quick starts
    Note

    Your overall progress is tracked and displayed as a progress bar and a progress percentage in the quick start footer.

9.3.6.7. Localize quick start

Enable translation key support for quick start titles, descriptions, and CTAs so that users can onboard in their preferred language.

Note

If a translation key is present but the corresponding localized string is missing, the system defaults to the original text defined in the quick start configuration (title, description, text). If no translation key is defined at all, the original text is displayed.

Prerequisites

  • You have enabled localization in your RHDH application.

Procedure

  1. For all quick start steps (both existing and new) in your configuration file, you must define both the original text and the new localization keys. For example, in the quickstart section of your custom app-config.yaml file, add the titleKey, descriptionKey, and textKey values, as follows:

    app-config.yaml fragment

    app:
      quickstart:
        # Existing quick start steps should also be updated with keys
        - title: 'Setup Authentication'
          titleKey: steps.setupAuth.title
          description: 'Learn the basics of navigating the {product-short} interface'
          descriptionKey: steps.setupAuth.description
          icon: 'home'
          cta:
            text: 'Get Started'
            textKey: steps.setupAuth.ctaTitle
            link: '/catalog'
    # ...

    where:

    title
    (Mandatory) Fallback for the title.
    titleKey
    Key for the translated title.
    description
    (Mandatory) Fallback for the description.
    descriptionKey
    Key for the translated description.
    text
    (Mandatory) Fallback for the CTA text.
    textKey
    Key for the translated CTA text.
  2. In your dynamic-plugins.yaml file, add the translationResources section to your red-hat-developer-hub-backstage-plugin-quickstart configuration, as follows:

    app-config.yaml fragment

    plugins:
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-quickstart
          disabled: false
          pluginConfig:
            dynamicPlugins:
              frontend:
                red-hat-developer-hub.backstage-plugin-quickstart:
                  # translationResources definition is required for translations to work
                  translationResources:
                    - importName: quickstartTranslations
                      ref: quickstartTranslationRef
                  # ... other configurations like mountPoints ...

    where:

    importName
    Enter the name used to reference the import.
    ref
    Reference to the resource definition.
  3. In your translation file, map the keys from the first step to the localized strings for each supported language.

    allTranslations.json fragment

    "plugin.quickstart": {
      "en": {
        "steps.setupAuth.title": "Manage plugins EN",
        "steps.setupAuth.description": "EN Browse and install extensions to add features, connect with external tools, and customize your experience.",
        "steps.setupAuth.ctaTitle": "Start"
      },
      "fr": {
        "steps.setupAuth.title": "Gérer les plugins FR",
        "steps.setupAuth.description": "FR Parcourez et installez des extensions pour ajouter des fonctionnalités, vous connecter à des outils externes et personnaliser votre expérience.",
        "steps.setupAuth.ctaTitle": "Commencer"
      }
    }

9.3.7. Customize the Tech Radar page to visualize technology adoption

9.3.7.1. Customize the Tech Radar page to visualize technology adoption

In Red Hat Developer Hub, the Tech Radar page is provided by the tech-radar dynamic plugin, which is disabled by default. For information about enabling dynamic plugins in Red Hat Developer Hub see Configuring dynamic plugins.

In Red Hat Developer Hub, you can configure Learning Paths by passing the data into the app-config.yaml file as a proxy. The base Tech Radar URL must include the /developer-hub/tech-radar proxy.

Note

Due to the use of overlapping pathRewrites for both the tech-radar and homepage quick access proxies, you must create the tech-radar configuration (^api/proxy/developer-hub/tech-radar) before you create the homepage configuration (^/api/proxy/developer-hub).

You can provide data to the Tech Radar page from the following sources:

  • JSON files hosted on GitHub or GitLab.
  • A dedicated service that provides the Tech Radar data in JSON format using an API.

9.3.7.2. Customize by using a JSON file

For ease of use and simplicity, you can configure the Tech Radar page by using a hosted JSON file.

Prerequisites

  • You have specified the data sources for the Tech Radar plugin in the integrations section of the app-config.yaml file. For example, you have enabled Developer Hub integration with GitHub.
  • You have enabled the ./dynamic-plugins/dist/backstage-community-plugin-tech-radar and /dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic plugins.

Procedure

  1. Publish the JSON file containing your Tech Radar data to a web server, such as GitHub or GitLab. You can find an example at https://raw.githubusercontent.com/backstage/community-plugins/main/workspaces/tech-radar/plugins/tech-radar-common/src/sampleTechRadarResponse.json.
  2. Configure Developer Hub to access the Tech Radar data from the hosted JSON files, by adding the following to the app-config.yaml file:

    techRadar:
      url: <tech_radar_data_url>
    <tech_radar_data_url>
    Enter the Tech Radar data hosted JSON URL.

9.3.7.3. Customize by using a customization service

For advanced scenarios, you can host your Red Hat Developer Hub customization service to offer data to all configurable Developer Hub pages, such as the Tech Radar page. You can even use a different service for each page.

Prerequisites

  • You have specified the data sources for the Tech Radar plugin in the integrations section of the app-config.yaml file. For example, you have enabled Developer Hub integration with GitHub.
  • You have enabled the ./dynamic-plugins/dist/backstage-community-plugin-tech-radar and /dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic plugins.

Procedure

  1. Deploy your Developer Hub customization service on the same OpenShift Container Platform cluster as your Developer Hub instance. You can find an example at red-hat-developer-hub-customization-provider, that provides the same data as default Developer Hub data. The customization service provides a Tech Radar data URL such as: http://<rhdh-customization-provider>/tech-radar.
  2. Add the dedicated service as an allowed host by adding the following code to the app-config.yaml file:

    backend:
       reading:
            allow:
              - host: '<rhdh_customization_provider_base_url>'
    <rhdh_customization_provider_base_url>
    Enter the base URL of your Tech Radar data URL, such as: <rhdh-customization-provider>.
  3. Add the following to the app-config.yaml file:

    techRadar:
        url: <tech_radar_data_url>
    <tech_radar_data_url>
    Enter your Tech Radar data URL, such as: http://<rhdh-customization-provider>/tech-radar.

9.3.8. Customize themes and branding to align with corporate standards

9.3.8.1. Customize themes and branding to align with corporate standards

By modifying the visual aspects of the interface, organizations can align Red Hat Developer Hub with their branding guidelines and improve the overall user experience.

The following default theme configurations are available for Red Hat Developer Hub:

The Red Hat Developer Hub theme
Default theme configurations to make your developer portal look like a standard Red Hat Developer Hub instance.
The Backstage theme
Default theme configurations to make your developer portal look like a standard Backstage instance.

You can change or disable particular parameters in a default theme or create a fully customized theme by modifying the app-config.yaml file. From the app-config.yaml file, you can customize common theme components, including the following components:

  • Company name and logo
  • Font color, size, and style of text in paragraphs, headings, headers, and buttons
  • Header color, gradient, and shape
  • Button color
  • Navigation indicator color

You can also customize some components from the Developer Hub GUI, such as the theme mode (Light Theme, Dark Theme, or Auto).

9.3.8.2. Configure the default theme mode

You can switch the RHDH interface between light, dark, or auto mode (which matches your system preference).

Note

In RHDH, theme configurations are used to change the look and feel of different UI components. So, you might notice changes in different UI components, such as buttons, tabs, sidebars, cards, and tables along with some changes in background color and font used on the RHDH pages.

Prerequisites

  • You are logged in to the RHDH web console.

Procedure

  1. From the Developer Hub web console, click Settings.
  2. From the Appearance panel, select Light, Dark, or Auto to change the theme mode.

    Theme mode selection in the Appearance panel

Verification

  • The interface immediately updates to reflect the selected theme.

9.3.8.3. Configure the branding logo

You can customize the branding logo of your Developer Hub instance by configuring the branding section in the app-config.yaml file.

Procedure

  • Customize the branding logo by configuring the branding section in the app-config.yaml file:

    app:
      branding:
        fullLogo: ${BASE64_EMBEDDED_FULL_LOGO}
        iconLogo: ${BASE64_EMBEDDED_ICON_LOGO}
    fullLogo
    Enter the logo on the expanded (pinned) sidebar as a base64 encoded image.
    iconLogo

    Enter the logo on the collapsed (unpinned) sidebar as a base64 encoded image.

    You can format the BASE64_EMBEDDED_FULL_LOGO environment variable as follows:

    BASE64_EMBEDDED_FULL_LOGO: "data:_<media_type>_;base64,<base64_data>"

    The following example demonstrates how to customize the BASE64_EMBEDDED_FULL_LOGO by using the data:_<media_type>_;base64,<base64_data> format:

    SVGLOGOBASE64=$(base64 -i logo.svg)
    BASE64_EMBEDDED_FULL_LOGO="data:image/svg+xml;base64,$SVGLOGOBASE64"

    Replace image/svg+xml with the correct media type for your image (for example, image/png and image/jpeg), and adjust the file extension accordingly. As a result, you can embed the logo directly without referencing an external file.

    You can also customize the width of the branding logo by setting a value for the fullLogoWidth field in the branding section, as shown in the following example:

    app:
      branding:
        fullLogoWidth: 110px
    # ...
    fullLogoWidth
    The default value for the logo width is 110px. The following units are supported: integer, px, em, rem, percentage.

9.3.8.4. Define custom color palettes

You can customize the color palettes of the light and dark theme modes in your Developer Hub instance by configuring the light.palette and dark.palette parameters in the branding.theme section of the app-config.yaml file.

Procedure

  • Configure the light.palette and dark.palette parameters in the branding.theme section of the app-config.yaml file:

    app:
      branding:
        theme:
          light:
            palette:
              primary:
                main: <light_primary_color>
              navigation:
                indicator: <light_indicator_color>
            pageTheme:
              default:
                backgroundColor: [<light_background_color_1>, <light_background_color_2>]
          dark:
            palette:
              primary:
                main: <dark_primary_color>
              navigation:
                indicator: <dark_indicator_color>
            pageTheme:
              default:
                backgroundColor: [<dark_background_color_1>, <dark_background_color_2>]
    # ...
    light|dark

    Enter the theme name: light or dark.

    palette.primary:main
    Enter the palette main primary color, such as #ffffff or white.
    palette.navigation:indicator
    Enter the palette navigation indicator color, which is a vertical bar that indicates the selected tab in the navigation panel, such as #FF0000 or red.
    pageTheme:default:backgroundColor
    Enter the default page theme background color, such as #ffffff or white.

9.3.8.5. Configure the page theme header

Customize the header color for the light and dark theme modes in your Developer Hub instance by modifying the branding.theme section of the app-config.yaml file.

Procedure

  • Modify the branding.theme section of the app-config.yaml file:

    app:
      branding:
        theme:
          light:
            palette: {}
            pageTheme:
              default:
                backgroundColor: "<default_light_background_color>"
                fontColor: "<default_light_font_color>"
                shape: none
              apis:
                backgroundColor: "<apis_light_background_color>"
                fontColor: "<apis_light_font_color>"
                shape: none
          dark:
            palette: {}
            pageTheme:
              default:
                backgroundColor: "<default_dark_background_color>"
                fontColor: "<default_dark_font_color>"
                shape: none
    # ...
    light
    Enter the theme mode, such as light or dark.
    default

    Enter the default page theme configuration

    backgroundColor
    Enter the page header background color, such as #ffffff or white.
    fontColor
    Enter the page header text color, such as #000000 or black.
    shape
    Enter the page header pattern, such as wave, round, or none. apis:: Enter the page id to configure, such as apis or home.

9.3.8.6. Customize typography

You can configure the typography section of the app-config.yaml file to change the default font family and size of the page text, as well as the font family and size of each heading level.

Procedure

  • Configure the typography section of the app-config.yaml file:

    app:
      branding:
        theme:
          light:
            typography:
              fontFamily: "Times New Roman"
              htmlFontSize: 11 # smaller is bigger
              h1:
                fontFamily: "Times New Roman"
                fontSize: 40
              h2:
                fontFamily: "Times New Roman"
                fontSize: 30
              h3:
                fontFamily: "Times New Roman"
                fontSize: 30
              h4:
                fontFamily: "Times New Roman"
                fontSize: 30
              h5:
                fontFamily: "Times New Roman"
                fontSize: 30
              h6:
                fontFamily: "Times New Roman"
                fontSize: 30
          dark:
            typography:
              fontFamily: "Times New Roman"
              htmlFontSize: 11 # smaller is bigger
              h1:
                fontFamily: "Times New Roman"
                fontSize: 40
              h2:
                fontFamily: "Times New Roman"
                fontSize: 30
              h3:
                fontFamily: "Times New Roman"
                fontSize: 30
              h4:
                fontFamily: "Times New Roman"
                fontSize: 30
              h5:
                fontFamily: "Times New Roman"
                fontSize: 30
              h6:
                fontFamily: "Times New Roman"
                fontSize: 30
    # ...

9.3.8.7. Load a custom React theme for advanced UI overrides

You can load a custom Developer Hub theme from a dynamic plugin.

Procedure

  1. Export a theme provider function in your dynamic plugin, for example:

    import { lightTheme } from './lightTheme'; // some custom theme
    import { UnifiedThemeProvider } from '@backstage/theme';
    export const lightThemeProvider = ({ children }: { children: ReactNode }) => (
      <UnifiedThemeProvider theme={lightTheme} children={children} />
    );

    For more information about creating a custom theme, see Backstage documentation - Creating a Custom Theme.

  2. Configure Developer Hub to load the theme in the UI by using the themes configuration field:

    dynamicPlugins:
      frontend:
        example.my-custom-theme-plugin:
          themes:
            - id: light
              title: Light
              variant: light
              icon: someIconReference
              importName: lightThemeProvider
    id
    Enter your theme ID, such as my_theme. Enter dark to override the default Developer Hub dark theme. Enter light to override the default Developer Hub light theme.

Verification

  • The theme is available in the Developer Hub Settings page.

9.3.8.8. Custom component options

You can use two component variants (Patternfly or MUI) to customize various components of your Developer Hub theme.

  • Patternfly
  • MUI

In addition to assigning a component variant to each parameter in the light or dark theme mode configurations, you can toggle the rippleEffect on or off.

The following code shows the options that you can use in the app-config.yaml file to configure the theme components for your Developer Hub instance:

app:
  branding:
    theme:
      light:
        options:
          rippleEffect: off / on
          paper: patternfly / mui
          buttons: patternfly / mui
          inputs: patternfly / mui
          accordions: patternfly / mui
          sidebars: patternfly / mui
          pages: patternfly / mui
          headers: patternfly / mui
          toolbars: patternfly / mui
          dialogs: patternfly / mui
          cards: patternfly / mui
          tables: patternfly / mui
          tabs: patternfly / mui
      dark:
        options:
          rippleEffect: off / on
          paper: patternfly / mui
          buttons: patternfly / mui
          inputs: patternfly / mui
          accordions: patternfly / mui
          sidebars: patternfly / mui
          pages: patternfly / mui
          headers: patternfly / mui
          toolbars: patternfly / mui
          dialogs: patternfly / mui
          cards: patternfly / mui
          tables: patternfly / mui
          tabs: patternfly / mui

9.3.8.9. Default Red Hat Developer Hub theme

You can use the default Red Hat Developer Hub theme configurations to make your Developer Hub instance look like a standard Red Hat Developer Hub instance. You can also modify the app-config.yaml file to customize or disable particular parameters.

9.3.8.9.1. Default Red Hat Developer Hub theme color palette

The app-config.yaml file uses the following configurations for the default Red Hat Developer Hub color palette:

app:
  branding:
    theme:
      light:
        variant: "rhdh"
        mode: "light"
        palette:
          background:
            default: "#F8F8F8"
            paper: "#FFFFFF"
          banner:
            closeButtonColor: "#FFFFFF"
            error: "#E22134"
            info: "#2E77D0"
            link: "#000000"
            text: "#FFFFFF"
            warning: "#FF9800"
          border: "#E6E6E6"
          bursts:
            backgroundColor:
              default: "#7C3699"
            fontColor: "#FEFEFE"
            gradient:
              linear: "linear-gradient(-137deg, #4BB8A5 0%, #187656 100%)"
            slackChannelText: "#ddd"
          errorBackground: "#FFEBEE"
          errorText: "#CA001B"
          gold: "#FFD600"
          highlight: "#FFFBCC"
          infoBackground: "#ebf5ff"
          infoText: "#004e8a"
          link: "#0A6EBE"
          linkHover: "#2196F3"
          mode: "light"
          navigation:
            background: "#222427"
            indicator: "#0066CC"
            color: "#ffffff"
            selectedColor: "#ffffff"
            navItem:
              hoverBackground: "#3c3f42"
            submenu:
              background: "#222427"
          pinSidebarButton:
            background: "#BDBDBD"
            icon: "#181818"
          primary:
            main: "#0066CC"
          secondary:
            main: "#8476D1"
          status:
            aborted: "#757575"
            error: "#E22134"
            ok: "#1DB954"
            pending: "#FFED51"
            running: "#1F5493"
            warning: "#FF9800"
          tabbar:
            indicator: "#9BF0E1"
          textContrast: "#000000"
          textSubtle: "#6E6E6E"
          textVerySubtle: "#DDD"
          warningBackground: "#F59B23"
          warningText: "#000000"
          text:
            primary: "#151515"
            secondary: "#757575"
          rhdh:
            general:
              disabledBackground: "#D2D2D2"
              disabled: "#6A6E73"
              searchBarBorderColor: "#E4E4E4"
              formControlBackgroundColor: "#FFF"
              mainSectionBackgroundColor: "#FFF"
              headerBottomBorderColor: "#C7C7C7"
              cardBackgroundColor: "#FFF"
              sidebarBackgroundColor: "#212427"
              cardBorderColor: "#C7C7C7"
              tableTitleColor: "#181818"
              tableSubtitleColor: "#616161"
              tableColumnTitleColor: "#151515"
              tableRowHover: "#F5F5F5"
              tableBorderColor: "#E0E0E0"
              tableBackgroundColor: "#FFF"
              tabsBottomBorderColor: "#D2D2D2"
              contrastText: "#FFF"
            primary:
              main: "#0066CC"
              focusVisibleBorder: "#0066CC"
            secondary:
              main: "#8476D1"
              focusVisibleBorder: "#8476D1"
            cards:
              headerTextColor: "#151515"
              headerBackgroundColor: "#FFF"
              headerBackgroundImage: "none"

      dark:
        variant: "rhdh"
        mode: "dark"
        palette:
          background:
            default: "#333333"
            paper: "#424242"
          banner:
            closeButtonColor: "#FFFFFF"
            error: "#E22134"
            info: "#2E77D0"
            link: "#000000"
            text: "#FFFFFF"
            warning: "#FF9800"
          border: "#E6E6E6"
          bursts:
            backgroundColor:
              default: "#7C3699"
            fontColor: "#FEFEFE"
            gradient:
              linear: "linear-gradient(-137deg, #4BB8A5 0%, #187656 100%)"
            slackChannelText: "#ddd"
          errorBackground: "#FFEBEE"
          errorText: "#CA001B"
          gold: "#FFD600"
          highlight: "#FFFBCC"
          infoBackground: "#ebf5ff"
          infoText: "#004e8a"
          link: "#9CC9FF"
          linkHover: "#82BAFD"
          mode: "dark"
          navigation:
            background: "#0f1214"
            indicator: "#0066CC"
            color: "#ffffff"
            selectedColor: "#ffffff"
            navItem:
              hoverBackground: "#3c3f42"
            submenu:
              background: "#0f1214"
          pinSidebarButton:
            background: "#BDBDBD"
            icon: "#404040"
          primary:
            main: "#1FA7F8"
          secondary:
            main: "#B2A3FF"
          status:
            aborted: "#9E9E9E"
            error: "#F84C55"
            ok: "#71CF88"
            pending: "#FEF071"
            running: "#3488E3"
            warning: "#FFB84D"
          tabbar:
            indicator: "#9BF0E1"
          textContrast: "#FFFFFF"
          textSubtle: "#CCCCCC"
          textVerySubtle: "#727272"
          warningBackground: "#F59B23"
          warningText: "#000000"

          rhdh:
            general:
              disabledBackground: "#444548"
              disabled: "#AAABAC"
              searchBarBorderColor: "#57585a"
              formControlBackgroundColor: "#36373A"
              mainSectionBackgroundColor: "#0f1214"
              headerBottomBorderColor: "#A3A3A3"
              cardBackgroundColor: "#292929"
              sidebarBackgroundColor: "#1b1d21"
              cardBorderColor: "#A3A3A3"
              tableTitleColor: "#E0E0E0"
              tableSubtitleColor: "#E0E0E0"
              tableColumnTitleColor: "#E0E0E0"
              tableRowHover: "#0f1214"
              tableBorderColor: "#515151"
              tableBackgroundColor: "#1b1d21"
              tabsBottomBorderColor: "#444548"
              contrastText: "#FFF"
            primary:
              main: "#1FA7F8"
              focusVisibleBorder: "#ADD6FF"
            secondary:
              main: "#B2A3FF"
              focusVisibleBorder: "#D0C7FF"
            cards:
              headerTextColor: "#FFF"
              headerBackgroundColor: "#0f1214"
              headerBackgroundImage: "none"

Alternatively, you can use the following variant and mode values in the app-config.yaml file to apply the previous default configuration:

app:
  branding:
    theme:
      light:
        variant: "rhdh"
        mode: "light"
      dark:
        variant: "rhdh"
        mode: "dark"
9.3.8.9.2. Default Red Hat Developer Hub page themes

The default Developer Hub header color is white in light mode and black in dark mode, as shown in the following app-config.yaml file configuration:

app:
  branding:
    theme:
      light:
        palette: {}
        defaultPageTheme: default
        pageTheme:
          default:
            backgroundColor: "#ffffff"
      dark:
        palette: {}
        defaultPageTheme: default
        pageTheme:
          default:
            backgroundColor: "#0f1214"

9.3.8.10. Default Backstage theme

You can use the default Backstage theme configurations to make your Developer Hub instance look like a standard Backstage instance. You can also modify the app-config.yaml file to customize or disable particular parameters.

9.3.8.10.1. Default Backstage theme color palette

The app-config.yaml file uses the following configurations for the default Backstage color palette:

app:
  branding:
    theme:
      light:
        variant: "backstage"
        mode: "light"
        palette:
          background:
            default: "#F8F8F8"
            paper: "#FFFFFF"
          banner:
            closeButtonColor: "#FFFFFF"
            error: "#E22134"
            info: "#2E77D0"
            link: "#000000"
            text: "#FFFFFF"
            warning: "#FF9800"
          border: "#E6E6E6"
          bursts:
            backgroundColor:
              default: "#7C3699"
            fontColor: "#FEFEFE"
            gradient:
              linear: "linear-gradient(-137deg, #4BB8A5 0%, #187656 100%)"
            slackChannelText: "#ddd"
          errorBackground: "#FFEBEE"
          errorText: "#CA001B"
          gold: "#FFD600"
          highlight: "#FFFBCC"
          infoBackground: "#ebf5ff"
          infoText: "#004e8a"
          link: "#0A6EBE"
          linkHover: "#2196F3"
          navigation:
            background: "#171717"
            color: "#b5b5b5"
            indicator: "#9BF0E1"
            navItem:
              hoverBackground: "#404040"
            selectedColor: "#FFF"
            submenu:
              background: "#404040"
          pinSidebarButton:
            background: "#BDBDBD"
            icon: "#181818"
          primary:
            main: "#1F5493"
          status:
            aborted: "#757575"
            error: "#E22134"
            ok: "#1DB954"
            pending: "#FFED51"
            running: "#1F5493"
            warning: "#FF9800"
          tabbar:
            indicator: "#9BF0E1"
          textContrast: "#000000"
          textSubtle: "#6E6E6E"
          textVerySubtle: "#DDD"
          warningBackground: "#F59B23"
          warningText: "#000000"

      dark:
        variant: "backstage"
        mode: "dark"
        palette:
          background:
            default: "#333333"
            paper: "#424242"
          banner:
            closeButtonColor: "#FFFFFF"
            error: "#E22134"
            info: "#2E77D0"
            link: "#000000"
            text: "#FFFFFF"
            warning: "#FF9800"
          border: "#E6E6E6"
          bursts:
            backgroundColor:
              default: "#7C3699"
            fontColor: "#FEFEFE"
            gradient:
              linear: "linear-gradient(-137deg, #4BB8A5 0%, #187656 100%)"
            slackChannelText: "#ddd"
          errorBackground: "#FFEBEE"
          errorText: "#CA001B"
          gold: "#FFD600"
          highlight: "#FFFBCC"
          infoBackground: "#ebf5ff"
          infoText: "#004e8a"
          link: "#9CC9FF"
          linkHover: "#82BAFD"
          mode: "dark"
          navigation:
            background: "#424242"
            color: "#b5b5b5"
            indicator: "#9BF0E1"
            navItem:
              hoverBackground: "#404040"
            selectedColor: "#FFF"
            submenu:
              background: "#404040"
          pinSidebarButton:
            background: "#BDBDBD"
            icon: "#404040"
          primary:
            dark: "#82BAFD"
            main: "#9CC9FF"
          secondary:
            main: "#FF88B2"
          status:
            aborted: "#9E9E9E"
            error: "#F84C55"
            ok: "#71CF88"
            pending: "#FEF071"
            running: "#3488E3"
            warning: "#FFB84D"
          tabbar:
            indicator: "#9BF0E1"
          textContrast: "#FFFFFF"
          textSubtle: "#CCCCCC"
          textVerySubtle: "#727272"
          warningBackground: "#F59B23"
          warningText: "#000000"

Alternatively, you can use the following variant and mode values in the app-config.yaml file to apply the previous default configuration:

app:
  branding:
    theme:
      light:
        variant: "backstage"
        mode: "light"
      dark:
        variant: "backstage"
        mode: "dark"
9.3.8.10.2. Default Backstage page themes

The default Backstage header color is white in light mode and black in dark mode, as shown in the following app-config.yaml file configuration:

app:
  branding:
    theme:
      light:
        palette: {}
        defaultPageTheme: default
        pageTheme:
          default:
            backgroundColor: ['#005B4B'] # teal
            fontColor: '#ffffff'
            shape: wave
          documentation:
            backgroundColor: ['#C8077A', '#C2297D'] # pinkSea
            fontColor: '#ffffff'
            shape: wave2
          tool:
            backgroundColor: ['#8912CA', '#3E00EA'] # purpleSky
            fontColor: '#ffffff'
            shape: round
          service:
            backgroundColor: ['#006D8F', '#0049A1'] # marineBlue
            fontColor: '#ffffff'
            shape: wave
          website:
            backgroundColor: ['#0027AF', '#270094'] # veryBlue
            fontColor: '#ffffff'
            shape: wave
          library:
            backgroundColor: ['#98002B', '#8D1134'] # rubyRed
            fontColor: '#ffffff'
            shape: wave
          other:
            backgroundColor: ['#171717', '#383838'] # darkGrey
            fontColor: '#ffffff'
            shape: wave
          app:
            backgroundColor: ['#BE2200', '#A41D00'] # toastyOrange
            fontColor: '#ffffff'
            shape: shapes.wave
          apis:
            backgroundColor: ['#005B4B'] # teal
            fontColor: '#ffffff'
            shape: wave2
          card:
            backgroundColor: ['#4BB8A5', '#187656'] # greens
            fontColor: '#ffffff'
            shape: wave

      dark:
        palette: {}
        defaultPageTheme: default
        pageTheme:
          default:
            backgroundColor: ['#005B4B'] # teal
            fontColor: '#ffffff'
            shape: wave
          documentation:
            backgroundColor: ['#C8077A', '#C2297D'] # pinkSea
            fontColor: '#ffffff'
            shape: wave2
          tool:
            backgroundColor: ['#8912CA', '#3E00EA'] # purpleSky
            fontColor: '#ffffff'
            shape: round
          service:
            backgroundColor: ['#006D8F', '#0049A1'] # marineBlue
            fontColor: '#ffffff'
            shape: wave
          website:
            backgroundColor: ['#0027AF', '#270094'] # veryBlue
            fontColor: '#ffffff'
            shape: wave
          library:
            backgroundColor: ['#98002B', '#8D1134'] # rubyRed
            fontColor: '#ffffff'
            shape: wave
          other:
            backgroundColor: ['#171717', '#383838'] # darkGrey
            fontColor: '#ffffff'
            shape: wave
          app:
            backgroundColor: ['#BE2200', '#A41D00'] # toastyOrange
            fontColor: '#ffffff'
            shape: shapes.wave
          apis:
            backgroundColor: ['#005B4B'] # teal
            fontColor: '#ffffff'
            shape: wave2
          card:
            backgroundColor: ['#4BB8A5', '#187656'] # greens
            fontColor: '#ffffff'
            shape: wave

9.3.9. Customize sidebar navigation and tabs to organize essential tools

9.3.9.1. Customize sidebar navigation and tabs to organize essential tools

You can customize navigation elements in Red Hat Developer Hub, including sidebar menu items, entity tab titles, and entity detail tab layouts.

9.3.9.3. Customize the sidebar menu items

9.3.9.3.1. Customize the sidebar menu items

Customize the sidebar menu items in Developer Hub by localizing menu labels, configuring dynamic plugin menu items, and adding or modifying custom menu items.

9.3.9.3.2. Localize sidebar menu items

You can add translation key support for sidebar menu items, so that users can onboard in their preferred language. In Developer Hub, all existing and newly created sidebar menu items support localization by using the titleKey translation key.

Note

If a translation key is present but the corresponding localized string is missing, the system defaults to the original text defined in the sidebar menu items configuration (title). If no translation key is defined at all, the original text is displayed.

Prerequisites

  • You have enabled localization in your RHDH application.

Procedure

  1. For sidebar menu items in your configuration file, you must define both the original text and the new localization keys. For example, in the dynamicPlugins.frontend.default.main-menu-items.menuItems.default.favorites section of your app-config.yaml file, add the titleKey, as follows:

    dynamicPlugins:
      frontend:
        default.main-menu-items:
            menuItems:
              default.favorites:
                title: Favorites
                titleKey: menuItem.favorites
                icon: favorite
                priority: 100
                enabled: true
  2. In your translation file, map the titleKey from the first step to the localized strings for each supported language.

    {
      "rhdh": {
        "en": {
          "menuItem.favorites": "Favorites"
        },
        "fr": {
          "menuItem.favorites": "Favoris"
        }
      }
    }
9.3.9.3.3. Configure custom menu items

You can configure dynamic plugin menu items to customize the sidebar navigation for your Developer Hub instance.

Procedure

  • In the app-config.yaml file, update the menuItems section of your <plugin_name> plugin. For example:

    dynamicPlugins:
      frontend:
        <plugin_name>:
          menuItems:
            <menu_item_name>:
              icon: # home | group | category | extension | school | <my_icon>
              title: <plugin_page_title>
              priority: 10
              parent: favorites
              enabled: true
    <plugin_name>
    Enter the plugin name. This name is the same as the scalprum.name key in the package.json file.
    <menu_item_name>
    Enter a unique name in the main sidebar navigation for either a standalone menu item or a parent menu item. If this field specifies a plugin menu item, the name of the menu item must match the name by using in the corresponding path in dynamicRoutes. For example, if dynamicRoutes defines path: /my-plugin, then menu_item_name must be defined as my-plugin.
    icon

    (Optional) Enter the icon name. You can use any of the following icons:

    • Default icons, such as home, group, category, extension, and school. To use default icons, set the icon as an (" ") empty string.
    • A custom icon, where <my_icon> specifies the name of your custom icon
    • An SVG icon, such as: icon: <svg width="20px" height="20px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill="#ffffff">…​</svg>
    • An HTML image, such as: icon: https://img.icons8.com/ios-glyphs/20/FFFFFF/shop.png
    title
    (Optional) Enter the menu item title. Omit it when the title is already specified in the dynamicRoutes configuration under menuItem.text. To hide the title from the sidebar, set the title as an (" ") empty string.
    priority
    (Optional) Enter an integer value to set the order in which menu items appear in the sidebar.
    parent
    (Optional) Enter the parent menu item under which the current item is nested. If this field is used, the parent menu item must be defined elsewhere in the menuItems configuration of any enabled plugin. You can define this field for each section.
    enabled
    (Optional) Enter false to hide the menu item from the sidebar. Enter true to display the menu item in the sidebar.
    dynamicPlugins:
      frontend:
        <package_name>:
          dynamicRoutes:
            - path: </my-plugin>
              module: CustomModule
              importName: <my_plugin>PluginPage
              menuItem:
                icon: # home | group | category | extension | school | <my_icon>
                text: <my-plugin label>
          menuItems:
            my-plugin:
              priority: 10
              parent: favorites
            favorites:
              icon: favorite
              title: Favorites
              priority: 100
    my-plugin
    Enter the value of the path field in dynamicRoutes.
    priority
    Enter an integer value to set the order in which plugins appear in the parent menu item.
    parent
    Enter the parent menu item id to nest this plugin under, such as favorites.
    favorites
    Configuration for the parent menu item.
    title
    Displays the title name for the parent menu item.
9.3.9.3.4. Modify or add a custom menu items

You can modify existing main menu items or add custom menu items to the sidebar navigation for your Developer Hub instance.

Procedure

  • In the app-config.yaml file, add a section to the default.main-menu-items > menuItems section. Use the default. prefix to identify the key as a main menu item.

    dynamicPlugins:
      frontend:
        default.main-menu-items:
          menuItems:
            default._<menu_group_parent_item_name>_:
              icon: # home | group | category | extension | school | _<my_icon>_
              title: _<menu_group_parent_title>_
              priority: 10
            default._<menu_item_name>_:
              parent: _<menu_group_parent_item_name>_
              icon:  # home | group | category | extension | school | _<my_icon>_
              title: _<my_menu_title>_
              to: _<path_to_the_menu_target_page>_
              priority: 100
              enabled: true
    default.<menu_group_parent_item_name>
    (Optional) Enter the menu group parent item name to configure static main menu items. If no default.<menu_item_name> has a parent value set, this field is not needed.
    icon
    Enter the menu icon. Required for parent menu items.
    title
    Enter the menu group title. Required for parent menu items.
    priority
    (Optional) Enter the order of this menu item within its menu level.
    default.<menu_item_name>
    Enter the menu item name for which you want to override the default value. Add the default. prefix to identify a main menu item.
    parent
    (Optional) Enter the parent menu item for this item. Required if <menu_item_name> is specified as the child of any menu items.
    icon
    (Optional) Enter the menu icon. To use the default icon, set the icon as an (" ") empty string.
    title
    (Optional) Enter the menu group title. Only required for adding a new custom main menu item. To hide a default main menu item title from the sidebar, set the title as an (" ") empty string.
    to
    (Optional) Enter the path that the menu item navigates to. If it is not set, it defaults to the home page.
    priority
    (Optional) Enter the order of this menu item within its menu level.
    enabled
    (Optional) If this field is used to display the menu item in the sidebar, set the value to true. To hide the menu item from the sidebar, set the value to false.
    default.main-menu-items:
          menuItems:
            default.catalog:
              icon: category
              title: My Catalog
              priority: 5
            default.learning-path:
              title: ''
            default.parentlist:
              title: Overview
              icon: bookmarks
            default.home:
              parent: default.parentlist
            default.references:
              title: References
              icon: school
              to: /references
              enabled: true
    icon
    (Optional) Enter the icon name, such as category, bookmarks`, school, and so on to change the default icon.
    title
    Enter an empty string '' to hide the learning path from the default sidebar.
    default.parentlist
    Enter the parent menu items.
    parent
    Enter the parent menu under which to nest the menu entry, such as default.parentlist.
    title
    Enter the menu entry name, such as My Catalog, Overview or References.
    to
    Enter the page to redirect to. For example, default.references redirects to the /references page.
    enabled
    (Optional) Enter true to display the menu item in the sidebar. Enter false to hide the menu item from the sidebar.

9.3.9.4. Customize entity tab titles

Red Hat Developer Hub provides a default opinionated tab set for catalog entity views. For consistency with your organization needs, you can rename, reorder, remove, and add tab titles.

Procedure

  • For each tab to modify, enter your required values in the entityTabs section in your app-config.yaml file:

    upstream:
      backstage:
        appConfig:
          dynamicPlugins:
            frontend:
             <plugin_name>:
                entityTabs:
                  - mountPoint: <mount_point>
                    path: <path>
                    title: <title>
                    priority: <priority>
    <plugin_name>
    Enter the plugin name, such as backstage-community.plugin-topology.
    mountPoint
    Enter the tab mount point, such as entity.page.topology.
    path
    Enter the tab path, such as /topology.
    title
    Enter the tab title, such as Topology.
    priority

    Optional.

    To reorder tabs, enter the tab priority, such as 42. Higher priority is displayed first.

    To remove a tab, enter a negative value, such as -1.

9.3.9.5. Change entity detail tab layouts

Each Red Hat Developer Hub entity detail tab has a default opinionated layout. For consistency with your organization needs, you can change the entity detail tab content when the plugin that contributes the tab content allows a configuration.

Prerequisites

  • The plugin that contributes the tab content can be configured to extend the default inherited configuration.

Procedure

  • Copy the plugin default configuration in your app-config.yaml file, and change the layout properties.

    global:
      dynamic:
        plugins:
          - package: <package_location>
            disabled: false
            pluginConfig:
              dynamicPlugins:
                frontend:
                  <plugin_name>:
                    mountPoints:
                      - mountPoint: <mount_point>
                        importName: <import_name>
                        config:
                          layout:
                            gridColumn:
                              lg: span 6
                              xs: span 12
    package
    Enter your package location, such as ./dynamic-plugins/dist/backstage-community-plugin-tekton.
    <plugin_name>
    Enter your plugin name, such as: backstage-community.plugin-tekton.
    mountPoint
    Copy the mount point defined in the plugin default configuration, such as: entity.page.ci/cards.
    importName
    Copy the import name defined in the plugin default configuration, such as: TektonCI.
    layout
    Enter your layout configuration. The tab content is displayed in a responsive grid that uses a 12 column-grid and supports different breakpoints (xs, sm, md, lg, xl) that can be specified for a CSS property, such as gridColumn. The example uses 6 of the 12 columns to show two Tekton CI cards side-by-side on large (lg) screens (span 6 columns) and shows them among themselves (xs and above span 12 columns).

9.3.9.6. Customize the sidebar menu items for your Developer Hub instance

You can customize the order and parent-child relationships of main menu items in the sidebar for your Developer Hub instance.

Procedure

  1. Open the app-config.yaml file.

    1. To customize the order and parent-child relationships for the main menu items, use the dynamicPlugins.frontend.default.main-menu-items.menuItems field.
    2. For dynamic plugin menu items, use the dynamicPlugins.frontend.<package_name>.menuItems field.

      The following example shows the app-config.yaml file configuration:

      dynamicPlugins:
        frontend:
          default.main-menu-items:
              menuItems:
                default.home:
                  title: Home
                  icon: home
                  priority: 100
                  enabled: true
                default.my-group:
                  title: My Group
                  icon: group
                  priority: 90
                  enabled: true
                default.catalog:
                  title: Catalog
                  icon: category
                  to: catalog
                  priority: 80
                  enabled: true
                default.apis:
                  title: APIs
                  icon: extension
                  to: api-docs
                  priority: 70
                  enabled: true
                default.learning-path:
                  title: Learning Paths
                  icon: school,
                  to: learning-paths
                  priority: 60
                  enabled: true
                default.create:
                  title: Self-service
                  icon: add
                  to: create
                  priority: 50
                  enabled: true

9.3.10. Customize the Home page layout to optimize developer workflows

9.3.10.1. Customize the Home page layout to optimize developer workflows

Persona-specific homepage layouts allow you to deliver targeted content, such as role-appropriate templates and links, to distinct user groups in Red Hat Developer Hub.

9.3.10.2. Customize Home page dashboard cards

Author default persona-based homepage layouts for different user roles to curate distinct starting experiences by selecting appropriate cards, templates, and resources that match each persona’s workflow needs.

Prerequisites

  • You have Red Hat Developer Hub 1.10 or later running.
  • You have enabled the homepage backend plugin.

    Important

    These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

    For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

    To enable the homepage backend plugin, add the following configuration to your dynamic-plugins.yaml file:

    plugins:
      - package: oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-homepage-backend:1.10!red-hat-developer-hub-backstage-plugin-homepage-backend
        disabled: false
  • You have administrative access to modify the app-config.yaml configuration file.

Procedure

  1. Identify your user personas and their workflow needs.

    Plan which types of content each persona requires on their homepage.

    Example persona planning:

    PersonaPrimary TasksNeeded Homepage Content

    Developer

    Write code, deploy services, review PRs

    Templates, catalog, quick access to repos

    Manager

    Monitor team progress, review metrics

    Dashboards, reports, team activity

    Data Scientist

    Run experiments, access data

    Notebooks, data sources, model registry

  2. Open your app-config.yaml configuration file.
  3. Define the homepage layout structure for each persona in the homepage.defaultWidgets section.

    For example, configure a developer persona homepage with cards appropriate for development workflows:

    homepage:
      defaultWidgets:
        # Developer persona layout
        - id: developer-onboarding
          ref: 'rhdh-onboarding-section'
          layout:
            xl: { w: 12, h: 6 }
            lg: { w: 12, h: 6 }
    
        - id: developer-quickaccess
          ref: quickaccess-card
          props:
            title: Developer Quick Access
          layout:
            xl: { w: 7, h: 8 }
            lg: { w: 7, h: 8 }
    
        - id: templates
          ref: rhdh-template-section
          layout:
            xl: { w: 12, h: 5 }
            lg: { w: 12, h: 5 }
    
        - id: starred-entities
          ref: catalog-starred-entities-card
          layout:
            xl: { w: 5, h: 4, x: 7 }
            lg: { w: 5, h: 4, x: 7 }

    The layout uses a 12-column grid system with properties:

    1. w (width): Number of columns (1-12)
    2. h (height): Number of grid rows
    3. x (x-position): Column offset (0-11)
    4. y (y-position): Row offset (optional)
  4. Configure a default homepage layout that all users can see.

    Create cards without visibility conditions so that all authenticated users see essential homepage content:

        # Default cards visible to all users
        - id: onboarding
          ref: 'rhdh-onboarding-section'
          layout:
            xl: { w: 12, h: 6 }
    
        - id: quickaccess-card
          ref: quickaccess-card
          layout:
            xl: { w: 6, h: 6 }
  5. Save the configuration file.

    Note

    The layouts you authored are not yet restricted to specific user groups. To control which personas see which layouts, proceed to attach these layouts to RBAC groups.

9.3.10.3. Attach homepages to groups to control access and automate layout assignment

Assign persona-specific homepage layouts to user groups to automate role-based content access.

Prerequisites

  • You have Red Hat Developer Hub 1.10 or later running.
  • You defined groups for each user persona (for example, group:default/developers, group:default/data-scientists, group:default/managers).
  • You authored persona-based homepage layouts in your app-config.yaml configuration file.
  • You have administrative access to modify the app-config.yaml configuration file.

Procedure

  1. Enable the homepage backend plugin.

    Important

    These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

    For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

    Add the following configuration to your dynamic-plugins.yaml file:

    plugins:
      - package: oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-homepage-backend:1.10!red-hat-developer-hub-backstage-plugin-homepage-backend
        disabled: false
  2. Identify your user personas and their corresponding groups.

    Important

    Replace the example group names below with your organization’s actual group names.

    PersonaGroup

    Developer

    group:default/developers

    Manager

    group:default/managers

    Data Scientist

    group:default/data-scientists

  3. Verify that you created the groups in your RHDH configuration.

    Check that the groups exist by using the RBAC web UI or by reviewing your RBAC configuration file. You must create all groups referenced in your persona mapping before configuring homepage visibility.

  4. Open your app-config.yaml configuration file.
  5. Attach persona-specific layouts to groups by adding the if.groups field to group cards under a shared visibility condition.

    For example, attach the developer persona layout to the developers group:

    homepage:
      defaultWidgets:
        # Attach developer layout to developers group
        - if:
            groups: [group:default/developers]
          children:
            - id: developer-onboarding
              ref: 'rhdh-onboarding-section'
              layout:
                xl: { w: 12, h: 6 }
                lg: { w: 12, h: 6 }
    
            - id: developer-quickaccess
              ref: quickaccess-card
              props:
                title: Developer Quick Access
              layout:
                xl: { w: 7, h: 8 }
                lg: { w: 7, h: 8 }
    
            - id: templates
              ref: rhdh-template-section
              layout:
                xl: { w: 12, h: 5 }
                lg: { w: 12, h: 5 }
    
            - id: starred-entities
              ref: catalog-starred-entities-card
              layout:
                xl: { w: 5, h: 4, x: 7 }
                lg: { w: 5, h: 4, x: 7 }

    The groups field accepts an array of group entity references. Users who belong to any of the listed groups see all child cards.

  6. Control visibility for multiple groups by adding additional if.groups configurations.

    Individual child cards can include their own if conditions to further restrict visibility beyond the parent group’s rules.

    Note

    The front-end positions cards according to layout coordinates (x, y, w, h), not array order. The configuration array order does not affect rendering position.

  7. Save the configuration file and restart Red Hat Developer Hub:

    $ kubectl rollout restart deployment/<rhdh-deployment-name>

    Replace <rhdh-deployment-name> with the name of your RHDH deployment.

    Important

    RHDH validates the homepage configuration at startup. If the configuration contains errors, RHDH will fail to start. Check the pod logs for configuration validation errors if the deployment does not become ready.

Verification

  1. Log in to Red Hat Developer Hub as a test user who belongs to one of the configured groups.

    The homepage displays only the cards configured for that user’s persona.

  2. Log in as a test user from a different group.

    The homepage displays a different set of cards based on the second user’s group membership.

  3. Log in as a test user who does not belong to any persona-specific group.

    The homepage displays only the default cards that have no if conditions.

9.3.10.4. Homepage backend configuration reference

Use these backend plugin configuration options, card structures, and API endpoints to customize and manage your homepage data.

9.3.10.4.1. Configuration options

The configuration fields available in the homepage section of your app-config.yaml file:

FieldTypeRequiredDescription

homepage.defaultWidgets

array

No

List of default homepage cards and groups with visibility rules and layout configuration. RHDH validates this configuration at startup. Configuration errors prevent RHDH from starting. Default: []

9.3.10.4.2. Card configuration

Each card in the homepage.defaultWidgets array supports the following fields:

FieldTypeRequiredDescription

id

string

Yes (for cards)

Unique identifier for the card. Each card must have a unique ID within the configuration.

ref

string

Yes (for cards)

Name of the widget component to render. Must match a registered mount point config.id in the dynamic home page plugin configuration.

layout

object

No

Responsive grid layouts for different screen breakpoints (xl, lg, md, sm, xs, xxs). Each layout specifies width (w), height (h), and optional x/y position.

props

object

No

Component-specific properties passed to the card. Properties vary by card type.

if

object

No

Visibility conditions that control which users can see this card. If not specified or all lists are empty, all users see the card.

9.3.10.4.3. Group configuration

Parent groups that contain multiple cards support the following fields:

Note

Groups must not include id or ref fields. Only individual cards require these fields.

FieldTypeRequiredDescription

children

array

Yes (for groups)

List of child cards that inherit the parent group’s visibility rules. Child cards can include their own if conditions to further restrict visibility.

if

object

No

Visibility conditions applied to all children. Child cards remain hidden if the parent fails its visibility check.

9.3.10.4.4. Configuration example

The following example shows a complete homepage backend configuration with persona-based visibility:

homepage:
  defaultWidgets:
    # Search bar - visible to all users
    - id: onboarding
      ref: 'rhdh-onboarding-section'
      layout:
        xl: { w: 12, h: 6 }
        lg: { w: 12, h: 6 }

    # Quick access card - visible to all users
    - id: quickaccess-card
      ref: quickaccess-card
      layout:
        xl: { w: 6, h: 8, x: 6 }

    # Group with shared visibility - visible only to admins
    - if:
        groups: [group:default/admins]
      children:
        - id: featured-docs
          ref: featured-docs-card
          layout:
            xl: { w: 12, h: 6 }

    # Templates - visible only to developers
    - id: templates
      ref: rhdh-template-section
      if:
        groups: [group:default/developers]
      layout:
        xl: { w: 12, h: 5 }
        lg: { w: 12, h: 5 }

9.3.10.5. Homepage visibility rule syntax

Review the visibility properties, access control parameters, and user group settings used to restrict or grant access to homepage cards.

9.3.10.5.1. Visibility condition fields

The if configuration section supports the following optional fields:

FieldTypeRequiredDescription

users

array of strings

No

User references that can see this card. Users whose reference matches any listed value can see the card. Example: user:default/jane

groups

array of strings

No

Groups whose members can see this card. Users who belong to any of the listed groups can see the card. RHDH verifies group membership through the catalog. Users who are not in the catalog cannot match group-based visibility conditions.

9.3.10.5.2. Logical operators

Visibility conditions use the following logical behavior:

  • Multiple values in one field (OR): When a field lists multiple values (for example, multiple groups), the user must match at least one value to see the card.
  • Multiple fields in one condition (OR): When an if block includes multiple fields (for example, both users and groups), the user must satisfy at least one condition from any field to see the card.
  • No visibility condition: When you omit the if section, or when all lists within if are empty, all authenticated users can see the card.
  • Parent group inheritance: When a parent group’s if condition fails, all child cards remain hidden, even if individual child cards have their own if conditions that would otherwise match.
9.3.10.5.3. Group-based visibility

The following example restricts card visibility to members of group:default/developers:

- id: templates
  ref: rhdh-template-section
  if:
    groups: [group:default/developers]
  layout:
    xl: { w: 12, h: 5 }
9.3.10.5.4. Multiple groups (OR logic)

The following example displays a card to members of either group:default/managers or group:default/team-leads:

- id: scorecard
  ref: scorecard-card
  if:
    groups: [group:default/managers, group:default/team-leads]
  layout:
    xl: { w: 6, h: 6 }
9.3.10.5.5. User-specific visibility

The following example restricts card visibility to a specific user by their user reference:

- id: admin-dashboard
  ref: admin-dashboard
  if:
    users: [user:default/admin]
  layout:
    xl: { w: 12, h: 6 }
9.3.10.5.6. Default visibility for all users

The following example makes a card visible to all authenticated users by omitting the if field:

- id: search-bar
  ref: searchbar
  layout:
    xl: { w: 10, h: 1, x: 1 }

Alternatively, an empty if object produces the same result:

- id: quickaccess-card
  ref: quickaccess-card
  if: {}
  layout:
    xl: { w: 6, h: 6 }
Note

Omitting if, using if: {}, or using if with all empty lists are functionally identical. All authenticated users can see the card.

9.3.10.5.7. Shared visibility for multiple cards

The following example applies a shared visibility condition to multiple cards using a parent with children:

- if:
    groups: [group:default/platform-team]
  children:
    - id: metrics-card
      ref: platform-metrics
      layout:
        xl: { w: 6, h: 8 }
    - id: logs-card
      ref: platform-logs
      layout:
        xl: { w: 6, h: 8 }

Both cards display only to members of group:default/platform-team. Only the individual child cards appear in the homepage, not the parent group configuration.

9.3.10.6. Available homepage cards

Integrate custom features from installed plugins into your Home page by using available cards. Configure card visibility by attaching cards to RBAC groups using visibility rules.

The following is a list of the available homepage cards:

  • Search bar
  • Quick access
  • Headline
  • Markdown
  • Placeholder
  • Catalog starred entities
  • Featured docs
Note

Each card can have a layouts definition, props that depend on the component you use, and optional visibilityRules to control which users can see the card.

9.3.10.7. Arrange homepage card layouts to optimize visual organization

Arrange and customize homepage card layouts to ensure your content scales correctly across different screen sizes.

The Home page layout uses a 12-column grid system. The grid uses the following layout properties:

  • w (width): Number of columns (1-12)
  • h (height): Number of grid rows (arbitrary units)
  • x (x-position): Column offset (0-11)
  • y (y-position): Row offset (optional, defaults to auto-placement)

You can define these layout properties for each card across multiple screen breakpoints:

  • Extra-large (xl)
  • Large (lg)
  • Medium (md)
  • Small (sm)
  • Extra-small (xs)
  • Extra-extra-small (xxs)

The default Home page is as shown in the following app-config.yaml file configuration:

dynamicPlugins:
  frontend:
    red-hat-developer-hub.backstage-plugin-dynamic-home-page:
      dynamicRoutes:
        - path: /
          importName: DynamicHomePage
      mountPoints:
        - mountPoint: home.page/cards
          importName: SearchBar
          config:
            layouts:
              xl: { w: 10, h: 1, x: 1 }
              lg: { w: 10, h: 1, x: 1 }
              md: { w: 10, h: 1, x: 1 }
              sm: { w: 10, h: 1, x: 1 }
              xs: { w: 12, h: 1 }
              xxs: { w: 12, h: 1 }
        - mountPoint: home.page/cards
          importName: QuickAccessCard
          config:
            layouts:
              xl: { w: 7, h: 8 }
              lg: { w: 7, h: 8 }
              md: { w: 7, h: 8 }
              sm: { w: 12, h: 8 }
              xs: { w: 12, h: 8 }
              xxs: { w: 12, h: 8 }
        - mountPoint: home.page/cards
          importName: CatalogStarredEntitiesCard
          config:
            layouts:
              xl: { w: 5, h: 4, x: 7 }
              lg: { w: 5, h: 4, x: 7 }
              md: { w: 5, h: 4, x: 7 }
              sm: { w: 12, h: 4 }
              xs: { w: 12, h: 4 }
              xxs: { w: 12, h: 4 }

Prerequisites

  • You have administrative access and can modify the app-config.yaml file for dynamic plugin configurations.

Procedure

  1. Optional: For persona-based homepage configuration with group-based visibility controls, enable the homepage backend plugin.

    Important

    These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

    For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

    Add the following configuration to your dynamic-plugins.yaml file:

    plugins:
      - package: oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-homepage-backend:1.10!red-hat-developer-hub-backstage-plugin-homepage-backend
        disabled: false
    Note

    The homepage backend plugin is only required for persona-based layouts with group-based visibility controls (the if.groups field). Basic homepage customization does not require the backend plugin.

  2. Configure different cards for your Home page in Red Hat Developer Hub as shown in the following code:

    Search

    You can use the SearchBar card to provide essential search functionality directly on the Home page.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: SearchBar
              config:
                layouts:
                  xl: { w: 10, h: 1, x: 1 }
                  lg: { w: 10, h: 1, x: 1 }
                  md: { w: 10, h: 1, x: 1 }
                  sm: { w: 10, h: 1, x: 1 }
                  xs: { w: 12, h: 1 }
                  xxs: { w: 12, h: 1 }
                props:
                  path: /search
                  queryParam: query
    PropDefaultDescription

    path

    /search

    Override the linked search path if needed

    queryParam

    query

    Override the search query parameter name if needed

    Quick access

    You can use the QuickAccessCard card to function as a customizable shortcut panel.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: QuickAccessCard
              config:
                layouts:
                  xl: { h: 8 }
                  lg: { h: 8 }
                  md: { h: 8 }
                  sm: { h: 8 }
                  xs: { h: 8 }
                  xxs: { h: 8 }
                props:
                  title: Quick Access
                  path: /quickaccess
    PropDefaultDescription

    title

    Quick Access

    Override the linked search path if needed

    path

    none

    Override the search query parameter name if needed

    Headline

    You can use the Headline card to display important information.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: Headline
              config:
                layouts:
                  xl: { h: 1 }
                  lg: { h: 1 }
                  md: { h: 1 }
                  sm: { h: 1 }
                  xs: { h: 1 }
                  xxs: { h: 1 }
                props:
                  title: Important info
    PropDefaultDescription

    title

    none

    Title

    Markdown

    You can use the Markdown card to display richly formatted content directly within the Home page layout. This card uses Markdown syntax to present structured information, such as lists and links (documentation and plugin repositories).

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: MarkdownCard
              config:
                layouts:
                  xl: { w: 6, h: 4 }
                  lg: { w: 6, h: 4 }
                  md: { w: 6, h: 4 }
                  sm: { w: 6, h: 4 }
                  xs: { w: 6, h: 4 }
                  xxs: { w: 6, h: 4 }
                props:
                  title: Company links
                  content: |
                    ### RHDH
                    * [Website](https://developers.redhat.com/rhdh/overview)
                    * [Documentation](https://docs.redhat.com/en/documentation/red_hat_developer_hub/)
                    * [Backstage Community Plugins](https://github.com/backstage/community-plugins)
                    * [RHDH Plugins](https://github.com/redhat-developer/rhdh-plugins)
                    * [RHDH Hub](https://github.com/redhat-developer/rhdh)
            - mountPoint: home.page/cards
              importName: Markdown
              config:
                layouts:
                  xl: { w: 6, h: 4, x: 6 }
                  lg: { w: 6, h: 4, x: 6 }
                  md: { w: 6, h: 4, x: 6 }
                  sm: { w: 6, h: 4, x: 6 }
                  xs: { w: 6, h: 4, x: 6 }
                  xxs: { w: 6, h: 4, x: 6 }
                props:
                  title: Important company links
                  content: |
                    ### RHDH
                    * [Website](https://developers.redhat.com/rhdh/overview)
                    * [Documentation](https://docs.redhat.com/en/documentation/red_hat_developer_hub/)
                    * [Documentation](https://docs.redhat.com/en/documentation/red_hat_developer_hub/)
                    * [Backstage Community Plugins](https://github.com/backstage/community-plugins)
                    * [RHDH Plugins](https://github.com/redhat-developer/rhdh-plugins)
                    * [RHDH Hub](https://github.com/redhat-developer/rhdh)
    Placeholder

    You can use the Placeholder card as a utility element for reserving space or for layout testing on the Home page.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: Placeholder
              config:
                layouts:
                  xl: { w: 1, h: 1 }
                  lg: { w: 1, h: 1 }
                  md: { w: 1, h: 1 }
                  sm: { w: 1, h: 1 }
                  xs: { w: 1, h: 1 }
                  xxs: { w: 1, h: 1 }
                props:
                  showBorder: true
                  debugContent: '1'
    Catalog starred entities

    You can use the CatalogStarredEntitiesCard card to provide a dedicated space on the Home page for users to view catalog entities that they have marked as starred.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: CatalogStarredEntitiesCard
    Featured docs

    You can use the FeaturedDocsCard card as a way to highlight specific documentation within Red Hat Developer Hub, as it is available for deployment on the Home page.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: FeaturedDocsCard
    EntitySection

    You can use the EntitySection card to create a visually engaging section that highlights catalog entities of various kinds, such as Component, API, Resource, and System.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: EntitySection
              config:
                layouts:
                  xl: { w: 12, h: 6 }
                  lg: { w: 12, h: 6 }
                  md: { w: 12, h: 6 }
                  sm: { w: 12, h: 6 }
                  xs: { w: 12, h: 6 }
                  xxs: { w: 12, h: 14.5 }
    OnboardingSection

    You can use the OnboardingSection card to quickly discover learning resources within RHDH.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: OnboardingSection
              config:
                layouts:
                  xl: { w: 12, h: 5 }
                  lg: { w: 12, h: 5 }
                  md: { w: 12, h: 5 }
                  sm: { w: 12, h: 5 }
                  xs: { w: 12, h: 7 }
                  xxs: { w: 12, h: 12 }
    TemplateSection

    You can use the TemplateSection card to quickly explore and initiate software templates in RHDH.

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          mountPoints:
            - mountPoint: home.page/cards
              importName: TemplateSection
              config:
                layouts:
                  xl: { w: 12, h: 5 }
                  lg: { w: 12, h: 5 }
                  md: { w: 12, h: 5 }
                  sm: { w: 12, h: 5 }
                  xs: { w: 12, h: 5 }
                  xxs: { w: 12, h: 14 }

9.3.10.8. Set up dynamic homepage layouts

The Home page uses a 12-column grid to position your cards. You can use the optimal parameters to define the layout of your Developer Hub Home page.

Prerequisites

  • Include the following optimal parameters in each of your breakpoints:

    • width (w)
    • height (h)
    • position (x and y)

Procedure

  1. Configure your Developer Hub app-config.yaml configuration file by choosing one of the following options:

    1. Use the full space on smaller windows and half of the space on larger windows as follows:

      dynamicPlugins:
        frontend:
          red-hat-developer-hub.backstage-plugin-dynamic-home-page:
            mountPoints:
              - mountPoint: home.page/cards
                importName: Placeholder
                config:
                  layouts:
                    xl: { w: 6, h: 2 }
                    lg: { w: 6, h: 2 }
                    md: { w: 6, h: 2 }
                    sm: { w: 12, h: 2 }
                    xs: { w: 12, h: 2 }
                    xxs: { w: 12, h: 2 }
                  props:
                    showBorder: true
                    debugContent: a placeholder
    2. Show the cards side by side by defining the x parameter as shown in the following example:

      dynamicPlugins:
        frontend:
          red-hat-developer-hub.backstage-plugin-dynamic-home-page:
            mountPoints:
              - mountPoint: home.page/cards
                importName: Placeholder
                config:
                  layouts:
                    xl: { w: 6, h: 2 }
                    lg: { w: 6, h: 2 }
                    md: { w: 6, h: 2 }
                    sm: { w: 12, h: 2 }
                    xs: { w: 12, h: 2 }
                    xxs: { w: 12, h: 2 }
                  props:
                    showBorder: true
                    debugContent: left
              - mountPoint: home.page/cards
                importName: Placeholder
                config:
                  layouts:
                    xl: { w: 6, h: 2, x: 6 }
                    lg: { w: 6, h: 2, x: 6 }
                    md: { w: 6, h: 2, x: 6 }
                    sm: { w: 12, h: 2, x: 0 }
                    xs: { w: 12, h: 2, x: 0 }
                    xxs: { w: 12, h: 2, x: 0 }
                  props:
                    showBorder: true
                    debugContent: right

      However, you can see a second card below this card by default.

    3. Show the cards in three columns by defining the x parameter as shown in the following example:

      dynamicPlugins:
        frontend:
          red-hat-developer-hub.backstage-plugin-dynamic-home-page:
            mountPoints:
              - mountPoint: home.page/cards
                importName: Placeholder
                config:
                  layouts:
                    xl: { w: 4, h: 2 }
                    lg: { w: 4, h: 2 }
                    md: { w: 4, h: 2 }
                    sm: { w: 6, h: 2 }
                    xs: { w: 12, h: 2 }
                    xxs: { w: 12, h: 2 }
                  props:
                    showBorder: true
                    debugContent: left
              - mountPoint: home.page/cards
                importName: Placeholder
                config:
                  layouts:
                    xl: { w: 4, h: 2, x: 4 }
                    lg: { w: 4, h: 2, x: 4 }
                    md: { w: 4, h: 2, x: 4 }
                    sm: { w: 6, h: 2, x: 6 }
                    xs: { w: 12, h: 2 }
                    xxs: { w: 12, h: 2 }
                  props:
                    showBorder: true
                    debugContent: center
              - mountPoint: home.page/cards
                importName: Placeholder
                config:
                  layouts:
                    xl: { w: 4, h: 2, x: 8 }
                    lg: { w: 4, h: 2, x: 8 }
                    md: { w: 4, h: 2, x: 8 }
                    sm: { w: 6, h: 2 }
                    xs: { w: 12, h: 2 }
                    xxs: { w: 12, h: 2 }
                  props:
                    showBorder: true
                    debugContent: right

Additional resources

9.3.10.9. Configure interface shortcut links

You can customize your homepage to suit your preferences by using the drag-and-drop, resizing, and widget management functionality.

You can do the following actions with the customizable homepage:

  • Drag and drop: Move cards around the layout
  • Resize: Adjust card dimensions
  • Add widget: Select from available cards to add to the homepage
  • Remove cards: Delete cards from the homepage
  • Restore defaults: Reset to the original card configuration
  • User persistence: Settings are saved depending on how you use Backstage Storage API

Additional cards automatically appear based on the installed and enabled plugins. The plugins provide the following two main components:

  • DynamicHomePage: The read-only homepage that displays configured cards without your customization.
  • DynamicCustomizableHomePage: The interactive homepage that allows users to move, resize, and manage cards.

The default homepage displays the OnboardingSection, the EntitySection, and the TemplateSection cards by default. These cards define the default width (w) and height (h) for the cards at various responsiveness levels.

The homepage automatically loads the following configuration:

dynamicPlugins:
  frontend:
    red-hat-developer-hub.backstage-plugin-dynamic-home-page:
      dynamicRoutes:
        - path: /
          importName: DynamicHomePage
      mountPoints:
        - mountPoint: home.page/cards
          importName: OnboardingSection
          config:
            layouts:
              xl: { w: 12, h: 6 }
              lg: { w: 12, h: 6 }
              md: { w: 12, h: 7 }
              sm: { w: 12, h: 8 }
              xs: { w: 12, h: 9 }
              xxs: { w: 12, h: 14 }
        - mountPoint: home.page/cards
          importName: EntitySection
          config:
            layouts:
              xl: { w: 12, h: 7 }
              lg: { w: 12, h: 7 }
              md: { w: 12, h: 8 }
              sm: { w: 12, h: 9 }
              xs: { w: 12, h: 11 }
              xxs: { w: 12, h: 15 }
        - mountPoint: home.page/cards
          importName: TemplateSection
          config:
            layouts:
              xl: { w: 12, h: 5 }
              lg: { w: 12, h: 5 }
              md: { w: 12, h: 5 }
              sm: { w: 12, h: 5 }
              xs: { w: 12, h: 7 }
              xxs: { w: 12, h: 13 }
              xs: { w: 12, h: 7.5 }
              xxs: { w: 12, h: 13.5 }

Procedure

  1. You can arrange the cards and adjust their dimensions using the drag-and-drop and resize functionality. The following is an example of an interactive homepage where you can add, remove, move, and resize cards:

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          dynamicRoutes:
            - path: /
              importName: DynamicCustomizableHomePage
          mountPoints:
             - mountPoint: home.page/cards
               importName: OnboardingSection
               config:
                layouts:
                  xl: { w: 12, h: 6 }
                  lg: { w: 12, h: 6 }
                  md: { w: 12, h: 7 }
                  sm: { w: 12, h: 8 }
                  xs: { w: 12, h: 9 }
                  xxs: { w: 12, h: 14 }
            - mountPoint: home.page/cards
              importName: EntitySection
              config:
                layouts:
                  xl: { w: 12, h: 7 }
                  lg: { w: 12, h: 7 }
                  md: { w: 12, h: 8 }
                  sm: { w: 12, h: 9 }
                  xs: { w: 12, h: 11 }
                  xxs: { w: 12, h: 15 }
            - mountPoint: home.page/cards
              importName: TemplateSection
              config:
                layouts:
                  xl: { w: 12, h: 5 }
                  lg: { w: 12, h: 5 }
                  md: { w: 12, h: 5 }
                  sm: { w: 12, h: 5 }
                  xs: { w: 12, h: 7.5 }
                  xxs: { w: 12, h: 13.5 }
            # Additional cards available in "Add widget" dialog
            - mountPoint: home.page/cards
              importName: RecentlyVisitedCard
            - mountPoint: home.page/cards
              importName: TopVisitedCard
  2. You can change the title by overriding the title property of the dynamic homepage plugin as shown in the following example:

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          dynamicRoutes:
            - path: /
              importName: DynamicHomePage # or DynamicCustomizableHomePage for customizable homepage
              config:
                props:
                  title: 'Howdy {{firstName}} or {{displayName}}'

    The title property supports two variables:

  3. {{displayName}}: This contains the full displayName of the catalog entity.
  4. {{firstName}}: This contains the first part (separated by a space) of the displayName.
  5. You can use a subtitle property which is not used by default as shown in the following example:

    dynamicPlugins:
      frontend:
        red-hat-developer-hub.backstage-plugin-dynamic-home-page:
          dynamicRoutes:
            - path: /
              importName: DynamicHomePage # or DynamicCustomizableHomePage
              config:
                props:
                  title: Our custom RHDH instance
                   subtitle: 'Hello {{displayName}}'

9.3.10.10. Customize QuickAccessCard card icons on the Red Hat Developer Hub homepage

As an administrator, you can customize the QuickAccessCard card icons on the Red Hat Developer Hub homepage to enhance its visual appeal and user experience. You can integrate custom branding or standard icons by leveraging a remote JSON configuration file.

Procedure

  1. Add the JSON Data source. The QuickAccessCard card on the homepage supports loading data from a JSON file. This JSON file can be hosted in your GitHub repository or any accessible endpoint.
  2. Configure the Proxy in your RHDH app-config.yaml file.

    To allow the homepage to fetch data from the hosted JSON file, add the following proxy configuration to your RHDH app-config.yaml file:

    proxy:
      endpoints:
      # customize your backstage instance
      '/developer-hub':
        target: https://raw.githubusercontent.com/ # For example, https://raw.githubusercontent.com/
        pathRewrite:
          '^/api/proxy/developer-hub$': <path_to_your>.json # For example, /redhat-developer/rhdh/main/packages/app/public/homepage/data.json
        changeOrigin: true
        secure: true

    The following table lists the supported icon types:

    Icon typeExampleRendered as

    Backstage system icon

    "catalog"

    Uses Backstage system [icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx)

    SVG String

    "<svg>…​</svg>"

    Renders inline SVG

    Image URL

    "https://example.com/icon.png"

    Renders external image. External images might be restricted to Content Security Policy (CSP) which can be configured in your RHDH app-config.yaml file.

    Relative Path

    "/homepage/icons/icon.png"

    Loads the icon from the app public folder (if present)

    Note

    SVGs must be valid strings when stored inside JSON (use single quotes inside <svg>).

    The following is an example of a JSON file:

    [
     {
     "title": "Community",
     "isExpanded": true,
     "links": [
     {
     "iconUrl": "https://img.icons8.com/ios/50/globe--v1.png",
     "label": "Website",
     "url": "https://developers.redhat.com/"
     },
     {
     "iconUrl": "https://img.icons8.com/ios/50/link--v1.png",
     "label": "Blog",
     "url": "https://developers.redhat.com/blog"
     },
     {
     "iconUrl": "github",
     "label": "GitHub",
     "url": "https://github.com/redhat-developer"
     },
     {
     "iconUrl": "https://img.icons8.com/color/48/slack.png",
     "label": "Slack",
     "url": "https://join.slack.com/xyz"
     },
     {
     "iconUrl": "https://img.icons8.com/color/48/youtube-squared.png",
     "label": "Videos for developers",
     "url": "https://developers.redhat.com/videos"
     },
     {
     "iconUrl": "<svg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' width='2048' height='2048' style='shape-rendering:geometricPrecision;text-rendering:geometricPrecision;image-rendering:optimizeQuality;fill-rule:evenodd;clip-rule:evenodd'><defs><style>.fil0{fill:none}.fil4{fill:#bdbdbd;fill-rule:nonzero}</style></defs><g id='Layer_x0020_1'><path class='fil0' d='M0 0h2048v2048H0z'/><path class='fil0' d='M255.999 255.999h1536v1536h-1536z'/><path class='fil0' d='M256 256h1536v1536H256z'/><g id='_342647616'><path id='_342648000' style='fill:#e53935;fill-rule:nonzero' d='m273.04 666.226 737.28-367.843 13.68-6.824 13.68 6.824 737.28 367.843 17.04 8.503v234.834L993.281 1418.52 255.999 909.563V674.729z'/><path id='_342647880' style='fill:#fff' d='M609.28 711.961h829.439V1541.4H609.28z'/><path id='_342647808' style='fill:#c62828;fill-rule:nonzero' d='m1024 1279.73 723.6-361.079 44.4-22.156v859.945H255.999V896.495l44.402 22.156z'/><path id='_342647736' class='fil4' d='M1331.2 896.285H716.716v-61.442H1331.2z'/><path id='_342647688' class='fil4' d='M1203.22 1049.88H844.698v-61.439h358.522z'/></g></g></svg>",
     "label": "Mailing List",
     "url": "https://groups.google.com/g/xyz"
     },
     ]
    }
    ]

Chapter 10. Secure

10.1. Secure

Manage authentication and authorization in Red Hat Developer Hub to control user access, verify identities, and enforce role-based policies.

You can enable authentication in Red Hat Developer Hub to allow users to sign in using credentials from an external identity provider, such as RHBK, GitHub, or Microsoft Azure, and provision user and group data to the software catalog.

Red Hat Developer Hub (RHDH) administrators can use role-based access control (RBAC) to manage authorizations of other users by defining roles, permissions, and policies for users and groups.

10.2. Configure authentication providers to verify user identities

10.2.1. Configure authentication providers to verify user identities

Enable authentication with your main identity provider to allow users to sign in to Red Hat Developer Hub using their organizational credentials.

10.2.2. Authentication methods and identity provider selection

10.2.2.1. Authentication methods and identity provider selection

User provisioning and authentication are two independent mechanisms in Red Hat Developer Hub. You can configure them separately depending on your requirements.

10.2.2.2. User provisioning

User provisioning and authentication are two independent mechanisms in Red Hat Developer Hub. You can configure them separately depending on your requirements.

10.2.2.2.1. User provisioning

To fully enable catalog features, provision user and group data from an Identity Provider (IdP) to the Developer Hub software catalog. Catalog provider plugins handle this task asynchronously. These plugins query the IdP for relevant user and group information, and create or update corresponding entities in the Developer Hub catalog. Scheduled provisioning ensures that the catalog accurately reflects the users and groups in your organization.

You can provision users and groups from any supported source, including Red Hat Build of Keycloak (RHBK), GitHub, GitLab, Microsoft Azure, or LDAP. LDAP provisioning works independently of your authentication provider. Following associations are supported:

User provisioningAuthentication

RHBK

RHBK

LDAP

RHBK

GitHub

GitHub

Microsoft Azure

Microsoft Azure

For example, you can authenticate users with RHBK while provisioning user and group data from your LDAP directory.

Configuring user provisioning is critical for several reasons.

  • Enabling authorization by allowing you to define access controls based on user and group memberships synchronized from your IdP.
  • Provisioning user and group data to the catalog is necessary for various catalog features that rely on understanding entity ownership and relationships between users, groups, and software components.

    Important

    Without this provisioning step, features such as displaying who owns a catalog entity might not function correctly.

Tip

To explore Developer Hub features in a non-production environment, you can:

  • To use Developer Hub without external IdP, enable the guest user to skip configuring authentication and authorization, log in as the guest user, and access all Developer Hub features.
  • To use Developer Hub without authorization policies and features relying on the software catalog, you can enable the dangerouslyAllowSignInWithoutUserInCatalog resolver option. This setting bypasses the check requiring a user to be in the catalog but still enforces authentication.
Important

Developer Hub uses a one-way synchronization model, where user and group data flow from your Identity Provider to the Developer Hub software catalog. As a result, deleting users or groups manually through the Developer Hub Web UI or REST API might be ineffective or cause inconsistencies, since Developer Hub will create those entities again during the next import.

10.2.2.2.2. Authentication

When a user attempts to access Developer Hub, Developer Hub redirects them to a configured authentication provider, such as Red Hat Build of Keycloak (RHBK), GitHub, GitLab, or Microsoft Azure. This external IdP is responsible for authenticating the user.

On successful authentication, the Developer Hub authentication plugin, configured in your app-config.yaml file, processes the response from the IdP, resolves the identity in the Developer Hub software catalog, and establishes a user session within Developer Hub.

Authentication works independently of user provisioning. By default you cannot authenticate users without provisioning them to the software catalog. You can override this behavior to authenticate users without provisioning them to the software catalog, by using the dangerouslyAllowSignInWithoutUserInCatalog parameter. However, provisioning is a prerequisite for full catalog functionality, such as entity ownership and group-based access controls.

10.2.3. Configure guest access to securely test non-production environments

10.2.3.1. Configure guest access to securely test non-production environments

For trial or non-production environments, you can enable guest access to explore Developer Hub features without configuring authentication. For production environments, disable guest access to ensure security.

10.2.3.2. Enable the Guest login

To allow users to log in as a guest on the login page, enable the guest login option.

Procedure

  1. In the app-config.yaml file, set the authentication environment to development:

    auth:
      environment: development
  2. Restart the Developer Hub application to apply the changes.

Verification

  1. Go to the login page of your Developer Hub instance.
  2. Verify that the option to log in as a guest is available.

10.2.3.3. Disable the Guest login

To prevent users from logging in as a guest on the login page, disable the guest login option.

Procedure

  1. In the app-config.yaml file, set the authentication environment to production:

    auth:
      environment: production
  2. Restart the Developer Hub application to apply the changes.

Verification

  1. Go to the login page of your Developer Hub instance.
  2. Verify that the option to log in as a guest is no longer available.

10.2.4. Share credentials with your identity provider to secure communications

10.2.4.1. Share credentials with your identity provider to secure communications

Share credentials between your identity provider and Red Hat Developer Hub to enable secure communication for authentication and user provisioning.

10.2.4.2. Share credentials with RHBK

Register your Red Hat Developer Hub application in Red Hat Build of Keycloak (RHBK) and store the credentials in Developer Hub to enable secure communication.

Prerequisites

Procedure

  1. Register your Developer Hub app in RHBK:

    1. Use an existing realm, or create a realm, with a distinctive Name such as <my_realm>. Save the value for the next step:
  2. RHBK realm base URL, such as: <your_rhbk_URL>/realms/<your_realm>.

    1. In the created realm, secure the first application, with:

      1. Client ID: A distinctive client ID, such as <RHDH>.
      2. Valid redirect URIs: Set to the OIDC handler URL: https://<my_developer_hub_domain>/api/auth/oidc/handler/frame.
      3. Go to the Credentials tab and copy the Client secret.
      4. Save the values for the next step:
  3. Client ID
  4. Client Secret

    1. In the same realm, get the credential information for an existing user or create a user. Save the user credential information for the verification steps.
  5. Create a long, complex, and unique string to use as the Developer Hub session secret key.
  6. Add the following key-value pairs to your Developer Hub secrets. You can use these secrets in the Developer Hub configuration files by using their environment variable name.

    KEYCLOAK_CLIENT_ID
    Enter the saved Client ID.
    KEYCLOAK_CLIENT_SECRET
    Enter the saved Client Secret.
    KEYCLOAK_BASE_URL
    Enter the saved RHBK realm base URL.
    KEYCLOAK_REALM
    Enter the realm name to provision users.
    KEYCLOAK_LOGIN_REALM
    Enter the realm name to authenticate users.
    SESSION_SECRET
    Enter the created session secret key.

Verification

  • Verify that the secret key-value pairs are stored in your Developer Hub secrets.

10.2.4.3. Share credentials with LDAP

Collect your LDAP credentials and store them in Red Hat Developer Hub to enable user and group provisioning from your LDAP directory.

Prerequisites

Procedure

  1. Collect the following LDAP credentials from your LDAP server:

    LDAP URL
    Your LDAP server URL, such as ldaps://ds.example.net.
    Bind DN
    Your bind distinguished name, such as cn=admin,OU=Users,DC=rhdh,DC=test.
    LDAP secret
    Your LDAP secret.
  2. Optional: To use a secure LDAP connection (ldaps://), store your LDAP certificates in the ldap_certs.pem file and your LDAP keys in the ldap_keys.pem file.

    Warning

    In production mode, use a secure LDAP connection.

  3. Add the LDAP_SECRET key-value pair to your Developer Hub secrets. You can use this secret in the Developer Hub configuration files by using its environment variable name.

    LDAP_SECRET
    Enter your LDAP secret.
  4. Optional: To use a secure LDAP connection (ldaps://), add your LDAP certificates and keys files to a an OpenShift secret.

    $ oc create secret generic my-rhdh-ldap-secrets \
        --from-file=./ldap_certs.pem \
        --from-file=./ldap_keys.pem

Verification

  • Verify that the secret key-value pairs are stored in your Developer Hub secrets.

10.2.4.4. Share credentials with GitHub

Register GitHub Apps and store the credentials in Red Hat Developer Hub to enable secure communication. For security, create two separate GitHub Apps following the principle of least privilege:

Integration App (Developer Hub to GitHub)
Authenticates Developer Hub to GitHub for catalog operations such as importing users, groups, and repositories. Requires: GITHUB_APP_APP_ID, GITHUB_APP_CLIENT_ID_INTEGRATION, GITHUB_APP_CLIENT_SECRET_INTEGRATION, and GITHUB_APP_PRIVATE_KEY.
Authentication App (user to Developer Hub)
Authenticates users signing in to Developer Hub with their GitHub credentials. Requires only OAuth credentials: GITHUB_APP_CLIENT_ID and GITHUB_APP_CLIENT_SECRET.

Prerequisites

Procedure

  1. Create a GitHub App for integration.

    Note

    Use a GitHub App instead of an OAuth app to use fine-grained permissions and short-lived tokens, scale with the number of installations by avoiding rate limits, and have a more transparent integration by avoiding to request user input.

    1. Register a GitHub App with the following configuration:

      GitHub App name
      Enter a unique name identifying your GitHub App, such as integrating-with-rhdh-<GUID>.
      Homepage URL
      Enter your Developer Hub URL: https://<my_developer_hub_domain>.
      Webhook
      Clear "Active".
      Repository permissions
      Contents
      Read-only
      Commit statuses
      Read-only
      Organization permissions
      Members
      Read-only
      Where can this GitHub App be installed?
      Select Only on this account.
    2. In the GeneralClients secrets section, click Generate a new client secret.
    3. In the GeneralPrivate keys section, click Generate a private key.
    4. In the Install App tab, choose an account to install your GitHub App on.
    5. Save the following values for the next step:
  2. App ID
  3. Client ID
  4. Client secret
  5. Private key
  6. Store the integration app credentials: Add the following key/value pairs to your Developer Hub secrets.

    GITHUB_APP_APP_ID
    Enter the saved App ID.
    GITHUB_APP_CLIENT_ID_INTEGRATION
    Enter the saved Client ID.
    GITHUB_APP_CLIENT_SECRET_INTEGRATION
    Enter the saved Client Secret.
    GITHUB_APP_PRIVATE_KEY
    Enter the saved Private key.
    GITHUB_URL
    Enter the GitHub host domain: https://github.com.
    GITHUB_ORG
    Enter your GitHub organization name, such as <your_github_organization_name>.
  7. Create a separate GitHub App for authentication.

    1. Register a GitHub App with the following configuration:

      GitHub App name
      Enter a unique name identifying your GitHub App, such as authenticating-with-rhdh-<GUID>.
      Homepage URL
      Enter your Developer Hub URL: https://<my_developer_hub_domain>.
      Authorization callback URL
      Enter your Developer Hub authentication backend URL: https://<my_developer_hub_domain>/api/auth/github/handler/frame.
      Webhook
      Clear "Active".
      Organization permissions
      Enable Read-only access to Members.
      Where can this GitHub App be installed?
      Select Only on this account.
    2. In the GeneralClients secrets section, click Generate a new client secret.
    3. Save the following values for the next step:
  8. Client ID
  9. Client secret
  10. Store the authentication app credentials: Add the following key/value pairs to your Developer Hub secrets.

    GITHUB_APP_CLIENT_ID
    Enter the saved Client ID.
    GITHUB_APP_CLIENT_SECRET
    Enter the saved Client Secret.

Verification

  • Verify that the secret key-value pairs for both apps are stored in your Developer Hub secrets.

10.2.4.5. Share credentials with Microsoft Azure

Register your Red Hat Developer Hub application in Microsoft Azure and store the credentials in Developer Hub to enable secure communication.

Prerequisites

  • You have the permission to register an application in Azure.

    Tip

    Alternatively, ask your Azure administrator to prepare the required Azure application.

  • You added a custom Developer Hub application configuration, and have enough permissions to change it.
  • Your Developer Hub backend can access the following hosts:

    login.microsoftonline.com
    The Microsoft Azure authorization server, which enables the authentication flow.
    graph.microsoft.com
    The server for retrieving organization data, including user and group data, to import into the Developer Hub catalog.

Procedure

  1. Register your Developer Hub app in Azure, by using the Azure portal.

    1. Sign in to the Microsoft Entra admin center.
    2. Optional: If you have access to multiple tenants, use the Settings icon in the top menu to switch to the tenant in which you want to register the application from the Directories + subscriptions menu.
    3. Browse to Applications > App registrations, and create a New registration with the configuration:

      Name
      Enter a name to identify your application in Azure, such as <Authenticating with Developer Hub>.
      Supported account types
      Select Accounts in this organizational directory only.
      Redirect URI
      Select a platform
      Select Web.
      URL
      Enter the backend authentication URI set in Developer Hub: https://<my_developer_hub_domain>/api/auth/microsoft/handler/frame
    4. On the Applications > App registrations > <Authenticating with Developer Hub> > Manage > API permissions page, Add a Permission, Microsoft Graph, select the following permissions:

      Application Permissions
      GroupMember.Read.All, User.Read.All

      Enter permissions that enable provisioning user and groups to the Developer Hub software catalog.

      Optional: Grant admin consent for these permissions. Even if your company does not require admin consent, consider doing so as it means users do not need to individually consent the first time they access Developer Hub.

      Delegated Permissions
      User.Read, email, offline_access, openid, profile

      Enter permissions that enable authenticating users.

      Optional: Enter optional custom scopes for the Microsoft Graph API that you define both here and in your app-config.yaml Developer Hub configuration file.

    5. On the Applications > App registrations > <Authenticating with Developer Hub> > Manage > Certificates & secrets page, in the Client secrets tab, create a New client secret.
    6. Save the following values for the next step:

      • Directory (tenant) ID
      • Application (client) ID
      • Application (client) Secret ID
  2. Add your Azure credentials to Developer Hub, by adding the following key/value pairs to your Developer Hub secrets:

    MICROSOFT_TENANT_ID
    Enter your saved Directory (tenant) ID.
    MICROSOFT_CLIENT_ID
    Enter your saved Application (client) ID.
    MICROSOFT_CLIENT_SECRET
    Enter your saved Application (client) secret.

Verification

  • Verify that the secret key-value pairs are stored in your Developer Hub secrets.

10.2.4.6. Share credentials with GitLab

Register a GitLab OAuth 2 application and store the credentials in Red Hat Developer Hub to enable user authentication with GitLab as a sign-in provider.

Prerequisites

Procedure

  1. Register the GitLab OAuth 2 application.

    Important

    You must use the required callback URL and permissions.

    1. Register a GitLab OAuth 2 application using the following configuration:

      GitLab OAuth 2 application name
      Enter a unique name, such as authenticating-with-rhdh-<GUID>.
      Redirect URI
      Enter your Developer Hub URL: https://<my_developer_hub_domain>.
      Authorization callback URL
      Enter your authentication backend URL: https://<my_developer_hub_domain>/api/auth/gitlab/handler/frame.
      Authorized application scope
      Enable email, profile, openid, and read_user.
    2. Save the application and record these values for the next step:
  2. OAuth 2 Client ID, available in the Application ID field
  3. OAuth 2 Client secret, accessible by selecting Copy in the Secret field
  4. Add your GitLab OAuth credentials to your RHDH secrets using the following key/value pairs. Use these environment variables in your RHDH configuration files.

    GITLAB_CLIENT_ID
    Enter the saved OAuth 2 Client ID.
    GITLAB_CLIENT_SECRET
    Enter the saved OAuth 2 Client Secret.
    GITLAB_URL
    Enter the GitLab host domain: `<gitlab_host_domain>`.
    GITLAB_PARENT_ORG
    Enter your GitLab organization name, such as <your_gitlab_organization_name>.

Verification

  • Verify that the secret key-value pairs are stored in your Developer Hub secrets.

10.2.5. Import users and groups to synchronize enterprise directory data

10.2.5.1. Import users and groups to synchronize enterprise directory data

Import users and groups from your identity provider to the Red Hat Developer Hub software catalog to enable user identity resolution and role-based access control.

10.2.5.2. Import users and groups from RHBK

10.2.5.2.1. Import users and groups from RHBK

Import users and groups from Red Hat Build of Keycloak (RHBK) to the Red Hat Developer Hub software catalog to enable user identity resolution and role-based access control.

10.2.5.2.2. Import users and groups from Red Hat Build of Keycloak (RHBK)

Import Red Hat Build of Keycloak (RHBK) users and groups to the Red Hat Developer Hub software catalog.

Prerequisites

Procedure

  1. Enable the Keycloak catalog provider plugin in your dynamic-plugins.yaml file.

    The plugin is named after RHBK upstream project.

    plugins:
      - package: './dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-keycloak-dynamic'
        disabled: false
  2. Add a catalog.providers.keycloakOrg section to your app-config.yaml file:

    catalog:
      providers:
        keycloakOrg:
          default:
            baseUrl: ${KEYCLOAK_BASE_URL}
            clientId: ${KEYCLOAK_CLIENT_ID}
            clientSecret: ${KEYCLOAK_CLIENT_SECRET}
            realm: ${KEYCLOAK_REALM}
            loginRealm: ${KEYCLOAK_LOGIN_REALM}
    baseUrl
    Enter your RHBK server URL, defined earlier.
    clientId
    Enter your Developer Hub application client ID in RHBK, defined earlier.
    clientSecret
    Enter your Developer Hub application client secret in RHBK, defined earlier.
    realm
    Enter the realm name to provision users.
    loginRealm
    Enter the realm name to authenticate users.
  3. Optional: Add optional fields to the keycloackOrg catalog provider section in your app-config.yaml file:

    catalog:
      providers:
        keycloakOrg:
          default:
            baseUrl: ${KEYCLOAK_BASE_URL}
            clientId: ${KEYCLOAK_CLIENT_ID}
            clientSecret: ${KEYCLOAK_CLIENT_SECRET}
            realm: ${KEYCLOAK_REALM}
            loginRealm: ${KEYCLOAK_LOGIN_REALM}
            userQuerySize: 100
            groupQuerySize: 100
            schedule:
              frequency: { hours: 1 }
              timeout: { minutes: 50 }
              initialDelay: { seconds: 15}
    userQuerySize
    Enter the user count to query simultaneously. Default value: 100.
    groupQuerySize
    Enter the group count to query simultaneously. Default value: 100.
    schedule
    frequency
    Enter the schedule frequency. Supports cron, ISO duration, and "human duration" as used in code.
    timeout
    Enter the timeout for the user provisioning job. Supports ISO duration and "human duration" as used in code.
    initialDelay
    Enter the initial delay to wait for before starting the user provisioning job. Supports ISO duration and "human duration" as used in code.

Verification

  • Check the console logs.

    Successful synchronization example:

    2025-06-27T16:02:34.647Z catalog info Read 5 Keycloak users and 3 Keycloak groups in 0.4 seconds. Committing... class="KeycloakOrgEntityProvider" taskId="KeycloakOrgEntityProvider:default:refresh" taskInstanceId="db55c34b-46b3-402b-b12f-2fbc48498e82" trace_id="606f80a9ce00d1c86800718c4522f7c6" span_id="7ebc2a254a546e90" trace_flags="01"
    
    2025-06-27T16:02:34.650Z catalog info Committed 5 Keycloak users and 3 Keycloak groups in 0.0 seconds. class="KeycloakOrgEntityProvider" taskId="KeycloakOrgEntityProvider:default:refresh" taskInstanceId="db55c34b-46b3-402b-b12f-2fbc48498e82" trace_id="606f80a9ce00d1c86800718c4522f7c6" span_id="7ebc2a254a546e90" trace_flags="01"
10.2.5.2.3. Create custom transformers

Customize how Red Hat Developer Hub provisions users and groups to Developer Hub software catalog entities, by creating a backend module that uses the keycloakTransformerExtensionPoint to offer custom user and group transformers for the Keycloak backend.

Procedure

  1. Create a new backend module with the yarn new command.

    $ yarn new
    ? What type of module would you like to create? backend-plugin-module
    ? Enter the ID of the plugin [required] catalog
    ? Enter the ID of the module [required] keycloak-org-transformer

    The command creates a plugin named catalog-backend-module-keycloak-org-transformer.

  2. Install required packages:

    $ yarn --cwd plugins/catalog-backend-module-keycloak-org-transformer add @backstage/plugin-catalog-backend-module-keycloak-org
  3. Refer to the sample plugin and implement plugins/catalog-backend-module-keycloak-org-transformer/src/module.ts.
  4. Package and export the plugin as a Dynamic Plugin, and embed the required package for the custom transformer.

    $ npx @red-hat-developer-hub/cli@latest plugin export \
      --embed-package @backstage/plugin-catalog-backend-module-keycloak-org
    Important

    Verify that the installed plugin version is compatible with the Backstage version.

    See the Dynamic plugins reference for the version to import.

  5. Publish and enable the plugin in Developer Hub. For more information, see Installing and viewing plugins in Red Hat Developer Hub.

Verification

  1. Every time that Developer Hub starts, it imports the users and groups. Check the console logs to verify the synchronization result.

    Successful synchronization example:

    {"class":"KeycloakOrgEntityProvider","level":"info","message":"Read 3 Keycloak users and 2 Keycloak groups in 1.5 seconds. Committing...","plugin":"catalog","service":"backstage","taskId":"KeycloakOrgEntityProvider:default:refresh","taskInstanceId":"bf0467ff-8ac4-4702-911c-380270e44dea","timestamp":"2024-09-25 13:58:04"}
    {"class":"KeycloakOrgEntityProvider","level":"info","message":"Committed 3 Keycloak users and 2 Keycloak groups in 0.0 seconds.","plugin":"catalog","service":"backstage","taskId":"KeycloakOrgEntityProvider:default:refresh","taskInstanceId":"bf0467ff-8ac4-4702-911c-380270e44dea","timestamp":"2024-09-25 13:58:04"}
  2. After the first import is complete, go to the Catalog page and select User to view the list of users.
  3. When you select a user, you see the information imported from RHBK. Verify that the user entities reflect the custom transformations you defined in the plugin.
  4. You can select a group, view the list, and access or review the information imported from RHBK. Verify that the group entities reflect the custom transformations you defined in the plugin.
  5. You can log in with an RHBK account.

10.2.5.3. Provision users with LDAP

10.2.5.3.1. Provision users with LDAP

Provision users and groups from your LDAP directory to the Red Hat Developer Hub software catalog to enable user identity resolution and role-based access control.

10.2.5.3.2. Enable user provisioning with LDAP

You can provision users and groups from a Lightweight Directory Access Protocol (LDAP) directory directly to the Red Hat Developer Hub software catalog.

Note

LDAP provisioning works with any authentication provider. You do not need Red Hat Build of Keycloak (RHBK) to use LDAP for user and group provisioning. For example, you can authenticate users with GitHub or Microsoft Azure while provisioning user and group data from your LDAP directory.

Prerequisites

Procedure

  1. Enable the LDAP catalog provider plugin in your dynamic-plugins.yaml file.

    plugins:
      - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-ldap-dynamic'
        disabled: false
  2. Enable provisioning LDAP users and groups to the Developer Hub software catalog, by adding the LDAP catalog provider section to your app-config.yaml file:

    1. Optional: Remove other catalog providers, by removing the other catalog providers section.
    2. Enter the mandatory fields:

      catalog:
        providers:
          ldapOrg:
            default:
              target: ldaps://ds.example.net
              bind:
                dn: cn=admin,ou=Users,dc=rhdh
                secret: ${LDAP_SECRET}
              users:
                - dn: OU=Users,OU=RHDH Local,DC=rhdh,DC=test
                  options:
                    filter: (uid=*)
              groups:
                - dn: OU=Groups,OU=RHDH Local,DC=rhdh,DC=test
              schedule:
                frequency: PT1H
                timeout: PT15M
      target
      Enter your LDAP server URL, such as ldaps://ds.example.net.
      bind

      Enter your service account information:

      dn
      Enter your service account distinguished name (DN), such as cn=admin,OU=Users,DC=rhdh,DC=test
      secret
      Enter the name of the variable containing your LDAP secret: ${LDAP_SECRET}.
      users

      Enter information about how to find your users:

      dn
      Enter the DN containing the user information.
      options
      filter
      Enter your filter, such as (uid=*) to provision to the RHDH software catalog only users with an existing uid.
      groups

      Enter information about how to find your groups:

      dn
      Enter the DN containing the group information.
      schedule

      Enter your schedule information:

      frequency
      Enter your schedule frequency, in the cron, ISO duration, or "human duration" format.
      timeout
      Enter your schedule timeout, in the ISO duration or "human duration" format.
      initialDelay
      Enter your schedule initial delay, in the ISO duration or "human duration" format.
    3. Optional: To change how Developer Hub maps LDAP user fields to the software catalog, enter optional maps and set fields.

      catalog:
        providers:
          ldapOrg:
            default:
              target: ldaps://ds.example.net
              bind:
                dn: cn=admin,ou=Users,dc=rhdh
                secret: ${LDAP_SECRET}
              users:
                - dn: OU=Users,OU=RHDH Local,DC=rhdh,DC=test
                  options:
                    filter: (uid=*)
                  map:
                    rdn: uid
                    name: uid
                    description: {}
                    displayName: cn
                    email: mail
                    picture: {}
                    memberOf: memberOf
                  set:
                    metadata.customField: 'hello'
              groups:
                - dn: OU=Groups,OU=RHDH Local,DC=rhdh,DC=test
              schedule:
                frequency: PT1H
                timeout: PT15M
      rdn
      To change the default value: uid, enter the relative distinguished name of each entry.
      name
      To change the default value: uid, enter the LDAP field to map to the RHDH metadata.name field.
      description
      To set a value, enter the LDAP field to map to the RHDH metadata.description field.
      displayName
      To change the default value: cn, enter the LDAP field to map to the RHDH metadata.displayName field.
      email
      To change the default value: mail, enter the LDAP field to map to the RHDH spec.profile.email field.
      picture
      To set a value, enter the LDAP field to map to the RHDH spec.profile.picture field.
      memberOf
      To change the default value: memberOf, enter the LDAP field to map to the RHDH spec.memberOf field.
      set
      To set a value, enter the hard coded JSON to apply to the entities after ingestion, such as metadata.customField: 'hello'.
    4. Optional: To change how Developer Hub maps LDAP group fields to the software catalog, enter optional groups.maps fields.

      catalog:
        providers:
          ldapOrg:
            default:
              target: ldaps://ds.example.net
              bind:
                dn: cn=admin,ou=Users,dc=rhdh
                secret: ${LDAP_SECRET}
              users:
                - dn: OU=Users,OU=RHDH Local,DC=rhdh,DC=test
                  options:
                    filter: (uid=*)
              groups:
                - dn: OU=Groups,OU=RHDH Local,DC=rhdh,DC=test
                  map:
                    rdn: uid
                    name: uid
                    description: {}
                    displayName: cn
                    email: mail
                    picture: {}
                    memberOf: memberOf
                    members: member
                    type: groupType
                  set:
                    metadata.customField: 'hello'
              schedule:
                frequency: PT1H
                timeout: PT15M
      rdn
      To change the default value: cn, enter the relative distinguished name of each entry.
      name
      To change the default value: cn, enter the LDAP field to map to the RHDH metadata.name field.
      description
      To set a value, enter the LDAP field to map to the RHDH metadata.description field.
      displayName
      To change the default value: cn, enter the LDAP field to map to the RHDH metadata.displayName field.
      email
      To change the default value: mail, enter the LDAP field to map to the RHDH spec.profile.email field.
      picture
      To set a value, enter the LDAP field to map to the RHDH spec.profile.picture field.
      memberOf
      To change the default value: memberOf, enter the LDAP field to map to the RHDH spec.memberOf field.
      members
      To change the default value: member, enter the LDAP field to map to the RHDH spec.children field.
      type
      To change the default value: groupType, enter the LDAP field to map to the RHDH spec.type field.
      set
      To set a value, enter the hard coded JSON to apply to the entities after ingestion, such as metadata.customField: 'hello'.
    5. Recommended: To use a secure LDAP connection (ldaps://), enter optional tls fields.

      catalog:
        providers:
          ldapOrg:
            default:
              target: ldaps://ds.example.net
              bind:
                dn: cn=admin,ou=Users,dc=rhdh
                secret: ${LDAP_SECRET}
              users:
      ldapOrg:
        default:
          tls:
            rejectUnauthorized: true
            keys: '/path/to/keys.pem'
            certs: '/path/to/certs.pem'
      rejectUnauthorized

      Set to false to allow self-signed certificates

      Warning

      This option is not recommended for production.

      keys
      Enter a file containing private keys in PEM format
      certs
      Enter a file containing cert chains in PEM format
    6. Optional: Enter configuration for vendor-specific attributes to set custom attribute names for distinguished names (DN) and universally unique identifiers (UUID) in LDAP directories. Default values are defined per supported vendor and automatically detected.

      catalog:
        providers:
          ldapOrg:
            default:
              vendor:
                dnAttributeName: customDN
                uuidAttributeName: customUUID
      dnAttributeName
      Enter the attribute name that holds the distinguished name (DN) for an entry.
      uuidAttributeName
      Enter the attribute name that holds a universal unique identifier (UUID) for an entry.
    7. Optional: Enter low level users and groups configuration in the options subsection.

      catalog:
        providers:
          ldapOrg:
            default:
              target: ldaps://ds.example.net
              bind:
                dn: cn=admin,ou=Users,dc=rhdh
                secret: ${LDAP_SECRET}
              users:
                options:
                  scope: sub
                  filter: (uid=*)
                  attributes:
                    - cn
                    - uid
                    - description
                  paged:
                  pageSize: 500
              groups:
                options:
                  scope: sub
                  filter: (cn=*)
                  attributes:
                    - cn
                    - uid
                    - description
                  paged:
                    pageSize: 500
                    pagePause: true
      scope
      To change the default value: one, enter how deep the search should go within the directory tree:
  3. base to search only the base DN.
  4. one to search one level below the base DN.
  5. sub to search all descendant entries.

    filter
    To change the default value: (objectclass=*), enter your LDAP filter. With the default mapping:
  6. For users, enter (uid=*) to make sure only users with valid uid field is synced, since users without uid will cause error and ingestion fails.
  7. For groups, enter (cn=*)

    Tip

    When you change the mapping, also update the filter.

    attributes
    To change the default value: all attributes ['*', '+'], enter the array of attribute names to import from LDAP.
    paged

    Enter a value to enable paged results.

    pageSize
    Enter a value to set the results page size, such as 500.
    pagePause
    Enter true to tell the client to wait for the asynchronous results of the next page, when the page limit has been reached.
  8. Recommended: To use a secure LDAP connection (ldaps://), mount your LDAP certificates and keys files in your Developer Hub deployment, by editing your Backstage custom resource.

    kind: Backstage
    spec:
      application:
        extraFiles:
          mountPath: /opt/ldap-secrets
          secrets:
            - name: my-rhdh-database-database-secrets
              key: ldap-certs.pem, ldap-keys.pem

Verification

  • To verify user and group provisioning, check the console logs.

    Successful synchronization example:

    2025-10-15T20:45:49.072Z catalog info Read 4 LDAP users and 6 LDAP groups in 0.3 seconds. Committing... class="LdapOrgEntityProvider" taskId="LdapOrgEntityProvider:default:refresh" taskInstanceId="9bb48fd5-2f55-4096-9fd0-61cee6679952" trace_id="6a318e2eadba84e20df773948668aa4c" span_id="cbec568cb6e64985" trace_flags="01"
    2025-10-15T20:45:49.075Z catalog info Committed 4 LDAP users and 6 LDAP groups in 0.0 seconds. class="LdapOrgEntityProvider" taskId="LdapOrgEntityProvider:default:refresh" taskInstanceId="9bb48fd5-2f55-4096-9fd0-61cee6679952" trace_id="6a318e2eadba84e20df773948668aa4c" span_id="cbec568cb6e64985" trace_flags="01"
10.2.5.3.3. Create custom transformers

Customize how Red Hat Developer Hub provisions users and groups to Developer Hub software catalog entities, by creating a backend module plugin that uses the ldapOrgEntityProviderTransformsExtensionPoint to offer custom user and group transformers for the LDAP backend.

Procedure

  1. Create a new backend module:

    $ yarn new
    ? What type of module would you like to create? backend-plugin-module
    ? Enter the ID if the plugin [required]? catalog
    ? Enter the ID of the module [required]? ldap-transformer

    The command creates a plugin named catalog-backend-module-ldap-transformer.

  2. Install required packages:

    $ yarn --cwd plugins/catalog-backend-module-ldap-transformer add @backstage/plugin-catalog-backend-module-ldap
  3. Refer to the sample plugin and implement plugins/catalog-backend-module-ldap-transformer/src/module.ts.
  4. Package and export the plugin as a Dynamic Plugin, and embed the required package for the custom transformer.

    $ npx @red-hat-developer-hub/cli@latest plugin export \
      --embed-package @backstage/plugin-catalog-backend-module-ldap
    Important

    Verify that the installed plugin version is compatible with the Backstage version.

    See the Dynamic plugins reference for the version to import.

  5. Publish and enable the plugin in Developer Hub. For more information, see Installing and viewing plugins in Red Hat Developer Hub.

Verification

  1. Every time that Developer Hub starts, it imports the users and groups. Check the console logs to verify the synchronization result.
  2. After the first import is complete, go to the Catalog page and select User to view the list of users.
  3. When you select a user, you see the information imported from LDAP. Verify that the user entities reflect the custom transformations you defined in the plugin.
  4. You can select a group, view the list, and access or review the information imported from LDAP. Verify that the group entities reflect the custom transformations you defined in the plugin.
  5. You can log in with an LDAP account.

10.2.5.4. Import users and groups from GitHub

10.2.5.4.1. Import users and groups from GitHub

Import users and groups from GitHub to the Red Hat Developer Hub software catalog to enable user identity resolution and role-based access control.

10.2.5.4.2. Import users and groups from GitHub

Import GitHub users and groups to the Red Hat Developer Hub software catalog.

Prerequisites

Procedure

  1. Enable the GitHub catalog provider plugin in your dynamic-plugins.yaml file.

    plugins:
      - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic'
        disabled: false
  2. Add a GitHub catalog provider and integration section to your app-config.yaml file:

    catalog:
      providers:
        githubOrg:
          id: githuborg
          githubUrl: "${GITHUB_URL}"
          orgs: [ "${GITHUB_ORG}" ]
          schedule:
            frequency:
              minutes: 30
            initialDelay:
              seconds: 15
            timeout:
              minutes: 15
    integrations:
      github:
        - host: "${GITHUB_URL}"
          apps:
            - appId: ${GITHUB_APP_APP_ID}
              clientId: ${GITHUB_APP_CLIENT_ID_INTEGRATION}
              clientSecret: ${GITHUB_APP_CLIENT_SECRET_INTEGRATION}
              privateKey: |
                ${GITHUB_APP_PRIVATE_KEY}
    id

    Enter a stable identifier for this provider, such as githuborg.

    Warning

    Entities from this provider are associated with this identifier. Therefore, do not to change the identifier over time since that might lead to orphaned entities or conflicts.

    githubUrl
    Enter the configured secret variable name: ${GITHUB_URL}.
    orgs
    Enter the configured secret variable name: ${GITHUB_ORG}.
    schedule.frequency
    Enter your schedule frequency, in the cron, ISO duration, or "human duration" format.
    schedule.timeout
    Enter your schedule timeout, in the ISO duration or "human duration" format.
    schedule.initialDelay
    Enter your schedule initial delay, in the ISO duration or "human duration" format.
    integrations.github.host
    Enter the configured secret variable name: ${GITHUB_URL}.
    integrations.github.apps.appId
    Enter the configured secret variable name: ${GITHUB_APP_APP_ID}.
    integrations.github.apps.clientId
    Enter the configured secret variable name: ${GITHUB_APP_CLIENT_ID_INTEGRATION}.
    integrations.github.apps.clientSecret
    Enter the configured secret variable name: ${GITHUB_APP_CLIENT_SECRET_INTEGRATION}.
    integrations.github.apps.privateKey
    Enter the configured secret variable name: ${GITHUB_APP_PRIVATE_KEY}.

Verification

  • Check user and group provisioning in the console logs.

    Successful synchronization example:

    {"class":"GithubMultiOrgEntityProvider","level":"info","message":"Reading GitHub users and teams for org: rhdh-dast","plugin":"catalog","service":"backstage","target":"https://github.com","taskId":"GithubMultiOrgEntityProvider:githuborg:refresh","taskInstanceId":"801b3c6c-167f-473b-b43e-e0b4b780c384","timestamp":"2024-09-09 23:55:58"}
    {"class":"GithubMultiOrgEntityProvider","level":"info","message":"Read 7 GitHub users and 2 GitHub groups in 0.4 seconds. Committing...","plugin":"catalog","service":"backstage","target":"https://github.com","taskId":"GithubMultiOrgEntityProvider:githuborg:refresh","taskInstanceId":"801b3c6c-167f-473b-b43e-e0b4b780c384","timestamp":"2024-09-09 23:55:59"}
10.2.5.4.3. Create custom transformers

Customize how Red Hat Developer Hub provisions users and groups to Developer Hub software catalog entities, by creating a backend module plugin that uses the githubOrgEntityProviderTransformsExtensionPoint to offer custom user and group transformers for the GitHub backend.

Procedure

  1. Create a new backend module:

    $ yarn new
    ? What type of module would you like to create? backend-plugin-module
    ? Enter the ID if the plugin [required]? catalog
    ? Enter the ID of the module [required]? github-org-transformer

    The command creates a plugin named catalog-backend-module-github-org-transformer.

  2. Install required packages:

    $ yarn --cwd plugins/catalog-backend-module-github-org-transformer add @backstage/plugin-catalog-backend-module-github-org
  3. (Optional) Install recommended packages to extend the default transformers or Transformer type checking:

    $ yarn --cwd plugins/catalog-backend-module-github-org-transformer add @backstage/plugin-catalog-backend-module-github
  4. (Optional) Install recommended packages for UserEntity or GroupEntity type checking:

    $ yarn --cwd plugins/catalog-backend-module-github-org-transformer add @backstage/catalog-model
  5. Refer to the sample plugin and implement your custom plugins/catalog-backend-module-github-org-transformer/src/module.ts and make your required transformations to user and group entities.
  6. Package and export the plugin as a Dynamic Plugin, and embed the required package for the custom transformer.

    $ npx @red-hat-developer-hub/cli@latest plugin export \
      --embed-package @backstage/plugin-catalog-backend-module-github \
      --embed-package @backstage/plugin-catalog-backend-module-github-org
    Important

    Verify that the installed plugin version is compatible with the Backstage version.

    See the Dynamic plugins reference for the version to import.

  7. Publish and enable the plugin in Developer Hub. For more information, see Installing and viewing plugins in Red Hat Developer Hub.

Verification

  1. Every time that Developer Hub starts, it imports the users and groups. Check the console logs to verify the synchronization result.
  2. After the first import is complete, go to the Catalog page and select User to view the list of users.
  3. When you select a user, you see the information imported from GitHub. Verify that the user entities reflect the custom transformations you defined in the plugin.
  4. You can select a group, view the list, and access or review the information imported from GitHub. Verify that the group entities reflect the custom transformations you defined in the plugin.
  5. You can log in with a GitHub account.

10.2.5.5. Import users and groups from Microsoft Azure

10.2.5.5.1. Import users and groups from Microsoft Azure

Import users and groups from Microsoft Azure to the Red Hat Developer Hub software catalog to enable user identity resolution and role-based access control.

10.2.5.5.2. Import users and groups from Microsoft Azure

Import Microsoft Azure users and groups to the Red Hat Developer Hub software catalog.

Prerequisites

Procedure

  1. Enable the Microsoft Graph catalog provider plugin in your dynamic-plugins.yaml file.

    plugins:
      - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-msgraph-dynamic'
        disabled: false
  2. Add a Microsoft Graph catalog provider section to your app-config.yaml file:

    catalog:
      providers:
        microsoftGraphOrg:
          providerId:
            target: https://graph.microsoft.com/v1.0
            tenantId: ${MICROSOFT_TENANT_ID}
            clientId: ${MICROSOFT_CLIENT_ID}
            clientSecret: ${MICROSOFT_CLIENT_SECRET}
            schedule:
              frequency:
                hours: 1
              timeout:
                minutes: 50
              initialDelay:
                minutes: 50
    target
    Enter https://graph.microsoft.com/v1.0 to define the MSGraph API endpoint the provider is connecting to. You might change this parameter to use a different version, such as the beta endpoint.
    tenantId
    Enter the configured secret variable name: ${MICROSOFT_TENANT_ID}.
    clientId
    Enter the configured secret variable name: ${MICROSOFT_CLIENT_ID}.
    clientSecret
    Enter the configured secret variable name: ${MICROSOFT_CLIENT_SECRET}.
    schedule
    frequency
    Enter the schedule frequency in the cron, ISO duration, or human duration format. In a large organization, user provisioning might take a long time, therefore avoid using a low value.
    timeout
    Enter the schedule timeout in the ISO duration or human duration format. In a large organization, user provisioning might take a long time, therefore avoid using a low value.
    initialDelay
    Enter the schedule initial delay in the ISO duration or human duration format.
  3. Optional: Add optional fields to the Microsoft authentication provider section in your app-config.yaml file:

    catalog:
      providers:
        microsoftGraphOrg:
          providerId:
            authority: https://login.microsoftonline.com/
            queryMode: advanced
            user:
              expand: manager
              filter: accountEnabled eq true and userType eq 'member'
              loadPhotos: true
              select: ['id', 'displayName', 'description']
            userGroupMember:
              filter: "displayName eq 'Backstage Users'"
              search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
            group:
              expand: member
              filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
              search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
              select: ['id', 'displayName', 'description']
    authority
    Enter your Azure authority URL if it is different from the default: https://login.microsoftonline.com.
    queryMode
    Enter advanced when the default basic query mode is insufficient for your queries to the Microsoft Graph API. See Microsoft Azure advanced queries.
    user

    Add this section to configure optional user query parameters.

    expand

    Enter your expansion parameter to include the expanded resource or collection referenced by a single relationship (navigation property) in your results. A single request can expand only one relationship. See Microsoft Graph query expand parameter.

    You can combine this parameter with userGroupMember.filter or user.filter.

    filter

    Enter your user filter. See Microsoft Graph API and Microsoft Graph API query filter parameters syntax.

    This parameter and userGroupMember.filter are mutually exclusive, specify only one.

    loadPhotos
    Developer Hub loads photos by default. Enter false to avoid loading user photos.
    select
    Enter the Microsoft Graph resource type list to retrieve.
    userGroupMember

    Add this section to use group membership to get users.

    filter

    Enter your filter to filter groups and fetch their members.

    This parameter and user.filter are mutually exclusive, specify only one.

    search

    Enter your search query to search for groups and fetch their members.

    This parameter and user.filter are mutually exclusive, specify only one.

    group

    Enter your configuration to get groups.

    expand

    Enter your expansion parameter to include the expanded resource or collection referenced by a single relationship (navigation property) in your results. A single request can expand only one relationship. See Customize Microsoft Graph responses with query parameters.

    You can combine this parameter with user.filter or userGroupMember.filter.

    filter
    Enter your group filter parameter. See Microsoft Graph API query group syntax.
    search
    Enter your group search parameter. See Microsoft Graph API query search parameter.
    select
    Enter the Microsoft Graph resource type list to retrieve.

Verification

  • Check the console logs for MicrosoftGraphOrgEntityProvider events.

    Successful synchronization example:

    2025-06-23T13:37:55.804Z catalog info Read 9 msgraph users and 3 msgraph groups in 1.5 seconds. Committing... class="MicrosoftGraphOrgEntityProvider" taskId="MicrosoftGraphOrgEntityProvider:providerId:refresh" taskInstanceId="e104a116-6481-4ceb-9bc4-0f8f9581f959" trace_id="e4c633659cffd6b1529afa55a5bfbad7" span_id="76affd0420e8baa6" trace_flags="01"
    
    2025-06-23T13:37:55.811Z catalog info Committed 9 msgraph users and 3 msgraph groups in 0.0 seconds. class="MicrosoftGraphOrgEntityProvider" taskId="MicrosoftGraphOrgEntityProvider:providerId:refresh" taskInstanceId="e104a116-6481-4ceb-9bc4-0f8f9581f959" trace_id="e4c633659cffd6b1529afa55a5bfbad7" span_id="76affd0420e8baa6" trace_flags="01"
10.2.5.5.3. Create custom transformers

Customize how Red Hat Developer Hub provisions users and groups to Developer Hub software catalog entities, by creating a backend module plugin that uses the microsoftGraphOrgEntityProviderTransformExtensionPoint to offer custom user and group transformers for the Azure backend.

Procedure

  1. Create a new backend module:

    $ yarn new
    ? What type of module would you like to create? backend-plugin-module
    ? Enter the ID if the plugin [required]? catalog
    ? Enter the ID of the module [required]? msgraph-transformer

    The command creates a plugin named catalog-backend-module-msgraph-transformer.

  2. Install required packages:

    $ yarn --cwd plugins/catalog-backend-module-msgraph-transformer add @backstage/plugin-catalog-backend-module-msgraph
  3. (Optional) Install recommended packages for UserEntity or GroupEntity type checking:

    $ yarn --cwd plugins/catalog-backend-module-msgraph-transformer add @backstage/catalog-model
  4. Refer to the sample plugin and implement plugins/catalog-backend-module-msgraph-transformer/src/module.ts.
  5. Package and export the plugin as a Dynamic Plugin, and embed the required package for the custom transformer.

    $ npx @red-hat-developer-hub/cli@latest plugin export \
      --embed-package @backstage/plugin-catalog-backend-module-msgraph
    Important

    Verify that the installed plugin version is compatible with the Backstage version.

    See the Dynamic plugins reference for the version to import.

  6. Publish and enable the plugin in Developer Hub. For more information, see Installing and viewing plugins in Red Hat Developer Hub.

Verification

  1. Every time that Developer Hub starts, it imports the users and groups. Check the console logs to verify the synchronization result.
  2. After the first import is complete, go to the Catalog page and select User to view the list of users.
  3. When you select a user, you see the information imported from Microsoft Entra ID. Verify that the user entities reflect the custom transformations you defined in the plugin.
  4. You can select a group, view the list, and access or review the information imported from Microsoft Azure. Verify that the group entities reflect the custom transformations you defined in the plugin.
  5. You can log in with an Entra ID account.

10.2.5.6. Import users and groups from GitLab

10.2.5.6.1. Import users and groups from GitLab

Import users and groups from GitLab to the Red Hat Developer Hub software catalog to enable user identity resolution and role-based access control.

10.2.5.6.2. Import users and groups from GitLab

Import GitLab users and groups to the Red Hat Developer Hub software catalog.

Prerequisites

Procedure

  • Add a GitLab catalog provider and integration section to your RHDH app-config.yaml file:

    catalog:
      providers:
        gitlab:
          default:
            host: ${GITLAB_HOST}
            orgEnabled: true
            group: ${GITLAB_PARENT_ORG}
            relations:
              - INHERITED
              - DESCENDANTS
              - SHARED_FROM_GROUPS
            groupPattern: [\s\S]*
            restrictUsersToGroup: true
            includeUsersWithoutSeat: true
            schedule:
              initialDelay:
                seconds: 0
              frequency:
                minutes: 50
              timeout:
                minutes: 50
    integrations:
      gitlab:
        - host: ${GITLAB_HOST}
          token: ${GITLAB_TOKEN}
    host
    Enter your GitLab instance address: ${GITLAB_HOST}.
    orgEnabled
    Set to true to enable the ingestion of GitLab organizational data, such as users and groups. For the GitLab site, you must also provide a value for the group parameter.
    group
    Enter your configured GitLab parent group: ${GITLAB_PARENT_ORG}.
    relations

    Optional. Specify the types of group memberships to include during ingestion. You can use the following values:

    INHERITED
    Optional. Includes members of any ancestor groups as members of the current group.
    DESCENDANTS
    Optional. Includes members of any descendant groups as members of the current group.
    SHARED_FROM_GROUPS
    Optional. Includes members of any invited groups as members of the current group.
    groupPattern
    Optional. Filters found groups based on provided pattern. Defaults to [\s\S]*, which means to not filter anything.
    restrictUsersToGroup
    Set to true to import only users who are direct members of the configured group.
    includeUsersWithoutSeat
    Set to true to include users who do not occupy a paid seat. This setting applies only to GitLab SaaS.
    schedule.initialDelay
    Enter your schedule initial delay, in the ISO duration or HumanDuration format.
    schedule.frequency
    Enter your schedule frequency, in the cron, ISO duration, or HumanDuration format.
    schedule.timeout
    Enter your schedule timeout, in the ISO duration or HumanDuration format.
    integrations.gitlab.host
    Enter your GitLab instance address: ${GITLAB_HOST}.
    integrations.gitlab.token
    Enter the configured secret variable name: ${GITLAB_TOKEN}.

Verification

  • Open RHDH and wait for first ingestion.
10.2.5.6.3. Create custom transformers

Customize how Red Hat Developer Hub provisions users and groups to Developer Hub software catalog entities, by creating a backend module plugin that uses the gitlabOrgEntityProviderTransformsExtensionPoint to offer custom user and group transformers for the GitLab backend.

Procedure

  1. Create a new backend module:

    $ yarn new
    ? What type of module would you like to create? backend-plugin-module
    ? Enter the ID if the plugin [required]? catalog
    ? Enter the ID of the module [required]? gitlab-org-transformer

    The command creates a plugin named catalog-backend-module-gitlab-org-transformer.

  2. Install required packages:

    $ yarn --cwd plugins/catalog-backend-module-gitlab-org-transformer add @backstage/plugin-catalog-backend-module-gitlab-org
  3. (Optional) Install recommended packages to extend the default transformers or Transformer type checking:

    $ yarn --cwd plugins/catalog-backend-module-gitlab-org-transformer add @backstage/plugin-catalog-backend-module-gitlab
  4. (Optional) Install recommended packages for UserEntity or GroupEntity type checking:

    $ yarn --cwd plugins/catalog-backend-module-gitlab-org-transformer add @backstage/catalog-model
  5. Refer to the sample plugin and implement plugins/catalog-backend-module-gitlab-org-transformer/src/module.ts.
  6. Package and export the plugin as a Dynamic Plugin, and embed the required package for the custom transformer.

    $ npx @red-hat-developer-hub/cli@latest plugin export \
      --embed-package @backstage/plugin-catalog-backend-module-gitlab \
      --embed-package @backstage/plugin-catalog-backend-module-gitlab-org \
      --ignore-version-check @backstage/backend-defaults
    Important

    Verify that the installed plugin version is compatible with the Backstage version.

    See the Dynamic plugins reference for the version to import.

  7. Publish and enable the plugin in Developer Hub. For more information, see Installing and viewing plugins in Red Hat Developer Hub.

Verification

  1. Every time that Developer Hub starts, it imports the users and groups. Check the console logs to verify the synchronization result.
  2. After the first import is complete, go to the Catalog page and select User to view the list of users.
  3. When you select a user, you see the information imported from GitLab. Verify that the user entities reflect the custom transformations you defined in the plugin.
  4. You can select a group, view the list, and access or review the information imported from GitLab. Verify that the group entities reflect the custom transformations you defined in the plugin.
  5. You can log in with a GitLab account.

10.2.5.7. Enable transitive parent groups

Enable transitive parent group resolution to include indirect parent groups in ownership entities for multi-level group hierarchies.

By default, Red Hat Developer Hub does not resolve indirect parent groups during authentication. In this case, with the following group hierarchy, the user_alice user is only a member of the group_developers group:

group_admin
  └── group_developers
    └── user_alice

To support multi-level group hierarchies when using the $ownerRefs alias, you can configure Developer Hub to include indirect parent groups in the user’s ownership entities. In that case the user_alice user is a member of both group_developers and group_admin groups.

Procedure

  • Enable the includeTransitiveGroupOwnership option in your app-config.yaml file.

    includeTransitiveGroupOwnership: true

10.2.6. Enable authentication to verify identities against enterprise directories

10.2.6.1. Enable authentication to verify identities against enterprise directories

Enable authentication with your main identity provider to allow users to sign in to Red Hat Developer Hub using their organizational credentials.

10.2.6.2. Enable authentication with RHBK

Configure Red Hat Build of Keycloak (RHBK) as your Red Hat Developer Hub sign-in provider by enabling the OIDC authentication provider.

Procedure

  1. The OIDC provider authentication backend plugin requires Developer Hub to support sessions. Enable session support by adding the session secret to your app-config.yaml file:

    auth:
      session:
        secret: ${SESSION_SECRET}
  2. Add an OIDC provider section to your app-config.yaml file:

    auth:
      environment: production
      providers:
        oidc:
          production:
            metadataUrl: ${KEYCLOAK_BASE_URL}
            clientId: ${KEYCLOAK_CLIENT_ID}
            clientSecret: ${KEYCLOAK_CLIENT_SECRET}
            prompt: auto
    signInPage: oidc
    environment: production
    Mark the environment as production to hide the Guest login in the Developer Hub home page.
    metadataUrl, clientId, clientSecret
    Configure the OIDC provider with your secrets.
    prompt

    Enter auto to allow the identity provider to automatically determine whether to prompt for credentials or bypass the login redirect if an active RHBK session exists.

    The identity provider defaults to none, which assumes that you are already logged in. Sign-in requests without an active session are rejected.

    signInPage
    Enter oidc to enable the OIDC provider as default sign-in provider.
  3. Optional: Add optional fields to the OIDC authentication provider section in your app-config.yaml file:

    auth:
      providers:
        oidc:
          production:
            metadataUrl: ${KEYCLOAK_BASE_URL}
            clientId: ${KEYCLOAK_CLIENT_ID}
            clientSecret: ${KEYCLOAK_CLIENT_SECRET}
            callbackUrl: ${KEYCLOAK_CALLBACK_URL}
            tokenEndpointAuthMethod: ${KEYCLOAK_TOKEN_ENDPOINT_METHOD}
            tokenSignedResponseAlg: ${KEYCLOAK_SIGNED_RESPONSE_ALG}
            additionalScopes: ${KEYCLOAK_SCOPE}
            signIn:
              resolvers:
                - resolver: oidcSubClaimMatchingKeycloakUserId
                - resolver: preferredUsernameMatchingUserEntityName
                - resolver: emailMatchingUserEntityProfileEmail
                - resolver: emailLocalPartMatchingUserEntityName
                  dangerouslyAllowSignInWithoutUserInCatalog: true
            sessionDuration: { hours: 24 }
      backstageTokenExpiration: { minutes: _<user_defined_value>_ }
    signInPage: oidc
    callbackUrl
    RHBK callback URL.
    tokenEndpointAuthMethod
    Enter your token endpoint authentication method.
    tokenSignedResponseAlg
    Token signed response algorithm.
    additionalScopes
    Enter additional RHBK scopes to request for during the authentication flow.
    signIn
    resolvers

    After successful authentication, the user signing in must be resolved to an existing user in the Developer Hub catalog. To best match users securely for your use case, consider configuring a specific resolver.

    Enter the resolver list to override the default resolver: oidcSubClaimMatchingKeycloakUserId.

    Available values:

    oidcSubClaimMatchingKeycloakUserId
    Matches the user with the immutable sub parameter from OIDC to the RHBK user ID. Consider using this resolver for enhanced security.
    oidcLdapUuidMatchingAnnotation

    Matches the user by their immutable LDAP UUID. Requires a custom client scope in Red Hat Build of Keycloak.

    For setup instructions, see Match users by LDAP UUID with Red Hat Build of Keycloak.

    emailLocalPartMatchingUserEntityName
    Matches the email local part with the user entity name.
    emailMatchingUserEntityProfileEmail
    Matches the email with the user entity profile email.
    preferredUsernameMatchingUserEntityName

    Matches the preferred username with the user entity name.

    The authentication provider tries each sign-in resolver in order until it succeeds, and fails if none succeed.

    Warning

    In production mode, configure only one resolver to make sure users are securely matched.

    dangerouslyAllowSignInWithoutUserInCatalog: true

    Configure the sign-in resolver to bypass the user provisioning requirement in the Developer Hub software catalog.

    Warning

    In production mode, do not enable the dangerouslyAllowSignInWithoutUserInCatalog option.

    sessionDuration
    Lifespan of the user session. Enter a duration in ms library format (such as '24h', '2 days'), ISO duration, or "human duration" as used in code.
    backstageTokenExpiration

    Enter a value to modify the Developer Hub token expiration from its default value of one hour. It refers to the validity of short-term cryptographic tokens, not to the session duration. The expiration value must be set between 10 minutes and 24 hours.

    Warning

    If multiple valid refresh tokens are issued due to frequent refresh token requests, older tokens will remain valid until they expire. Enhance security and prevent potential misuse of older tokens by enabling a refresh token rotation strategy in your RHBK realm.

    1. From the Configure section of the navigation menu, click Realm Settings.
    2. From the Realm Settings page, click the Tokens tab.
    3. From the Refresh tokens section of the Tokens tab, toggle the Revoke Refresh Token to the Enabled position.
  4. To disable the guest login option, in the app-config.yaml file, set the authentication environment to production:

    auth:
      environment: production

Verification

  1. Go to the Developer Hub login page.
  2. Your Developer Hub sign-in page displays Sign in using OIDC and the Guest user sign-in is disabled.
  3. Log in with OIDC by using the saved Username and Password values.

10.2.6.3. Match users by LDAP UUID with RHBK

When you use Red Hat Build of Keycloak with LDAP user federation, configure the oidcLdapUuidMatchingAnnotation sign-in resolver to match users by their immutable LDAP UUID for secure user resolution. This requires a custom client scope in Red Hat Build of Keycloak that exposes the LDAP UUID as a token claim.

Prerequisites

  • LDAP user federation is configured in Red Hat Build of Keycloak.
  • LDAP provisioning is enabled in Red Hat Developer Hub. For more information, see Enable user provisioning with LDAP.
  • A Red Hat Developer Hub client is created in Red Hat Build of Keycloak.

Procedure

  1. In the Red Hat Build of Keycloak admin console, go to Client scopes and click Create client scope. Name the scope ldap_uuid.
  2. In the ldap_uuid scope, click the Mappers tab, then click Add mapper > Configure a new mapper > User Attribute. Configure the mapper with the following values:

    • Name: LDAP_ID
    • User Attribute: LDAP_ID
    • Token Claim Name: ldap_uuid
    • Claim JSON Type: String
    • Add to ID token: ON
    • Add to userinfo: ON
  3. Go to Clients > your Red Hat Developer Hub client > Client scopes. Click Add client scope and add ldap_uuid as a Default scope.
  4. Optional: Add the oidcLdapUuidMatchingAnnotation resolver to your app-config.yaml file, to replace the default ldap_uuid resolver:

    auth:
      providers:
        oidc:
          production:
            signIn:
              resolvers:
                - resolver: oidcLdapUuidMatchingAnnotation
                  ldapUuidKey: ldap_uuid
    ldapUuidKey
    Enter the token claim name containing the LDAP UUID value. The default value is ldap_uuid. This value must match the Token Claim Name configured in step 2.
  5. Restart the Red Hat Developer Hub application to apply the changes.

10.2.6.4. Enable authentication with GitHub

Configure GitHub as your Red Hat Developer Hub sign-in provider.

Procedure

  1. Add a GitHub authentication provider section to your app-config.yaml file:

    auth:
      environment: production
      providers:
        github:
          production:
            clientId: ${GITHUB_APP_CLIENT_ID}
            clientSecret: ${GITHUB_APP_CLIENT_SECRET}
    signInPage: github
    environment
    Enter production to disable the Guest login option in the Developer Hub login page.
    clientId
    Enter the configured secret variable name: ${GITHUB_APP_CLIENT_ID}.
    clientSecret
    Enter the configured secret variable name: ${GITHUB_APP_CLIENT_SECRET}.
    signInPage
    Enter github to enable the GitHub provider as your Developer Hub sign-in provider.
  2. Optional: Add optional fields to the GitHub authentication provider section in your app-config.yaml file:

    auth:
      environment: production
      providers:
        github:
          production:
            clientId: ${GITHUB_APP_CLIENT_ID}
            clientSecret: ${GITHUB_APP_CLIENT_SECRET}
            callbackUrl: <your_intermediate_service_url/handler>
            sessionDuration: { hours: 24 }
            signIn:
              resolvers:
                - resolver: usernameMatchingUserEntityName
                  dangerouslyAllowSignInWithoutUserInCatalog: true
    signInPage: github
    callbackUrl
    Enter the callback URL that GitHub uses when initiating an OAuth flow, such as: <your_intermediate_service_url/handler>. Define it when Developer Hub is not the immediate receiver, such as in cases when you use one OAuth app for many Developer Hub instances.
    sessionDuration
    Enter the user session lifespan, in ms library format (such as '24h', '2 days'), ISO duration, or "human duration".
    signIn
    resolvers
    After successful authentication, Developer Hub resolves the user signing in to an existing user in the Developer Hub catalog. Configure a specific resolver to best match users securely for your use case..

    Enter the resolver list to override the default resolver: usernameMatchingUserEntityName.

    The authentication provider tries each sign-in resolver in order until it succeeds. If none of the attempts succeed, the sign-in fails.

    Warning

    In production mode, configure only one resolver to make sure users are securely matched.

    resolver
    Enter the sign-in resolver name. Available resolvers: usernameMatchingUserEntityName, preferredUsernameMatchingUserEntityName, emailMatchingUserEntityProfileEmail.
    dangerouslyAllowSignInWithoutUserInCatalog

    Enter true to configure the sign-in resolver to bypass the user provisioning requirement in the Developer Hub software catalog.

    Warning

    In production mode, do not enable dangerouslyAllowSignInWithoutUserInCatalog.

  3. To disable the guest login option, in the app-config.yaml file, set the authentication environment to production:

    auth:
      environment: production

Verification

  1. Go to the Developer Hub login page.
  2. Your Developer Hub sign-in page displays Sign in using GitHub and the Guest user sign-in is disabled.
  3. Log in with a GitHub account.

10.2.6.5. Enable authentication with Microsoft Azure

Configure Microsoft Azure as your Red Hat Developer Hub sign-in provider.

Procedure

  1. Add the Microsoft authentication provider to your app-config.yaml file:

    auth:
      environment: production
      providers:
        microsoft:
          production:
            clientId: ${MICROSOFT_CLIENT_ID}
            clientSecret: ${MICROSOFT_CLIENT_SECRET}
            tenantId: ${MICROSOFT_TENANT_ID}
    signInPage: microsoft
    environment
    Enter production to disable the Guest login option in the Developer Hub login page.
    clientId
    Enter the configured secret variable name: ${MICROSOFT_CLIENT_ID}.
    clientSecret
    Enter the configured secret variable name: ${MICROSOFT_CLIENT_SECRET}.
    tenantId
    Enter the configured secret variable name: ${MICROSOFT_TENANT_ID}.
    signInPage
    Enter microsoft to set the Azure provider as your Developer Hub sign-in provider.
  2. Optional: Add optional fields to the Microsoft authentication provider section in your app-config.yaml file:

    auth:
      environment: production
      providers:
        microsoft:
          production:
            clientId: ${MICROSOFT_CLIENT_ID}
            clientSecret: ${MICROSOFT_CLIENT_SECRET}
            tenantId: ${MICROSOFT_TENANT_ID}
            domainHint: ${MICROSOFT_TENANT_ID}
            additionalScopes:
               - Mail.Send
            sessionDuration:
              hours: 24
            signIn:
              resolvers:
                - resolver: usernameMatchingUserEntityName
                  dangerouslyAllowSignInWithoutUserInCatalog: true
    signInPage: microsoft
    domainHint

    Leave this parameter empty, or enter the tenant ID when your application registration is single-tenant.

    Leave this parameter empty when your application registration is multitenant.

    Enter the tenant ID to reduce login friction for users with accounts in multiple tenants, by automatically filtering out accounts from other tenants. For more information, see Home Realm Discovery.

    additionalScopes
    Enter the list of additional scopes to add scopes for the application registration. The default and mandatory value lists following scopes: openid, offline_access, profile, email, User.Read.
    sessionDuration
    Lifespan of the user session. Enter a duration in ms library (such as '24h', '2 days'), ISO duration, or "human duration" format.
    signIn.resolvers

    After successful authentication, Developer Hub resolves the user signing in to an existing user in the Developer Hub catalog. To best match users securely for your use case, consider configuring a specific resolver.

    Enter the resolver list to override the default resolver: userIdMatchingUserEntityAnnotation.

    The authentication provider tries each sign-in resolver in order until it succeeds, and fails if none succeed.

    Warning

    In production mode, configure only one resolver to make sure users are securely matched.

    resolver

    Enter the sign-in resolver name. Available resolvers:

    emailMatchingUserEntityAnnotation
    Use this resolver to look up the user by matching their Microsoft email to the email entity annotation.
    emailLocalPartMatchingUserEntityName
    Use this resolver to look up the user by matching their Microsoft email user name to the user entity name.
    emailMatchingUserEntityProfileEmail
    Use this resolver to look up the user by matching their Microsoft email to the user entity profile email.
    dangerouslyAllowSignInWithoutUserInCatalog

    Enter true to configure the sign-in resolver to bypass the user provisioning requirement in the Developer Hub software catalog.

    Warning

    In production mode, do not enable dangerouslyAllowSignInWithoutUserInCatalog.

  3. To disable the guest login option, in the app-config.yaml file, set the authentication environment to production:

    auth:
      environment: production

Verification

  1. Go to the Developer Hub login page.
  2. Your Developer Hub sign-in page displays Sign in using Microsoft and the Guest user sign-in is disabled.
  3. Log in with an Azure account.

10.2.6.6. Enable authentication with GitLab

Configure GitLab as your Red Hat Developer Hub sign-in provider.

Procedure

  1. Add a GitLab authentication provider section to your RHDH app-config.yaml file:

    includeTransitiveGroupOwnership: true
    signInPage: gitlab
    auth:
      environment: production
      session:
        secret: <name_of_secret>
      providers:
        gitlab:
          production:
            audience: https://${GITLAB_HOST}
            clientId: ${GITLAB_CLIENT_ID}
            clientSecret: ${GITLAB_CLIENT_SECRET}
            callbackUrl: https://__<my_developer_hub_domain>__/api/auth/gitlab/handler/frame
    audience
    Enter your GitLab instance address: https://${GITLAB_HOST}
    clientId
    Enter the configured client ID: ${GITLAB_CLIENT_ID}.
    clientSecret
    Enter the configured secret variable name: ${GITLAB_CLIENT_SECRET}.
    callbackUrl
    Enter your Developer Hub authentication backend URL: https://<my_developer_hub_domain>/api/auth/gitlab/handler/frame
  2. To disable the guest login option, in the app-config.yaml file, set the authentication environment to production:

    auth:
      environment: production

Verification

  1. Go to the Developer Hub login page.
  2. Your Developer Hub sign-in page displays Sign in using GitLab and the Guest user sign-in is disabled.
  3. Log in with a GitLab account.

10.2.6.7. Enable authentication with PingFederate

You can enable authentication with PingFederate to allow users to sign in to Developer Hub by using their PingFederate credentials and match authenticated users to their LDAP catalog entities.

Prerequisites

Procedure

  1. Configure the LDAP Data Store for binary attributes.

    Configure the Data Store to treat unique identifiers as binary data to ensure they are processed correctly for OGNL transformations.

    1. In PingFederate, go to System > Data Stores and edit your LDAP store.
    2. In Advanced options > LDAP Binary Attributes, add objectGUID to the list.
    3. In the Attribute Source lookup configuration, set the Encoding Type for objectGUID to Hex.
  2. Create the Authentication Policy Contract.

    The contract bridges the LDAP directory and the OIDC policy, transforming the binary GUID into a string format.

    1. Create a new contract named rhdh-contract.
    2. Add an Attribute Source linked to your LDAP Data Store.
    3. Set the Search Filter to sAMAccountName=${username}.
    4. Expose the LDAP UUID attribute (for example, objectGUID for Active Directory) within the contract. Under Contract Fulfillment, map the sub claim to the objectGUID from LDAP by using an Expression source.
    5. Enter the following OGNL expression to format the binary GUID as a UUID string:

      #GUID = #this.get("ds.<ldap-data-source-id>.objectGUID").toString(),
      #GUID.substring(6,8) + #GUID.substring(4,6) + #GUID.substring(2,4) + #GUID.substring(0,2) + "-" +
      #GUID.substring(10,12) + #GUID.substring(8,10) + "-" +
      #GUID.substring(14,16) + #GUID.substring(12,14) + "-" +
      #GUID.substring(16,20) + "-" + #GUID.substring(20,32)

      Replace <ldap-data-source-id> with the ID of your LDAP Data Store in PingFederate.

  3. Configure OAuth and OIDC scopes.

    Ensure PingFederate allows the standard OIDC scopes requested by Developer Hub.

    1. Navigate to System > OAuth Scopes.
    2. Ensure email and profile are added to the Common Scopes list.
  4. Bridge the contract to the OIDC policy.

    Configure the policy to deliver the transformed UUID through the sub claim in the ID token and UserInfo endpoint.

    1. Access Token Mapping: Map the sub field from rhdh-contract to your Access Token Manager.
    2. OIDC Policy Fulfillment: Fulfill the sub claim by selecting Access Token as the source and sub as the value.
    3. Enable Delivery: In the OIDC Policy Attribute Contract, select the ID Token and UserInfo checkboxes for the sub claim.
    4. Extend Contract: Add ldap_uuid to the Attribute Contract and map it to the sub value by using the Access Token to ensure consistency.
  5. Create the OIDC client.

    1. In PingFederate, go to Applications > OAuth Clients and click Add Client.
    2. Under Client Authentication, select Client Secret, generate a secret, and save it.
    3. Enter the Redirect URI: https://<my_developer_hub_domain>/api/auth/oidc/handler/frame.
    4. Under Allowed Grant Types, select Authorization Code.
    5. Under OpenID Connect > Policy, select the OIDC policy you created.
    6. Save the following values for the next step:

      1. Client ID
      2. Client Secret
      3. OIDC metadata URL: The .well-known/openid-configuration endpoint URL for your PingFederate instance.
  6. Create a long, complex, and unique string to use as the Developer Hub session secret key.
  7. Add your PingFederate credentials and the session secret key to Developer Hub, by adding the following key-value pairs to your Developer Hub secrets. You can use these secrets in the Developer Hub configuration files by using their environment variable name.

    AUTH_OIDC_CLIENT_ID
    Enter the saved Client ID.
    AUTH_OIDC_CLIENT_SECRET
    Enter the saved Client Secret.
    AUTH_OIDC_METADATA_URL
    Enter the saved OIDC metadata URL.
    SESSION_SECRET
    Enter the created session secret key.
  8. Enable session support by adding the session secret to your app-config.yaml file:

    auth:
      session:
        secret: ${SESSION_SECRET}
  9. Enable the PingFederate authentication provider with the LDAP UUID matching resolver by adding the OIDC provider section in your app-config.yaml file:

    auth:
      environment: production
      providers:
        oidc:
          production:
            metadataUrl: ${AUTH_OIDC_METADATA_URL}
            clientId: ${AUTH_OIDC_CLIENT_ID}
            clientSecret: ${AUTH_OIDC_CLIENT_SECRET}
            signIn:
              resolvers:
                - resolver: oidcLdapUuidMatchingAnnotation
                  ldapUuidKey: sub
    signInPage: oidc
    environment: production
    Mark the environment as production to hide the Guest login on the Developer Hub home page.
    metadataUrl
    Enter your PingFederate OIDC metadata URL, defined earlier.
    clientId
    Enter your Developer Hub application client ID in PingFederate, defined earlier.
    clientSecret
    Enter your Developer Hub application client secret in PingFederate, defined earlier.
    oidcLdapUuidMatchingAnnotation
    Match the authenticated user to an LDAP catalog entity by using the LDAP UUID. By default, Developer Hub attempts to match the ldap_uuid claim from the UserInfo endpoint to the LDAP catalog entity.
    ldapUuidKey
    Enter the claim key containing the LDAP UUID. Set to sub to use the sub claim, which contains the transformed UUID from the PingFederate policy contract.
    signInPage
    Enter oidc to enable the OIDC provider as the default sign-in provider.

Verification

  1. Go to the Developer Hub login page.
  2. Verify that the Developer Hub sign-in page displays Sign in using OIDC and the Guest user sign-in is disabled.
  3. Log in with OIDC by using your PingFederate user credentials.

10.2.6.8. Enable GitHub as an auxiliary authentication provider

If your primary authentication provider is not GitHub, you can configure GitHub as an auxiliary provider to grant users the GitHub permissions needed for templates or plugins, without re-resolving user identities.

Prerequisites

  • You have enough permissions in GitHub to create and manage a GitHub App.

    Tip

    Alternatively, ask your GitHub administrator to prepare the required GitHub App.

  • You have added a custom Developer Hub application configuration, and have enough permissions to change it.
  • You have configured a primary authentication provider to provision user and group identities to the Red Hat Developer Hub software catalog, and establish Developer Hub user sessions.

Procedure

  1. Add the auth.providers.github section to your app-config.yaml file:

    auth:
      providers:
        github:
          production:
            clientId: ${GITHUB_APP_CLIENT_ID}
            clientSecret: ${GITHUB_APP_CLIENT_SECRET}
            disableIdentityResolution: true

    where: clientId:: Enter the configured secret variable name: ${GITHUB_APP_CLIENT_ID}.

    clientSecret
    Enter the configured secret variable name: ${GITHUB_APP_CLIENT_SECRET}.
    disableIdentityResolution
    Enter true to skip user identity resolution for this provider to enable sign-in from an auxiliary authentication provider.
    Warning

    Do not enable this setting on the primary authentication provider you plan on using for sign-in and identity management.

  2. To disable the guest login option, in the app-config.yaml file, set the authentication environment to production:

    auth:
      environment: production

Verification

  1. Go to the Developer Hub login page.
  2. Log in with your primary authentication provider account.
  3. In the top user menu, go to Settings > Authentication Providers.
  4. In the GitHub line, click the Sign in button and log in.
  5. In the GitHub line, the button displays Sign out.

10.2.7. Connect your platform to external identity providers and APIs

10.2.7.1. Connect your platform to external identity providers and APIs

Enable authentication with external services to allow Red Hat Developer Hub to communicate with secondary identity providers and external APIs.

10.2.7.2. Configure service-to-service authentication to secure API calls

10.2.7.2.1. Configure service-to-service authentication to secure API calls

You can configure service-to-service authentication to secure communication between services, including plugin-to-plugin and external-service-to-plugin communication.

Important

The availability of service-to-service authentication might vary for REST APIs. Each plugin defines the restrictions on this feature. Consult your specific plugin’s documentation for detailed limitations.

For example, the RBAC plugin supports exclusively all GET requests, but no POST requests.

10.2.7.2.2. Use a static token

You can use a static token to enable service-to-service authentication. This method is simpler to set up than JWKS tokens but requires careful token management to ensure security. * Following security best practices.

Some security best practices when using static tokens include:

Regular rotation
Rotate tokens on a regular schedule to limit the impact of potential leaks. Document the rotation process to ensure consistency.
Secure storage
Never store tokens in plain text in the app-config.yaml configuration file. Instead, use the environment variable mechanism available in Developer Hub.
Access control
Implement the principle of least privilege, restricting tokens to specific plugins and operations; regularly review and update access permissions.
Analyze logs
Monitor and track token usage to identify unusual patterns and set up alerts for failed authentication attempts if you have a monitoring system integration available.
Documentation
Document all authentication methods in use and keep an inventory of all tokens and their purposes, and keep security policies up to date.

Static token authentication might be a good solution for simple, non-critical scenarios, such as:

Development and testing environments
These require quick setup and configuration, simple debugging and troubleshooting, and easy integration with development tools. Static token authentication can be an easy option, especially when using ephemeral testing environments.
Simple automation tasks
Basic CI/CD pipelines, simple maintenance scripts, and basic monitoring systems.
Internal tools and utilities
Development tools, testing frameworks, and internal automation scripts.

However, static token authentication might not be suitable for:

  • Production environments with high security requirements.
  • Systems handling sensitive data.
  • Large-scale deployments with many external services.
  • Environments requiring frequent token rotation.

Prerequisites

  • You have administrative access to configure Developer Hub in your OpenShift cluster.

Procedure

  1. Generate a secure token.

    You can use a tool such as Node.js:

    $ node -p'require('crypto').randomBytes(24).toString('base64')'

    This command generates a 24-byte random value and encodes it in base64 format. The resulting token is sufficiently strong for authentication purposes, and properly encoded for use in HTTP headers.

  2. Add the generated token in your Developer Hub secrets in OpenShift to define the <YOUR_SERVICE_TOKEN_ENV_VAR> environment variable where your services can access it.
  3. Add the generated token or JWKS URL to your app-config.yaml Developer Hub configuration file in OpenShift.

    backend:
      auth:
        - type: static
          options:
            token: "$<YOUR_SERVICE_TOKEN_ENV_VAR>"
            subject: "<your_service_name>"
          accessRestrictions:
            - plugin: "<target_plugin_name>"
    type
    Enter static to specify that authentication is using a static token.
    options

    Enter the configuration options for static token authentication.

    token
    Enter the environment variable name from the earlier step.
    subject
    (Optional) Enter a unique identifier for the service that will be using this token.
    plugin
    (Optional) Enter the name of the target plugin that the service will communicate with.
  4. Use the token in the Authorization header of your service requests.

    When making requests from one service to another, include the static token in the Authorization header as follows:

    Authorization: Bearer <your_generated_token>

    Replace <your_generated_token> with the actual token you generated in step 1.

    For instance, to list all available locations in the catalog by using the curl command, you would use:

    $ curl --location --request GET 'https://<my_developer_hub_domain>/api/catalog/locations' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <your_generated_token>'

Verification

  • In the Audit Logs of the service receiving the request, verify that Developer Hub authenticated the request successfully by using the subject value as the actor.
10.2.7.2.3. Use JSON web key sets (JWKS) tokens

You can use JSON Web Key Sets (JWKS) tokens to enable service-to-service authentication.

Consider using JWKS tokens when you need a more secure and scalable authentication method compared to static tokens. While JWKS tokens require more setup and configuration, they offer enhanced security features that are crucial for production environments and sensitive applications:

Asymmetric encryption
Your trusted Identity Provider issues JWKS tokens by using asymmetric encryption. JWKS uses a pair of shared keys: one public, one private, instead of a single shared static token. The Identity Provider signs the JSON Web Token (JWT) with its private key, then Developer Hub verifies it using the public key fetched from the JWKS endpoint. Developer Hub can validate these tokens without sharing secret keys directly. This means Developer Hub never has access to the private signing key, reducing the risk of compromise.
Easy key rotation
The Identity Provider can rotate signing keys regularly without requiring changes to Developer Hub afterward. This minimizes downtime and enhances security.
Ability to validate claims
JWKS tokens include claims such as issuer and audience. Developer Hub can verify these claims to ensure the token is from a trusted source and prevent the external service from using the token in unintended contexts.

The diagram illustrates the authentication flow between an external service and Developer Hub:

  • The external service requests, receives, and returns an access token from the identity provider to request a resource from Developer Hub.
  • The identity provider issues a JWKS token signed with its private key, and provides the public key via the JWKS endpoint.
  • Developer Hub receives and validates the token and its claims.
The diagram illustrates the authentication flow between an external service and Developer Hub.

Prerequisites

  • You have administrative access to configure Developer Hub in your OpenShift cluster.
  • Developer Hub can access a JWKS endpoint available from your Identity Provider.
  • You have configured the external service to obtain a JWT from your Identity Provider and include it in the Authorization header of requests to Developer Hub.

Procedure

  • Add the JWKS URL to your app-config.yaml Developer Hub configuration file:

    backend:
      auth:
        externalAccess:
          - type: jwks
            options:
              url: <your_jwks_endpoint>
              algorithm: RS256
              issuer: <your_issuer_claim>
              audience: <your_audience_claim>
              subjectPrefix: <your_subject_prefix>

    where:

    type
    Enter jwks to specify that authentication is using JWKS tokens.
    options

    Enter the configuration options for JWKS authentication.

    url
    Enter the URL of your JWKS endpoint, such as http://your-idp.example.com/well-known/jwks.json.
    algorithm
    (Optional) Enter the signing algorithm used by your Identity Provider, such as RS256.
    issuer
    (Optional) Enter the expected issuer claim in the token iss field, such as http://your-idp.example.com.
    audience
    (Optional) Enter the expected audience claim in the token aud field, such as management.
    subjectPrefix
    (Optional) Enter a prefix to add to the subject claim, and to display in the Audit Log for debugging and tracking purposes, such as your_prefix.
10.2.7.2.4. Set access restrictions to external service tokens

By default, when you configure service-to-service access in Red Hat Developer Hub, any external service with a valid token has unrestricted access to all backend plugins and actions. To limit the scope of an external service, you can define access restrictions.

Procedure

  1. Restrict access to specific plugins.

    For example, to restrict access to the catalog plugin for the static tokens, add the following accessRestrictions section to your app-config.yaml Developer Hub configuration file:

    backend:
      auth:
        externalAccess:
          - type: static
              accessRestrictions:
              - plugin: catalog
    type
    Specify whether this is a jwks or static token.
    plugin
    Specify the allowed plugin, such as catalog, scaffolder, or techdocs.

    With this configuration:

    1. The token is only allowed to make requests to the catalog plugin.
    2. The token has unrestricted access to all actions within the catalog plugin.
  2. Restrict access by action attributes, to filter permissions based on what kind of action to allow.

    List the specific actions defined by the permission, such as create and read.

    backend:
      auth:
        externalAccess:
          - type: jwks
            accessRestrictions:
              - plugin: catalog
                permissionAttribute:
                  action:
                    - create
                    - read
  3. Restrict access by explicit permission IDs, to control access at the permission rule level.

    List the exact ID of the permission to allow.

    backend:
      auth:
        externalAccess:
          - type: jwks
            accessRestrictions:
              - plugin: catalog
                permission:
                  - catalog.entity.create
                  - catalog.entity.read

    By choosing between explicit permission IDs and action-based attributes, you can strike the right balance between precision and flexibility depending on your external service needs.

10.2.8. Configure session expiration and auto-logout policies

10.2.8.1. Configure session expiration and auto-logout policies

You can manage how long users stay authenticated in Red Hat Developer Hub by configuring session duration and auto-logout settings.

10.2.8.2. Session management

Session management in Red Hat Developer Hub involves multiple mechanisms that control how long users stay authenticated and what happens when sessions expire.

10.2.8.2.1. What happens when a session expires

When a session approaches expiration, Developer Hub can display a pre-expiration warning dialog that includes a countdown timer. The timing of this warning depends on how you configure the auto-logout feature.

After the session expires, Developer Hub redirects the user to the login page. To continue working, the user must re-authenticate with the configured identity provider and is then returned to Developer Hub.

10.2.8.2.2. AutoLogout (frontend inactivity)

The AutoLogout feature monitors user activity in the browser and logs out the user after a configurable idle period. AutoLogout revokes the refresh token for Developer Hub, but does not end the Identity Provider (IdP) session. The logout mechanism is the same as if you manually logout from the user settings page.

You configure AutoLogout under the auth.autologout section of your app-config.yaml file.

10.2.8.2.3. Session duration (provider-level)

Session duration controls the absolute session lifetime regardless of user activity. This is a backend HTTP-only cookie configuration. When this duration elapses, no warning popup is displayed. Instead, the user is redirected to the sign-in page the next time they interact with Developer Hub, such as navigating to a new page or refreshing the browser.

You configure session duration per provider by using the auth.providers.<name>.<env>.sessionDuration parameter in your app-config.yaml file. This parameter accepts milliseconds, ISO duration, or human-readable duration values (for example, 24h, 2 days).

10.2.8.2.4. Identity Provider session settings

Your Identity Provider (IdP), such as Red Hat Build of Keycloak, GitHub, Microsoft Azure, or GitLab, maintains its own session timeout independently of Developer Hub.

Signing out of Developer Hub does not end the IdP SSO session. This is expected behavior. If the IdP session is still active when a user signs back in to Developer Hub, re-authentication might be seamless, with no password prompt.

10.2.8.2.5. How the mechanisms interact

The three session management mechanisms operate at different layers:

AutoLogout
Triggers on user inactivity in the browser. Frontend-only: does not revoke tokens or end server-side sessions.
Session duration
Controls the absolute session lifetime on the server side. The session expires after the configured duration regardless of user activity. No warning popup is displayed; the user is redirected to the sign-in page on next interaction.
Identity Provider session
Outlives Developer Hub sign-out. A user might re-enter Developer Hub without a password prompt if the IdP session is still active.

The mechanism with the shortest timeout takes effect first. For example, if AutoLogout is set to 30 minutes of idle time but the session duration is set to 15 minutes, the session expires after 15 minutes regardless of user activity.

10.2.8.3. Configure session management

You can configure the session duration for your authentication provider in Red Hat Developer Hub.

Prerequisites

  • You have administrative access to the Red Hat Developer Hub configuration files.

Procedure

  1. To set the absolute session lifetime for an authentication provider, add the sessionDuration parameter to your app-config.yaml file:

    auth:
      providers:
        <name>:
          <env>:
            sessionDuration: 24h
    sessionDuration

    Enter the session lifetime in milliseconds, ISO duration, or human-readable format (for example, 24h, 2 days). When this duration elapses, the session expires regardless of user activity.

    This parameter is not set by default.

  2. Restart the Red Hat Developer Hub application to apply the changes.

10.2.8.4. Enable auto-logout for inactive users

To enhance security, you can configure Red Hat Developer Hub to automatically log out users after a specified period of inactivity. This helps prevent unauthorized access to stale user sessions.

Procedure

  1. Add the auth.autologout section to your {my-app-config.yaml} file.

    auth:
      autologout:
        enabled: true
        idleTimeoutMinutes: 60
        promptBeforeIdleSeconds: 10
        useWorkerTimers: false
        logoutIfDisconnected: true

    where:

    enabled

    Enter true to enable auto-logout.

    Enter false to disable auto-logout.

    The default value is false.

    idleTimeoutMinutes

    (Optional) Enter the number of minutes of inactivity before automatically logging out the user.

    The default value is 60 minutes.

    promptBeforeIdleSeconds

    (Optional) Enter the number of seconds before the auto-logout occurs to prompt the user about the pending logout.

    The default value is 10 seconds.

    useWorkerTimers

    (Optional) Enter false to use main thread timers, when your browser does not support web workers. Your browser might stop timers in inactive tabs, which can affect the auto-logout functionality.

    Enter true to use web worker timers for tracking user activity, and avoid issues when your browser stops timers in inactive tabs.

    The default value is false.

    logoutIfDisconnected

    (Optional) Enter true to log out the users with no active connection, in case of network issues, or when they have no active Developer Hub tab open in their browser.

    Enter false to keep the user logged in during temporary disconnections, or when they have no active Developer Hub tab open in their browser.

    The default value is true.

  2. Restart the Red Hat Developer Hub application to apply the changes.

Verification

  1. Log in to the Red Hat Developer Hub application.
  2. Remain inactive for the duration specified in idleTimeoutMinutes.
  3. Observe that a prompt is displayed before the auto-logout occurs, as specified in promptBeforeIdleSeconds.
  4. Confirm that you are automatically logged out after the inactivity period.

10.2.8.5. Reduce the size of issued tokens

If user identity tokens grow large and cause HTTP errors, you can use the omitIdentityTokenOwnershipClaim flag to remove the ent claim from the JWT payload and reduce token size.

Procedure

  • In the app-config.yaml file, set omitIdentityTokenOwnershipClaim to true as follows:

    auth:
      omitIdentityTokenOwnershipClaim: true

10.3. Define authorization policies to restrict access based on user roles

10.3.1. Define authorization policies to restrict access based on user roles

Configure role-based access control (RBAC) to define roles, permissions, and policies for users and groups in Developer Hub.

Role-based access control (RBAC) is a security concept that defines how to control access to resources in a system by specifying a mapping between users of the system and the actions that those users can perform on resources in the system. You can use RBAC to define roles with specific permissions and then assign the roles to users and groups.

RBAC on Developer Hub is built on top of the Permissions framework, which defines RBAC policies in code. Rather than defining policies in code, you can use the Developer Hub RBAC feature to define policies in a declarative fashion by using a simple CSV based format. You can define the policies by using Developer Hub web interface or REST API instead of editing the CSV directly.

An administrator can define authorizations in Developer Hub by taking the following steps:

  1. Enable the RBAC feature and give authorized users access to the feature.
  2. Define roles and policies by combining the following methods:

    • The Developer Hub policy administrator uses the Developer Hub web interface or REST API.
    • The Developer Hub administrator edits the main Developer Hub configuration file.
    • The Developer Hub administrator edits external files.

10.3.2. Role-based access control in Developer Hub

Administrators can authorize users to perform actions and define what users can do in Developer Hub.

Role-based access control (RBAC) is a security concept that defines how to control access to resources in a system by specifying a mapping between users of the system and the actions that those users can perform on resources in the system. You can use RBAC to define roles with specific permissions and then assign the roles to users and groups.

RBAC on Developer Hub is built on top of the Permissions framework, which defines RBAC policies in code. Rather than defining policies in code, you can use the Developer Hub RBAC feature to define policies in a declarative fashion by using a simple CSV based format. You can define the policies by using Developer Hub web interface or REST API instead of editing the CSV directly.

An administrator can define authorizations in Developer Hub by taking the following steps:

  1. Enable the RBAC feature and give authorized users access to the feature.
  2. Define roles and policies by combining the following methods:

    • The Developer Hub policy administrator uses the Developer Hub web interface or REST API.
    • The Developer Hub administrator edits the main Developer Hub configuration file.
    • The Developer Hub administrator edits external files.

10.3.3. Enable the RBAC plugin

Enable the RBAC plugin and declare policy administrators to manage permissions and access the RBAC REST API and Web UI.

The role-based access control (RBAC) feature is disabled by default. Enable the RBAC plugin and declare policy administrators to start using RBAC features.

The permission policies for users and groups in the Developer Hub are managed by permission policy administrators. Only permission policy administrators can access the RBAC REST API.

Procedure

  1. The RBAC plugin is installed but disabled by default. To enable the ./dynamic-plugins/dist/backstage-community-plugin-rbac plugin, edit your dynamic-plugins.yaml with the following content.

    dynamic-plugins.yaml fragment

    plugins:
      - package: ./dynamic-plugins/dist/backstage-community-plugin-rbac
        disabled: false

    See Installing and viewing plugins in Red Hat Developer Hub.

  2. Declare policy administrators to enable a select number of authenticated users to configure RBAC policies through the REST API or Web UI, instead of changing the CSV file directly.

    The permissions can be specified in a separate CSV file referenced in your my-rhdh-app-config config map, or permissions can be created using the REST API or Web UI.

    To declare users such as <your_policy_administrator_name> as policy administrators, edit your custom Developer Hub ConfigMap, such as app-config-rhdh, and add following code to the app-config.yaml content:

    app-config.yaml fragment

    permission:
      enabled: true
      rbac:
        admin:
          users:
            - name: user:default/<your_policy_administrator_name>

  3. To display the available permissions provided by installed plugins in the Developer Hub UI, you must supply the corresponding list of plugin IDs. There are two ways to do this, by updating your application configuration or by using the RBAC REST API permissions endpoint.

    1. To supply plugins by updating your application configuration, you can specify the plugins with permissions in your app-config.yaml file as follows:

      app-config.yaml fragment

      permission:
        enabled: true
        rbac:
          admin:
            users:
              - name: user:default/<your_policy_administrator_name>
          pluginsWithPermission:
            - catalog
            - scaffolder
            - permission

    2. To specify the plugins with permissions by using the RBAC REST API permissions endpoint, see the RBAC REST API permissions endpoint.

Verification

  1. Sign out from the existing Red Hat Developer Hub session and log in again using the declared policy administrator account.
  2. With RBAC enabled, most features are disabled by default.

    1. Navigate to the Catalog page in RHDH. The Create button is not visible. You cannot create new components.
    2. Navigate to the API page. The Register button is not visible.

Next steps

  • Explicitly enable permissions to resources in Developer Hub.

10.3.4. Determine your policy source

Identify the source of permission policies and roles to keep data consistency and find which source controls each resource.

You can configure Red Hat Developer Hub policy and roles by using different sources. To keep data consistency, Developer Hub associates each permission policy and role with one unique source. You can only use this source to change the resource.

The available sources are:

Configuration file

Configure roles and policies in the Developer Hub app-config.yaml configuration file, for instance to declare your policy administrators.

The Configuration file pertains to the default role:default/rbac_admin role provided by the RBAC plugin. The default role has limited permissions to create, read, update, delete permission policies or roles, and to read catalog entities.

Note

In case the default permissions are insufficient for your administrative requirements, you can create a custom admin role with the required permission policies.

REST API
Configure roles and policies by using the Developer Hub Web UI or by using the REST API.
CSV file
Configure roles and policies by using external CSV files.
Legacy

The legacy source applies to policies and roles defined before RBAC backend plugin version 2.1.3, and is the least restrictive among the source location options.

Important

Replace the permissions and roles using the legacy source with the permissions using the REST API or the CSV file sources.

Procedure

  • To find the source of a role or policy, use a GET request.

10.3.5. Design policy rules

Design policy rules carefully to avoid permission conflicts and unintended access denials in Developer Hub.

Carefully design your policies to avoid permission conflicts that can result in unintended access denials.

Red Hat Developer Hub applies policies as follows:

  • The default policy is deny.
  • A conditional rule overrides a basic rule.
  • A deny basic rule overrides an allow basic rule.
  • An allow conditional rule overrides a deny basic rule.
  • A deny conditional rule overrides an allow conditional rule.

Procedure

  1. Use allow rules to explicitly allow access.
  2. Avoid creating deny rules unless you know precisely how they can affect existing basic allow rules and existing conditional rules.

10.3.6. Manage roles using the Web UI

10.3.6.1. Manage roles using the Web UI

Use the Developer Hub Web UI to create, modify, and delete roles and assign permissions to users and groups.

Policy administrators can use the Developer Hub web interface (Web UI) to assign specific roles and permissions to individual users or groups. Assigning roles ensures that access to resources and functionalities is regulated across the Developer Hub.

With the policy administrator role in Developer Hub, you can assign permissions to users and groups. This role allows you to view, create, change, and delete the roles by using the Developer Hub Web UI.

10.3.6.2. Create a role

Create a role in Developer Hub by using the Web UI to define permissions, users, and groups.

You can create a role in the Red Hat Developer Hub using the Web UI.

Prerequisites

  • If RBAC is enabled, you have a role with the following permissions: policy.entity.create, policy.entity.read, catalog.entity.read.

Procedure

  1. Go to Administration at the bottom of the sidebar in the Developer Hub.

    The RBAC tab is displayed, showing all the created roles in the Developer Hub.

  2. (Optional) Click any role to view the role information on the OVERVIEW page.
  3. Click CREATE to create a role.
  4. Enter the name and description of the role in the given fields and click NEXT.
  5. Add users and groups using the search field, and click NEXT.
  6. Select Plugin and Permission from the drop-downs in the Add permission policies section.
  7. Select or clear the Policy that you want to set in the Add permission policies section, and click NEXT.
  8. Review the added information in the Review and create section.
  9. Click CREATE.

Verification

The created role is displayed in the list available in the RBAC tab.

10.3.6.3. Edit a role

Edit a role in Developer Hub by using the Web UI to change role details, users, groups, and permission policies.

You can edit a role in the Red Hat Developer Hub using the Web UI.

Note

The policies generated from a policy.csv or ConfigMap file cannot be edited or deleted using the Developer Hub Web UI.

Prerequisites

  • If RBAC is enabled, you have a role with the following permissions: policy.entity.update, policy.entity.read, catalog.entity.read.
  • The role that you want to edit is created in the Developer Hub.

Procedure

  1. Go to Administration at the bottom of the sidebar in the Developer Hub.

    The RBAC tab is displayed, showing all the created roles in the Developer Hub.

  2. (Optional) Click any role to view the role information on the OVERVIEW page.
  3. Select the edit icon for the role that you want to edit.
  4. Edit the details of the role, such as name, description, users and groups, and permission policies, and click NEXT.
  5. Review the edited details of the role and click SAVE.

Verification

  1. After saving the changes, you can view the edited details of the role on the OVERVIEW page of the role.
  2. You can also edit a role’s users and groups or permissions by using the edit icon on the Users and Groups or Permissions cards on the OVERVIEW page.

10.3.6.4. Delete a role

Delete a role in Developer Hub by using the Web UI to remove roles that are no longer needed.

You can delete a role in the Red Hat Developer Hub using the Web UI.

Note

The policies generated from a policy.csv or ConfigMap file cannot be edited or deleted using the Developer Hub Web UI.

Prerequisites

  • If RBAC is enabled, you have a role with the following permissions: policy.entity.delete, policy.entity.read, catalog.entity.read.
  • The role that you want to delete is created in the Developer Hub.

Procedure

  1. Go to Administration at the bottom of the sidebar in the Developer Hub.

    The RBAC tab is displayed, showing all the created roles in the Developer Hub.

  2. (Optional) Click any role to view the role information on the OVERVIEW page.
  3. Select the delete icon from the Actions column for the role that you want to delete.

    The Delete this role? pop-up is displayed on the screen.

  4. Click DELETE.

10.3.7. Manage policies using the REST API

10.3.7.1. Manage policies using the REST API

Automate the maintenance of permission policies and roles by using the Developer Hub RBAC REST API.

To automate the maintenance of Red Hat Developer Hub permission policies and roles, you can use Developer Hub role-based access control (RBAC) REST API.

You can perform the following actions with the REST API:

  • Retrieve information about:

    • All permission policies
    • Specific permission policies
    • Specific roles
    • Static plugins permission policies
  • Create, update, or delete:

    • Permission policy
    • Role

10.3.7.2. Send requests by using the curl utility

Send RBAC REST API requests by using the curl utility to create, update, and delete roles and permission policies.

You can send RBAC REST API requests by using the curl utility.

Procedure

  1. Find your Bearer token to authenticate to the REST API.

    1. In your browser, open the web console Network tab.
    2. In the main screen, reload the Developer Hub Homepage.
    3. In the web console Network tab, search for the query?term= network call.
    4. Save the token in the response JSON for the next steps.
  2. In a terminal, run the curl command and review the response:

    GET request, or DELETE request not requiring JSON body data

    Enter a curl command with the following parameters and review the response:

    $ curl -v \
      -H "Authorization: Bearer <token>" \
      -X <method> "https://<my_developer_hub_domain>/<endpoint>" \
    POST or PUT request, or DELETE request requiring JSON body data

    Enter a curl command with the following parameters and review the response:

    $ curl -v -H "Content-Type: application/json" \
      -H "Authorization: Bearer <token>" \
      -X <method> "https://<my_developer_hub_domain>/<endpoint>" \
      -d <body>
    <token>
    Enter your saved authorization token.
    <method>

    Enter the HTTP method for your API endpoint.

    GET
    To retrieve specified information from a specified resource endpoint.
    POST
    To create or update a resource.
    PUT
    To update a resource.
    DELETE
    To delete a resource.
    https://<my_developer_hub_domain>
    Enter your Developer Hub URL.
    <endpoint>
    Enter the API endpoint to which you want to send a request, such as /api/permission/policies.
    <body>

    Enter the JSON body with data that your API endpoint requires with the HTTP POST, or PUT request, and might require with the HTTP DELETE request.

    • To create a role:

      $ curl -v -H "Content-Type: application/json" \
        -H "Authorization: Bearer <token>" \
        -X POST "https://<my_developer_hub_domain>/api/permission/roles" \
        -d '{
            "memberReferences": ["group:default/example"],
            "name": "role:default/test",
            "metadata": { "description": "This is a test role" }
          }'
    • To update a role:

      $ curl -v -H "Content-Type: application/json" \
        -H "Authorization: Bearer <token>" \
        -X PUT "https://<my_developer_hub_domain>/api/permission/roles/role/default/test" \
        -d '{
                "oldRole": {
                  "memberReferences":  [ "group:default/example" ],
                  "name": "role:default/test"
                },
                "newRole": {
                  "memberReferences": [ "group:default/example", "user:default/test" ],
                  "name": "role:default/test"
                }
              }'
    • To create a permission policy:

      $ curl -v -H "Content-Type: application/json" \
        -H "Authorization: Bearer $token" \
        -X POST "https://<my_developer_hub_domain>/api/permission/policies" \
        -d '[{
            "entityReference":"role:default/test",
            "permission": "catalog-entity",
            "policy": "read", "effect":"allow"
          }]'
    • To update a permission policy:

      $ curl -v -H "Content-Type: application/json" \
        -H "Authorization: Bearer $token" \
        -X PUT "https://<my_developer_hub_domain>/api/permission/policies/role/default/test" \
        -d '{
               "oldPolicy": [
                 {
                   "permission": "catalog-entity", "policy": "read", "effect": "allow"
                 }
               ],
               "newPolicy":
                 [
                   {
                     "permission": "policy-entity", "policy": "read", "effect": "allow"
                   }
                 ]
             }'
    • To create a condition:

      $ curl -v -H "Content-Type: application/json" \
        -H "Authorization: Bearer $token" \
        -X POST "https://<my_developer_hub_domain>/api/permission/roles/conditions" \
        -d '{
            "result": "CONDITIONAL",
            "roleEntityRef": "role:default/test",
            "pluginId": "catalog",
            "resourceType": "catalog-entity",
            "permissionMapping": ["read"],
            "conditions": {
              "rule": "IS_ENTITY_OWNER",
              "resourceType": "catalog-entity",
              "params": {"claims": ["group:default/janus-authors"]}
            }
          }'
    • To update a condition:

      $ curl -v -H "Content-Type: application/json" \
        -H "Authorization: Bearer $token" \
        -X PUT "https://<my_developer_hub_domain>/api/permission/roles/conditions/1" \
        -d '{
                "result":"CONDITIONAL",
                "roleEntityRef":"role:default/test",
                "pluginId":"catalog",
                "resourceType":"catalog-entity",
                "permissionMapping": ["read",  "update", "delete"],
                "conditions": {
                  "rule": "IS_ENTITY_OWNER",
                  "resourceType": "catalog-entity",
                  "params": {"claims": ["group:default/janus-authors"]}
                }
             }'

Verification

  • Review the returned HTTP status code:

    200 OK
    The request was successful.
    201 Created
    The request resulted in a new resource being successfully created.
    204 No Content
    The request was successful, and the response payload has no more content.
    400 Bad Request
    Input error with the request.
    401 Unauthorized
    Lacks valid authentication for the requested resource.
    403 Forbidden
    Refusal to authorize request.
    404 Not Found
    Could not find requested resource.
    409 Conflict
    Request conflict with the current state and the target resource.

10.3.7.3. Send requests by using a REST client

Send RBAC REST API requests by using any REST client with authorization tokens and appropriate HTTP methods.

You can send RBAC REST API requests by using any REST client.

Procedure

  1. Find your Bearer token to authenticate to the REST API.

    1. In your browser, open the web console Network tab.
    2. In the main screen, reload the Developer Hub Homepage.
    3. In the web console Network tab, search for the query?term= network call.
    4. Save the token in the response JSON for the next steps.
  2. In your REST client, run a command with the following parameters and review the response:

    Authorization
    Enter your saved authorization token.
    HTTP method

    Enter the HTTP method for your API endpoint.

    GET
    To retrieve specified information from a specified resource endpoint.
    POST
    To create or update a resource.
    PUT
    To update a resource.
    DELETE
    To delete a resource.
    URL
    Enter your Developer Hub URL and API endpoint: https://<my_developer_hub_domain>/<endpoint>, such as https://<my_developer_hub_domain>/api/permission/policies.
    Body
    Enter the JSON body with data that your API endpoint might need with the HTTP POST request.

10.3.7.4. Send requests by using an external service

Send GET requests to the RBAC REST API from an external service authenticated with a service-to-service token.

You can send GET requests to the RBAC REST API by using an external service authenticated by using a service-to-service token.

Prerequisites

Procedure

  1. The external service sends a GET request to the RBAC REST API with the service-to-service token in the Authorization header.
  2. The RBAC REST API validates the service-to-service token, and then processes the request if the token is valid. Otherwise, the RBAC REST API returns an error response.
  3. The RBAC REST API returns the response to the external service.
  4. The external service processes the response from the RBAC REST API.

10.3.7.5. Supported REST API endpoints

10.3.7.5.1. Supported REST API endpoints

Reference information about the supported RBAC REST API endpoints for managing roles, permission policies, conditional policies, and user statistics in Developer Hub.

10.3.7.5.2. Roles

Reference information about RBAC REST API endpoints for managing roles, permissions, and conditional policies.

The RBAC REST API provides endpoints for managing roles, permissions, and conditional policies in the Developer Hub and for retrieving information about the roles and policies.

10.3.7.5.2.1. Roles

The RBAC REST API supports the following endpoints for managing roles in the Red Hat Developer Hub.

[GET] /api/permission/roles

Returns all roles in Developer Hub.

Example response (JSON):

[
  {
    "memberReferences": ["user:default/username"],
    "name": "role:default/guests"
  },
  {
    "memberReferences": [
      "group:default/groupname",
      "user:default/username"
    ],
    "name": "role:default/rbac_admin"
  }
]
[GET] /api/permission/roles/<kind>/<namespace>/<name>

Returns information for a single role in Developer Hub.

Example response (JSON):

[
  {
    "memberReferences": [
      "group:default/groupname",
      "user:default/username"
    ],
    "name": "role:default/rbac_admin"
  }
]
[POST] /api/permission/roles/<kind>/<namespace>/<name>
Creates a role in Developer Hub.
NameDescriptionTypePresence

body

The memberReferences, group, namespace, and name the new role to be created.

Request body

Required

Example request body (JSON):

+

{
  "memberReferences": ["group:default/test"],
  "name": "role:default/test_admin"
}

Example response:

+

201 Created
[PUT] /api/permission/roles/<kind>/<namespace>/<name>
Updates memberReferences, kind, namespace, or name for a role in Developer Hub.

Request parameters: The request body contains the oldRole and newRole objects:

NameDescriptionTypePresence

body

The memberReferences, group, namespace, and name the new role to be created.

Request body

Required

Example request body (JSON):

+

{
  "oldRole": {
    "memberReferences": ["group:default/test"],
    "name": "role:default/test_admin"
  },
  "newRole": {
    "memberReferences": ["group:default/test", "user:default/test2"],
    "name": "role:default/test_admin"
  }
}

Example response:

+

200 OK
[DELETE] /api/permission/roles/<kind>/<namespace>/<name>?memberReferences=<VALUE>
Deletes the specified user or group from a role in Developer Hub.
NameDescriptionTypePresence

kind

Kind of the entity

String

Required

namespace

Namespace of the entity

String

Required

name

Name of the entity

String

Required

memberReferences

Associated group information

String

Required

Example response:

+

204
[DELETE] /api/permission/roles/<kind>/<namespace>/<name>
Deletes a specified role from Developer Hub.
NameDescriptionTypePresence

kind

Kind of the entity

String

Required

namespace

Namespace of the entity

String

Required

name

Name of the entity

String

Required

Example response:

+

204
10.3.7.5.2.2. Permission policies

The RBAC REST API supports the following endpoints for managing permission policies in the Red Hat Developer Hub.

[GET] /api/permission/policies
Returns permission policies list for all users.

Example response (JSON):

+

[
  {
    "entityReference": "role:default/test",
    "permission": "catalog-entity",
    "policy": "read",
    "effect": "allow",
    "metadata": {
      "source": "csv-file"
    }
  },
  {
    "entityReference": "role:default/test",
    "permission": "catalog.entity.create",
    "policy": "use",
    "effect": "allow",
    "metadata": {
      "source": "csv-file"
    }
  },
]
[GET] /api/permission/policies/<kind>/<namespace>/<name>
Returns permission policies related to the specified entity reference.
NameDescriptionTypePresence

kind

Kind of the entity

String

Required

namespace

Namespace of the entity

String

Required

name

Name related to the entity

String

Required

Example response (JSON):

+

[
  {
    "entityReference": "role:default/test",
    "permission": "catalog-entity",
    "policy": "read",
    "effect": "allow",
    "metadata": {
      "source": "csv-file"
    }
  },
  {
    "entityReference": "role:default/test",
    "permission": "catalog.entity.create",
    "policy": "use",
    "effect": "allow",
    "metadata": {
      "source": "csv-file"
    }
  }
]
[POST] /api/permission/policies
Creates a permission policy for a specified entity.
NameDescriptionTypePresence

entityReference

Reference values of an entity including kind, namespace, and name

String

Required

permission

Permission from a specific plugin, resource type, or name

String

Required

policy

Policy action for the permission, such as create, read, update, delete, or use

String

Required

effect

Indication of allowing or not allowing the policy

String

Required

Example request body (JSON):

+

[
  {
    "entityReference": "role:default/test",
    "permission": "catalog-entity",
    "policy": "read",
    "effect": "allow"
  }
]

Example response:

+

201 Created
[PUT] /api/permission/policies/<kind>/<namespace>/<name>
Updates a permission policy for a specified entity.

Request parameters: The request body contains the oldPolicy and newPolicy objects:

NameDescriptionTypePresence

permission

Permission from a specific plugin, resource type, or name

String

Required

policy

Policy action for the permission, such as create, read, update, delete, or use

String

Required

effect

Indication of allowing or not allowing the policy

String

Required

Example request body (JSON):

+

{
  "oldPolicy": [
    {
      "permission": "catalog-entity",
      "policy": "read",
      "effect": "allow"
    },
    {
      "permission": "catalog.entity.create",
      "policy": "create",
      "effect": "allow"
    }
  ],
  "newPolicy": [
    {
      "permission": "catalog-entity",
      "policy": "read",
      "effect": "deny"
    },
    {
      "permission": "policy-entity",
      "policy": "read",
      "effect": "allow"
    }
  ]
}

Example response:

+

200
[DELETE] /api/permission/policies/<kind>/<namespace>/<name>?permission={value1}&policy={value2}&effect={value3}
Deletes a permission policy added to the specified entity.
NameDescriptionTypePresence

kind

Kind of the entity

String

Required

namespace

Namespace of the entity

String

Required

name

Name related to the entity

String

Required

permission

Permission from a specific plugin, resource type, or name

String

Required

policy

Policy action for the permission, such as create, read, update, delete, or use

String

Required

effect

Indication of allowing or not allowing the policy

String

Required

Example response:

+

204 No Content
[DELETE] /api/permission/policies/<kind>/<namespace>/<name>
Deletes all permission policies added to the specified entity.
NameDescriptionTypePresence

kind

Kind of the entity

String

Required

namespace

Namespace of the entity

String

Required

name

Name related to the entity

String

Required

Example request body (JSON):

+

[
  {
    "entityReference": "role:default/test",
    "permission": "catalog-entity",
    "policy": "delete",
    "effect": "allow"
  },
  {
    "entityReference": "role:default/test",
    "permission": "catalog-entity",
    "policy": "update",
    "effect": "allow"
  }
]

Example response:

+

204 No Content
[GET] /api/permission/plugins/policies
Returns permission policies for all static plugins.

Example response (JSON):

+

[
  {
    "pluginId": "catalog",
    "policies": [
      {
        "isResourced": true,
        "permission": "catalog-entity",
        "policy": "read"
      },
      {
        "isResourced": false,
        "permission": "catalog.entity.create",
        "policy": "create"
      },
      {
        "isResourced": true,
        "permission": "catalog-entity",
        "policy": "delete"
      },
      {
        "isResourced": true,
        "permission": "catalog-entity",
        "policy": "update"
      },
      {
        "isResourced": false,
        "permission": "catalog.location.read",
        "policy": "read"
      },
      {
        "isResourced": false,
        "permission": "catalog.location.create",
        "policy": "create"
      },
      {
        "isResourced": false,
        "permission": "catalog.location.delete",
        "policy": "delete"
      }
    ]
  },
  ...
]
[GET] /api/permission/plugins/id
Returns object with list plugin IDs:

Example response (JSON):

+

[
  {
    "ids": ["catalog", "permission"]
  }
]
[POST] /api/permission/plugins/id
Add more plugins IDs defined in the request object.

Request Parameters: object in JSON format.

Example request body (JSON):

+

[
  {
    "ids": ["scaffolder"]
  }
]

Returns a status code of 200 and JSON with actual object stored in the server:

Example response (JSON):

+

[
  {
    "ids": ["catalog", "permission", "scaffolder"]
  }
]
[DELETE] /api/permission/plugins/id
Delete plugins IDs defined in the request object.

Request Parameters: object in JSON format.

Example request body (JSON):

+

[
  {
    "ids": ["scaffolder"]
  }
]

Returns a status code of 200 and JSON with actual object stored in the server:

Example response (JSON):

+

[
  {
    "ids": ["catalog", "permission"]
  }
]
Note

To prevent an inconsistent state after a deployment restart, the REST API does not allow deletion of plugin IDs that were provided by using the application configuration. These ID values can only be removed through the configuration file.

10.3.7.5.2.3. Conditional policies

The RBAC REST API supports the following endpoints for managing conditional policies in the Red Hat Developer Hub.

[GET] /api/permission/plugins/condition-rules
Returns available conditional rule parameter schemas for the available plugins that are enabled in Developer Hub.

Example response (JSON):

+

[
   {
      "pluginId": "catalog",
      "rules": [
         {
            "name": "HAS_ANNOTATION",
            "description": "Allow entities with the specified annotation",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "annotation": {
                     "type": "string",
                     "description": "Name of the annotation to match on"
                  },
                  "value": {
                     "type": "string",
                     "description": "Value of the annotation to match on"
                  }
               },
               "required": [
                  "annotation"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "HAS_LABEL",
            "description": "Allow entities with the specified label",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "label": {
                     "type": "string",
                     "description": "Name of the label to match on"
                  }
               },
               "required": [
                  "label"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "HAS_METADATA",
            "description": "Allow entities with the specified metadata subfield",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "key": {
                     "type": "string",
                     "description": "Property within the entities metadata to match on"
                  },
                  "value": {
                     "type": "string",
                     "description": "Value of the given property to match on"
                  }
               },
               "required": [
                  "key"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "HAS_SPEC",
            "description": "Allow entities with the specified spec subfield",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "key": {
                     "type": "string",
                     "description": "Property within the entities spec to match on"
                  },
                  "value": {
                     "type": "string",
                     "description": "Value of the given property to match on"
                  }
               },
               "required": [
                  "key"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "IS_ENTITY_KIND",
            "description": "Allow entities matching a specified kind",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "kinds": {
                     "type": "array",
                     "items": {
                        "type": "string"
                     },
                     "description": "List of kinds to match at least one of"
                  }
               },
               "required": [
                  "kinds"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "IS_ENTITY_OWNER",
            "description": "Allow entities owned by a specified claim",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "claims": {
                     "type": "array",
                     "items": {
                        "type": "string"
                     },
                     "description": "List of claims to match at least one on within ownedBy"
                  }
               },
               "required": [
                  "claims"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         }
      ]
   }
   ... <another plugin condition parameter schemas>
]
[GET] /api/permission/roles/conditions/:id
Returns conditions for the specified ID.

Example response (JSON):

+

{
  "id": 1,
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/test",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["read"],
  "conditions": {
    "anyOf": [
      {
        "rule": "IS_ENTITY_OWNER",
        "resourceType": "catalog-entity",
        "params": {
          "claims": ["group:default/team-a"]
        }
      },
      {
        "rule": "IS_ENTITY_KIND",
        "resourceType": "catalog-entity",
        "params": {
          "kinds": ["Group"]
        }
      }
    ]
  }
}
[GET] /api/permission/roles/conditions
Returns list of all conditions for all roles.

Example response (JSON):

+

[
  {
    "id": 1,
    "result": "CONDITIONAL",
    "roleEntityRef": "role:default/test",
    "pluginId": "catalog",
    "resourceType": "catalog-entity",
    "permissionMapping": ["read"],
    "conditions": {
      "anyOf": [
        {
          "rule": "IS_ENTITY_OWNER",
          "resourceType": "catalog-entity",
          "params": {
            "claims": ["group:default/team-a"]
          }
        },
        {
          "rule": "IS_ENTITY_KIND",
          "resourceType": "catalog-entity",
          "params": {
            "kinds": ["Group"]
          }
        }
      ]
    }
  }
]
[POST] /api/permission/roles/conditions
Creates a conditional policy for the specified role.
NameDescriptionTypePresence

result

Always has the value CONDITIONAL

String

Required

roleEntityRef

String entity reference to the RBAC role, such as role:default/dev

String

Required

pluginId

Corresponding plugin ID, such as catalog

String

Required

permissionMapping

Array permission action, such as ['read', 'update', 'delete']

String array

Required

resourceType

Resource type provided by the plugin, such as catalog-entity

String

Required

conditions

Condition JSON with parameters or array parameters joined by criteria

JSON

Required

name

Name of the role

String

Required

metadata.description

The description of the role

String

Optional

Example request body (JSON):

+

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/test",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["read"],
  "conditions": {
    "rule": "IS_ENTITY_OWNER",
    "resourceType": "catalog-entity",
    "params": {
      "claims": ["group:default/team-a"]
    }
  }
}

Example response (JSON):

+

{
  "id": 1
}
[PUT] /permission/roles/conditions/:id
Updates a condition policy for a specified ID.
NameDescriptionTypePresence

result

Always has the value CONDITIONAL

String

Required

roleEntityRef

String entity reference to the RBAC role, such as role:default/dev

String

Required

pluginId

Corresponding plugin ID, such as catalog

String

Required

permissionMapping

Array permission action, such as ['read', 'update', 'delete']

String array

Required

resourceType

Resource type provided by the plugin, such as catalog-entity

String

Required

conditions

Condition JSON with parameters or array parameters joined by criteria

JSON

Required

name

Name of the role

String

Required

metadata.description

The description of the role

String

Optional

Example request body (JSON):

+

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/test",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["read"],
  "conditions": {
    "anyOf": [
      {
        "rule": "IS_ENTITY_OWNER",
        "resourceType": "catalog-entity",
        "params": {
          "claims": ["group:default/team-a"]
        }
      },
      {
        "rule": "IS_ENTITY_KIND",
        "resourceType": "catalog-entity",
        "params": {
          "kinds": ["Group"]
        }
      }
    ]
  }
}

Example response:

+

200
[DELETE] /api/permission/roles/conditions/:id
Deletes a conditional policy for the specified ID.

Example response:

+

204
10.3.7.5.2.4. User statistics

The licensed-users-info-backend plugin exposes various REST API endpoints to retrieve data related to logged-in users.

No additional configuration is required for the licensed-users-info-backend plugin. If the RBAC backend plugin is enabled, then an administrator role must be assigned to access the endpoints, as the endpoints are protected by the policy.entity.read permission.

The base URL for user statistics endpoints is http://SERVER:PORT/api/licensed-users-info, such as http://localhost:7007/api/licensed-users-info.

[GET] /users/quantity
Returns the total number of logged-in users.

Example request:

+

curl -X GET "http://localhost:7007/api/licensed-users-info/users/quantity" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token"

Example response:

+

{ "quantity": "2" }
[GET] /users
Returns a list of logged-in users with their details.

Example request:

+

curl -X GET "http://localhost:7007/api/licensed-users-info/users" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token"

Example response:

+

[
  {
    "userEntityRef": "user:default/dev",
    "lastTimeLogin": "Thu, 22 Aug 2024 16:27:41 GMT",
    "displayName": "John Leavy",
    "email": "dev@redhat.com"
  }
]
[GET] /users
Returns a list of logged-in users in CSV format.

Example request:

+

curl -X GET "http://localhost:7007/api/licensed-users-info/users" \
-H "Content-Type: text/csv" \
-H "Authorization: Bearer $token"

Example response:

+

userEntityRef,displayName,email,lastTimeLogin
user:default/dev,John Leavy,dev@redhat.com,"Thu, 22 Aug 2024 16:27:41 GMT"
10.3.7.5.3. User statistics

Monitor active user counts and download user lists by using the licensed-users-info-backend plugin for licensing transparency.

In Red Hat Developer Hub, the licensed-users-info-backend plugin provides statistical information about the logged-in users by using the Web UI or REST API endpoints.

The licensed-users-info-backend plugin enables administrators to monitor the number of active users on Developer Hub. Using this feature, organizations can compare their actual usage with the number of licenses they have purchased. Additionally, you can share the user metrics with Red Hat for transparency and exact licensing.

The licensed-users-info-backend plugin is enabled by default. This plugin enables a Download User List link at the bottom of the Administration → RBAC tab.

10.3.8. Define policies in external files to provision permissions during cluster deployment

10.3.8.1. Define policies in external files to provision permissions during cluster deployment

Configure permissions and roles in external files before starting Developer Hub to automate maintenance.

To automate Red Hat Developer Hub maintenance, you can configure permissions and roles in external files, before starting Developer Hub.

10.3.8.2. Define authorizations by using the Operator

Define permissions and roles in external CSV and YAML files and configure Developer Hub to use them with the Operator.

To automate Red Hat Developer Hub maintenance, you can define permissions and roles in external files, before starting Developer Hub. You need to prepare your files, upload them to your OpenShift Container Platform project, and configure Developer Hub to use the external files.

Procedure

  1. Define your policies in a rbac-policies.csv CSV file by using the following format:

    1. Define role permissions:

      p, <role_entity_reference>, <permission>, <action>, <allow_or_deny>
      <role_entity_reference>
      Role entity reference, such as: role:default/guest.
      <permission>

      Permission, such as: bulk.import, catalog.entity.read, or catalog.entity.refresh, or permission resource type, such as: bulk-import or catalog-entity.

      See: Permission policies reference.

      <action>
      Action type, such as: use, read, create, update, delete.
      <allow_or_deny>
      Access granted: allow or deny.
    2. Assign the role to a group or a user:

      g, <group_or_user>, <role_entity_reference>
      <group_or_user>

      Group, such as: user:default/mygroup, or user, such as: user:default/myuser.

      p, role:default/guests, catalog-entity, read, allow
      p, role:default/guests, catalog.entity.create, create, allow
      g, user:default/my-user, role:default/guests
      g, group:default/my-group, role:default/guests
  2. Define your conditional policies in a rbac-conditional-policies.yaml YAML file by using the following format:

    result: CONDITIONAL
    roleEntityRef: <role_entity_reference>
    pluginId: <plugin_id>
    permissionMapping:
      - read
      - update
      - delete
    conditions: <conditions>

    See: Conditional policies reference.

  3. Upload your rbac-policies.csv and rbac-conditional-policies.yaml files to a rbac-policies config map in your OpenShift Container Platform project containing Developer Hub.

    $ oc create configmap rbac-policies \
         --from-file=rbac-policies.csv \
         --from-file=rbac-conditional-policies.yaml
  4. Update your Backstage custom resource to mount in the Developer Hub filesystem your files from the rbac-policies config map:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    spec:
      application:
        extraFiles:
          mountPath: /opt/app-root/src
          configMaps:
            - name: rbac-policies
  5. Update your Developer Hub app-config.yaml configuration file to use the rbac-policies.csv and rbac-conditional-policies.yaml external files:

    permission:
      enabled: true
      rbac:
        conditionalPoliciesFile: /opt/app-root/src/rbac-conditional-policies.yaml
        policies-csv-file: /opt/app-root/src/rbac-policies.csv
        policyFileReload: true

10.3.8.3. Define authorizations by using the Helm Chart

Define permissions and roles in external CSV and YAML files and configure Developer Hub to use them with Helm.

To automate Red Hat Developer Hub maintenance, you can define permissions and roles in external files, before starting Developer Hub. You need to prepare your files, upload them to your OpenShift Container Platform project, and configure Developer Hub to use the external files.

Procedure

  1. Define your policies in a rbac-policies.csv CSV file by using the following format:

    1. Define role permissions:

      p, <role_entity_reference>, <permission>, <action>, <allow_or_deny>
      <role_entity_reference>
      Role entity reference, such as: role:default/guest.
      <permission>

      Permission, such as: bulk.import, catalog.entity.read, or catalog.entity.refresh, or permission resource type, such as: bulk-import or catalog-entity.

      See: Permission policies reference.

      <action>
      Action type, such as: use, read, create, update, delete.
      <allow_or_deny>
      Access granted: allow or deny.
    2. Assign the role to a group or a user:

      g, <group_or_user>, <role_entity_reference>
      <group_or_user>

      Group, such as: user:default/mygroup, or user, such as: user:default/myuser.

      Sample rbac-policies.csv:

      p, role:default/guests, catalog-entity, read, allow
      p, role:default/guests, catalog.entity.create, create, allow
      g, user:default/my-user, role:default/guests
      g, group:default/my-group, role:default/guests
  2. Define your conditional policies in a rbac-conditional-policies.yaml YAML file by using the following format:

    result: CONDITIONAL
    roleEntityRef: <role_entity_reference>
    pluginId: <plugin_id>
    permissionMapping:
      - read
      - update
      - delete
    conditions: <conditions>

    See: Conditional policies reference.

  3. Upload your rbac-policies.csv and rbac-conditional-policies.yaml files to a rbac-policies config map in your OpenShift Container Platform project containing Developer Hub.

    $ oc create configmap rbac-policies \
         --from-file=rbac-policies.csv \
         --from-file=rbac-conditional-policies.yaml
  4. Update your Developer Hub Backstage Helm chart to mount in the Developer Hub filesystem your files from the rbac-policies config map:

    1. In the Developer Hub Helm Chart, go to Root Schema → Backstage chart schema → Backstage parameters → Backstage container additional volume mounts.
    2. Select Add Backstage container additional volume mounts and add the following values:

      mountPath
      /opt/app-root/src/rbac
      Name
      rbac-policies
    3. Add the RBAC policy to the Backstage container additional volumes in the Developer Hub Helm Chart:

      name
      rbac-policies
      configMap
      defaultMode
      420
      name
      rbac-policies
  5. Update your Developer Hub app-config.yaml configuration file to use the rbac-policies.csv and rbac-conditional-policies.yaml external files:

    permission:
      enabled: true
      rbac:
        conditionalPoliciesFile: /opt/app-root/src/rbac-conditional-policies.yaml
        policies-csv-file: /opt/app-root/src/rbac-policies.csv
        policyFileReload: true

10.3.8.4. Configure RBAC for Extensions

You can grant access to Extensions plugin management by adding permission policies to your RBAC CSV file.

Prerequisites

Procedure

  1. Add the following policies to your CSV file to allow users to view and manage plugins in Extensions:

    g, user:default/<YOUR_USERNAME>, role:default/extensions-admin
    p, role:default/extensions-admin, extensions.plugin.configuration.read, read, allow
    p, role:default/extensions-admin, extensions.plugin.configuration.write, create, allow
    p, role:default/extensions-admin, catalog.entity.read, read, allow

    See Extensions permissions.

  2. Optional: Restrict access to specific plugins by defining a conditional policy in the rbac-conditional-policies.yaml file as described in Defining conditional policies:

    result: CONDITIONAL
    roleEntityRef: "role:default/extensions-admin"
    pluginId: extensions
    resourceType: extensions-plugin
    permissionMapping:
      - create
    conditions:
      rule: HAS_NAME
      resourceType: extensions-plugin
      params:
        pluginNames: [<your_plugin_name>]

    where:

    pluginNames

    Enter the plugin name or title for user access.

    This policy allows users to install or update only the specified plugins and restricts access to all other plugins.

  3. Optional: Restrict access by annotation by defining a conditional policy:

    result: CONDITIONAL
    roleEntityRef: "role:default/extensions-admin"
    pluginId: extensions
    resourceType: extensions-plugin
    permissionMapping:
      - create
    conditions:
      rule: HAS_ANNOTATION
      resourceType: extensions-plugin
      params:
        annotation: "extensions.backstage.io/certified-by"
        value: "Red Hat"

    This policy allows users to install or update only the plugins that have the specified annotation.

Verification

  • Verify that the user can view and manage plugins in Extensions.

10.3.9. Configure guest access

10.3.9.1. Configure guest access

Enable guest access to test role and policy creation without configuring an authentication provider.

Use guest access with the role-based access control (RBAC) front-end plugin to allow a user to test role and policy creation without the need to set up and configure an authentication provider.

Note

Guest access is not recommended for production.

10.3.9.2. Configure the RBAC backend plugin

Enable the permission framework and configure admin users by updating the app-config-rhdh.yaml file.

You can configure the RBAC backend plugin by updating the app-config.yaml file to enable the permission framework.

Prerequisites

  • You have installed the @backstage-community/plugin-rbac plugin in Developer Hub. For more information, see Configuring dynamic plugins.

Procedure

  • Update the app-config.yaml file to enable the permission framework as shown:

    permission
      enabled: true
      rbac:
        admin:
          users:
            - name: user:default/guest
        pluginsWithPermission:
          - catalog
          - permission
          - scaffolder
    Note

    The pluginsWithPermission section of the app-config.yaml file includes only three plugins by default. Update the section as needed to include any additional plugins that also incorporate permissions.

10.3.9.3. Set up the guest authentication provider

Enable guest authentication for testing RBAC features without configuring a full authentication provider.

You can enable guest authentication and use it alongside the RBAC front-end plugin.

Prerequisites

  • You have installed the @backstage-community/plugin-rbac plugin in Developer Hub. For more information, see Configuring dynamic plugins.

Procedure

  • In the app-config.yaml file, add the user entity reference to resolve and enable the dangerouslyAllowOutsideDevelopment option, as shown in the following example:

    auth:
      environment: development
      providers:
        guest:
          userEntityRef: user:default/guest
          dangerouslyAllowOutsideDevelopment: true
    Note

    You can use user:default/guest as the user entity reference to match the added user under the permission.rbac.admin.users section of the app-config.yaml file.

10.3.10. Permission policy parameters and definitions

Reference information about resource type and basic permission types in Developer Hub.

Permission policies in Red Hat Developer Hub are a set of rules to govern access to resources or functionalities. These policies state the authorization level that is granted to users based on their roles. The permission policies are implemented to keep security and confidentiality within a given environment.

You can define the following types of permissions in Developer Hub:

  • resource type
  • basic

The distinction between the two permission types depends on whether a permission includes a defined resource type.

You can define the resource type permission by using either the associated resource type or the permission name as shown in the following example:

p, role:default/myrole, catalog.entity.read, read, allow
g, user:default/myuser, role:default/myrole

p, role:default/another-role, catalog-entity, read, allow
g, user:default/another-user, role:default/another-role

You can define the basic permission in Developer Hub using the permission name as shown in the following example:

p, role:default/myrole, catalog.entity.create, create, allow
g, user:default/myuser, role:default/myrole

10.3.11. Define conditional policies

Use conditional policies with criteria, objects, and aliases to filter access to Developer Hub resources based on dynamic parameters.

The permission framework in Red Hat Developer Hub provides conditions, supported by the RBAC backend plugin (backstage-plugin-rbac-backend). The conditions work as content filters for the Developer Hub resources that are provided by the RBAC backend plugin.

The RBAC backend API stores conditions assigned to roles in the database. When you request to access the front-end resources, the RBAC backend API searches for the corresponding conditions and delegates them to the appropriate plugin by using its plugin ID. If you are assigned to multiple roles with different conditions, then the RBAC backend merges the conditions by using the anyOf criteria.

Conditional criteria

A condition in Developer Hub is a simple condition with a rule and parameters. However, a condition can also contain a parameter or an array of parameters combined by conditional criteria. The supported conditional criteria includes:

allOf
Ensures that all conditions within the array must be true for the combined condition to be satisfied.
anyOf
Ensures that at least one of the conditions within the array must be true for the combined condition to be satisfied.
not
Ensures that the condition within it must not be true for the combined condition to be satisfied.
Conditional object

The plugin specifies the parameters supported for conditions. You can access the conditional object schema from the RBAC API endpoint to understand how to construct a conditional JSON object, which is then used by the RBAC backend plugin API.

A conditional object contains the following parameters:

ParameterTypeDescription

result

String

Always has the value CONDITIONAL

roleEntityRef

String

String entity reference to the RBAC role, such as role:default/dev

pluginId

String

Corresponding plugin ID, such as catalog

permissionMapping

String array

Array permission actions, such as ['read', 'update', 'delete']

resourceType

String

Resource type provided by the plugin, such as catalog-entity

conditions

JSON

Condition JSON with parameters or array parameters joined by criteria

Conditional policy aliases

The RBAC backend plugin (backstage-plugin-rbac-backend) supports the use of aliases in conditional policy rule parameters. The conditional policy aliases are dynamically replaced with the corresponding values during policy evaluation. Each alias in conditional policy is prefixed with a $ sign indicating its special function.

The supported conditional aliases include:

$currentUser

This alias is replaced with the user entity reference for the user who requests access to the resource. For example, if user Tom from the default namespace requests access, $currentUser becomes user:default/tom.

Example conditional policy object with $currentUser alias:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/developer",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["delete"],
  "conditions": {
    "rule": "IS_ENTITY_OWNER",
    "resourceType": "catalog-entity",
    "params": {
      "claims": ["$currentUser"]
    }
  }
}
$ownerRefs

This alias is replaced with ownership references, usually as an array that includes the user entity reference and the user’s parent group entity reference. For example, for user Tom from team-a, $ownerRefs becomes ['user:default/tom', 'group:default/team-a'].

Example conditional policy object with $ownerRefs alias:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/developer",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["delete"],
  "conditions": {
    "rule": "IS_ENTITY_OWNER",
    "resourceType": "catalog-entity",
    "params": {
      "claims": ["$ownerRefs"]
    }
  }
}

10.3.12. Download user statistics

Download the list of active users in CSV format from the RBAC page in Developer Hub.

You can download the list of users in CSV format by using the Developer Hub web interface.

Prerequisites

  • RBAC plugins (@backstage-community/plugin-rbac and @backstage-community/plugin-rbac-backend) must be enabled in Red Hat Developer Hub.
  • If RBAC is enabled, you have a role with the following permission: policy.entity.read.

Procedure

  1. In Red Hat Developer Hub, navigate to Administration and select the RBAC tab.
  2. At the bottom of the RBAC page, click Download User List.
  3. Optional: Change the file name in the Save as field and click Save.
  4. To access the downloaded users list, go to the Downloads folder on your local machine and open the CSV file.

10.3.13. Manage Orchestrator plugin permissions using RBAC policies

You can configure Role-Based Access Control (RBAC) policies so that users can view workflow details without the permission to run those workflows. This configuration restricts user interaction to authorized workflows.

The Orchestrator plugin uses specific permission strings to control access to workflows and instances. After you enable the role-based access control (RBAC) plugin, you must grant the following permissions in your rbac-policy.csv file to view and manage workflows in the Orchestrator UI:

orchestrator.workflow (read)
Lists and views workflow definitions and their instances. If this permission is missing, the workflow list in the UI appears empty.
orchestrator.workflow.use (update)
Executes or aborts a workflow.
orchestrator.workflowAdminView (read)
Accesses the workflow definition editor and instance variables.
orchestrator.instanceAdminView (read)
Views all workflow instances, including those created by other users.

Prerequisites

  • You have identified the [workflowId] for each workflow you want to restrict.
  • You have enabled the RBAC plugin.
  • You have configured the policies-csv-file path in your app-config.yaml.

Procedure

  1. Identify the workflowId from your workflow definition file:

    id: greeting
    version: '1.0'
  2. In your RBAC policy CSV file, define the permissions using the p, role, permission, action, allow format.

    Note

    Generic permissions (for example, orchestrator.workflow) take precedence over specific permissions targeting a workflowId, (for example, orchestrator.workflow.greeting). You cannot grant generic access and then selectively deny a specific ID.

  3. Add the following example policies to your CSV file to establish basic user and administrator roles:

    # Minimal user role - can only view and run specific workflows
    p, role:default/workflowUser, orchestrator.workflow.greeting, read, allow
    p, role:default/workflowUser, orchestrator.workflow.use.greeting, update, allow
    
    # Support role - can view all workflows and instances, but not execute
    p, role:default/workflowSupport, orchestrator.workflow, read, allow
    p, role:default/workflowSupport, orchestrator.instanceAdminView, read, allow
    
    # Full admin role - complete access to all Orchestrator functions
    p, role:default/workflowAdmin, orchestrator.workflow, read, allow
    p, role:default/workflowAdmin, orchestrator.workflow.use, update, allow
    p, role:default/workflowAdmin, orchestrator.workflowAdminView, read, allow
    p, role:default/workflowAdmin, orchestrator.instanceAdminView, read, allow
    
    # Assign users to the roles
    g, user:default/example_user, role:default/workflowUser
  4. In your RHDH app-config.yaml file, enable permissions by adding the orchestrator plugin to the rbac section and setting policyFileReload to true.

    permission:
      enabled: true
      rbac:
        policies-csv-file: <absolute_path_to_the_policy_file>
        pluginsWithPermission:
          - orchestrator
        policyFileReload: true
        admin:
          users:
            - name: user:default/YOUR_USER
  5. Restart the application to apply the changes.

Verification

  1. Log in as a user assigned to the workflowUser role.
  2. Navigate to the Orchestrator plugin and verify that the workflow appears in the list.
Important

You can view dynamic permissions containing a workflowId in the RBAC UI, but you cannot modify them in the interface. You must use the policy CSV file or the RBAC API to manage these specific workflow permissions.

Additional resources

10.3.14. Orchestrator plugin permissions

The Orchestrator plugin uses the Red Hat Developer Hub permission mechanism and the Role-Based Access Control (RBAC) plugin to restrict access to backend endpoints. Orchestrator supports decoupling visibility (read) from running (update) using specific workflow IDs instead of generic permissions.

Permission nameResource TypePolicyDescription

orchestrator.workflow

named resource

read

Lists and reads all workflow definitions.

Lists and reads their instances

orchestrator.workflow.[workflowId]

named resource

read

Lists and reads a specific workflow definition.

Lists and reads instances created for this particular workflow.

orchestrator.workflow.use

named resource

update

Runs or aborts any workflow.

orchestrator.workflow.use.[workflowId]

named resource

update

Runs or aborts a specific workflow.

orchestrator.workflowAdminView

named resource

read

Views instance variables and the workflow definition editor.

orchestrator.instanceAdminView

named resource

read

Views all workflow instances, including those created by other users.

Warning

Generic permissions override specific denial policies within the same action type. To maintain granular control, avoid granting generic permissions if you intend to restrict specific workflows.

  • Granting orchestrator.workflow (read) prevents you from denying access to orchestrator.workflow.[workflowId] (read).
  • Granting orchestrator.workflow.use (update) prevents you from denying access to orchestrator.workflow.use.[workflowId] (update).

The [workflowId] must match the unique identifier in your workflow definition file. For example, in the workflow definition below, the identifier is greeting:

id: greeting
version: '1.0'
specVersion: '0.8'
name: Greeting workflow
description: YAML based greeting workflow
annotations:
  - 'workflow-type/infrastructure'
dataInputSchema: 'schemas/greeting.sw.input-schema.json'
extensions:
  - extensionid: workflow-output-schema
    outputSchema: schemas/workflow-output-schema.json

10.3.15. Delegate RBAC management to decentralize administration

10.3.15.1. Delegate RBAC management to decentralize administration

Delegate RBAC responsibilities to team leads by using the multitenancy feature and IS_OWNER conditional rule.

An enterprise customer requires the ability to delegate role-based access control (RBAC) responsibilities to other individuals in the organization. In this scenario, you, as the administrator, can give access to the RBAC plugin specifically to designated users, such as team leads. Each team lead is then able to manage permissions only for users within their assigned team or department, without visibility into or control over permissions outside their assigned scope. This approach allows team leads to manage access and permissions for their own teams independently, while administrators keep global oversight.

In Red Hat Developer Hub, you can delegate RBAC access by using the multitenancy feature of the RBAC plugin, specifically the IS_OWNER conditional rule. You can either use the web UI or the RBAC backend API, depending on your preferred workflow and level of automation:

  • Use the web UI to create roles, assign users or groups, define permissions, and apply ownership conditions through an intuitive interface.
  • Use the API for a more flexible and automatable approach, where you can programmatically manage roles, permissions, and ownership conditions using authenticated curl requests.

By delegating RBAC access through either method, you can expect the following outcomes:

  • Team leads can manage RBAC settings for their teams independently.
  • Visibility of other users' or teams' permissions is restricted.
  • Administrators retain overarching control while delegating team-specific access.

Use groups to configure persona-specific homepage layouts, ensuring users see homepage content appropriate to their role.

10.3.15.2. Configure RBAC delegation

10.3.15.2.1. Configure RBAC delegation

Configure RBAC delegation to allow designated users to manage permissions for their teams by using the web UI or the RBAC backend API.

10.3.15.2.2. Delegate access using the Web UI

Delegate RBAC access to team leads by using the Web UI to create roles with IS_OWNER conditional rules.

You can delegate the RBAC access in Red Hat Developer Hub by using the web UI.

Prerequisites

  • Your RHDH instance is running with the RBAC plugin installed and configured.
  • You have administrative access to RHDH.

Procedure

  1. Log in to your RHDH instance with administrator credentials.
  2. Navigate to Administration → RBAC.
  3. Click Create Role and define a new role for team leads, such as role:default/team_lead.
  4. In the Members section, add the user or group, such as user:default/team_lead.
  5. Grant permissions required by team leads, such as:

    policy.entity.create
    To allow policy creation.
    catalog-entity:read
    To allow catalog access.
  6. Apply conditions to limit access as follows:

    IS_OWNER
    Use the IS_OWNER rule to ensure team leads can only manage resources they own.
  7. Click Save to create the role and apply changes.

Verification

  • Log in as a team lead.
  • Verify the following:

    • RBAC UI is accessible.
    • Only users or roles related to their team are visible.
    • No access to roles or permissions outside their scope is granted.
10.3.15.2.3. Delegate access using the API

Delegate RBAC access to team leads by using the RBAC backend API to create roles with IS_OWNER conditional rules.

You can delegate the RBAC access in Red Hat Developer Hub by using the RBAC backend API.

Prerequisites

  • Your RHDH instance is running with the RBAC plugin installed and configured.
  • You have administrative access to RHDH.
  • You have API access using curl or another tool.

Procedure

  1. Create a new role designated for team leads by using the RBAC backend API:

    For example, to create a new role for the team lead by using the RBAC backend API:

    $ curl -X POST 'http://localhost:7007/api/permission/roles' \
    --header "Authorization: Bearer $ADMIN_TOKEN" \
    --header "Content-Type: application/json" \
    --data '{
      "memberReferences": ["user:default/team_lead"],
      "name": "role:default/team_lead",
      "metadata": {
        "description": "This is an example team lead role"
      }
    }'
  2. Allow team leads to read catalog entities and create permissions in the RBAC plugin using the following API request:

    For example, to grant the team lead role permission to create RBAC policies and read catalog entities:

    $ curl -X POST 'http://localhost:7007/api/permission/policies' \
    --header "Authorization: Bearer $ADMIN_TOKEN" \
    --header "Content-Type: application/json" \
    --data '[
      {
        "entityReference": "role:default/team_lead",
        "permission": "policy.entity.create",
        "policy": "create",
        "effect": "allow"
      },
      {
        "entityReference": "role:default/team_lead",
        "permission": "catalog-entity",
        "policy": "read",
        "effect": "allow"
      }
    ]'
  3. To ensure team leads can only manage what they own, use the IS_OWNER conditional rule as follows:

    For example, to apply a conditional access policy by using the IS_OWNER rule for the team lead role:

    $ curl -X POST 'http://localhost:7007/api/permission/roles/conditions' \
    --header "Authorization: Bearer $ADMIN_TOKEN" \
    --header "Content-Type: application/json" \
    --data '{
     "result": "CONDITIONAL",
     "pluginId": "permission",
     "resourceType": "policy-entity",
     "conditions": {
       "rule": "IS_OWNER",
       "resourceType": "policy-entity",
       "params": {
         "owners": [
           "user:default/team_lead"
         ]
       }
     },
     "roleEntityRef": "role:default/team_lead",
     "permissionMapping": [
       "read",
       "update",
       "delete"
     ]
    }'

    The previous example of conditional policy limits visibility and control to only owned roles and policies.

  4. Log in to RHDH as team lead and verify the following:

    1. Use the following request and verify that you do not see any roles:

      For example, to retrieve roles visible to the team lead:

      $ curl -X GET 'http://localhost:7007/api/permission/roles' \
      --header "Authorization: Bearer $TEAM_LEAD_TOKEN"
    2. Use the following request to create a new role for their team:

      For example, to create a new role for their team with ownership assigned:

      $ curl -X POST 'http://localhost:7007/api/permission/roles' \
      --header "Authorization: Bearer $TEAM_LEAD_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{
        "memberReferences": ["user:default/team_member"],
        "name": "role:default/team_a",
        "metadata": {
          "description": "This is an example team_a role",
          "owner": "user:default/team_lead"
        }
      }'
      Note

      You can set the ownership during creation, but you can also update the ownership at any time.

    3. Use the following request to assign a permission policy to the new role:

      For example, to grant read access to catalog entities for the new role:

      $ curl -X POST 'http://localhost:7007/api/permission/policies' \
      --header "Authorization: Bearer $ADMIN_TOKEN" \
      --header "Content-Type: application/json" \
      --data '[
        {
          "entityReference": "role:default/team_a",
          "permission": "catalog-entity",
          "policy": "read",
          "effect": "allow"
        }
      ]'
    4. Use the following request to verify that only team-owned roles and policies are visible:

      For example, to retrieve roles and permission policies visible to the team lead:

      $ curl -X GET 'http://localhost:7007/api/permission/roles' \
      --header "Authorization: Bearer $TEAM_LEAD_TOKEN"
      
      $ curl -X GET 'http://localhost:7007/api/permission/policies' \
      --header "Authorization: Bearer $TEAM_LEAD_TOKEN"

Verification

  • Log in as a team lead and verify the following:

    • The RBAC UI is accessible.
    • Only the assigned users or group is visible.
    • Permissions outside the scoped team are not viewable or editable.
  • Log in as an administrator and verify that you retain full visibility and control.

Chapter 11. Observe

11.1. Observe

Monitor, troubleshoot, and maintain your Developer Hub deployment by configuring system logs and application metrics, managing telemetry collection, reviewing audit logs, centralizing workflow observability, and collecting diagnostic data.

11.2. Monitor system logs and application metrics to ensure platform availability

11.2.1. Monitor system logs and application metrics to ensure platform availability

Monitor Developer Hub by configuring log levels, enabling metrics monitoring on OpenShift Container Platform, and setting up platform-specific monitoring with Amazon Prometheus or Azure Monitor.

11.2.2. Configure log levels

11.2.2.1. Configure log levels

Control the amount and type of information that Developer Hub writes to its logs by configuring the LOG_LEVEL environment variable using the Operator or Helm chart.

11.2.2.2. Configure the log level with the Red Hat Developer Hub Operator

Configure the application log level through the LOG_LEVEL environment variable by using the Red Hat Developer Hub Operator to control the minimum severity level of events that your application logs.

Prerequisites

  • You have access to the Backstage custom resource (CR) used to deploy the application.

Procedure

  • Include the environment variable LOG_LEVEL in your Backstage CR. For example:

    spec:
      # Other fields omitted
      application:
        extraEnvs:
          envs:
            - name: LOG_LEVEL
              value: debug

    You can use any of the values in the following table.

    Table 11.1. LOG_LEVEL values in order of increasing severity

    ValueDescription

    debug

    Detailed information, typically useful only when troubleshooting.

    info

    General information about the operation of the application. This is the default level.

    warn

    Potential issues or situations that might require attention.

    error

    Errors that occurred during the operation but are not critical.

    critical

    Unrecoverable errors that must be addressed immediately to restore functionality.

11.2.2.3. Configure the log level with the Red Hat Developer Hub Helm chart

Configure the application log level through the LOG_LEVEL environment variable by using the Red Hat Developer Hub Helm chart to control the minimum severity level of events that your application logs.

Prerequisites

  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Helm chart.

Procedure

  • Add LOG_LEVEL to your Helm chart values.yaml file. For example:

    upstream:
      backstage:
        # --- Truncated ---
        extraEnvVars:
          - name: LOG_LEVEL
            value: debug

    You can use any of the values in the following table.

    Table 11.2. LOG_LEVEL values in order of increasing severity

    ValueDescription

    debug

    Detailed information, typically useful only when troubleshooting.

    info

    General information about the operation of the application. This is the default level.

    warn

    Potential issues or situations that might require attention.

    error

    Errors that occurred during the operation but are not critical.

    critical

    Unrecoverable errors that must be addressed immediately to restore functionality.

11.2.3. Enable metrics monitoring on OpenShift Container Platform

11.2.3.1. Enable metrics monitoring on OpenShift Container Platform

Enable metrics monitoring for Developer Hub on OpenShift Container Platform by creating a ServiceMonitor custom resource (CR) to scrape metrics from the /metrics service endpoint.

11.2.3.1.1. Additional resources

11.2.3.2. Enable metrics monitoring in a Red Hat Developer Hub Operator installation on an OpenShift Container Platform cluster

Enable and view metrics for an Operator-installed Red Hat Developer Hub instance from the OpenShift Container Platform web console by setting the spec.monitoring.enabled field in your custom resource (CR).

Prerequisites

  • Your OpenShift Container Platform cluster has monitoring for user-defined projects enabled.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Red Hat Developer Hub Operator.
  • You have installed the OpenShift CLI (oc).

Procedure

  1. Use the OpenShift CLI (oc) to edit your existing Red Hat Developer Hub CR.

    $ oc edit Backstage <instance_name>
  2. In the CR, locate the spec field and add the monitoring configuration block.

    spec:
      monitoring:
        enabled: true
  3. Save the RHDH CR. The RHDH Operator detects the configuration and automatically creates the corresponding ServiceMonitor custom resource (CR).

    Note

    The Operator automatically configures the ServiceMonitor with the correct labels (app.kubernetes.io/instance and app.kubernetes.io/name) that match your Backstage CR. The ServiceMonitor will be named metrics-<cr_name>. No additional label configuration is required.

Verification

  1. From the OpenShift Container Platform web console, select the Observe view.
  2. Click the Dashboard tab to view metrics for Red Hat Developer Hub pods.
  3. From the OpenShift Container Platform web console, click Project > Services and verify the labels for backstage-developer-hub.

11.2.3.3. Enable metrics monitoring in a Helm chart installation on an OpenShift Container Platform cluster

Enable and view metrics for a Red Hat Developer Hub Helm deployment from the OpenShift Container Platform web console by configuring metrics monitoring during a chart upgrade.

Prerequisites

  • Your OpenShift Container Platform cluster has monitoring for user-defined projects enabled.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Helm chart.

Procedure

  1. From the OpenShift Container Platform web console, select the Topology view.
  2. Click the overflow menu of the Red Hat Developer Hub Helm chart, and select Upgrade.

    Helm chart overflow menu showing the Upgrade option
  3. On the Upgrade Helm Release page, select the YAML view option in Configure via, then configure the metrics section in the YAML, as shown in the following example:

    upstream:
    # ...
      metrics:
        serviceMonitor:
          enabled: true
          path: /metrics
    # ...
  4. Click Upgrade.

Verification

  1. From the OpenShift Container Platform web console, select the Observe view.
  2. Click the Dashboard tab to view metrics for Red Hat Developer Hub pods.

11.2.4. Configure AWS monitoring

11.2.4.1. Configure AWS monitoring

Configure Developer Hub to use Amazon Prometheus for metrics monitoring and Amazon CloudWatch for logging when hosting on Amazon Web Services (AWS) infrastructure.

11.2.4.2. Configure annotations for monitoring with Amazon Prometheus by using the Red Hat Developer Hub Operator

Configure the required pod annotations by using the Red Hat Developer Hub Operator to enable monitoring with Amazon Prometheus.

Prerequisites

  • You have configured Prometheus for your Elastic Kubernetes Service (EKS) clusters.
  • You have created an Amazon managed service for the Prometheus workspace.
  • You have configured Prometheus to import the Developer Hub metrics.
  • You have ingested Prometheus metrics into the created workspace.

Procedure

  1. As an administrator of the Red Hat Developer Hub Operator, edit the default configuration to add Prometheus annotations as follows:

    # Update OPERATOR_NS accordingly
    $ OPERATOR_NS=rhdh-operator
    $ kubectl edit configmap backstage-default-config -n "${OPERATOR_NS}"
  2. Find the deployment.yaml key in the config map and add the annotations to the spec.template.metadata.annotations field as follows:

    deployment.yaml: |-
      apiVersion: apps/v1
      kind: Deployment
      # --- truncated ---
      spec:
        template:
          # --- truncated ---
          metadata:
            labels:
             rhdh.redhat.com/app:  # placeholder for 'backstage-<cr_name>'
            # --- truncated ---
            annotations:
              prometheus.io/scrape: 'true'
              prometheus.io/path: '/metrics'
              prometheus.io/port: '9464'
              prometheus.io/scheme: 'http'
      # --- truncated ---
  3. Save your changes.

Verification

To verify if the scraping works:

  1. Use kubectl to port-forward the Prometheus console to your local machine as follows:

    $ kubectl --namespace=prometheus port-forward deploy/prometheus-server 9090
  2. Open your web browser and navigate to http://localhost:9090 to access the Prometheus console.
  3. Monitor relevant metrics, such as process_cpu_user_seconds_total.

11.2.4.3. Configure annotations for monitoring with Amazon Prometheus by using the Red Hat Developer Hub Helm chart

Configure the required pod annotations by using the Red Hat Developer Hub Helm chart to enable monitoring with Amazon Prometheus.

Prerequisites

  • You have configured Prometheus for your Elastic Kubernetes Service (EKS) clusters.
  • You have created an Amazon managed service for the Prometheus workspace.
  • You have configured Prometheus to import the Developer Hub metrics.
  • You have ingested Prometheus metrics into the created workspace.

Procedure

  • To annotate the backstage pod for monitoring, update your values.yaml file as follows:

    upstream:
      backstage:
        # --- TRUNCATED ---
        podAnnotations:
          prometheus.io/scrape: 'true'
          prometheus.io/path: '/metrics'
          prometheus.io/port: '9464'
          prometheus.io/scheme: 'http'

Verification

To verify if the scraping works:

  1. Use kubectl to port-forward the Prometheus console to your local machine as follows:

    $ kubectl --namespace=prometheus port-forward deploy/prometheus-server 9090
  2. Open your web browser and navigate to http://localhost:9090 to access the Prometheus console.
  3. Monitor relevant metrics, such as process_cpu_user_seconds_total.

11.2.4.4. Retrieve logs from Amazon CloudWatch

Retrieve and query logs from your Developer Hub instance by using Amazon CloudWatch Container Insights and Logs Insights.

Prerequisites

  • CloudWatch Container Insights is used to capture logs and metrics for Amazon Elastic Kubernetes Service. For more information, see Logging for Amazon Elastic Kubernetes Service documentation.
  • To capture the logs and metrics, install the Amazon CloudWatch Observability EKS add-on in your cluster. Following the setup of Container Insights, you can access container logs using Logs Insights or Live Tail views.
  • CloudWatch names the log group where all container logs are consolidated in the following manner:

    /aws/containerinsights/<cluster_name>/application

Procedure

  • To retrieve logs from the Developer Hub instance, run a query such as:

    fields @timestamp, @message, kubernetes.container_name
    | filter kubernetes.container_name in ["install-dynamic-plugins", "backstage-backend"]

11.2.5. Configure Azure monitoring

11.2.5.1. Configure Azure monitoring

Monitor resource utilization, diagnose issues, and collect logs for Developer Hub on Azure Kubernetes Service (AKS) by using Managed Prometheus Monitoring and Azure Monitor.

11.2.5.2. Enable Azure Monitor metrics

Enable managed Prometheus monitoring for your Azure Kubernetes Service (AKS) cluster to collect metrics and monitor Developer Hub performance through Azure Monitor.

Prerequisites

  • You have an AKS cluster.
  • You have the Azure CLI installed.

Procedure

  • To enable managed Prometheus monitoring, use the --enable-azure-monitor-metrics option with either the az aks create or az aks update command:

    $ az aks create/update --resource-group <your_resource_group> --name <your_cluster> --enable-azure-monitor-metrics

    This command installs the metrics add-on, which gathers Prometheus metrics.

Verification

11.2.5.3. Configure annotations for AKS monitoring by using the Operator

Configure the pod annotations for monitoring Developer Hub specific metrics on Azure Kubernetes Service (AKS) by using the Red Hat Developer Hub Operator.

Procedure

  1. As an administrator of the Operator, edit the default configuration to add Prometheus annotations:

    # Update OPERATOR_NS accordingly
    OPERATOR_NS=rhdh-operator
    $ kubectl edit configmap backstage-default-config -n "${OPERATOR_NS}"
  2. Find the deployment.yaml key in the ConfigMap and add the annotations to the spec.template.metadata.annotations field:

    deployment.yaml: |-
      apiVersion: apps/v1
      kind: Deployment
      # --- truncated ---
      spec:
        template:
          # --- truncated ---
          metadata:
            labels:
             rhdh.redhat.com/app:  # placeholder for 'backstage-<cr_name>'
            # --- truncated ---
            annotations:
              prometheus.io/scrape: 'true'
              prometheus.io/path: '/metrics'
              prometheus.io/port: '9464'
              prometheus.io/scheme: 'http'
      # --- truncated ---
  3. Save your changes.

Verification

  • Navigate to the corresponding Azure Monitor Workspace and view the metrics under Monitoring → Metrics.

11.2.5.4. Configure annotations for AKS monitoring by using the Helm chart

Configure the pod annotations for monitoring Developer Hub specific metrics on Azure Kubernetes Service (AKS) by using the Helm chart.

Procedure

  • Update your values.yaml file to annotate the backstage pod for monitoring:

    upstream:
      backstage:
        # --- TRUNCATED ---
        podAnnotations:
          prometheus.io/scrape: 'true'
          prometheus.io/path: '/metrics'
          prometheus.io/port: '9464'
          prometheus.io/scheme: 'http'

Verification

  • Navigate to the corresponding Azure Monitor Workspace and view the metrics under Monitoring → Metrics.

11.2.5.5. View live logs with Azure Kubernetes Service (AKS)

Access live data logs generated by Kubernetes objects for your Developer Hub instance on AKS.

Prerequisites

  • You have deployed Developer Hub on AKS.

For more information, see Installing Red Hat Developer Hub on Microsoft Azure Kubernetes Service (AKS).

Procedure

  1. Navigate to the Azure Portal.
  2. Search for the resource group <your_resource_group> and locate your AKS cluster <your_cluster>.
  3. Select Kubernetes resources → Workloads from the menu.
  4. Select the <your_rhdh_cr>-developer-hub (in case of Helm Chart installation) or <your_rhdh_cr>-backstage (in case of Operator-backed installation) deployment.
  5. Click Live Logs in the left menu.
  6. Select the pod.

    Note

    There must be only single pod.

Verification

  • Live log data is collected and displayed.

11.2.5.6. View real-time log data with Azure Kubernetes Service (AKS)

View real-time log data from the Container Engine for your Developer Hub instance on AKS.

Prerequisites

  • You have deployed Developer Hub on AKS.

For more information, see Installing Red Hat Developer Hub on Microsoft Azure Kubernetes Service (AKS).

Procedure

  1. Navigate to the Azure Portal.
  2. Search for the resource group <your_resource_group> and locate your AKS cluster <your_cluster>.
  3. Select MonitoringInsights from the menu.
  4. Go to the Containers tab.
  5. Find the backend-backstage container and click it to view real-time log data as it is generated by the Container Engine.

11.3. Manage telemetry collection to balance data insights with privacy requirements

11.3.1. Telemetry data collection and analysis

Red Hat Developer Hub collects and analyzes telemetry data by default to improve your experience.

Red Hat collects and analyzes the following data:

Web Analytics

Web Analytics use the Segment tool. It is the tracking of user behavior and interactions with Red Hat Developer Hub. Specifically, it tracks the following:

  • Events of page visits and clicks on links or buttons.
  • System-related information, for example, locale, time zone, user agent including browser and operating system details.
  • Page-related information, for example, title, category, extension name, URL, path, referrer, and search parameters.
  • Anonymous IP addresses, recorded as 0.0.0.0.
  • Anonymous username hashes, which are unique identifiers used solely to identify the number of unique users of the RHDH application.
System Observability

System Observability uses the OpenTelemetry tool. It is the tracking of the performance of the RHDH. Specifically, it tracks the following metrics:

  • Key system metrics such as CPU usage, memory usage, and other performance indicators.
  • Information about system components, such as the locale, time zone, and user agent (including details of the browser and operating system).
  • Traces and logs monitor system processes, allowing you to troubleshoot potential issues impacting the performance of RHDH.

With RHDH, you can customize the Web Analytics and System Observability configuration based on your needs.

11.3.2. Disable telemetry collection

11.3.2.1. Disable telemetry collection

You can disable telemetry data collection by disabling the analytics-provider-segment plugin. Use either the Helm chart or the Red Hat Developer Hub Operator.

For example, in an air-gapped environment, you can disable this feature to avoid outbound requests that affect the responsiveness of the RHDH application.

11.3.2.2. Disable telemetry data collection using the Operator

You can disable the telemetry data collection feature by using the Operator.

Prerequisites

  • You have logged in as an administrator in the OpenShift Container Platform web console.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Operator.

Procedure

  1. Perform one of the following steps:
  2. If you have created the dynamic-plugins-rhdh ConfigMap file and not configured the analytics-provider-segment plugin, add the plugin to the list of plugins and set its plugins.disabled parameter to true.
  3. If you have created the dynamic-plugins-rhdh ConfigMap file and configured the analytics-provider-segment plugin, search the plugin in the list of plugins and set its plugins.disabled parameter to true.
  4. If you have not created the ConfigMap file, create it with the following YAML code:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: './dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment'
            disabled: true
  5. Set the value of the dynamicPluginsConfigMapName parameter to the name of your dynamic-plugins-rhdh config map in your Backstage custom resource:

    # ...
    spec:
      application:
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
    # ...
  6. Save the configuration changes.

11.3.2.3. Disable telemetry data collection using the Helm chart

You can disable the telemetry data collection feature by using the Helm chart.

Prerequisites

  • You have logged in as an administrator in the OpenShift Container Platform web console.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Helm chart.

Procedure

  1. In the Developer perspective of the OpenShift Container Platform web console, go to the Helm view to see the list of Helm releases.
  2. Click the overflow menu on the Helm release that you want to use and select Upgrade.

    Note

    You can also create a new Helm release by clicking the Create button and edit the configuration to disable telemetry.

  3. Use either the Form view or YAML view to edit the Helm configuration:

    • Using Form view

      1. Expand Root Schema → global → Dynamic plugins configuration. → List of dynamic plugins that should be installed in the backstage application.
      2. Click the Add list of dynamic plugins that should be installed in the backstage application. link.
      3. Perform one of the following steps:

        • If you have not configured the plugin, add the following value in the Package specification of the dynamic plugin to install. It should be usable by the npm pack command. field:

          ./dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment

          Disabling telemetry data collection in the Helm chart
        • If you have configured the plugin, find the Package specification of the dynamic plugin to install. It should be usable by the npm pack command. field with the ./dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment value.
      4. Select the Disable the plugin checkbox.
      5. Click Upgrade.
    • Using YAML view

      1. Perform one of the following steps:

        • If you have not configured the plugin, add the following YAML code in your values.yaml Helm configuration file:

          # ...
          global:
            dynamic:
              plugins:
                - package: './dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment'
                  disabled: true
          # ...
        • If you have configured the plugin, search it in your Helm configuration and set the value of the plugins.disabled parameter to true.
      2. Click Upgrade.

11.3.3. Enable telemetry collection

11.3.3.1. Enable telemetry collection

Red Hat Developer Hub enables the telemetry data collection feature by default. However, if you have disabled the feature and want to re-enable it, you must enable the analytics-provider-segment plugin by using the Helm chart or the Red Hat Developer Hub Operator configuration.

11.3.3.2. Enable telemetry data collection using the Operator

You can enable the telemetry data collection feature by using the Operator.

Prerequisites

  • You have logged in as an administrator in the OpenShift Container Platform web console.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Operator.

Procedure

  1. Perform one of the following steps:
  2. If you have created the dynamic-plugins-rhdh ConfigMap file and not configured the analytics-provider-segment plugin, add the plugin to the list of plugins and set its plugins.disabled parameter to false.
  3. If you have created the dynamic-plugins-rhdh ConfigMap file and configured the analytics-provider-segment plugin, search the plugin in the list of plugins and set its plugins.disabled parameter to false.
  4. If you have not created the ConfigMap file, create it with the following YAML code:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: './dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment'
            disabled: false
  5. Set the value of the dynamicPluginsConfigMapName parameter to the name of your dynamic-plugins-rhdh config map in your Backstage custom resource:

    # ...
    spec:
      application:
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
    # ...
  6. Save the configuration changes.

11.3.3.3. Enable telemetry data collection using the Helm chart

You can enable the telemetry data collection feature by using the Helm chart.

Prerequisites

  • You have logged in as an administrator in the OpenShift Container Platform web console.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Helm chart.

Procedure

  1. In the Developer perspective of the OpenShift Container Platform web console, go to the Helm view to see the list of Helm releases.
  2. Click the overflow menu on the Helm release that you want to use and select Upgrade.

    Note

    You can also create a new Helm release by clicking the Create button and edit the configuration to enable telemetry.

  3. Use either the Form view or YAML view to edit the Helm configuration:

    • Using Form view

      1. Expand Root Schema → global → Dynamic plugins configuration. → List of dynamic plugins that should be installed in the backstage application.
      2. Click the Add list of dynamic plugins that should be installed in the backstage application. link.
      3. Perform one of the following steps:

        • If you have not configured the plugin, add the following value in the Package specification of the dynamic plugin to install. It should be usable by the npm pack command. field:

          ./dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment

        • If you have configured the plugin, find the Package specification of the dynamic plugin to install. It should be usable by the npm pack command. field with the ./dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment value.
      4. Clear the Disable the plugin checkbox.
      5. Click Upgrade.
    • Using YAML view

      1. Perform one of the following steps:

        • If you have not configured the plugin, add the following YAML code in your Helm configuration file:

          # ...
          global:
            dynamic:
              plugins:
                - package: './dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment'
                  disabled: false
          # ...
        • If you have configured the plugin, search it in your Helm configuration and set the value of the plugins.disabled parameter to false.
      2. Click Upgrade.

11.3.4. Customize the Segment source

11.3.4.1. Customize the Segment source

The analytics-provider-segment plugin sends the collected web analytics data to Red Hat by default. However, you can configure a new Segment source that receives web analytics data based on your needs. For configuration, you need a unique Segment write key that points to the Segment source.

Note

Create your own web analytics data collection notice for your application users.

11.3.4.2. Customize Segment source using the Operator

You can configure integration with your Segment source by using the Red Hat Developer Hub Operator.

Prerequisites

  • You have logged in as an administrator in the OpenShift Container Platform web console.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Operator.

Procedure

  1. Add the following YAML code in your Backstage custom resource (CR):

    # ...
    spec:
      application:
        extraEnvs:
          envs:
            - name: SEGMENT_WRITE_KEY
              value: <segment_key>
    # ...

    Replace <segment_key> with a unique identifier for your Segment source.

  2. Save the configuration changes.

11.3.4.3. Customize Segment source using the Helm chart

You can configure integration with your Segment source by using the Red Hat Developer Hub Helm chart.

Prerequisites

  • You have logged in as an administrator in the OpenShift Container Platform web console.
  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Helm chart.

Procedure

  1. In the Developer perspective of the OpenShift Container Platform web console, go to the Helm view to see the list of Helm releases.
  2. Click the overflow menu on the Helm release that you want to use and select Upgrade.
  3. Use either the Form view or YAML view to edit the Helm configuration:

    • Using Form view

      1. Expand Root Schema → Backstage Chart Schema → Backstage Parameters → Backstage container environment variables.
      2. Click the Add Backstage container environment variables link.
      3. Enter the name and value of the Segment key.

        Configuring the Segment source key in the Helm chart
      4. Click Upgrade.
    • Using YAML view

      1. Add the following YAML code in your Helm configuration file:

        # ...
        upstream:
          backstage:
            extraEnvVars:
              - name: SEGMENT_WRITE_KEY
                value: <segment_key>
        # ...

        Replace <segment_key> with a unique identifier for your Segment source.

      2. Click Upgrade.

11.4. Capture and review audit logs to trace user activities and maintain accountability

11.4.1. Audit logs overview

Audit logs are a chronological set of records documenting the user activities, system events, and data changes that affect your Red Hat Developer Hub users, administrators, or components.

Administrators can view Developer Hub audit logs in the OpenShift Container Platform web console to monitor scaffolder events, changes to the RBAC system, and changes to the Catalog database. Audit logs include the following information:

  • Name of the audited event
  • Actor that triggered the audited event, for example, terminal, port, IP address, or hostname
  • Event metadata, for example, date, time
  • Event status, for example, success, failure
  • Severity levels, for example, info, debug, warn, error

You can use the information in the audit log to achieve the following goals:

Enhance security
Trace activities, including those initiated by automated systems and software templates, back to their source. Know when software templates are executed, and the details of application and component installations, updates, configuration changes, and removals.
Automate compliance
Use streamlined processes to view log data for specified points in time for auditing purposes or continuous compliance maintenance.
Debug issues
Use access records and activity details to fix issues with software templates or plugins.
Note

Audit logs are not forwarded to the internal log store by default because the internal log store does not offer secure storage. You are responsible for ensuring that the system to which you forward audit logs is compliant with your organizational and governmental regulations, and is properly secured.

11.4.2. Configure audit logs for Developer Hub on OpenShift Container Platform

Configure logging deployment, log collector, and log forwarding components to enable audit logging for Developer Hub on OpenShift Container Platform.

Prerequisites

  • You have access to the OpenShift Container Platform web console.
  • You have cluster-admin privileges.

Procedure

  1. Configure the logging deployment, including both the CPU and memory limits for each logging component.

    For more information, see Red Hat OpenShift Container Platform - Configuring your Logging deployment.

  2. To configure the logging collector, configure the spec.collection stanza in the ClusterLogging custom resource (CR) to use a supported modification to the log collector and collect logs from STDOUT.

    For more information, see Red Hat OpenShift Container Platform - Configuring the logging collector.

  3. To configure log forwarding, send logs to specific endpoints inside and outside your OpenShift Container Platform cluster by specifying a combination of outputs and pipelines in a ClusterLogForwarder CR.

    For more information, see Red Hat OpenShift Container Platform - Enabling JSON log forwarding and Red Hat OpenShift Container Platform - Configuring log forwarding.

11.4.3. Forward Red Hat Developer Hub audit logs to Splunk

Forward audit logs from Developer Hub to Splunk by using the OpenShift Logging Operator and a ClusterLogForwarder instance.

Prerequisites

  • You have a cluster running on a supported OpenShift Container Platform version.
  • You have an account with cluster-admin privileges.
  • You have a Splunk Cloud account or Splunk Enterprise installation.

Procedure

  1. Log in to your OpenShift Container Platform cluster.
  2. Install the OpenShift Logging Operator in the openshift-logging namespace and switch to the namespace:

    $ oc project openshift-logging
  3. Create a serviceAccount named log-collector:

    $ oc create sa log-collector
  4. Bind the collect-application-logs role to the serviceAccount:

    $ oc create clusterrolebinding log-collector --clusterrole=collect-application-logs --serviceaccount=openshift-logging:log-collector
  5. Generate a hecToken in your Splunk instance.
  6. Create a key/value secret in the openshift-logging namespace and verify the secret:

    $ oc -n openshift-logging create secret generic splunk-secret --from-literal=hecToken=<HEC_Token>
    $ oc -n openshift-logging get secret/splunk-secret -o yaml
  7. Create a basic `ClusterLogForwarder`resource YAML file as follows:

    apiVersion: logging.openshift.io/v1
    kind: ClusterLogForwarder
    metadata:
      name: instance
      namespace: openshift-logging

    For more information, see Creating a log forwarder.

  8. Define the following ClusterLogForwarder configuration using OpenShift web console or OpenShift CLI:

    1. Specify the log-collector as serviceAccount in the YAML file:

      serviceAccount:
        name: log-collector
    2. Configure inputs to specify the type and source of logs to forward. The following configuration enables the forwarder to capture logs from all applications in a provided namespace:

      inputs:
        - name: my-app-logs-input
          type: application
          application:
            includes:
              - namespace: my-rhdh-project
            containerLimit:
              maxRecordsPerSecond: 100

      For more information, see Forwarding application logs from specific pods.

    3. Configure outputs to specify where to send the captured logs. In this step, focus on the splunk type. You can either use the tls.insecureSkipVerify option if the Splunk endpoint uses self-signed TLS certificates (not recommended) or supply the certificate chain by using a Secret.

      outputs:
        - name: splunk-receiver-application
          type: splunk
          splunk:
            authentication:
              token:
                key: hecToken
                secretName: splunk-secret
            index: main
            url: 'https://my-splunk-instance-link'
            rateLimit:
              maxRecordsPerSecond: 250

      For more information, see Forwarding logs to Splunk in OpenShift Container Platform documentation.

    4. Optional: Filter logs to include only audit logs:

      filters:
        - name: audit-logs-only
          type: drop
          drop:
            - test:
              - field: .message
                notMatches: isAuditEvent

      For more information, see Filtering logs by content in OpenShift Container Platform documentation.

    5. Configure pipelines to route logs from specific inputs to designated outputs. Use the names of the defined inputs and outputs to specify inputRefs and outputRefs in each pipeline:

      pipelines:
        - name: my-app-logs-pipeline
          detectMultilineErrors: true
          inputRefs:
            - my-app-logs-input
          outputRefs:
            - splunk-receiver-application
          filterRefs:
            - audit-logs-only
  9. Run the following command to apply the ClusterLogForwarder configuration:

    $ oc apply -f <ClusterLogForwarder-configuration.yaml>
  10. Optional: To reduce the risk of log loss, configure your ClusterLogForwarder pods using the following options:

    1. Define the resource requests and limits for the log collector as follows:

      collector:
        resources:
          requests:
            cpu: 250m
            memory: 64Mi
            ephemeral-storage: 250Mi
          limits:
            cpu: 500m
            memory: 128Mi
            ephemeral-storage: 500Mi
    2. Define tuning options for log delivery, including delivery, compression, and RetryDuration. You can apply tuning per output as needed.

      tuning:
        delivery: AtLeastOnce
        compression: none
        minRetryDuration: 1s
        maxRetryDuration: 10s
      AtLeastOnce
      The AtLeastOnce delivery mode ensures that if the log forwarder crashes or restarts, the forwarder re-sends any logs read but not yet delivered to their destination. The forwarder might duplicate some logs after a crash.

Verification

  1. Verify that your Splunk instance receives logs by viewing them in the Splunk dashboard.
  2. Troubleshoot any issues using OpenShift Container Platform and Splunk logs as needed.

11.4.4. View audit logs in Developer Hub

You can view, search, filter, and manage audit log data directly from the Red Hat OpenShift Container Platform web console. To isolate these logs from other data types, filter your results by using the isAuditEvent field.

Prerequisites

  • You are logged in as an administrator in the OpenShift Container Platform web console.

Procedure

  1. From the Developer perspective of the OpenShift Container Platform web console, click the Topology tab.
  2. From the Topology view, click the pod that you want to view audit log data for.
  3. From the pod panel, click the Resources tab.
  4. From the Pods section of the Resources tab, click View logs.
  5. From the Logs view, enter isAuditEvent into the Search field to filter audit logs from other log types. You can use the arrows to browse the logs containing the isAuditEvent field.

11.4.5. Review RBAC audit log events

The Role-Based Access Control (RBAC) backend plugin in Red Hat Developer Hub provides audit logging to track administrative changes, permission evaluations, and policy updates.

Administrators can use these logs to monitor who performed an action, when it occurred, and the outcome of the operation. Each audit log entry includes an eventId that represents a logical group of actions.

11.4.5.1. RBAC audit log events

role-write
Tracks the creation, modification, or removal of RBAC roles via the REST API, CSV file, or configuration.
role-read
Tracks requests to retrieve information about one or all existing RBAC roles.
policy-write
Tracks when permission policies are created, updated, or deleted.
policy-read
Tracks requests to retrieve or list defined permission policies.
condition-write
Tracks when conditional policies (logic-based rules) are modified via YAML or API.
condition-read
Tracks requests to retrieve conditional policy definitions.
permission-evaluation
Tracks when the RBAC system evaluates a user’s identity against policies to allow or deny an action on a resource.
plugin-policies-read
Tracks requests to list the available permission policies supported by installed plugins.
plugin-ids-write
Tracks updates to the list of plugins that are integrated with the permission framework.

11.4.5.2. RBAC audit log metadata fields

RBAC audit logs contain a meta object with event-specific details:

source
The origin of the event, such as rest, csv-file, configuration, or externalProviderPluginId.
actionType
The specific operation performed: create, update, delete, or create_or_update.
roleEntityRef
The entity reference of the specific role affected by the event.
members
A list of users or groups associated with the role when the event occurs.
decision
In evaluation events, indicates the policy decision: allow or deny.
result
The final outcome of a permission check, such as AuthorizeResult.

11.4.5.3. Example audit log entries

The following examples show how RBAC events appear in the Developer Hub logs.

An RBAC role creation event with status="initiated":

[backend]: 2025-03-25T17:24:17.438Z permission info permission.role-write isAuditEvent=true eventId="role-write" severityLevel="medium" actor={"actorId":"user:default/admin","ip":"::1"} request={"url":"/api/permission/roles","method":"POST"} meta={"actionType":"create", "source":"rest"} status="initiated"

An RBAC role creation event with status="succeeded":

[backend]: 2025-03-25T17:24:17.458Z permission info permission.role-write isAuditEvent=true eventId="role-write" severityLevel="medium" actor={"actorId":"user:default/admin"} request={"url":"/api/permission/roles","method":"POST"} meta={"actionType":"create", "source":"rest","roleEntityRef":"role:default/test-role"} status="succeeded"

11.5. Centralize workflow observability

11.5.1. Centralize workflow observability

Monitor and troubleshoot serverless workflows by deploying observability manifests, diagnosing failures with centralized logging, optimizing performance with distributed tracing, and filtering workflow data by trace attributes.

11.5.2. Apply deployment manifests

11.5.2.1. Apply deployment manifests

Deploy a complete observability stack for SonataFlow workflows with ready-to-use Jaeger and Loki manifests. These pre-configured examples help you monitor workflow performance and logs immediately without manual setup.

11.5.2.2. Jaeger distributed tracing deployment manifests

Deploy Jaeger to visualize distributed traces from SonataFlow workflows. Use these manifests to set up trace collection with pre-configured OTLP endpoints and resource limits for development or production environments.

Jaeger provides distributed tracing visualization for SonataFlow workflows.

apiVersion: v1
kind: Namespace
metadata:
  name: jaeger-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jaeger
  namespace: jaeger-system
  labels:
    app: jaeger
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jaeger
  template:
    metadata:
      labels:
        app: jaeger
    spec:
      containers:
      - name: jaeger
        image: jaegertracing/all-in-one:1.59
        env:
        - name: COLLECTOR_OTLP_ENABLED
          value: "true"
        ports:
        - containerPort: 16686
          name: query
        - containerPort: 4317
          name: otlp-grpc
        - containerPort: 4318
          name: otlp-http
        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        readinessProbe:
          httpGet:
            path: /
            port: 14269
          initialDelaySeconds: 5
        livenessProbe:
          httpGet:
            path: /
            port: 14269
          initialDelaySeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: jaeger-collector
  namespace: jaeger-system
  labels:
    app: jaeger
spec:
  selector:
    app: jaeger
  ports:
  - name: otlp-grpc
    port: 4317
    targetPort: 4317
  - name: otlp-http
    port: 4318
    targetPort: 4318
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  name: jaeger-query
  namespace: jaeger-system
  labels:
    app: jaeger
spec:
  selector:
    app: jaeger
  ports:
  - name: query-http
    port: 16686
    targetPort: 16686
  type: ClusterIP
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: jaeger-query
  namespace: jaeger-system
spec:
  to:
    kind: Service
    name: jaeger-query
  port:
    targetPort: query-http
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect

Add these properties to the application.properties file of your workflow:

# Direct connection to Jaeger
quarkus.otel.exporter.otlp.endpoint=http://jaeger-collector.jaeger-system.svc.cluster.local:4317
quarkus.otel.exporter.otlp.protocol=grpc
quarkus.otel.traces.exporter=cdi

# Additional Jaeger-specific propagation
quarkus.otel.propagators=tracecontext,baggage,jaeger

For production environments, use the Jaeger Operator with Elasticsearch storage:

apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
  name: jaeger-production
  namespace: observability
spec:
  strategy: production
  storage:
    type: elasticsearch
    elasticsearch:
      nodeCount: 3
      storage:
        storageClassName: gp3
        size: 50Gi
      resources:
        requests:
          cpu: 500m
          memory: 4Gi
        limits:
          cpu: 1000m
          memory: 8Gi
  collector:
    replicas: 2
    resources:
      requests:
        cpu: 200m
        memory: 256Mi
      limits:
        cpu: 500m
        memory: 512Mi

11.5.2.3. Loki log aggregation deployment manifests

Deploy Loki to aggregate logs from SonataFlow workflows using OpenTelemetry Protocol. These manifests include pre-configured OTLP settings, structured metadata support, and resource limits for immediate log collection.

Loki supports OpenTelemetry Protocol (OTLP) for direct log ingestion from SonataFlow workflows.

apiVersion: v1
kind: ConfigMap
metadata:
  name: loki-config
  namespace: observability
data:
  loki-config.yaml: |
    auth_enabled: false

    server:
      http_listen_port: 3100
      grpc_listen_port: 9096

    common:
      path_prefix: /loki
      storage:
        filesystem:
          chunks_directory: /loki/chunks
          rules_directory: /loki/rules
      replication_factor: 1
      ring:
        instance_addr: 127.0.0.1
        kvstore:
          store: inmemory

    distributor:
      otlp_config:
        # Default resource attributes as index labels
        default_resource_attributes_as_index_labels:
          - service.name
          - service.namespace
          - deployment.environment
          - k8s.namespace.name
          - k8s.cluster.name

    limits_config:
      # Enable structured metadata (default in Loki 3.0+)
      allow_structured_metadata: true
      # Maximum number of index labels per stream
      max_label_names_per_series: 15

    schema_config:
      configs:
        - from: 2024-01-01
          store: tsdb
          object_store: filesystem
          schema: v13  # Required for OTLP support
          index:
            prefix: index_
            period: 24h
apiVersion: apps/v1
kind: Deployment
metadata:
  name: loki
  namespace: observability
  labels:
    app: loki
spec:
  replicas: 1
  selector:
    matchLabels:
      app: loki
  template:
    metadata:
      labels:
        app: loki
    spec:
      securityContext:
        fsGroup: 10001
        runAsUser: 10001
        runAsNonRoot: true
      containers:
      - name: loki
        image: grafana/loki:3.0.0
        args:
          - -config.file=/etc/loki/loki-config.yaml
        ports:
        - containerPort: 3100
          name: http-metrics
        - containerPort: 9096
          name: grpc
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
          limits:
            cpu: 1000m
            memory: 2Gi
        volumeMounts:
        - name: config
          mountPath: /etc/loki
        - name: storage
          mountPath: /loki
        livenessProbe:
          httpGet:
            path: /ready
            port: 3100
          initialDelaySeconds: 45
        readinessProbe:
          httpGet:
            path: /ready
            port: 3100
          initialDelaySeconds: 45
      volumes:
      - name: config
        configMap:
          name: loki-config
      - name: storage
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: loki
  namespace: observability
  labels:
    app: loki
spec:
  selector:
    app: loki
  ports:
  - name: http-metrics
    port: 3100
    targetPort: 3100
  - name: grpc
    port: 9096
    targetPort: 9096
  type: ClusterIP

To route logs to Loki and traces to Jaeger, use the following configuration:

# OpenTelemetry Configuration
quarkus.otel.enabled=true
quarkus.otel.traces.enabled=true
quarkus.otel.metrics.enabled=true
quarkus.otel.logs.enabled=true

# OTLP Exporter - Send logs to Loki, traces to Jaeger
quarkus.otel.exporter.otlp.logs.endpoint=http://loki.observability.svc.cluster.local:3100/otlp
quarkus.otel.exporter.otlp.traces.endpoint=http://jaeger-collector.observability.svc.cluster.local:4317
quarkus.otel.exporter.otlp.protocol=grpc

# JSON Logging for better structure
quarkus.log.console.json=true
quarkus.log.console.json.pretty-print=false

# Include trace correlation in logs
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) traceId=%X{traceId}, spanId=%X{spanId} %s%e%n

# Resource attributes for Loki labels
quarkus.otel.resource.attributes=\
  service.name=greeting-workflow,\
  service.namespace=workflows,\
  deployment.environment=production

11.5.2.4. OpenTelemetry Collector deployment manifest

Deploy an OpenTelemetry Collector to route workflow telemetry to multiple backends. Use this intermediate layer for advanced log filtering, processing, and multi-destination export beyond direct workflow integration.

Deploy an OpenTelemetry collector between workflows and backends for advanced log processing, filtering, and multi-destination export.

# Collector routes to both Jaeger and Loki
exporters:
  otlp/jaeger:
    endpoint: jaeger-collector:4317
  otlphttp/loki:
    endpoint: http://loki:3100/otlp

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/loki]

11.5.3. Diagnose workflow failures using centralized logging

11.5.3.1. Diagnose workflow failures using centralized logging

Search all workflow logs from a single dashboard in Red Hat Developer Hub to diagnose failures quickly. Use structured logging to connect process instances with traces and set up automated alerts for workflow failures.

11.5.3.2. Enable JSON logging to search logs instantly without manual parsing

Output logs as JSON instead of plain text so log platforms can automatically filter by process instance, error level, or trace ID. Structured logging eliminates manual parsing and enables instant searches across millions of log entries.

SonataFlow workflows support structured JSON logging with automatic process instance correlation through:

  • Process instance context: Automatic processInstanceId correlation in all log entries
  • Structured format: JSON logs optimized for machine processing and aggregation
  • Multi-tenancy support: Log isolation by workflow and process instance

Prerequisites

  • You have deployed SonataFlow workflow by using the SonataFlow Operator on OpenShift or Kubernetes.
  • You have included the io.quarkus:quarkus-logging-json extension in your workflow QUARKUS_EXTENSIONS environment variable.
  • You have cluster-admin permissions for deploying log aggregation stack.

Procedure

  1. Update your workflow build configuration to include the JSON logging extension:

    export QUARKUS_EXTENSIONS="${QUARKUS_EXTENSIONS},io.quarkus:quarkus-logging-json"
  2. Open the {workflow-name}-props ConfigMap for your workflow.
  3. Add the following properties to the application.properties section:

    # Enable JSON logging with Quarkus JSON logging extension
    quarkus.log.console.json=true
    quarkus.log.console.json.pretty-print=false
    
    # Include all MDC context fields in JSON output
    # - processInstanceId: Set automatically by SonataFlow/Kogito
    # - traceId, spanId: Set by Quarkus OpenTelemetry (requires quarkus.otel.enabled=true)
    quarkus.log.console.json.print-details=true
    
    # Set log levels for workflow components
    quarkus.log.category."org.kie.kogito".level=DEBUG
    quarkus.log.category."io.serverlessworkflow".level=INFO
    
    # Optional: Enable additional context logging
    quarkus.log.category."org.kie.kogito.services.context".level=DEBUG
  4. Save the ConfigMap and restart the workflow pod.

    The following is an example of a workflow ConfigMap with an enabled JSON logging:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: greetings-props
      namespace: sonataflow-infra
    data:
      application.properties: |
        # JSON logging configuration
        quarkus.log.console.json=true
        quarkus.log.console.json.pretty-print=false
        quarkus.log.console.json.print-details=true
    
        # Log levels
        quarkus.log.category."org.kie.kogito".level=DEBUG
        quarkus.log.category."io.serverlessworkflow".level=INFO

Verification

  1. Check the pod logs to verify the JSON format and the presence of the processInstanceId:

    oc logs <workflow_pod_name> | grep processInstanceId
    {"timestamp":"...","level":"INFO","message":"...","mdc":{"processInstanceId":"abc-123-..."}}
Note

If the Mapped Diagnostic Context (MDC) fields are empty, verify the following:

  1. The workflow has processed at least one instance.
  2. The SonataFlow version matches the required configuration for MDC propagation.

11.5.3.3. Rotate logs automatically to prevent pod crashes from full disks

Automatically archive old logs before the disk fills up and crashes your workflow pods. Log rotation keeps recent logs available for debugging while preventing storage from becoming a production incident.

Important

When using file-based logging in Kubernetes, mount the log directory to a volume to prevent data loss or pod instability.

Prerequisites

  • You have configured a shared Kubernetes volume in the SonataFlow custom resource.
  • Your workflow image includes the JSON logging extension.

Procedure

  1. Add the following properties to the workflow ConfigMap to enable file-based JSON output:

    quarkus.log.file.enable=true
    quarkus.log.file.path=/var/log/sonataflow/workflow.log
    quarkus.log.file.json=true
  2. Configure log rotation settings to manage disk usage:

    quarkus.log.file.rotation.max-file-size=10M
    quarkus.log.file.rotation.max-backup-index=5
    quarkus.log.file.rotation.rotate-on-boot=true

    This configuration does the following:

  3. Rotates logs when they reach 10MB
  4. Keeps up to 5 backup files
  5. Adds date suffix to rotated files
  6. Rotates on application startup
  7. Set log level for file output:

    quarkus.log.file.level=INFO
  8. Update the SonataFlow custom resource (CR) to mount the volume at the log path:

    spec:
      podTemplate:
        container:
          volumeMounts:
          - name: shared-logs
            mountPath: /var/log/sonataflow
      volumes:
      - name: shared-logs
        emptyDir:
          sizeLimit: 500Mi
  9. After applying the configuration, restart your workflow pod and check the log output:

    # Get workflow pod name
    oc get pods -n sonataflow-infra -l sonataflow.org/workflow-app=your-workflow
    
    # Check logs for JSON format
    oc logs -n sonataflow-infra your-workflow-pod-name | head -5

Verification

  1. Access the workflow container and verify the log file exists and is receiving JSON data:

    oc exec <pod_name> -- ls -l /var/log/sonataflow/workflow.log
  2. Verify that the file contains JSON data:

    oc exec <pod_name> -- head -n 5 /var/log/sonataflow/workflow.log

11.5.3.5. Centralize logs for workflow troubleshooting

Query logs from all workflow pods in your Red Hat Developer Hub cluster using a single Grafana dashboard. Centralized logging allows you to search by process ID, error type, or time range from a browser.

Prerequisites

  • You have running Loki and Grafana instances in the cluster.
  • You have configured workflow for file-based JSON logging.
  • You have cluster-admin permissions.

Procedure

  1. Deploy the PLG stack by using Helm:

    # Add Grafana Helm repository
    helm repo add grafana https://grafana.github.io/helm-charts
    helm repo update
    
    # Create namespace
    oc new-project sonataflow-observability
    
    # Deploy Loki stack
    helm install loki-stack grafana/loki-stack \
      --namespace sonataflow-observability \
      --set loki.persistence.enabled=true \
      --set loki.persistence.size=20Gi \
      --set promtail.config.logLevel=info \
      --set grafana.enabled=true
    Note

    For production deployments, use a custom values.yaml file with appropriate resource limits and security contexts.

  2. Create a ConfigMap for the Promtail sidecar by selecting the configuration that matches your logging method:

    1. Scrape container stdout

      Use this configuration to collect logs from container stdout by using Kubernetes service discovery:

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: promtail-config
        namespace: sonataflow-observability
      data:
        config.yml: |
          server:
            http_listen_port: 3101
      
          clients:
            - url: http://loki:3100/loki/api/v1/push
      
          scrape_configs:
          - job_name: sonataflow-workflows
            kubernetes_sd_configs:
            - role: pod
              namespaces:
                names: ["sonataflow-infra"]
      
            relabel_configs:
            - source_labels: [__meta_kubernetes_pod_label_sonataflow_org_workflow_app]
              action: keep
              regex: (.+)
      
            - source_labels: [__meta_kubernetes_pod_name]
              target_label: pod
      
            - source_labels: [__meta_kubernetes_pod_label_sonataflow_org_workflow_app]
              target_label: workflow
      
            pipeline_stages:
            - json:
                expressions:
                  timestamp: timestamp
                  level: level
                  logger: logger
                  message: message
                  processInstanceId: mdc.processInstanceId
                  traceId: mdc.traceId
                  spanId: mdc.spanId
      
            - labels:
                level:
                logger:
                processInstanceId:
                traceId:
    2. Scrape JSON log files

      If you use [file-based JSON logging](#file-based-json-logging), configure Promtail to read from the shared log volume:

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: promtail-sidecar-config
        namespace: sonataflow-infra
      data:
        config.yml: |
          server:
            http_listen_port: 3101
      
          clients:
            - url: http://loki.sonataflow-observability.svc.cluster.local:3100/loki/api/v1/push
      
          positions:
            filename: /var/log/positions.yaml
      
          scrape_configs:
          - job_name: sonataflow-json-files
            static_configs:
            - targets:
                - localhost
              labels:
                job: sonataflow-workflows
                __path__: /var/log/sonataflow/*.log
      
            pipeline_stages:
            - json:
                expressions:
                  timestamp: timestamp
                  level: level
                  logger: loggerName
                  message: message
                  processInstanceId: mdc.processInstanceId
                  traceId: mdc.traceId
                  spanId: mdc.spanId
      
            - labels:
                level:
                logger:
                processInstanceId:
                traceId:
      
            - timestamp:
                source: timestamp
                format: RFC3339Nano
  3. Add the Promtail sidecar container to your SonataFlow custom resource:

    apiVersion: sonataflow.org/v1alpha08
    kind: SonataFlow
    metadata:
      name: my-workflow
      namespace: sonataflow-infra
    spec:
      podTemplate:
        container:
          volumeMounts:
          - name: shared-logs
            mountPath: /var/log/sonataflow
        containers:
        - name: promtail-sidecar
          image: grafana/promtail:2.9.0
          args:
            - -config.file=/etc/promtail/config.yml
          volumeMounts:
          - name: shared-logs
            mountPath: /var/log/sonataflow
            readOnly: true
          - name: promtail-config
            mountPath: /etc/promtail
          - name: positions
            mountPath: /var/log
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 100m
              memory: 128Mi
        volumes:
        - name: shared-logs
          emptyDir:
            sizeLimit: 500Mi
        - name: promtail-config
          configMap:
            name: promtail-sidecar-config
        - name: positions
          emptyDir: {}
  4. Querying logs in Grafana: After deploying the stack, use the following LogQL queries in the Grafana Explore view:

    1. Filter logs by process instance

      {job="sonataflow-workflows"} | json | processInstanceId="abc-123-def-456"
    2. Find workflow errors:

      {job="sonataflow-workflows", workflow="onboarding"} | json | level="ERROR"
    3. Trace correlation:

      {job="sonataflow-workflows"} | json | traceId="4bf92f3577b34da6a3ce929d0e0e4736"
    4. Process instance timeline:

      {job="sonataflow-workflows"} | json | processInstanceId="abc-123-def-456" | line_format "{{.timestamp}} [{{.level}}] {{.message}}"

Verification

  1. Access the Grafana Explore view.
  2. Run the following LogQL query, replacing <instance_id> with a valid ID:

    {job="sonataflow-workflows"} | json | processInstanceId="<instance_id>"

    Confirm that Grafana displays the log entries associated with the specified process instance.

11.5.3.6. Monitor workflow health with automated alerts

Set up automated alerts to notify your team when workflows fail at high rates, process instances become stuck, or runtimes exceed thresholds. Proactive alerting reduces mean time to detection for production issues.

Prerequisites

  • You have enabled a structured JSON logging to provide metadata for LogQL and PromQL queries.
  • You have installed a monitoring stack, such as Prometheus or Loki with Alertmanager in the cluster.

Procedure

  1. Create a configuration file containing the following alert rule groups based on your monitoring requirements:

    • To monitor failure rates:

      - alert: WorkflowHighErrorRate
        expr: rate({job="sonataflow-workflows", level="ERROR"}[5m]) > 0.1
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "High error rate in SonataFlow workflows"
    • To identify stalled process instances:

      - alert: WorkflowInstanceStuck
        expr: |
          time() - max by (process_instance_id) (
            {job="sonataflow-workflows"} | json | unwrap timestamp[1h]
          ) > 3600
        labels:
          severity: critical
    • To identify long-running workflows:

        - alert: LongRunningWorkflow
          expr: |
            time() - min by (process_instance_id) (
              {job="sonataflow-workflows"} | json | message="Workflow started" | unwrap timestamp[24h]
            ) > 7200
          labels:
            severity: warning
          annotations:
            summary: "Workflow {{ $labels.process_instance_id }} running longer than 2 hours"
  2. Apply the alert rules to your cluster.

Verification

  1. Access the monitoring dashboard, such as the Prometheus or OpenShift Console.
  2. Verify that the alerts appear in the list under the Alerts tab.

11.5.3.7. Route alerts to existing tools to reduce response time

Receive failure notifications where your team already monitors incidents instead of checking a separate dashboard. Routing alerts to existing channels ensures on-call engineers see critical workflow issues immediately.

Prerequisites

  • You have a valid webhook URL for the notification service (for example, Slack webhook).

Procedure

  1. Define a receiver and a routing path in your Alertmanager configuration:

    route:
      group_by: ['alertname', 'workflow']
      group_wait: 10s
      group_interval: 10s
      repeat_interval: 1h
      receiver: 'web.hook'
    
    receivers:
    - name: 'web.hook'
      slack_configs:
      - api_url: 'YOUR_SLACK_WEBHOOK_URL'
        channel: '#workflow-alerts'
        title: 'SonataFlow Alert'
        text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
  2. Reload the Alertmanager configuration to apply the changes.

Verification

  1. Trigger a test alert in your workflow environment.
  2. Monitor the external notification service (for example, the Slack channel #workflow-alerts). A notification appears in the external service containing the summary and details of the triggered alert.

11.5.3.8. Diagnose missing observability data to restore visibility

To restore monitoring visibility in Red Hat Developer Hub, you must identify why logs or traces are missing. Use these diagnostic steps to resolve issues with plain text logs, empty process instance IDs, or missing traces in Jaeger.

Prerequisites

  • You have access to the OpenShift (oc) CLI.
  • You have administrator permissions for the sonataflow-infra and sonataflow-observability namespaces.
  • You have access to the workflow project pom.xml and ConfigMap files.

Procedure

  1. Verify JSON log formatting.

    If logs appear as plain text instead of structured JSON, verify the following:

  2. The io.quarkus:quarkus-logging-json extension is defined in the pom.xml file.
  3. The quarkus.log.console.json=true property is set in the {workflow-name}-props ConfigMap.
  4. The workflow image was rebuilt and redeployed after adding the extension.
  5. The workflow pod was restarted after applying ConfigMap changes.
  6. Diagnose missing process instance context.

    If logs are in JSON format but the processInstanceId field is missing or empty, verify the following:

  7. Workflow instances are actively running.
  8. The following property is set in the workflow ConfigMap:

    quarkus.log.console.json.print-details=true
  9. The SonataFlow version in use supports automatic Mapped Diagnostic Context (MDC) population.
  10. Resolve log collection failures in Loki.

    If logs are generated but do not appear in Loki or the aggregation dashboard, verify the following:

  11. The Promtail or Fluent Bit label selector matches the workflow pod labels.
  12. The collector has the required Role-Based Access Control (RBAC) permissions to read logs from the workflow namespace.
  13. The scrape_configs in the collector configuration include the correct namespace.
  14. Check the collector logs for permission errors:

    oc logs -l app=promtail -n sonataflow-observability
  15. Mitigate high resource usage.

    If JSON logging causes performance degradation or high storage costs, implement the following changes:

  16. Increase the log level for verbose categories to reduce output volume:

    quarkus.log.category."org.kie.kogito".level=WARN
  17. Enable asynchronous logging to reduce the impact on workflow execution time:

    quarkus.log.console.async=true
  18. Configure log rotation and retention policies in the aggregation backend.

Verification

  1. After applying a fix, trigger a workflow execution.
  2. Inspect the latest log entries. The logs appear in JSON format and include valid processInstanceId, traceId, and spanId fields:

    oc logs <workflow_pod_name> --tail=10

11.5.3.9. Integrate Loki logs for Orchestrator workflows

To troubleshoot and debug errors, integrate Loki logs into the Red Hat Developer Hub interface. You must install the Loki backend module and configure the connection details.

Prerequisites

  • You have enabled the Orchestrator plugins in your Red Hat Developer Hub instance.
  • You have a running Loki instance.
  • You have stored your Orchestrator logs in the Loki instance.

Procedure

  1. Enable the Loki backend module in the redhat-developer-hub-dynamic-plugins ConfigMap.

    Enabling the Loki backend module in the ConfigMap
  2. Open the ConfigMap and select the YAML view.
  3. Add the Loki backend module to the plugins section:

    - disabled: false
          package: oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend-module-loki:{{inherit}}
    Adding the Loki backend module plugin to the ConfigMap
  4. Save the file.
  5. In your application app-config.yaml ConfigMap file, add the Loki workflow log provider integration to the orchestrator section:

    Adding the Loki workflow log provider configuration
    Loki workflow log provider configuration in the ConfigMap
    Note

    The base URl might vary depending on where you store and access the Loki logs.

    To obtain the base URL, run the following command:

    LOKI_HOST=$(oc get route logging-loki -n openshift-logging -o jsonpath='{.spec.host}')
    echo "https://$LOKI_HOST/api/logs/v1/application/"
    orchestrator:
      workflowLogProvider:
        loki:
          baseUrl: <LOKI_BASE_URL>
    	token: <AUTH_TOKEN>
    	rejectUnauthorized: false
         # logPipelineFilters:
          # - '| filter1'
          # - '|= filter2'
          # logStreamSelectors:
          #   - label: 'app'
          #     value: '=~".+"'

    where:

    baseUrl: Specifies the base URL of your Loki instance. This value is required.

    token: The access token for authentication. This value is required. To find your current token, run the oc whoami -t command.

    rejectUnauthorized: Set to false if using self-signed certificates.

    Optional Parameters

    logPipelineFilters: Multiple Log Pipeline Filters can be specified in the logPipelineFilters section. See the Loki documentation to learn more about the log pipeline filters and their values and usage.

    logStreamSelectors: Specifies log stream selectors to filter the logs. By default, the plugin retrieves logs with the openshift_log_type="application". For more information about selector syntax, see the Grafana Loki documentation.

  6. Save the ConfigMap.
  7. Restart the Red Hat Developer Hub pod to apply the changes.

Verification

  1. Navigate to the Orchestrator plugin in the RHDH interface.
  2. Select a workflow instance.
  3. Click View Logs to display the workflow instance logs.

11.5.3.10. OpenTelemetry configurations

Configuration properties that control where traces are sent, how often they are sampled, and which service name appears in your monitoring dashboard. Reference this table to tune telemetry behavior for your environment.

PropertyDescriptionDefault

quarkus.otel.enabled

Enables or disables OpenTelemetry support.

false

quarkus.otel.service.name

Specify the service name that appears in the trace backend.

unset

quarkus.otel.exporter.otlp.endpoint

The URL of the OTLP-compatible collector.

http://localhost:4317

quarkus.otel.exporter.otlp.protocol

The transport protocol. Supported values are grpc or http/protobuf.

grpc

quarkus.otel.traces.sampler

The sampling strategy. For example, always_on, always_off, or parentbased_always_on.

parentbased_always_on

11.5.4. Optimize workflow performance

11.5.4.1. Optimize workflow performance

To maintain high performance in Red Hat Developer Hub, you must identify and resolve execution delays. Use distributed tracing to visualize the execution path and workflows and determine where time is spent across service boundaries.

11.5.4.2. Collect traces to monitor workflow performance

To monitor workflows in Red Hat Developer Hub, you must enable distributed tracing. Distributed tracing shows the executed path of workflow steps and identifies where failures occur.

To enable observability features such as tracing and metrics in the SonataFlow runtime, you must add the OpenTelemetry addon and configure the workflow properties. The sonataflow-addons-quarkus-opentelemetry addon provides a standard configuration with minimal setup required.

The OpenTelemetry integration for SonataFlow includes the following capabilities:

  • Distributed tracing: Track workflow execution across services and steps.
  • Metrics collection: Monitor performance, duration, and success rates.
  • Log aggregation: Centralize logs with trace correlation.
  • Context propagation: Maintain trace context across workflow boundaries and asynchronous operations.

Prerequisites

  • You have installed and configured the SonataFlow Operator.
  • You have cluster-admin or equivalent permissions to deploy observability infrastructure and modify ConfigMaps.
  • A Kubernetes or OpenShift cluster is available.

Procedure

  1. Add the OpenTelemetry addon to the QUARKUS_EXTENSIONS environment variable during the image build process:

    export QUARKUS_EXTENSIONS="${QUARKUS_EXTENSIONS},org.apache.kie.sonataflow:sonataflow-addons-quarkus-opentelemetry"
  2. Open the {workflow-name}-props ConfigMap for your workflow.
  3. In the application.properties section, enable the OpenTelemetry integration and configure the service attributes:

    # Application Identity
    quarkus.application.name=my-workflow
    quarkus.application.version=1.0.0
    
    # OpenTelemetry Configuration
    quarkus.otel.enabled=true
    quarkus.otel.traces.enabled=true
    quarkus.otel.metrics.enabled=true
    quarkus.otel.logs.enabled=true
    
    # Service Resource Attributes
    quarkus.otel.resource.attributes=\
      service.name=my-workflow,\
      service.namespace=workflows,\
      service.version=1.0.0,\
      deployment.environment=production
    
    # SonataFlow Specific Configuration
    # Master switch for SonataFlow OpenTelemetry integration
    sonataflow.otel.enabled=true
    # Service identification (uses Quarkus application name/version as defaults)
    sonataflow.otel.service-name=${quarkus.application.name:kogito-workflow-service}
    sonataflow.otel.service-version=${quarkus.application.version:unknown}
    # Enable span creation for workflow states
    sonataflow.otel.spans.enabled=true
    # Enable process lifecycle events (start, complete, error, state transitions)
    sonataflow.otel.events.enabled=true
  4. Save the ConfigMap and restart the workflow pod to apply the changes.

Verification

  1. Verify that the OpenTelemetry addon is loaded by checking the pod logs:

    oc logs -n workflows deployment/onboarding-workflow | grep "sonataflow-addons-quarkus-opentelemetry"
  2. Verify the trace report status:

    oc logs -n workflows deployment/greeting | grep -i "export\|batch"
  3. Confirm that the observability backend, such as Jaeger, is receiving data:

    oc logs -n observability deployment/jaeger | grep -i "span\|trace"

11.5.4.3. Connect traces to existing monitoring to avoid tool sprawl

Route workflow traces to the observability tools your team already uses instead of learning a new system. Exporter configuration sends telemetry data to Jaeger, Grafana, or any OTLP-compatible platform.

Prerequisites

  • You have enabled OpenTelemetry in your workflow.
  • An observability platform (Jaeger or OpenTelemetry Collector) is available in your cluster.

Procedure

  1. Configure an export strategy based on your environment requirements:

    • Configure the OTLP exporter with batch processing (Recommended)

      For production environments, use an OTLP exporter with batch processing to reduce network overhead and improve performance:

      # OTLP exporter - Direct to Jaeger
      quarkus.otel.exporter.otlp.endpoint=http://jaeger-collector.observability.svc.cluster.local:4317
      quarkus.otel.exporter.otlp.protocol=grpc
      quarkus.otel.traces.exporter=cdi
      
      # Batch processing for production
      quarkus.otel.bsp.schedule.delay=5s
      quarkus.otel.bsp.max.export.batch.size=512
      quarkus.otel.bsp.export.timeout=2s
      quarkus.otel.bsp.max.queue.size=2048
    • Configure direct export to an external platform

      For development or simple integrations, use a direct export configuration:

      # Example: Direct export to Jaeger
      quarkus.otel.exporter.otlp.endpoint=http://jaeger-collector:4317
      quarkus.otel.exporter.otlp.protocol=grpc
      quarkus.otel.traces.exporter=cdi
  2. Externalize the configuration for production deployments by using environment variables. This ensures that your deployment remains secure and flexible across environments.

    # Externalized Configuration
    quarkus.otel.exporter.otlp.endpoint=${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4317}
    quarkus.otel.exporter.otlp.headers=${OTEL_EXPORTER_OTLP_HEADERS:}
    quarkus.application.name=${OTEL_SERVICE_NAME:my-workflow}
    quarkus.otel.resource.attributes=${OTEL_RESOURCE_ATTRIBUTES:deployment.environment=dev}

11.5.4.4. Troubleshooting reference for trace connectivity and authentication issues

Symptom-to-solution reference table for missing traces, authentication failures, and broken context propagation. Use this troubleshooting guide when traces fail to appear in Jaeger, authentication errors occur, or telemetry delivery stops working.

SymptomPotential causeResolution

Traces do not appear in the dashboard.

OpenTelemetry is disabled or the endpoint is unreachable.

Verify the quarkus.otel.enabled property and test endpoint connectivity.

Authentication errors (401/403).

Missing or invalid authorization headers.

Configure the quarkus.otel.exporter.otlp.headers property with a valid token.

High memory usage in the collector.

Large telemetry batches or high traffic volume.

Implement a memory_limiter processor in the collector configuration.

Context is lost between workflow steps.

Incorrect propagator configuration.

Ensure quarkus.otel.propagators includes all required formats (for example, tracecontext and baggage).

11.5.4.4.1. Diagnose missing traces
  1. Verify that OpenTelemetry is enabled in the workflow ConfigMap:

    oc get cm {workflow-name}-props -n workflows -o yaml
    1. Check the pod logs for initialization errors:

      oc logs deployment/{deployment-name} -n workflows | grep -i "otel"
    2. Test the connection to the Jaeger collector from within the workflow pod:

      oc exec deployment/{deployment-name} -- curl -v http://jaeger-collector:4317
  2. Configure authentication headers. If your observability platform requires authentication, add the following property to your application.properties file:

    quarkus.otel.exporter.otlp.headers=authorization=Bearer ${API_TOKEN}
  3. Resolve context propagation issues. To ensure trace IDs are maintained across service boundaries, configure the following propagators and enable JSON logging to verify the IDs in the output:
# Include required propagators
quarkus.otel.propagators=tracecontext,baggage,jaeger

# Enable JSON logging to verify trace IDs
quarkus.log.console.json=true

11.5.5. Trace attribute definitions and filtering keys

Automatic span attributes that identify workflow executions, instances, and states. Use these attributes in Jaeger queries to locate specific workflow runs, filter by version, or trace process instances through various execution states.

To locate specific workflow executions or trace a process through various states, use the automatic span attributes generated by SonataFlow. Each span includes the following specific attributes:

  • sonataflow.process.id: Indicates the ID of the workflow definition.
  • sonataflow.process.instance.id: Indicates the unique ID for the specific execution instance.
  • sonataflow.process.version: Indicates the version of the workflow definition.
  • sonataflow.workflow.state: Indicates the name of the current workflow state, for example, StartEvent.
  • sonataflow.process.instance.state: Indicates the current state of the process instance, such as ACTIVE, COMPLETED, ERROR, or SUSPENDED.
  • sonataflow.transaction.id: Indicates the ID used to correlate multiple workflows in a single business transaction.
  • sonataflow.tracker.*: Indicates custom attributes converted from X-TRACKER-* headers.
  • service.name and service.version: Indicates the service identification details from the configuration.

11.6. Collect diagnostic data to troubleshoot platform issues

11.6.1. Diagnostic data collection overview

The must-gather tool collects diagnostic data and logging information from your cluster, which helps Red Hat Support resolve your deployment issues efficiently.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

Use must-gather when you open a support ticket with Red Hat Global Support Services, troubleshoot deployment issues, or capture deployment state before RHDH upgrades.

Note

Typical collection size ranges from 10 MB to 50 MB for basic collections and 500 MB to 2 GB when including heap dumps. Plan for adequate storage and bandwidth when collecting for support tickets.

Important

The must-gather output might contain sensitive information such as configuration values, environment variables, application logs, and resource definitions. While the tool automatically sanitizes known secret types, you should review the output before sharing it with support to check for domain-specific sensitive data.

11.6.2. Run must-gather on OpenShift to collect diagnostic data

11.6.2.1. Run must-gather on OpenShift to collect diagnostic data

Run the must-gather tool on OpenShift Container Platform or Kubernetes clusters to collect diagnostic data for troubleshooting Developer Hub deployments. You can also collect diagnostic data from air-gapped clusters by using a mirrored must-gather image.

11.6.2.2. Run must-gather on OpenShift to collect diagnostic data

Collect diagnostic data from RHDH deployments on OpenShift Container Platform.

Prerequisites

  • You have deployed Red Hat Developer Hub on OpenShift Container Platform.
  • Cluster administrator access or RBAC permissions for resource inspection.
  • Authenticated OpenShift CLI (oc) (OpenShift Container Platform).

Procedure

  1. Run must-gather:

    $ oc adm must-gather --image=registry.access.redhat.com/rhdh/rhdh-must-gather-rhel9:1.10

    Output: ./must-gather.local.<timestamp>

    Note

    The must-gather tool automatically detects and collects data from all RHDH instances in the cluster, regardless of whether they were deployed using the Operator or Helm chart.

    For advanced scenarios, you can limit data collection:

    1. Skip Helm-based deployments: -- /usr/bin/gather --without-helm
    2. Skip Operator-based deployments: -- /usr/bin/gather --without-operator

Verification

  • Confirm that the output directory exists:

    $ ls must-gather.local.<timestamp>/

    The directory contains subdirectories for each deployment method found:

    • operator/ - Data from Operator-based deployments
    • helm/ - Data from Helm-based deployments

11.6.2.3. Run must-gather on Kubernetes to collect diagnostic data

Collect diagnostic data from RHDH deployments on supported Kubernetes platforms.

Prerequisites

  • You have deployed Red Hat Developer Hub on a supported Kubernetes platform.
  • Cluster administrator access or RBAC permissions for resource inspection.
  • Authenticated CLI: kubectl and helm.

Procedure

  1. Install must-gather:

    $ helm upgrade --install my-rhdh-must-gather redhat-developer-hub-must-gather \
      --repo https://charts.openshift.io \
      --namespace rhdh-diagnostics \
      --create-namespace
    Note

    The must-gather tool automatically detects and collects data from all RHDH instances in the cluster, regardless of whether they were deployed using the Operator or Helm chart.

    For advanced scenarios, you can limit data collection using Helm values:

    1. Skip Helm-based deployments: --set gather.withHelm=false
    2. Skip Operator-based deployments: --set gather.withOperator=false
  2. Wait for collection:

    $ kubectl wait --for=condition=ready pod \
      -l app.kubernetes.io/instance=my-rhdh-must-gather,app.kubernetes.io/component=gather \
      --timeout=3600s -n rhdh-diagnostics
  3. Extract data:

    $ kubectl exec deploy/my-rhdh-must-gather -c data-holder -n rhdh-diagnostics -- \
      tar czf - -C /must-gather . > rhdh-must-gather-output.tar.gz
  4. Clean up:

    $ helm uninstall my-rhdh-must-gather -n rhdh-diagnostics

Verification

  • Confirm that the output archive contains diagnostic data:

    $ tar -tzf rhdh-must-gather-output.tar.gz

    The archive contains subdirectories for each deployment method found:

    • operator/ - Data from Operator-based deployments
    • helm/ - Data from Helm-based deployments

11.6.2.4. Collect diagnostic data from air-gapped clusters with a mirrored must-gather image

Mirror the must-gather image to your registry to enable diagnostic data collection from disconnected clusters.

Prerequisites

  • skopeo tool installed on the machine with registry access.
  • Access to an internal container registry.
  • For OpenShift Container Platform: Cluster administrator access to update the global pull secret.
  • For Kubernetes: Ability to create secrets in target namespaces.

Procedure

  1. Choose your mirroring workflow based on network access:

    Partially disconnected:

    Your local machine can access both the internet and the internal registry.

    Fully disconnected:

    Requires a bastion host or approved file transfer method to move images.

  2. Mirror the must-gather image:

    For partially disconnected environments:

    $ skopeo copy \
      docker://registry.access.redhat.com/rhdh/rhdh-must-gather-rhel9:*<version>* \
      docker://<internal-registry>/rhdh/rhdh-must-gather:*<version>*

    For fully disconnected environments:

    On a machine with internet access, pull the must-gather image:

    $ skopeo copy \
      docker://registry.access.redhat.com/rhdh/rhdh-must-gather-rhel9:*<version>* \
      dir:./rhdh-must-gather-<version>

    Pull the Helm chart:

    $ helm pull redhat-developer-hub-must-gather --repo https://charts.openshift.io

    Transfer the image directory and the redhat-developer-hub-must-gather-<version>.tgz chart file to your bastion host. Push the image to the internal registry:

    $ skopeo copy \
      dir:./rhdh-must-gather-<version> \
      docker://<internal-registry>/rhdh/rhdh-must-gather:*<version>*

    Replace <version> with the must-gather version that matches your RHDH deployment and <internal-registry> with your internal registry hostname.

  3. Configure image pull authentication:

    Note

    If your internal registry requires authentication, you must configure image pull secrets before running must-gather. Without proper credentials, the must-gather pod fails with ImagePullBackOff errors.

    On OpenShift Container Platform:

    Add your internal registry credentials to the cluster-wide pull secret. For instructions, see Updating the global cluster pull secret in the Red Hat OpenShift Container Platform documentation.

    On Kubernetes:

    Create a docker-registry secret:

    $ kubectl create secret docker-registry must-gather-pull-secret \
      --docker-server=<internal-registry> \
      --docker-username=<username> \
      --docker-password=<password> \
      -n rhdh-diagnostics
  4. Run must-gather using the mirrored image:

    On OpenShift Container Platform:

    $ oc adm must-gather --image=<internal-registry>/rhdh/rhdh-must-gather:*<version>*

    On Kubernetes (partially disconnected):

    $ helm upgrade --install my-rhdh-must-gather redhat-developer-hub-must-gather \
      --repo https://charts.openshift.io \
      --namespace rhdh-diagnostics \
      --create-namespace \
      --set image.registry=<internal-registry> \
      --set image.repository=rhdh/rhdh-must-gather \
      --set image.tag=<version> \
      --set imagePullSecrets[0].name=must-gather-pull-secret

    On Kubernetes (fully disconnected):

    $ helm upgrade --install my-rhdh-must-gather /path/to/redhat-developer-hub-must-gather-<version>.tgz \
      --repo https://charts.openshift.io \
      --namespace rhdh-diagnostics \
      --create-namespace \
      --set image.registry=<internal-registry> \
      --set image.repository=rhdh/rhdh-must-gather \
      --set image.tag=<version> \
      --set imagePullSecrets[0].name=must-gather-pull-secret

Verification

  • Verify that the collection starts without ImagePullBackOff errors:

    $ oc get pods -n openshift-must-gather-<random>  # On OpenShift
    $ kubectl get pods -n rhdh-diagnostics           # On Kubernetes

Troubleshooting

ImagePullBackOff errors:

Check that registry credentials are configured correctly and that the image path matches your registry structure.

Certificate errors:

If your internal registry uses self-signed certificates, configure certificate trust on the cluster. For OpenShift Container Platform, see Configuring image registry repository mirroring in the Red Hat OpenShift Container Platform documentation.

11.6.3. Collect heap dumps to diagnose memory issues

Collect Node.js heap snapshots when you troubleshoot memory leaks, out-of-memory errors, or when support requests memory analysis.

Prerequisites

  • Sufficient storage for heap dump files (50 MB to 500 MB each).
  • For SIGUSR2 method: Node.js 12+ for --heapsnapshot-signal flag support.

Procedure

  1. Choose the heap dump collection method:

    Inspector protocol (default):

    • Works out of the box
    • Use unless your deployment sets --disable-sigusr1 in NODE_OPTIONS

    SIGUSR2 signal:

    • Requires configuring NODE_OPTIONS in your deployment first
    • Use when the inspector protocol is not available
  2. If using SIGUSR2, configure NODE_OPTIONS:

    Note

    Skip this step if using the inspector protocol (default method).

    Operator deployments:

    apiVersion: rhdh.redhat.com/v1alpha1
    kind: Backstage
    metadata:
      name: my-rhdh
    spec:
      application:
        extraEnvs:
          - name: NODE_OPTIONS
            value: "--heapsnapshot-signal=SIGUSR2 --diagnostic-dir=/tmp"

    Apply the change:

    $ oc apply -f backstage-cr.yaml

    Helm deployments:

    upstream:
      backstage:
        extraEnvVars:
          - name: NODE_OPTIONS
            value: "--heapsnapshot-signal=SIGUSR2 --diagnostic-dir=/tmp"

    Update the release:

    $ helm upgrade my-rhdh redhat-developer-hub/backstage -f values.yaml -n <namespace>

    Wait for pods to restart before proceeding.

  3. Increase the liveness probe timeout to prevent pod restarts:

    Important

    RHDH stops responding during heap dump collection, and large memory footprints (1GB+) can cause liveness probe failures. Plan collection during maintenance windows or low-traffic periods.

    Operator deployments:

    Update the Backstage custom resource to patch the deployment:

    apiVersion: rhdh.redhat.com/v1alpha1
    kind: Backstage
    metadata:
      name: my-rhdh
    spec:
      deployment:
        patch:
          spec:
            template:
              spec:
                containers:
                  - name: backstage-backend
                    livenessProbe:
                      failureThreshold: 180

    Apply the change:

    $ oc apply -f backstage-cr.yaml

    Helm deployments:

    Update your Helm values:

    upstream:
      backstage:
        livenessProbe:
          failureThreshold: 180

    Apply the change:

    $ helm upgrade my-rhdh redhat-developer-hub/backstage -f values.yaml -n <namespace>

    Wait for pods to restart before proceeding.

  4. Run must-gather with heap dumps enabled:

    On OpenShift Container Platform:

    For inspector protocol (default):

    $ oc adm must-gather --image=registry.access.redhat.com/rhdh/rhdh-must-gather-rhel9:1.10 -- /usr/bin/gather --with-heap-dumps

    For SIGUSR2 method:

    $ oc adm must-gather --image=registry.access.redhat.com/rhdh/rhdh-must-gather-rhel9:1.10 -- /usr/bin/gather --with-heap-dumps --heap-dump-method sigusr2

    On supported Kubernetes platforms:

    For inspector protocol (default):

    gather:
      heapDump:
        enabled: true
        method: "inspector"

    For SIGUSR2 method:

    gather:
      heapDump:
        enabled: true
        method: "sigusr2"

    Collection takes 5-15 minutes depending on pod count and memory size.

Verification

Check for .heapsnapshot files:

$ find must-gather.local.<timestamp> -name "*.heapsnapshot"  # On OpenShift
$ tar -tzf rhdh-must-gather-output.tar.gz | grep heapsnapshot  # On Kubernetes
If collection starts but times out before completing

You see progress messages but collection eventually times out before finishing. Check the must-gather logs for warnings about liveness probe settings:

[WARN] Pod 'xxx' may restart during heap dump collection!
[WARN]   Current: failureThreshold=3 × periodSeconds=10s = 30s before restart
[WARN]   Required: at least 900s (HEAP_DUMP_TIMEOUT)

Set your liveness probe timeout longer than the collection time.

For Operator-based deployments, update the Backstage custom resource:

spec:
  deployment:
    patch:
      spec:
        template:
          spec:
            containers:
              - name: backstage-backend
                livenessProbe:
                  failureThreshold: 180

Apply with oc apply -f backstage-cr.yaml.

For Helm-based deployments, patch the deployment directly:

$ oc patch deployment <deployment-name> -n <namespace> \
  -p '{"spec":{"template":{"spec":{"containers":[{"name":"backstage-backend","livenessProbe":{"failureThreshold":180}}]}}}}'

Wait for your pods to restart with the new configuration, then run heap dump collection again.

If collection times out

Large memory footprints (multiple gigabytes) can take 10-15 minutes to snapshot. Increase the heap dump timeout to allow more time for collection.

On OpenShift Container Platform, set the timeout using an environment variable:

$ oc adm must-gather --image=registry.access.redhat.com/rhdh/rhdh-must-gather-rhel9:1.10 \
  -- /usr/bin/env HEAP_DUMP_TIMEOUT=1800 /usr/bin/gather --with-heap-dumps

On Kubernetes, set the timeout in your Helm values:

gather:
  heapDump:
    enabled: true
    timeout: "1800"

11.6.4. Diagnostic data types and collection scope

The must-gather tool uses collectors to gather specific types of diagnostic data.

Reduce collection time by:

  • Excluding collectors not needed for your deployment
  • Filtering to specific namespaces
  • Enabling optional collectors only when required

11.6.4.1. Default-enabled collectors

The following collectors run by default. Exclude collectors not needed for your deployment using --without-<collector> flags:

platform collector
Collects cluster version and platform type (OpenShift Container Platform, AKS, EKS, or GKE). Disable with --without-platform.
helm collector
Collects Helm release information. Use for Helm-based deployments only. Disable with --without-helm.
operator collector
Collects Operator logs and custom resources. Use for Operator-based deployments only. Disable with --without-operator.
orchestrator collector
Collects workflow data for the Orchestrator plugin. Use to troubleshoot Orchestrator workflows only. Disable with --without-orchestrator.
route-ingress collector
Collects route definitions (OpenShift Container Platform) and ingress configurations (Kubernetes). Use to troubleshoot external access only. Disable with --without-route or --without-ingress.
namespace-inspect collector
Collects namespace resources for support teams. Limit to specific namespaces using --namespaces. Recommended for all collections. Disable with --without-namespace-inspect.

11.6.4.2. Opt-in collectors

The following collectors do not run by default. Enable them only when needed:

cluster-info collector

Collects cluster-wide state information beyond basic platform metadata. Enable with --cluster-info.

Important

Enable this collector only when support requests it, as it significantly increases collection time and may impact cluster performance during collection.

heap-dumps collector

Collects Node.js memory snapshots for diagnosing memory issues. Enable with --with-heap-dumps.

Requirements:

  • Liveness probe timeout increased to prevent pod restarts
  • Sufficient storage (50 MB to 500 MB per heap dump file)

Use only when:

  • Troubleshooting memory leaks
  • Support requests memory analysis
  • Diagnosing out-of-memory errors

11.6.5. Configuration options for diagnostic collection

Reference tables for must-gather command-line flags, environment variables, and Helm chart values.

11.6.5.1. Command-line flags

Command-line flags are available when running the gather script directly. On OpenShift Container Platform, pass these flags after -- /usr/bin/gather. On Kubernetes, use the equivalent Helm chart values instead.

FlagDescriptionDefaultExample

--namespaces

Comma-separated list of namespaces to collect data from.

All namespaces

--namespaces rhdh-prod,rhdh-plugins

--cluster-info

Include cluster-wide state information. Use only when requested by support.

Not included

--cluster-info

--with-heap-dumps

Trigger Node.js heap snapshots and collect heap dump files for memory analysis.

Not included

--with-heap-dumps

--heap-dump-instances

Comma-separated list of specific RHDH instance names to collect heap dumps from. Supports exact match, prefix match, or contains match. Only applies when --with-heap-dumps is enabled.

All RHDH instances

--heap-dump-instances backstage-cr-1,helm-2

--heap-dump-method

Method to trigger heap dumps. Valid values: inspector or sigusr2.

inspector

--heap-dump-method sigusr2

--without-operator

Exclude the Operator collector. Use for Helm-based deployments.

Operator collector included

--without-operator

--without-helm

Exclude the Helm collector. Use for Operator-based deployments.

Helm collector included

--without-helm

--without-orchestrator

Exclude the Orchestrator collector. Use when not using Orchestrator functionality.

Orchestrator collector included

--without-orchestrator

--without-platform

Exclude the platform collector.

Platform collector included

--without-platform

--without-route

Exclude the route collector (OpenShift Container Platform routes).

Route collector included

--without-route

--without-ingress

Exclude the ingress collector (Kubernetes ingress resources).

Ingress collector included

--without-ingress

--without-namespace-inspect

Exclude the namespace-inspect collector. Not recommended as it aids support navigation.

Namespace-inspect collector included

--without-namespace-inspect

11.6.5.2. Environment variables

Environment variables control must-gather operational behavior when running the gather script directly. When using the Helm chart, use the Helm chart values described in the next section instead of environment variables.

VariableDescriptionDefaultHelm Chart Equivalent

LOG_LEVEL

Logging verbosity level. Valid values: debug, info, trace.

info

gather.logLevel

CMD_TIMEOUT

Timeout for individual kubectl and Helm commands (seconds).

30

gather.cmdTimeout

MUST_GATHER_SINCE

Relative time duration to limit log collection (for example, 1h, 30m).

Not set (collects all available logs)

gather.since

MUST_GATHER_SINCE_TIME

Absolute RFC3339 timestamp to limit log collection.

Not set (collects all available logs)

gather.sinceTime

HEAP_DUMP_TIMEOUT

Timeout in seconds for heap dump generation per pod.

600 (10 minutes)

gather.heapDump.timeout

11.6.5.3. Helm chart values

When deploying must-gather on Kubernetes platforms using the Helm chart, configure collection options using a values file. The following table shows key Helm values and their equivalent command-line flags or environment variables.

Helm Value PathDescriptionEquivalent Command-line Flag or Environment Variable

gather.namespaces

Array of namespaces to collect from.

--namespaces

gather.clusterInfo

Boolean to include cluster-wide state information. Use only when requested by support.

--cluster-info

gather.heapDump.enabled

Boolean to collect heap dumps from Node.js backend pods.

--with-heap-dumps

gather.heapDump.instances

Array of specific RHDH instance names to collect heap dumps from.

--heap-dump-instances

gather.heapDump.method

Method to trigger heap dumps. Valid values: inspector or sigusr2.

--heap-dump-method

gather.heapDump.timeout

Timeout in seconds for heap dump collection.

HEAP_DUMP_TIMEOUT

gather.withOperator

Boolean to enable or disable the Operator collector. Set to false for Helm-based RHDH deployments.

--without-operator (inverted logic)

gather.withHelm

Boolean to enable or disable the Helm collector. Set to false for Operator-based RHDH deployments.

--without-helm (inverted logic)

gather.withOrchestrator

Boolean to enable or disable the Orchestrator collector. Set to false when not using Orchestrator.

--without-orchestrator (inverted logic)

gather.logLevel

Log level for must-gather operations. Valid values: info, debug, trace.

LOG_LEVEL

gather.cmdTimeout

Timeout in seconds for individual kubectl or helm commands.

CMD_TIMEOUT

gather.since

Relative time duration to limit log collection (for example, 1h, 30m).

MUST_GATHER_SINCE

gather.sinceTime

Absolute RFC3339 timestamp to limit log collection.

MUST_GATHER_SINCE_TIME

Note

Helm boolean values use positive logic (withX: true means include), while command-line flags use negative logic (--without-X means exclude).

11.6.6. Diagnostic data output structure and organization

The must-gather output directory organizes data by collector type, namespace, and resource type.

11.6.6.1. Top-level directory structure

The must-gather output directory contains files and subdirectories organized by collection method and data type. The following table shows the top-level structure:

PathContents

version and must-gather.log

Collection metadata including timestamps, must-gather version, collectors that ran, and collection parameters.

sanitization-report.txt

Data sanitization summary and details.

all-routes.txt

All OpenShift Container Platform routes cluster-wide.

all-ingresses.txt

All Kubernetes ingresses cluster-wide.

cluster-info/

Cluster-wide information (only present if you specified --cluster-info).

namespace-inspect/

Deep namespace inspect data (collected by default).

platform/

Platform and infrastructure information.

helm/

Helm deployment data (native releases and standalone deployments). Only present if Helm-deployed RHDH instances are detected.

orchestrator/

Orchestrator-flavored deployment data (if detected). Only present if Orchestrator components are detected.

operator/

Operator deployment data (if RHDH operators found). Only present if RHDH operators are detected.

11.6.6.2. Heap dump file locations

When the tool collects heap dumps with the --with-heap-dumps flag, they appear within deployment-specific directories, not under namespace-inspect/namespaces/. The location depends on the installation method:

Heap dump file paths by deployment type:

  • Helm releases: helm/releases/ns=<namespace>/<release>/deployment/heap-dumps/…​
  • Helm standalone: helm/standalone/ns=<namespace>/<workload>/deployment/heap-dumps/…​
  • Operator: operator/backstage-crs/ns=<namespace>/<cr>/deployment/heap-dumps/…​

Example:

helm/releases/ns=rhdh-prod/developer-hub/deployment/heap-dumps/pod=backstage-developer-hub-7d8f9c5b-xk2m4/container=backstage-backend/heapdump-20260430-143022.heapsnapshot

Analyze heap dump files using Chrome DevTools, Node.js heap analysis tools, or memory profilers.

11.6.6.3. Common diagnostic data locations

The following table shows where to find frequently needed diagnostic information in the must-gather output:

Diagnostic DataLocation

Backend pod logs

namespace-inspect/namespaces/<namespace>/pods/<backstage-pod>/backstage-backend/logs/current.log

PostgreSQL connection configuration

namespace-inspect/namespaces/<namespace>/core/configmaps/<app-config-configmap>.yaml

Operator logs

operator/ns=<namespace>/logs.txt

Backstage custom resource definition

operator/backstage-crs/<backstage-cr-name>.yaml

Route or Ingress definitions

all-routes.txt (OpenShift Container Platform) or all-ingresses.txt (Kubernetes)

Helm release values

helm/releases/ns=<namespace>/<release-name>/values.yaml

Deployment configurations

namespace-inspect/namespaces/<namespace>/apps/deployments/<deployment-name>.yaml

Service definitions

namespace-inspect/namespaces/<namespace>/core/services/<service-name>.yaml

Platform and cluster version

platform/platform.json or platform/platform.txt

Heap dumps for memory analysis

helm/releases/ns=<namespace>/<release>/deployment/heap-dumps/ (Helm) or operator/backstage-crs/ns=<namespace>/<cr>/deployment/heap-dumps/ (Operator)

Chapter 12. Integrate

12.1. Integrate

Integrate Red Hat Developer Hub with AI assistants, external tools, and infrastructure platforms to enhance developer productivity and streamline workflows.

12.2. Enable AI assistance for developers

12.2.1. Enable AI assistance for developers

Red Hat Developer Lightspeed for Red Hat Developer Hub (Developer Lightspeed for RHDH) is an AI-powered virtual assistant for Red Hat Developer Hub (RHDH). You can interact with Developer Lightspeed for RHDH to explore RHDH capabilities in detail.

12.2.2. Developer Lightspeed for RHDH architecture

12.2.2.1. Developer Lightspeed for RHDH architecture

Red Hat Developer Lightspeed for Red Hat Developer Hub is enabled by default on Red Hat Developer Hub (RHDH) instances. To provide developers with chat assistance, configure your deployment settings by using either the Operator or the Helm chart.

12.2.2.2. Retrieval augmented generation (RAG) embeddings for grounded AI responses

Use retrieval-augmented generation (RAG) embeddings to ground artificial intelligence (AI) responses in your internal documentation and provide verified citations during user interactions.

The RHDH documentation serves as the primary data source for RAG operations. To provide accurate citations to production documentation during inference, the system uses RAG embeddings stored within a vector database.

The system processes RAG data through the following sequence:

  • An initialization container copies the RAG data to a shared volume.
  • The Lightspeed Core Service (LCORE) sidecar container mounts the shared volume to access the data.
  • The sidecar layer uses the embeddings to attach precise documentation references to the chat responses.

12.2.2.3. Configure the virtual assistant components

Configure Developer Lightspeed for RHDH by updating your Backstage custom resource (CR) to map environment variables, manage configurations, and set access rights.

Prerequisites

  • The RHDH Operator is installed on your cluster.
  • You have cluster administrator privileges.

Procedure

  1. Create an opaque Kubernetes Secret containing your operational credentials and query safety guardrails before applying the Backstage CR. Refer to the following key definitions for required environment variables:

    Important

    To disable an inference provider or configuration feature, you must leave the corresponding ENABLE_* variable completely unset. Setting an ENABLE_* variable to false does not disable the component because the underlying system checks only whether the variable is defined.

    KeyDescription

    ENABLE_VLLM

    Enables the vLLM platform when set to "true".

    VLLM_URL

    Specifies the target API endpoint URL for vLLM (for example, https://<api_endpoint>/v1).

    VLLM_API_KEY

    Stores the authorization token for your vLLM platform.

    ENABLE_OPENAI

    Enables the OpenAI platform when set to "true".

    OPENAI_API_KEY

    Stores the authorization secret key for OpenAI.

    ENABLE_OLLAMA

    Enables the Ollama platform when set to "true".

    OLLAMA_URL

    Specifies the target endpoint URL for Ollama.

    ENABLE_VERTEX_AI

    Enables the Vertex AI platform when set to "true".

    VERTEX_AI_PROJECT

    Specifies your Google Cloud project ID.

    VERTEX_AI_LOCATION

    Specifies your target Google Cloud region.

    GOOGLE_APPLICATION_CREDENTIALS

    Specifies the file path of your mounted Google Cloud service account credentials JSON file.

    ENABLE_VALIDATION

    Activates query safety validation guardrails when set to "true".

    VALIDATION_PROVIDER

    Defines the active provider managing the verification routines (for example, openai or vllm).

    VALIDATION_MODEL_NAME

    Specifies the exact verification model to use (for example, gpt-4o-mini).

    The following code shows an example configuration Secret for vLLM with validation:

    apiVersion: v1
    kind: Secret
    metadata:
      name: lightspeed-auth-secrets
    type: Opaque
    stringData:
      ENABLE_VLLM: "true"
      VLLM_URL: "https://<api_endpoint>/v1"
      VLLM_API_KEY: "<api_key>"
      ENABLE_VALIDATION: "true"
      VALIDATION_PROVIDER: "vllm"
      VALIDATION_MODEL_NAME: "llama3.1"
  2. Map your secret inside the extraEnvs section of the Backstage CR to complete container provisioning:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: lightspeed-rhdh
    spec:
      application:
        extraEnvs:
          secrets:
            - name: lightspeed-auth-secrets
              containers:
                - lightspeed-core
  3. Optional: To protect settings such as Model Context Protocol (MCP) server additions from being overwritten during reconciliation loops, define a custom ConfigMap mapping in the extraFiles section of the CR:

        extraFiles:
          configMaps:
            - name: "my-custom-config"
              mountPath: /app-root
              key: lightspeed-stack.yaml
              containers:
                - lightspeed-core
  4. Configure access rights by updating the RBAC policy inside your Backstage CR:

    To grant non-administrator teams access to the virtual assistant, append permission lines to the rbac-policies.csv section, replacing <team> with your target team name:

    p, role:default/<team>, lightspeed.chat.read, read, allow
    p, role:default/<team>, lightspeed.chat.create, create, allow
  5. Apply the updated custom resource manifest to your cluster:

    $ oc apply -f <backstage_cr_file>.yaml

Verification

  1. Log in to your console instance.
  2. Verify that the Open Lightspeed floating action button (FAB) appears on the home page.
  3. Select the FAB and confirm that the chat window initializes successfully.

12.2.2.4. Configure Developer Lightspeed for RHDH by using the Helm chart

Configure Developer Lightspeed for RHDH by using the Helm chart to manage large language model (LLM) providers, enable validation guardrails, and authorize custom role-based access control (RBAC) policies.

Prerequisites

  • You have access to a running RHDH instance deployed with Helm.
  • You have operational credentials for your chosen LLM provider.

Procedure

  1. Create a manual Kubernetes Secret to store your provider credentials by adding the required keys to your Secret based on your provider requirements:

    Important

    To disable an inference provider or configuration feature, you must leave the corresponding ENABLE_* variable completely unset. Setting an ENABLE_* variable to false does not disable the component because the underlying system checks only whether the variable is defined.

    KeyDescription

    ENABLE_VLLM

    Enables the vLLM platform when set to "true".

    VLLM_URL

    Specifies the target API endpoint URL for vLLM (for example, https://<api_endpoint>/v1).

    VLLM_API_KEY

    Stores the authorization token for your vLLM platform.

    ENABLE_OPENAI

    Enables the OpenAI platform when set to "true".

    OPENAI_API_KEY

    Stores the authorization secret key for OpenAI.

    ENABLE_OLLAMA

    Enables the Ollama platform when set to "true".

    OLLAMA_URL

    Specifies the target endpoint URL for Ollama.

    ENABLE_VERTEX_AI

    Enables the Vertex AI platform when set to "true".

    VERTEX_AI_PROJECT

    Specifies your Google Cloud project ID.

    VERTEX_AI_LOCATION

    Specifies your target Google Cloud region.

    GOOGLE_APPLICATION_CREDENTIALS

    Specifies the file path of your mounted Google Cloud service account credentials JSON file.

    ENABLE_VALIDATION

    Activates query safety validation guardrails when set to "true".

    VALIDATION_PROVIDER

    Defines the active provider managing the verification routines (for example, openai or vllm).

    VALIDATION_MODEL_NAME

    Specifies the exact verification model to use (for example, gpt-4o-mini).

    Note
    • By default, the Helm installation creates a temporary Kubernetes Secret containing keys for various LLM providers. On subsequent helm upgrade cycles, the system overwrites this default Secret. Create a manual Kubernetes Secret to persist your credentials.
    • Vertex AI requires custom architecture mapping and has received limited testing.
    Tip

    To filter and reject off-topic user queries, you can optionally configure query safety validation guardrails within this Secret by defining the ENABLE_VALIDATION, VALIDATION_PROVIDER, and VALIDATION_MODEL_NAME keys.

  2. Reference your manual secret inside the values.yaml file:

    global:
      lightspeed:
        secret:
          create: false
          name: "my-custom-secret"
  3. Optional: Configuration files such as lightspeed-stack.yaml, config.yaml and rhdh-profile.py are managed by the Helm deployment and overwrites changes on Helm upgrade runs. To protect changes to a file, create a custom config map and reference it in the values.yaml file:

    Important

    Only modify the create and nameOverride fields. Keep the default mount paths and file configurations unchanged.

    global:
      lightspeed:
        configMaps:
          - name: stack
            create: false
            nameOverride: "my-custom-stack"
            mountPath: /app-root/lightspeed-stack.yaml
            subPath: lightspeed-stack.yaml
            sourceFile: lightspeed-stack.yaml
            optional: false
  4. Configure access rights by updating your RBAC definitions:

    To grant non-administrator teams access to the virtual assistant, append permission lines to the rbac-policies.csv section, replacing <team> with your target team name:

    p, role:default/<team>, lightspeed.chat.read, read, allow
    p, role:default/<team>, lightspeed.chat.create, create, allow
  5. Run the helm upgrade command to apply your configurations to the cluster.

Verification

  1. Log in to your console instance.
  2. Verify that the Open Lightspeed floating action button (FAB) appears on the home page.
  3. Select the FAB and confirm that the chat window initializes successfully.

12.2.2.5. Disable Developer Lightspeed for RHDH by using the Operator

Disable the Developer Lightspeed for RHDH chat interface and stop associated container processes to remove the service from your Operator-backed deployment.

Prerequisites

  • You have access to the cluster where your instance is deployed.
  • You have cluster administrator privileges.

Procedure

  1. Open your Backstage custom resource (CR) YAML file.
  2. In the spec section, set the enabled flag to false for the lightspeed flavour. This disables the chat interface and prevents the Operator from injecting unconfigured sidecar containers:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: lightspeed-disabled
    spec:
      flavours:
        - name: lightspeed
          enabled: false
  3. Apply the updated custom resource manifest to your cluster:

    oc apply -f <backstage_cr_file>.yaml

Verification

  1. Log in to your console instance.
  2. Verify that the Open Lightspeed floating action button (FAB) no longer appears on the home page.

12.2.2.6. Disable Developer Lightspeed for RHDH by using the Helm chart

Disable the Developer Lightspeed for RHDH chat interface and stop associated container processes to remove the service from your Helm-deployed environment.

Prerequisites

  • You have access to the cluster where your instance is deployed.
  • You have cluster administrator privileges.

Procedure

  1. Open your Helm values.yaml file.
  2. Update the global.lightspeed.enabled parameter to false to disable the chat interface:

    global:
      lightspeed:
        enabled: false
  3. Run the helm upgrade command to apply the configuration change to your cluster.

Verification

  1. Log in to your console instance.
  2. Verify that the Open Lightspeed floating action button (FAB) no longer appears on the home page.

12.2.2.7. Customize the system prompt and UI options

12.2.2.7.1. Customize the system prompt and UI options

You can customize Developer Lightspeed for RHDH to align model behavior with your operational goals, enhance developer productivity, and ensure secure data retention.

12.2.2.7.2. Enable user feedback to improve model performance

Enable user feedback collection to allow users to rate chat responses and submit text comments directly within the console interface.

The Lightspeed Core Service (LCORE) stores this data as JSON files inside your cluster. Because Red Hat does not collect or access this data, platform administrators must manage, analyze, and delete these files locally.

Prerequisites

  • You have platform administrator privileges.
  • You created and referenced a custom config map in your deployment to ensure configuration changes persist during system upgrades or Operator reconciliation loops. For more information, see Provision your custom Red Hat Developer Hub configuration.

Procedure

  1. In your custom configuration file, such as lightspeed-stack.yaml, modify the user_data_collection block to configure your data preferences:

    • To enable feedback collection, set the feedback_enabled parameter to true:

      user_data_collection:
        feedback_enabled: true
        feedback_storage: "/tmp/data/feedback"
        transcripts_enabled: true
        transcripts_storage: "/tmp/data/transcripts"
    • To disable feedback collection, set the feedback_enabled parameter to false:

      user_data_collection:
        feedback_enabled: false
        feedback_storage: "/tmp/data/feedback"
        transcripts_enabled: true
        transcripts_storage: "/tmp/data/transcripts"
      Note

      Do not modify the feedback_storage or transcripts_storage data paths when disabling feedback. Altering these path strings prevents the service from locating existing historical logs.

  2. Apply the updated configuration file changes to your cluster by running your platform’s standard deployment or upgrade sequence.
12.2.2.7.3. Customize AI responses by using system prompts

Configure a custom system prompt to provide environmental context to the large language model (LLM). This custom instruction prefixes user queries, guiding the assistant to generate artificial intelligence (AI) responses tailored to your RHDH instance.

Prerequisites

  • You have administrative access to the RHDH host platform filesystem.

Procedure

  1. In your app-config.yaml file, add or modify the systemPrompt parameter under the lightspeed section, specifying your custom instruction string:

    lightspeed:
      # ... other lightspeed configurations
      systemPrompt: "You are a helpful assistant focused on Red Hat Developer Hub development."
  2. Save the file.
  3. Restart the RHDH service to apply the updated system prompt configuration.
12.2.2.7.4. Customize chat history storage

Configure chat history storage to choose between non-persistent local logs and a persistent external database for user conversations.

By default, the system stores chat history in a non-persistent local database within the Lightspeed Core Service (LCORE) container. To retain data across system restarts, you must configure a PostgreSQL database connection.

Warning

Storing chat history records user prompts and responses. You must assess data privacy and security implications if your user chat history contains private, sensitive, or confidential information. For users that want to have their chat data removed, they must request their platform administrator to perform this action. Red Hat does not collect or access this chat history data.

Prerequisites

Procedure

  1. In your custom configuration file, such as lightspeed-stack.yaml, modify the conversation_cache block to specify your storage configuration:

    • To enable persistent storage, add your PostgreSQL database credentials and endpoint properties:

      conversation_cache:
        type: "postgres"
        postgres:
          host: _<your_database_host>_
          port: _<your_database_port>_
          db: _<your_database_name>_
          user: _<your_user_name>"_
          password: _<postgres_password>_
      • To retain the default non-persistent SQLite setup, verify that the parameters match the following paths:

        conversation_cache:
          type: "sqlite"
          sqlite:
            db_path: '/tmp/cache.db'
  2. Restart the LCORE service to apply your new database configuration.

12.2.2.8. Mirror Lightspeed images for air-gapped environments

Mirror the required Developer Lightspeed for RHDH container images and plugins to your local registry to provide chat assistance in an air-gapped environment.

The prepare-restricted-environment.sh script does not automatically parse Developer Lightspeed for RHDH images from the bundle manifest, so mirror these images manually before running the script.

Prerequisites

  • You have a target mirror registry accessible to your disconnected cluster.
  • You authenticated to the Red Hat Container Registry and your target mirror registry.
  • If deploying on OpenShift Container Platform, you have updated the cluster pull secret (pull-secret in the openshift-config namespace) to include the authentication credentials for your mirror registry. The kubelet requires these credentials to pull all Red Hat Developer Hub images.

Procedure

  1. Extract the deployment configurations from the official Operator bundle:

    BUNDLE_IMAGE="registry.redhat.io/rhdh/rhdh-operator-bundle:1.10"
    CONTAINER_ID=$(podman create "${BUNDLE_IMAGE}")
    podman cp $CONTAINER_ID:/manifests/rhdh-flavour-lightspeed-config_v1_configmap.yaml ./lightspeed-config.yaml
    podman rm $CONTAINER_ID
  2. Identify the initialization and sidecar container image tags from the extracted configuration file:

    LS_RAG_IMAGE=$(yq '.data["deployment.yaml"]' lightspeed-config.yaml | yq '.spec.template.spec.initContainers[] | select(.name == "init-rag-data") | .image')
    LS_CORE_IMAGE=$(yq '.data["deployment.yaml"]' lightspeed-config.yaml | yq '.spec.template.spec.containers[] | select(.name == "lightspeed-core") | .image')
  3. Mirror the images to your internal registry by running the skopeo copy command:

    skopeo copy docker://${LS_RAG_IMAGE} docker://<mirror_registry>/<ls_rag_repo>@<digest>
    skopeo copy docker://${LS_CORE_IMAGE} docker://<mirror_registry>/<ls_core_repo>@<digest>

12.2.2.9. Mirror Developer Lightspeed for RHDH images for Helm deployments on OpenShift Container Platform

Mirror the required Developer Lightspeed for RHDH container images to your local registry by using the oc-mirror plugin when deploying the Helm chart on an OpenShift Container Platform cluster.

Prerequisites

  • You have a target mirror registry accessible to your disconnected OpenShift Container Platform cluster.
  • You authenticated to the Red Hat Container Registry and your target mirror registry.
  • You have updated the cluster install secret (pull-secret in the openshift-config namespace) to include the authentication credentials for your mirror registry. The kubelet requires these credentials to pull the sidecar images. For more information, see Provision your Red Hat Container Registry pull secret to your Red Hat Developer Hub instance namespace.

Procedure

  1. Identify the initialization and sidecar container images from the default values file of the chart:

    helm show values redhat-developer-hub --repo https://charts.openshift.io/ --version 1.10.1 > values.default.yaml
    
    LS_RAG_IMAGE=$(yq '.global.lightspeed.initContainer.image | .registry + "/" + .repository' values.default.yaml)
    LS_RAG_DIGEST=$(yq '.global.lightspeed.initContainer.image.tag' values.default.yaml)
    LS_CORE_IMAGE=$(yq '.global.lightspeed.sidecar.image | .registry + "/" + .repository' values.default.yaml)
    LS_CORE_DIGEST=$(yq '.global.lightspeed.sidecar.image.tag' values.default.yaml)
  2. Add these images to the additionalImages section of your ImageSetConfiguration file:

    apiVersion: mirror.openshift.io/v2alpha1
    kind: ImageSetConfiguration
    mirror:
      additionalImages:
        - name: ${LS_RAG_IMAGE}:${LS_RAG_DIGEST}
        - name: ${LS_CORE_IMAGE}:${LS_CORE_DIGEST}
      helm:
        repositories:
          - name: openshift-charts
            url: https://charts.openshift.io
            charts:
              - name: redhat-developer-hub
                version: "1.10"

12.2.2.10. Mirror Developer Lightspeed for RHDH images for Helm deployments on Kubernetes

Isolate image references, copy them manually to your internal registry, and update your configuration file when deploying the Helm chart on non-OpenShift platforms.

Prerequisites

  • You have a target mirror registry accessible to your disconnected cluster.
  • You authenticated to the Red Hat Container Registry and your target mirror registry.
  • You have configured an image pull secret in your target namespace to authenticate with your mirror registry, or your cluster is configured to allow the kubelet to pull images from your mirror registry.

Procedure

  1. Extract the image references from the default values file of the chart:

    $ helm show values redhat-developer-hub --repo https://charts.openshift.io/ --version 1.10.1 > values.default.yaml
    
    LS_RAG_IMAGE=$(yq '.global.lightspeed.initContainer.image | .registry + "/" + .repository' values.default.yaml)
    LS_RAG_DIGEST=$(yq '.global.lightspeed.initContainer.image.tag' values.default.yaml)
    LS_CORE_IMAGE=$(yq '.global.lightspeed.sidecar.image | .registry + "/" + .repository' values.default.yaml)
    LS_CORE_DIGEST=$(yq '.global.lightspeed.sidecar.image.tag' values.default.yaml)
  2. Mirror the images to your internal mirror registry:

    skopeo copy --all docker://${LS_RAG_IMAGE}:${LS_RAG_DIGEST} docker://<mirror_registry_name>/<ls_rag_repo_name>:${LS_RAG_DIGEST}
    skopeo copy --all docker://${LS_CORE_IMAGE}:${LS_CORE_DIGEST} docker://<mirror_registry_name>/<ls_core_repo_name>:${LS_CORE_DIGEST}
  3. Update your custom Helm values file with the mirrored registry locations and plugin references. Mirror the dynamic plugins to the local registry before you add their package paths to the file. For mirroring instructions, see Mirroring Red Hat Developer Hub dynamic plugins in disconnected environments:

    global:
      lightspeed:
        initContainer:
          image:
            registry: "<mirror_registry_name>"
            repository: <ls_rag_repo_name>
            tag: "${LS_RAG_DIGEST}"
        sidecar:
          image:
            registry: "<mirror_registry_name>"
            repository: <ls_core_repo_name>
            tag: "${LS_CORE_DIGEST}"
        plugins:
          - package: "oci://<mirror_registry_name>/rhdh/red-hat-developer-hub-backstage-plugin-lightspeed@<ls_frontend_digest>"
            disabled: false
          - package: "oci://<mirror_registry_name>/rhdh/red-hat-developer-hub-backstage-plugin-lightspeed-backend@<ls_backend_digest>"
            disabled: false

12.2.3. Build a private knowledge base with Lightspeed Notebooks

12.2.3.1. Build a private knowledge base with Lightspeed Notebooks

Use Developer Lightspeed for RHDH Notebooks to research, troubleshoot, and analyze projects by using a large language model (LLM) grounded in your own documentation. Notebooks use Retrieval-Augmented Generation (RAG) to ensure that responses are based strictly on the files you upload.

12.2.3.2. Solve project-specific challenges

Configure Red Hat Developer Hub and Red Hat Developer Lightspeed for Red Hat Developer Hub to provide users with private, document-based AI workspaces.

Prerequisites

  • A deployed instance of RHDH.
  • By using the OpenShift CLI (oc), you have access, with developer permissions, to the OpenShift Container Platform cluster aimed at containing your Developer Hub instance.
  • A Lightspeed Stack service is running and accessible to the backend.
  • A supported large language model (LLM), such as Granite 7B or higher, is available.

Procedure

  1. Enable the notebook feature and define your model by adding the following configuration to your app-config.yaml file:

    lightspeed:
      notebooks:
        enabled: true
        queryDefaults:
          model: ${NOTEBOOKS_QUERY_MODEL} # Use the exact model name
          provider_id: ${NOTEBOOKS_QUERY_PROVIDER_ID}
    Note

    If the model name is incorrect, an error message appears in the logs and the user interface.

  2. Grant user access through role-based access control (RBAC) policies by defining permissions in your rbac-policy-csv file:

    1. Add the permission policy:

      p, role:default/_<your_team_name>_, lightspeed.notebooks.use, update, allow
    2. Assign the role to specific users:

      g, user:default/_<your_user_name>_, role:default/_<your_team_name>_
  3. Apply the updated configuration and restart the service.

Verification

  1. Log in to RHDH using an account assigned to the RBAC role defined in the configuration.
  2. Confirm that the Notebooks tab is visible next to the Chat tab in the primary navigation bar.
  3. Click the Notebooks tab and ensure the My Notebooks dashboard loads without error messages.

12.2.3.3. Enable data persistence for Developer Lightspeed for RHDH Notebooks

To persist Notebook sessions, documents, and AI history across service restarts, you must configure the Notebooks storage backends to use persistent volumes.

By default, the service uses ephemeral storage in the /tmp directory, which the system clears during a pod restart.

Prerequisites

  • By using the OpenShift CLI (oc), you have access, with developer permissions, to the OpenShift Container Platform cluster aimed at containing your Developer Hub instance.
  • You have authored and provisioned a custom config map for your deployment. For more information, see link:Provision your custom Red Hat Developer Hub configuration.
  • A Persistent Volume Claim (PVC) is provisioned in your cluster and mounted to the LCORE container (for example, at /var/lib/lightspeed-data).

Procedure

  1. Update your custom config map llama-stack-configs/config.yaml file to point the kv_notebooks storage backend to your persistent mount point:

    spec:
      initContainers:
        - name: init-notebooks-dir
          # ... complete init container
      containers:
        - name: lightspeed-core
          image: quay.io/lightspeed-core/lightspeed-stack:0.5.1
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: notebooks-storage
              mountPath: /var/lib/lightspeed-data
            - name: config  # ← Added all ConfigMap mounts
              mountPath: /app-root/config.yaml
              subPath: config.yaml
            - name: lightspeed-config
              mountPath: /app-root/lightspeed-stack.yaml
              subPath: lightspeed-stack.yaml
            - name: profile
              mountPath: /app-root/rhdh-profile.py
              subPath: rhdh-profile.py
          livenessProbe:  # ← Added health checks
            httpGet:
              path: /readiness
              port: 8080
          readinessProbe:
            httpGet:
              path: /readiness
              port: 8080
      volumes:  # ← Added all volume definitions
        - name: notebooks-storage
          persistentVolumeClaim:
            claimName: lightspeed-notebooks-pvc
        - name: config
          configMap:
            name: llama-stack-config
        - name: lightspeed-config
          configMap:
            name: lightspeed-core-config
        - name: profile
          configMap:
            name: rhdh-profile
  2. Update your deployment manifest to include the init container, volume mounts, and volume definitions:

    spec:
      template:
        spec:
          initContainers:
            - name: init-notebooks-storage
              image: registry.access.redhat.com/ubi9/ubi-minimal
              command: ["sh", "-c", "mkdir -p /var/lib/lightspeed-data/notebooks && chmod -R 777 /var/lib/lightspeed-data/notebooks"]
              volumeMounts:
                - name: lightspeed-notebooks
                  mountPath: /var/lib/lightspeed-data
          containers:
            - name: lightspeed-stack
              image: quay.io/lightspeed-core/lightspeed-stack:0.5.1
              ports:
                - containerPort: 8080
              volumeMounts:
                - name: lightspeed-notebooks
                  mountPath: /var/lib/lightspeed-data
                - name: config
                  mountPath: /app-root/config.yaml
                  subPath: config.yaml
              livenessProbe:
                httpGet:
                  path: /readiness
                  port: 8080
              readinessProbe:
                httpGet:
                  path: /readiness
                  port: 8080
          volumes:
            - name: lightspeed-notebooks
              persistentVolumeClaim:
                claimName: lightspeed-notebooks-pvc
            - name: config
              configMap:
                name: llama-stack-config
  3. Apply the updated configuration and restart the service.

Verification

  1. In Red Hat Developer Hub, create a Notebook and upload a test document.
  2. Send a message to the virtual assistant and verify that the response is based on the document.
  3. Restart the pod:

    $ oc delete pod <pod_name>
  4. After the pod recovers, refresh the My Notebooks dashboard.
  5. Verify that the Notebook and the uploaded file are still accessible.

12.2.4. Large language model (LLM) requirements

To plan your Developer Lightspeed for RHDH deployment, you must determine which compatible large language model (LLM) inference provider fits your infrastructure.

Developer Lightspeed for RHDH operates on a Bring Your Own Model (BYOM) architecture. Because the service does not include a native model, you must connect a compatible inference provider during installation.

The underlying LCORE service integrates with platforms that support either the OpenAI API specification or the vLLM inference engine. Developer Lightspeed for RHDH supports the following inference provider configurations:

  • OpenAI: Cloud-based inference services.
  • vLLM: Enterprise inference servers, which include models hosted on Red Hat OpenShift AI and Red Hat Enterprise Linux AI.
  • Ollama: Desktop inference servers.
  • Gemini: Services through Vertex AI.

When configuring your deployment, you must account for the following provider behaviors:

  • Red Hat OpenShift AI routing: Because the configuration lacks an explicit Red Hat OpenShift AI provider option, you must route these deployments through the vLLM provider settings.
  • vLLM URL syntax: The vllm provider type communicates with endpoints that conform to the OpenAI API schema. You must manually append /v1 to the configured provider URL because the system does not add it automatically. This configuration also applies to other hosted, OpenAI-compliant inference providers.

12.2.5. OpenAI model integration for your deployment

Use OpenAI models to provide generative artificial intelligence (AI) inference services, such as GPT 5, for your Developer Lightspeed for RHDH deployment.

The system connects directly to the OpenAI API platform to route user prompts and return model insights. To configure this large language model (LLM) provider, you must have an active API key generated from your OpenAI developer account.

12.2.6. Ollama model integration requirements

To integrate the open-source Ollama framework with Developer Lightspeed for RHDH, you must ensure that your network topology allows the Developer Lightspeed for RHDH service to route traffic to the Ollama server endpoint.

The Ollama server operates as a containerized layer, providing a command-line interface (CLI) to download, manage, and execute open-source models such as Llama 3 and Mistral. You can deploy Ollama on both local workstations and cluster environments.

However, a cluster-deployed Developer Lightspeed for RHDH instance cannot access an Ollama server that runs exclusively on a workstation localhost interface. For cluster deployments, the Ollama server must reside on an externally accessible network perimeter or run directly inside the cluster.

The following integration configurations are supported:

  • Both Developer Lightspeed for RHDH and Ollama deploy on a local workstation.
  • Developer Lightspeed for RHDH deploys locally and connects to an externally accessible cluster Ollama server.
  • Both Developer Lightspeed for RHDH and Ollama deploy inside the cluster infrastructure.

12.2.7. vLLM model integration for high-throughput inference

Use the open-source vLLM high-throughput serving framework to optimize memory utilization and manage high volumes of concurrent requests for your Developer Lightspeed for RHDH deployment.

The vLLM framework operates as an enterprise inference server that optimizes memory allocation to maximize the processing efficiency of large language models (LLMs). Integrating vLLM ensures that your environment maintains high performance and responsiveness under heavy concurrent user traffic.

Additional resources

12.2.8. Vertex AI integration for Gemini models

To use Gemini models with Developer Lightspeed for RHDH, you can configure Google Cloud Vertex AI to act as your managed large language model (LLM) inference provider.

The underlying LCORE service connects to Vertex AI to access hosted Gemini models. This integration provides Developer Lightspeed for RHDH with enterprise-grade language processing and chat assistance capabilities without requiring you to maintain a local inference server.

Additional resources

12.2.9. Manage user data security

Review data routing and privacy practices to evaluate how Developer Lightspeed for RHDH handles chat messages and operational information transmitted to large language model (LLM) providers.

Developer Lightspeed for RHDH sends your chat messages directly to your configured large language model (LLM) provider. Because these messages can contain sensitive operational data regarding your cluster, users, or business environment, ensure that your provider compliance policies align with your organizational security standards.

Developer Lightspeed for RHDH has limited capabilities to filter or redact the information you submit during user interactions. To mitigate data exposure risks, do not enter proprietary or confidential information into Developer Lightspeed for RHDH. To encourage user compliance, Developer Lightspeed for RHDH displays a mandatory warning at the start of each sessions, reminding users to omit personal or sensitive details.

12.2.10. User feedback collection

Review how Developer Lightspeed for RHDH collects and isolates user feedback data within your cluster to manage local storage requirements and data privacy standards.

Developer Lightspeed for RHDH saves user feedback submissions, including numerical ratings and text commentary, locally within the pod filesystem. Because Red Hat does not collect, access, or transmit this data, local platform administrators must manage and monitor these storage directories.

12.2.11. Bring Your Own Model integration

Review Bring Your Own Model (BYOM) requirements to select and integrate an OpenAI API-compatible inference service with Lightspeed Core Service.

Developer Lightspeed for RHDH relies on a BYOM architecture that let you connect the Lightspeed Core Service (LCORE) layer to any OpenAI API-compatible inference platforms. To establish connection compatibility, your chosen inference service must satisfy the following technical criteria:

  • The service must conform to the OpenAI API specification for chat completions.
  • The host environment must match the specified infrastructure configuration and installation instructions.

Various commercial and open-source inference services support the OpenAI API specification. Because operational costs, performance metrics, and data security controls vary by provider, you must evaluate and test prospective platforms locally to select the service that best meets your organizational requirements.

Additional resources

12.2.12. Your compliance and data-sharing responsibility

Review compliance requirements and data-sharing responsibilities to ensure that user interactions with Developer Lightspeed for RHDH align with your organization’s data privacy policies.

All data that users submit through prompts and responses within Developer Lightspeed for RHDH is transmitted directly to your configured large language model (LLM) inference service. Platform administrators must ensure that these external data transfers comply with corporate security standards, governance frameworks, and local data protection policies.

12.2.13. Configure Model Context Protocol tools to enhance AI interactions with portal data

12.2.13.1. Configure Model Context Protocol tools to enhance AI interactions with portal data

Leverage the Model Context Protocol (MCP) server to integrate Red Hat Developer Hub with AI clients through a standardized method for accessing RHDH information and workflows using defined MCP tools.

12.2.13.2. Connect AI applications to external systems using MCP

Model Context Protocol (MCP) connects AI applications to external systems, enabling Developer Hub MCP tools through the mcp-actions-backend plugin.

Important

This section describes Developer Preview features in the Model Context Protocol plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

Model Context Protocol (MCP) connects AI models and applications (MCP clients) to external systems (MCP servers) to access information and workflows. MCP servers define the tools that MCP clients can interact with. Red Hat Developer Hub (RHDH) supports MCP tools through the mcp-actions-backend plugin available in Backstage 1.40 or later.

Important

You must verify that your model supports tool calling before you enable Model Context Protocol (MCP) features. Using an incompatible model results in error messages.

12.2.13.3. Install MCP server plugins

To run MCP tools within RHDH, you must add the MCP server plugin to your configuration. This installation enables the backend infrastructure required to manage MCP actions.

Prerequisites

  • Your RHDH instance is installed and running.

Procedure

  • In your dynamic plugins ConfigMap (for example, dynamic-plugins-rhdh.yaml), add the updated MCP server plugin:

    plugins:
        - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:<tag>
          disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

Verification

  • Confirm the plugins are active by checking the RHDH logs for "loaded" status messages, or by verifying that the corresponding MCP tools appear in your product tool registry.

12.2.13.4. Install the MCP tool plugins

Install individual extras plugins to expose specific capabilities for the Software Catalog, TechDocs, and Scaffolder features.

Important

The previous MCP plugins (software-catalog-mcp-tool and techdocs-mcp-tool) are deprecated and no longer updated. You must use the new extras versions listed in the following procedure to receive updates and new features.

Prerequisites

  • Your RHDH instance is installed and running.

Procedure

  • Install any of the following MCP tools that you want to use:

    • Software Catalog MCP extras:

        - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-extras:<tag>
          disabled: false

      where:

      <tag>

      Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

      1. Find your Backstage version in the RHDH release notes preface.
      2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

        Tip

        To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    • TechDocs MCP extras:

      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-extras:<tag>
        disabled: false

      where:

      <tag>

      Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

      1. Find your Backstage version in the RHDH release notes preface.
      2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

        Tip

        To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    • Scaffolder MCP extras:

      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scaffolder-mcp-extras:<tag>
          disabled: false

      where:

      <tag>

      Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

      1. Find your Backstage version in the RHDH release notes preface.
      2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

        Tip

        To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

Verification

  • Confirm the plugins are active by checking the RHDH logs for "loaded" status messages, or by verifying that the corresponding MCP tools appear in your product tool registry.

12.2.13.5. Configure MCP tokens and endpoints

12.2.13.5.1. Configure MCP tokens and endpoints

When using third-party MCP integrations, you can store your personal access tokens securely and manage credentials in Red Hat Developer Lightspeed for Red Hat Developer Hub so that the AI acts on your behalf.

12.2.13.5.2. Configure MCP tokens and endpoints to authorize client access

Configure Model Context Protocol (MCP) server endpoints, database backends, and authentication tokens to securely authorize client applications to interact with your developer portal.

This configuration is a prerequisite for MCP clients to use the defined MCP tools and access the exposed capabilities of RHDH.

Procedure

  1. In your Red Hat Developer Hub app-config.yaml file, configure a static token for authentication against the MCP server endpoint. MCP clients (such as Cursor, Continue, or Lightspeed Core) use these tokens to authenticate against the Backstage MCP server. For example:

    backend:
      auth:
        externalAccess:
          - type: static
            options:
              token: ${MCP_TOKEN}
              subject: mcp-clients

    where:

    ${MCP_TOKEN}

    Set the token value that you generate manually and share with your MCP clients.

    Note

    Tokens must be long and complex strings without whitespace to prevent brute-force guessing.

    1. To generate a sample token, use the following command:
    $ node -p `require("crypto").randomBytes(24).toString("base64")`
  2. Register the MCP tools that you install as a plugin source in your app-config.yaml file:

    • To use the installed extras plugins, you must register them as plugin sources:

      backend:
        actions:
          pluginSources:
            - software-catalog-mcp-extras
            - techdocs-mcp-extras
            - scaffolder-mcp-extras
    • To fetch entities or manage components, you must register the catalog plugin source. If your workflow requires scaffolding tools, you must also register the scaffolder plugin source. These plugins are optional and required only when using these specific tools.

      backend:
        actions:
          pluginSources:
            - catalog
            - scaffolder
    • If you are using OpenAI models with the RHDH MCP server, add the following configuration to your app-config.yaml file to disable namespaced toolnames:

      mcpActions:
        namespacedToolNames: false
    # Full app-config.yaml file example with MCP configuration
    app:
      title: AI Dev Developer Hub
      baseUrl: "${RHDH_BASE_URL}"
    auth:
      environment: development
      session:
        secret: "${BACKEND_SECRET}"
      providers:
        guest:
          dangerouslyAllowOutsideDevelopment: true
    backend:
      actions:
        pluginSources:
          - software-catalog-mcp-extras
          - techdocs-mcp-extras
          - scaffolder-mcp-extras
          - catalog
          - scaffolder
      auth:
        externalAccess:
          - type: static
            options:
              token: ${MCP_TOKEN}
              subject: mcp-clients
        keys:
          - secret: "${BACKEND_SECRET}"
      baseUrl: "${RHDH_BASE_URL}"
      cors:
        origin: "${RHDH_BASE_URL}"
    signInPage: oidc
12.2.13.5.3. Configure MCP clients to access the RHDH server

Configure Model Context Protocol (MCP) client applications with server URLs and authentication to enable interaction with the RHDH server.

You must configure an MCP client before it can interact with the MCP server. For a list of supported clients and their specific configurations, see Example Clients.

Prerequisites

  • You have one of the following endpoints for the server URL, where <my_developer_hub_domain> is the hostname of your RHDH instance.

    • Streamable: https://<my_developer_hub_domain>/api/mcp-actions/v1
    • SSE (Legacy): `https://<my_developer_hub_domain>/api/mcp-actions/v1/sse

      Note

      Some clients do not yet support the Streamable endpoint. Use the SSE (Legacy) endpoint if your client requires it.

  • You have set the MCP_TOKEN environment variable in your MCP server configuration as the bearer token for authentication.

Procedure

  1. Configure Developer Lightspeed for RHDH as a client. For more details, see {developer-lightspeed-link}[Red Hat Developer Lightspeed for Red Hat Developer Hub].

    1. In the lightspeed-stack.yaml configuration, add the following mcp_servers configuration:

      mcp_servers:
        - name: mcp::backstage
          provider_id: model-context-protocol
          url: https://<my_developer_hub_domain>/api/mcp-actions/v1
          authorization_headers:
            Authorization: "client"
      model-context-protocol
      Enter the tool runtime provider defined in the llama-stack run.yaml configuration for LCORE.
    2. Optional: To use a custom Llama Stack configuration, add the following code to the run.yaml Llama Stack configuration file.

      providers:
        tool_runtime:
        - provider_id: model-context-protocol
          provider_type: remote::model-context-protocol
          config: {}
    3. To authorize requests to the MCP endpoint using <MCP_TOKEN>, add one or more servers to the mcpServers list in the Developer Lightspeed for RHDH app-config.yaml file, to make POST requests to LCORE:

      lightspeed:
        mcpServers:
        - name: mcp::backstage
          token: ${MCP_TOKEN}
        - name: _<mcp_server_name>_
          token: ${MCP_TOKEN_2}

      where:

      name
      Enter the server name. This must match the name configured in the LCORE.
      token
      Optional: Enter the static token used to authorize requests. You can also configure the token through the MCP Server Settings in the Developer Lightspeed for RHDH user interface. The setting remains disabled until you configure the token.
    4. Optional: Query the LCORE /v1/streaming_query endpoint directly by providing the MCP_TOKEN in the header:

      curl -X POST \
        -H `Content-Type: application/json` \
        -H `MCP-HEADERS: {"mcp::backstage": {"Authorization": "Bearer <MCP_TOKEN>"}}` \
        -d `{"query": "Can you give me all catalog templates of type 'service', "model": "gpt-4o-mini", "provider": "openai"}` \
        _<url>_/v1/streaming_query

      where:

      <url>
      Enter the LCORE endpoint. Use localhost or the service name pass:c,a,q:[<RHDH_servicename>.my-rhdh-project.svc.cluster.local:8080] if you are inside the Backstage container.
  2. Configure Cursor as a client.

    1. From your Desktop app, navigate to Cursor Settings, select MCP Tools > New MCP Server and add the following configuration:

      {
        "mcpServers": {
          "backstage-actions": {
            "url": "https://<my_developer_hub_domain>/api/mcp-actions/v1",
            "headers": {
              "Authorization": "Bearer <mcp_token>"
            }
          }
        }
      }

      where:

      <mcp_token>
      Enter the previously configured static token
      <my_developer_hub_domain>
      Enter the hostname of your RHDH instance
  3. Configure Continue as a client.

    1. In your agent yaml configuration file, add the following configuration:

      mcpServers:
        - name: backstage-actions
          type: sse
          url: https://<my_developer_hub_domain>/api/mcp-actions/v1/sse
          requestOptions:
            headers:
              Authorization: "Bearer <mcp_token>"

      where:

      <mcp_token>
      Enter the previously configured static token
      <my_developer_hub_domain>
      Enter the hostname of your RHDH instance
12.2.13.5.4. Enable encryption and database storage for tokens

To protect sensitive credentials and persist user preferences, you must configure encryption and database settings in the app-config.yaml file.

Configuring encryption prevents the system from storing Model Context Protocol (MCP) tokens as plain text in the database.

Prerequisites

  • You have administrator access to the RHDH environment.
  • Your backend secet is available in the BACKEND_SECRET environment variable.

Procedure

  1. To enable encryption for MCP server tokens, add the following snippet to the backend section of your app-config.yaml file:

    backend:
      auth:
        keys:
        - secret: ${BACKEND_SECRET}
  2. To store MCP server user preferences, configure the database connection. Use the configuration example that matches your environment:

    • Local development (In-memory):

      backend:
        database:
          client: better-sqlite3
          connection: ':memory:'
    • Local path storage:

      backend:
        database:
          client: better-sqlite3
          connection:
            directory: './sqlite-data'
    • Deployed PostgreSQL database:

      backend:
        database:
          client: pg
          connection:
            host: localhost
            port: 5432
            user: ${POSTGRES_USER}
            password: ${POSTGRES_PASSWORD}

Verification

  • Restart the RHDH instance and ensure no errors appear in the logs related to the backend-auth or database plugins.
12.2.13.5.5. Toggle MCP tools in the chat interface

Use the Red Hat Developer Lightspeed for Red Hat Developer Hub chat interface options to securely configure your personal tokens, toggle specific Model Context Protocol (MCP) services, and directly control the data context made available to the AI assistant.

You can use the MCP settings panel in the Developer Lightspeed for RHDH chat interface to review server status and enable or disable specific tools for your session.

Prerequisites

  • An administrator has configured encryption and database storage for the backend.
  • You have a valid Personal Access Token for the MCP servers you want to enable.

Procedure

  1. In the Red Hat Developer Lightspeed for Red Hat Developer Hub chat box, click the Chatbot options menu icon in the header.
  2. Select MCP settings.

    MCP in chat
  3. In the MCP settings panel, perform any of the following actions to configure your session:

    • Review server status: View whether available MCP servers are enabled or disabled.
    • View available tools: View the count of specific tools available for each server under Status.
    • Configure personal tokens:

      • To add or update a token, click the Edit icon, enter your Personal Access Token in the field, and click Save. The system validates the token automatically.
      • To remove or replace a token, click the Edit icon and select Forget Token.

        MCP PAT in chat
    • Enable or disable servers: Use the toggles to select which servers provide tools for your chat session.

      Note

      You must configure a token before you can enable a server that requires authentication.

Verification

  1. Submit a query in the chat that requires an MCP tool, such as requesting catalog resources or server information.
  2. If you enabled a server, verify that the response contains data from that specific MCP tool.
  3. If you disabled a server, verify that Developer Lightspeed for RHDH uses standard documentation or general knowledge instead of the MCP tool to provide the response.

12.2.13.6. Enable Software Catalog MCP tools

12.2.13.6.1. Enable Software Catalog MCP tools

Install the Model Context Protocol (MCP) server and its associated tool plugins to expose Red Hat Developer Hub portal capabilities, such as the Software Catalog and TechDocs, to your external AI assistant.

12.2.13.6.2. Enable Software Catalog MCP tools to allow the AI to query component metadata

Enable and use the Software Catalog MCP tools so that the AI assistant can seamlessly query internal software component metadata, relations, and ownership information on your behalf.

Use Software Catalog MCP tools to manage and retrieve RHDH entities such as Components, Systems, Resources, APIs, Locations, Users, and Groups.

Software Catalog tool reference:

The software-catalog-mcp-extras plugin provides tools to interact with the software catalog. By default, these tools return data in a JSON array format.

The following table lists the available tools in the software-catalog-mcp-tool plugin:

ToolDescriptionParameters

fetch-catalog-entities

Lists RHDH entities such as components, APIs, and resources.

kind, type, name, owner, lifecycle, tags, verbose

catalog-register-tool

Registers a new entity in the software catalog using a catalog-info.yaml file URL.

url

catalog-unregister-tool

Removes an existing entity from the software catalog.

entityRef

software-template-metadata-tool

Retrieves metadata for a specific software template.

templateRef

12.2.13.6.3. Fetch entities using fetch-catalog-entities

List Developer Hub entities including components, APIs, and resources using the fetch-catalog-entities tool.

The fetch-catalog-entities tool lists RHDH entities, including components, APIs, and resources.

Common query examples: * "Fetch all ai-model resources in the Backstage catalog" * "Fetch the API definition for the beneficiary-management-api API" * "Construct a curl command based on the API definition for the “insert beneficiary” endpoint in the beneficiary-management-api"

The following table lists the parameters for the fetch-catalog-entities tool:

ParameterDescriptionExample

kind

Filters by entity kind.

"Component"

type

Filters by entity type. [NOTE]: You must use the kind parameter with this filter.

"model-server"

name

Specifies a specific entity name.

"vllm-model-server"

owner

Filters entities by their owner.

"test-platform"

lifecycle

Filters entities by their lifecycle.

"development"

tags

Filters entities by their tags.

["genai", "ibm", "llm"]

verbose

Retrieves the full Backstage entity object instead of a shortened output when set to true.

true

12.2.13.6.4. Register entities using catalog-register-tool

Add new entities to the Software Catalog using the catalog-register-tool.

Use the catalog-register-tool to add new entities to your Software Catalog.

Table 12.1. catalog-register-tool parameters

ParameterDescription

url

The URL to the catalog-info.yaml file.

12.2.13.6.5. Unregister entities using catalog-unregister-tool

Remove existing entities from the Software Catalog using the catalog-unregister-tool.

Use the catalog-unregister-tool to remove an existing entity from the Software Catalog.

The following table lists the parameters for the catalog-unregister-tool:

ParameterDescription

location

A valid catalog location URL or a UUID.

12.2.13.6.6. Retrieve Software Template metadata

Retrieve metadata for specific Software Templates using the software-template-metadata-tool.

Use the software-template-metadata-tool to retrieve metadata for a specific Software Template.

The following table lists the parameters for the software-template-metadata-tool:

ParameterDescription

templateRef

The reference identifier for the Software Template.

12.2.13.7. Enable TechDocs MCP tools

12.2.13.7.1. Enable TechDocs MCP tools

Install the Model Context Protocol (MCP) server and its associated tool plugins to expose Red Hat Developer Hub portal capabilities, such as the Software Catalog and TechDocs, to your external AI assistant.

12.2.13.7.2. Enable TechDocs MCP tools to allow the AI to read and analyze internal documentation

Enable and use TechDocs MCP tools to allow the AI assistant to search, read, and analyze your internal technical documentation to resolve queries with accurate portal data.

The TechDocs MCP tool enables MCP clients to search and retrieve documentation from RHDH for use as context in AI applications.

The following table lists the TechDocs tools and parameters:

ToolDescriptionParameters

fetch-techdocs

Lists all entities with registered TechDocs. Includes metadata such as lastModified and build information.

entityType, namespace, owner, lifecycle, tags

analyze-techdocs-coverage

Calculates the percentage of entities with TechDocs configured to identify documentation gaps.

entityType, namespace, owner, lifecycle, tags

retrieve-techdocs-content

Retrieves the content of a specific TechDocs resource.

entityRef, pagePath

12.2.13.7.3. Retrieve TechDocs URLs and metadata using fetch-techdocs

List all Backstage entities with TechDocs including URLs, metadata, timestamps, and build information using the fetch-techdocs tool.

The fetch-techdocs TechDocs MCP tool lists all Backstage entities with TechDocs. By default, the tool returns results in a JSON array format. Each entry includes entity details and TechDocs metadata, like last update timestamp and build information.

By default, each entry in the JSON array is an entity with the following fields: name, title, tags, description, owner, lifecycle, namespace, kind, techDocsUrl, matadataUrl, and metadata.

The following examples show common queries:

  • “Fetch all techdocs from the Backstage server”
  • “Fetch all techdocs of the default namespace”
  • “Fetch all techdocs created by user:john.doe”

Table 12.2. fetch-techdocs TechDocs MCP tool.

NameDescriptionExample

entityType

Filters entities by their type.

"Component"

namespace

Filter entities by their namespace.

"default"

owner

Filters entities by owner.

"user:john.doe"

lifecycle

Filters entities by their lifecycle.

"development"

tags

Filters entities by their tags.

["genai, "ibm", "llm", "granite", "conversational", "task-text-generation"]

12.2.13.7.4. Measure documentation gaps using analyze-techdocs-coverage

Calculate documentation coverage percentage and identify gaps using the analyze-techdocs-coverage tool with entity attribute filters.

The analyze-techdocs-coverage TechDocs MCP tool calculates the percentage of entities that have TechDocs configured. Use this tool to identify documentation gaps and improve overall documentation coverage.

You can filter results by the following entity attributes: * type * namespace * owner * lifecycle * tags By default, analyze-techdocs-coverage returns a JSON entity that includes the totalEntities, entitiesWithDocs, and coveragePercentage fields.

The following examples show common queries:

  • “What is the coverage of techdocs in the backstage server”
  • “What is the coverage of techdocs in the default namespace”

The following table lists the parameters for the analyze-techdocs-coverage TechDocs MCP tool:

NameDescriptionExample

entityType

Filters entities by their type.

"Component"

namespace

Filter entities by their namespace.

"default"

owner

Filters entities by owner.

"user:john.doe"

lifecycle

Filters entities by their lifecycle.

"development"

tags

Filters entities by their tags.

["genai, "ibm", "llm", "granite", "conversational", "task-text-generation"]

12.2.13.7.5. Find a specific TechDoc using retrieve-techdocs-content

Retrieve TechDocs content for specific Software Catalog entities using the retrieve-techdocs-content tool with entityRef, name, title, and content fields.

The retrieve-techdocs-content TechDocs MCP tool retrieves the content of a TechDocs resource, enabling AI clients to access documentation content for specific Software Catalog entities. By default, the tool returns a JSON entity with the following fields: entityRef, name, title, kind, namespace, content, path, contentType, lastModified, and metadata.

The following examples show common queries:

  • “Fetch techdoc with reference component:default/my-service”
  • “Fetch page about.html from techdoc with reference component:default/my-service”

The following table describes the parameters for the retrieve-techdocs-content TechDocs MCP tool.

NameDescriptionExample

entityRef

Specifies the entity to retrieve using the kind:namespace/name format.

"component:default/my-service"

pagePath

Specifies the path to a specific documentation page. Defaults to index.html

"index.html"

12.2.13.8. Enable Scaffolder MCP tools

12.2.13.8.1. Enable Scaffolder MCP tools

Use the Scaffolder Model Context Protocol (MCP) (scaffolder-mcp-extras) tools to query available actions, validate template dry-runs, and retrieve task logs during Software Template development in RHDH.

12.2.13.8.2. Automate software resource creation

With Software Template validation, you can verify YAML configuration and execution logic in a sandboxed environment. This preliminary testing ensures that your templates function as intended before you deploy them to a production environment.

The validation process involves the following key components:

  • User interaction: You must provide the template YAML content, required input values, and any additional files.
  • Agent invocation: The AI agent maps these inputs to the templateYAML, values, and files parameters to call the dry-run tool.
  • Outcome processing: The AI agent interprets the valid status and execution logs to provide a plain-language summary or troubleshooting steps if validation fails.
12.2.13.8.3. Scaffolder dry-run tool reference

Use this tool to perform a sandboxed dry-run execution of a Scaffolder template.

The following table describes the input fields:

Input parameterDescriptionExample

templateYaml

Full YAML content of the template.

apiVersion: scaffolder…​

values

Key-value map of required input values.

{"name": "my-service"}

files

Additional files including path and content.

[{"path": "README.md", "content": "# Example"}]

The following table describes the output fields:

Output fieldDescriptionExample

valid

Boolean indicating if the template passed validation.

true

message

Summary of the dry-run result.

"Template validation successful"

errors

List of error messages if valid is false.

["YAML parsing error…​"]

log

List of execution log objects.

 

log[].message

Log message text from the dry run.

"Running step: fetch:template"

log[].stepId

ID of the step associated with the log.

"fetch"

log[].status

Step status, such as processing.

"processing"

output

Template output produced by the dry run.

{"repoUrl": "…​"}

steps

List of execution step objects.

 

steps[].id

ID of the step.

"fetch"

steps[].name

Display name of the step.

"Fetch Template"

steps[].action

Action identifier used by the step.

"fetch:template"

12.2.13.8.4. Software Template execution with Scaffolder MCP tools

Automate resource creation, such as repositories or components, by executing Software Templates through the AI agent.

By using Scaffolder MCP tools, the AI agent interacts directly with your existing software templates to streamline the development lifecycle.

The execution process relies on three core components:

  • User interaction: You must identify a reference for the target template (for example, template:default/create-node) and provide the necessary input values and secrets.
  • Agent invocation: The AI agent maps the data to the templateRef, values, and secrets parameters to execute the template.
  • Outcome processing: The AI agent confirms the execution and provides the taskId to the user for progress tracking.
12.2.13.8.5. Scaffolder execution tool reference

Run a Software Template to create repositories, register components, or provision infrastructure.

The following table describes the inputs fields:

Input parameterDescriptionExample

templateRef

Entity reference of the target template.

template:default/create-node

values

Key-value map of required input values.

{"owner": "team-a"}

secrets

Optional: Secrets required for execution.

{"githubToken": "ghp_abc"}

The following table describes the output fields:

Output field

Description

taskId

ID of the created task used for log tracking.

12.2.13.8.6. Scaffolder task monitoring with MCP tools

Scaffolder task monitoring provides visibility into the lifecycle of automated resource creation. By using MCP tools, you can track the progress of templates and retrieve execution results for workflows initiated by an AI agent.

Monitoring capabilities include the following features:

  • User interaction: You must ask for a status update on your tasks or a list of recent activities.
  • Agent invocation: The AI agent calls the task list tool. To restrict results to only include your own tasks, the agent must set the owned parameter to true.
  • Outcome processing: The AI agent filters and summarizes the tasks[] list, reporting statuses such as processing, completed, or failed.
12.2.13.8.7. Scaffolder tasks list tool reference

Use the Scaffolder tasks list tool to retrieve and filter a list of Scaffolder tasks.

The following table describes the input fields:

Input parameterDescriptionExample

owned

If true, returns only tasks created by the current user.

true

limit

Maximum number of tasks to return per request.

5

offset

Number of tasks to skip for pagination.

10

The following table describes the output fields:

Output fieldDescriptionExample

tasks[]

A list of Scaffolder tasks including ID, timestamps, and status. Statuses include: open, processing, completed, failed, cancelled, and stale.

{"id": "b8e7f2a1…​", "status": "processing"}

12.2.13.8.8. Automate Software Templates

Use this tool to list all installed Scaffolder actions and their associated metadata. This tool requires no input parameters. The following table describes the output fields.

Output fieldDescription

actions

List containing action IDs and descriptions.

actions[].id

Action identifier (for example, fetch:plain).

actions[].description

Summary of the action’s function.

actions[].schema.input

JSON Schema for input parameters.

actions[].schema.output

JSON Schema for output values.

actions[].examples

Usage examples provided by the action.

12.2.13.8.9. Get Scaffolder task logs

Retrieve log events for a task to monitor execution progress or diagnose template failures.

The following table describes the input parameters:

Input parameterDescriptionExample

taskId

Unique identifier for a task.

b8e7f2a1-3c4d-4e6f-8a9b-0c1d2e3f4a5b

after

Optional: Return only events after this event ID.

1847

The following table describes the output parameters:

Output parameterDescriptionExample

log

The log output for the specified task ID. Each log entry includes the message, stepId, and step status. Event types include log, completion, cancelled, or recovered.

"2026-03-27…​ Finished step Fetch skeleton"

12.2.14. Accelerate AI model discovery by integrating the OpenShift AI Connector

12.2.14.1. Accelerate AI model discovery by integrating the OpenShift AI Connector

Integrate AI models and model servers from Red Hat OpenShift AI directly into the Red Hat Developer Hub (RHDH) Catalog to provide a unified hub for discovering and consuming AI components.

12.2.14.2. How AI assets map to the Red Hat Developer Hub Catalog

Important

This section describes Developer Preview features in the OpenShift AI Connector for Red Hat Developer Hub plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

The OpenShift AI Connector for Red Hat Developer Hub (OpenShift AI Connector for RHDH) discovers AI assets managed within Red Hat OpenShift AI. The connector automatically converts AI models and model servers into Backstage entities to provide a unified view for developer teams.

For more information on model registry components, see Overview of model registries and model catalog.

12.2.14.3. Configure AI asset mapping

12.2.14.3.1. Configure AI asset mapping

The OpenShift AI Connector for Red Hat Developer Hub (OpenShift AI Connector for RHDH) discovers AI assets managed within Red Hat OpenShift AI. The connector automatically converts AI models and model servers into Backstage entities to provide a unified view for developer teams.

12.2.14.3.2. Model-to-Entity mapping

The following table maps RHOAI components to Backstage entity kinds.

RHOAI ArtifactRHDH/Backstage Entity KindRHDH/Backstage Entity TypePurpose

Model Server (InferenceService)

Component

model-server

Represents a running, accessible AI model endpoint. See Configuring your model-serving platform.

AI Model (Model Registry Version)

Resource

ai-model

Represents the specific AI model artifact, for example, Llama-3-8B.

Model Server API Details

API

openapi (Default)

Provides the OpenAPI/Swagger specification for the REST endpoint of the model. See Red Hat OpenShifT AI: API Tiers

Model Cards

TechDocs

N/A

Associates model cards from the RHOAI model catalog with the Resource entities. See Registering a model from the model catalog.

Once the OpenShift AI Connector for RHDH is installed and connected with RHOAI, the transfer of information commences automatically.

12.2.14.3.3. Data mapping specifications

Review the key data that the connector automatically propagates from RHOAI.

  • InferenceServices (Component type model-server):

    • URL of the OpenShift Route (if exposed).
    • URL of the Kubernetes Service.
    • Authentication requirement status.
  • Model registry (Resource type ai-model):

    • Model description, asset URIs, and author or owner information.
  • Model catalog:

    • Links to the Model Card (as RHDH TechDocs).
    • Model license URL.
12.2.14.3.4. Enrich AI model metadata for enhanced Red Hat Developer Hub experience

Enrich the RHDH experience by adding custom properties to your RHOAI model metadata, so that the OpenShift AI Connector for Red Hat Developer Hub populates additional fields in the catalog entities.

For more details, see Editing model version metadata in a model registry.

Property KeyEntity Field PopulatedDescription

API Spec

API Definition Tab

The OpenAPI / Swagger JSON specification for the model REST API.

API Type

API Type

Correlates to supported RHDH/Backstage API types (defaults to openapi).

TechDocs

TechDocs

URL pointing to a Git repository that follows RHDH TechDocs conventions for the Model Card. Use this setting only if the Model Card to TechDocs mapping is inactive.

Homepage URL

Links

The home page URL for the model.

Owner

Owner

Overrides the default OpenShift user as the entity owner.

Lifecycle

Lifecycle

Expresses the lifecycle concept of RHDH/Backstage.

How to use

Links

A URL that points to usage documentation.

License

Links

A URL to the license file of the model.

rhdh.modelcatalog.io/model-name

Annotations

A key piece of metadata is the name of the model used when communicating with the model server’s REST API. OpenShift AI Connector for Red Hat Developer Hub stores this name in the rhdh.modelcatalog.io/model-name annotation on the Resource entity, and will default this annotation’s value to the combined names of the ResourceModel and ModelVersion in the model registry, or the KServe InferenceService name if the model registry is not used, as those often line up with the model name used when communicating with the model server’s REST API. But the names are not guaranteed to match. When the names do not match, provide the correct model name for model REST API invocations.

12.2.14.4. Set up OpenShift AI Connector for Red Hat Developer Hub with Red Hat OpenShift AI

To install the OpenShift AI Connector for Red Hat Developer Hub, you must manually update your RHDH-related Kubernetes resources.

Important

This section describes Developer Preview features in the OpenShift AI Connector for Red Hat Developer Hub plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

Prerequisites

  • To import model cards from the model catalog into TechDocs, you must use RHOAI 2.25.

    Note

    If you upgraded to RHOAI 2.25 from an earlier version, you must manually enable the model catalog dashboard and model registry before you can import model cards.

  • If you used the model catalog in earlier versions of RHOAI, TechDocs propagation does not work for any models you registered into the model registry while at those earlier versions; only models registered into model registry from a RHOAI 2.25 model catalog have their model cards transferred to RHDH as TechDocs.
  • For the rest of the features, version 2.20 or later suffices. Enabling model registry and its associated dashboard allows for a user experience that more directly allows for customizing AI Model metadata. For best overall experience, RHOAI 2.25 is recommended.

For more details, see Enabling the model registry component.

Procedure

  1. Configure RHOAI-related RBAC and credentials.

    A Kubernetes ServiceAccount and a service-account-token Secret are required for the connector to retrieve data from RHOAI. The following resources must be created, replacing namespace names (ai-rhdh for RHDH, rhoai-model-registries for RHOAI) as needed:

    1. ServiceAccount (rhdh-rhoai-connector). For example:

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: rhdh-rhoai-connector
        namespace: ai-rhdh
    2. ClusterRole and ClusterRoleBinding (rhdh-rhoai-connector) to allow access to OpenShift Container Platform resources such as routes, services, and inferenceservices. For example:

      # Example for `ClusterRole`
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: rhdh-rhoai-connector
        annotations:
          argocd.argoproj.io/sync-wave: "0"
      rules:
        - apiGroups:
            - apiextensions.k8s.io
          resources:
            - customresourcedefinitions
          verbs:
            - get
        - apiGroups:
            - route.openshift.io
          resources:
            - routes
          verbs:
            - get
            - list
            - watch
        - apiGroups: [""]
          resources:
            - serviceaccounts
            - services
          verbs:
            - get
            - list
            - watch
      
        - apiGroups: ["serving.kserve.io"]
          resources: ["inferenceservices"]
          verbs: ["get", "list", "watch"]
      # Example for `ClusterRoleBinding`
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: rhdh-rhoai-connector
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: rhdh-rhoai-connector
      subjects:
        - kind: ServiceAccount
          name: rhdh-rhoai-connector
          namespace: ai-rhdh
    3. Role and RoleBinding to allow ConfigMap updates within the RHDH namespace (ai-rhdh). For example:

      # Example for `Role` and `Rolebinding` in the {product-very-short} namespace (`ai-rhdh`)
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: rhdh-rhoai-connector
        namespace: ai-rhdh
      rules:
        - apiGroups: [""]
          resources: ["configmaps"]
          verbs: ["get", "list", "watch", "create", "update", "patch"]
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: rhdh-rhoai-connector
        namespace: ai-rhdh
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: rhdh-rhoai-connector
      subjects:
        - kind: ServiceAccount
          name: rhdh-rhoai-connector
          namespace: ai-rhdh
    4. RoleBinding in the RHOAI namespace (rhoai-model-registries) to grant the RHDH ServiceAccount read permissions to the model registry data (binding to registry-user-modelregistry-public).

      # Example for `RoleBinding` in the {rhoai-short} namespace (rhoai-model-registries)
      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        # if using ODH then change rhoai to odh in the name and namespace here
        name: rhdh-rhoai-dashboard-permissions
        # namespace: odh-model-registries
        namespace: rhoai-model-registries
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: registry-user-modelregistry-public
      subjects:
        - apiGroup: rbac.authorization.k8s.io
          kind: Group
          name: system:serviceaccounts:ai-rhdh
    5. Secret (rhdh-rhoai-connector-token) of type kubernetes.io/service-account-token that goes along with the rhdh-rhoai-connector ServiceAccount.

      apiVersion: v1
      kind: Secret
      metadata:
        name: rhdh-rhoai-connector-token
        namespace: ai-rhdh
        annotations:
          kubernetes.io/service-account.name: rhdh-rhoai-connector
      type: kubernetes.io/service-account-token
  2. Update your RHDH dynamic plugin configuration. The RHDH Pod requires two dynamic plugins.

    1. In your RHDH dynamic plugins ConfigMap, add the following code:

      plugins:
        - disabled: false
          package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-catalog-backend-module-model-catalog:<tag>
        - disabled: false
          package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-catalog-techdoc-url-reader-backend:<tag>

      where:

      <tag>
      Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  3. Find your Backstage version in the RHDH release notes preface.
  4. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  5. Add the Connector sidecar containers to the RHDH Pod.
  6. If RHDH was installed by using the Operator, modify your RHDH custom resource (CR) instance.
  7. If RHDH was installed by using the Helm charts, modify the Deployment specification.

    The system relies on three sidecar containers (OpenShift AI Connector for Red Hat Developer Hub) running alongside the backstage-backend container. Add these sidecar containers to your configuration referencing the rhdh-rhoai-connector-token Secret:

  8. location: Provides the REST API for RHDH plugins to fetch model metadata.
  9. storage-rest: Maintains a cache of AI Model metadata in a ConfigMap called bac-import-model.
  10. rhoai-normalizer: Acts as a Kubernetes controller and RHOAI client, normalizing RHOAI metadata for the connector. The following code block is an example:

    spec:
      template:
        spec:
          containers:
            - env:
                - name: NORMALIZER_FORMAT
                  value: JsonArrayFormat
                - name: POD_IP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.podIP
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              envFrom:
                - secretRef:
                    name: rhdh-rhoai-connector-token
              image: quay.io/redhat-ai-dev/model-catalog-location-service@sha256:c4471e07be6e0dbe821613053e6264a552cacda7f8604dbf306e6ac9e81e8ab9
              imagePullPolicy: Always
              name: location
              ports:
                - containerPort: 9090
                  name: location
                  protocol: TCP
              volumeMounts:
                - mountPath: /opt/app-root/src/dynamic-plugins-root
                  name: dynamic-plugins-root
              workingDir: /opt/app-root/src
            - env:
                - name: NORMALIZER_FORMAT
                  value: JsonArrayFormat
                - name: STORAGE_TYPE
                  value: ConfigMap
                - name: BRIDGE_URL
                  value: http://localhost:9090
                - name: POD_IP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.podIP
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              envFrom:
                - secretRef:
                    name: rhdh-rhoai-connector-token
              image: quay.io/redhat-ai-dev/model-catalog-storage-rest@sha256:609f6866c7913a87c51912260803c219e564fa7dc90c2ff735ff6dfc5797bc3b
              imagePullPolicy: Always
              name: storage-rest
              volumeMounts:
                - mountPath: /opt/app-root/src/dynamic-plugins-root
                  name: dynamic-plugins-root
              workingDir: /opt/app-root/src
            - env:
                - name: NORMALIZER_FORMAT
                  value: JsonArrayFormat
                - name: POD_IP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.podIP
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              envFrom:
                - secretRef:
                    name: rhdh-rhoai-connector-token
              image: quay.io/redhat-ai-dev/model-catalog-rhoai-normalizer@sha256:9f19742450a3a9c6d9c01d8341a20db7eb5a52a39348f488ae06b6aa49754a26
              imagePullPolicy: Always
              name: rhoai-normalizer
              volumeMounts:
                - mountPath: /opt/app-root/src/dynamic-plugins-root
                  name: dynamic-plugins-root
              workingDir: /opt/app-root/src
              args:
                - '--metrics-address=:8081'
  11. Enable Connector in your RHDH app-config.yaml file. In your Backstage `app-config.extra.yaml file, configure Entity Provider under the catalog.providers section:

    providers:
      modelCatalog:
        development:
          baseUrl: http://localhost:9090

    where:

    modelCatalog
    Specifies the name of the provider.
    development
    Defines future connector capability beyond a single baseUrl.
    baseUrl
    For Developer Preview, this value is the only one supported. Future releases might support external routes.

12.2.14.5. Populate AI model catalog metadata

12.2.14.5.1. Populate AI model catalog metadata

Enrich the RHDH experience by adding custom properties to your RHOAI model metadata, so that the OpenShift AI Connector for Red Hat Developer Hub populates additional fields in the catalog entities.

12.2.14.5.2. Set up OpenShift AI Connector for Red Hat Developer Hub with Red Hat OpenShift AI

To install the OpenShift AI Connector for Red Hat Developer Hub, you must manually update your RHDH-related Kubernetes resources.

Important

This section describes Developer Preview features in the OpenShift AI Connector for Red Hat Developer Hub plugin. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. Customers can use these features to test functionality and provide feedback during the development process. Developer Preview features might not have any documentation, are subject to change or removal at any time, and have received limited testing. Red Hat might provide ways to submit feedback on Developer Preview features without an associated SLA.

For more information about the support scope of Red Hat Developer Preview features, see Developer Preview Support Scope.

Prerequisites

  • To import model cards from the model catalog into TechDocs, you must use RHOAI 2.25.

    Note

    If you upgraded to RHOAI 2.25 from an earlier version, you must manually enable the model catalog dashboard and model registry before you can import model cards.

  • If you used the model catalog in earlier versions of RHOAI, TechDocs propagation does not work for any models you registered into the model registry while at those earlier versions; only models registered into model registry from a RHOAI 2.25 model catalog have their model cards transferred to RHDH as TechDocs.
  • For the rest of the features, version 2.20 or later suffices. Enabling model registry and its associated dashboard allows for a user experience that more directly allows for customizing AI Model metadata. For best overall experience, RHOAI 2.25 is recommended.

For more details, see Enabling the model registry component.

Procedure

  1. Configure RHOAI-related RBAC and credentials.

    A Kubernetes ServiceAccount and a service-account-token Secret are required for the connector to retrieve data from RHOAI. The following resources must be created, replacing namespace names (ai-rhdh for RHDH, rhoai-model-registries for RHOAI) as needed:

    1. ServiceAccount (rhdh-rhoai-connector). For example:

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: rhdh-rhoai-connector
        namespace: ai-rhdh
    2. ClusterRole and ClusterRoleBinding (rhdh-rhoai-connector) to allow access to OpenShift Container Platform resources such as routes, services, and inferenceservices. For example:

      # Example for `ClusterRole`
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: rhdh-rhoai-connector
        annotations:
          argocd.argoproj.io/sync-wave: "0"
      rules:
        - apiGroups:
            - apiextensions.k8s.io
          resources:
            - customresourcedefinitions
          verbs:
            - get
        - apiGroups:
            - route.openshift.io
          resources:
            - routes
          verbs:
            - get
            - list
            - watch
        - apiGroups: [""]
          resources:
            - serviceaccounts
            - services
          verbs:
            - get
            - list
            - watch
      
        - apiGroups: ["serving.kserve.io"]
          resources: ["inferenceservices"]
          verbs: ["get", "list", "watch"]
      # Example for `ClusterRoleBinding`
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: rhdh-rhoai-connector
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: rhdh-rhoai-connector
      subjects:
        - kind: ServiceAccount
          name: rhdh-rhoai-connector
          namespace: ai-rhdh
    3. Role and RoleBinding to allow ConfigMap updates within the RHDH namespace (ai-rhdh). For example:

      # Example for `Role` and `Rolebinding` in the {product-very-short} namespace (`ai-rhdh`)
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: rhdh-rhoai-connector
        namespace: ai-rhdh
      rules:
        - apiGroups: [""]
          resources: ["configmaps"]
          verbs: ["get", "list", "watch", "create", "update", "patch"]
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: rhdh-rhoai-connector
        namespace: ai-rhdh
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: rhdh-rhoai-connector
      subjects:
        - kind: ServiceAccount
          name: rhdh-rhoai-connector
          namespace: ai-rhdh
    4. RoleBinding in the RHOAI namespace (rhoai-model-registries) to grant the RHDH ServiceAccount read permissions to the model registry data (binding to registry-user-modelregistry-public).

      # Example for `RoleBinding` in the {rhoai-short} namespace (rhoai-model-registries)
      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        # if using ODH then change rhoai to odh in the name and namespace here
        name: rhdh-rhoai-dashboard-permissions
        # namespace: odh-model-registries
        namespace: rhoai-model-registries
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: registry-user-modelregistry-public
      subjects:
        - apiGroup: rbac.authorization.k8s.io
          kind: Group
          name: system:serviceaccounts:ai-rhdh
    5. Secret (rhdh-rhoai-connector-token) of type kubernetes.io/service-account-token that goes along with the rhdh-rhoai-connector ServiceAccount.

      apiVersion: v1
      kind: Secret
      metadata:
        name: rhdh-rhoai-connector-token
        namespace: ai-rhdh
        annotations:
          kubernetes.io/service-account.name: rhdh-rhoai-connector
      type: kubernetes.io/service-account-token
  2. Update your RHDH dynamic plugin configuration. The RHDH Pod requires two dynamic plugins.

    1. In your RHDH dynamic plugins ConfigMap, add the following code:

      plugins:
        - disabled: false
          package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-catalog-backend-module-model-catalog:<tag>
        - disabled: false
          package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-catalog-techdoc-url-reader-backend:<tag>

      where:

      <tag>
      Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  3. Find your Backstage version in the RHDH release notes preface.
  4. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  5. Add the Connector sidecar containers to the RHDH Pod.
  6. If RHDH was installed by using the Operator, modify your RHDH custom resource (CR) instance.
  7. If RHDH was installed by using the Helm charts, modify the Deployment specification.

    The system relies on three sidecar containers (OpenShift AI Connector for Red Hat Developer Hub) running alongside the backstage-backend container. Add these sidecar containers to your configuration referencing the rhdh-rhoai-connector-token Secret:

  8. location: Provides the REST API for RHDH plugins to fetch model metadata.
  9. storage-rest: Maintains a cache of AI Model metadata in a ConfigMap called bac-import-model.
  10. rhoai-normalizer: Acts as a Kubernetes controller and RHOAI client, normalizing RHOAI metadata for the connector. The following code block is an example:

    spec:
      template:
        spec:
          containers:
            - env:
                - name: NORMALIZER_FORMAT
                  value: JsonArrayFormat
                - name: POD_IP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.podIP
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              envFrom:
                - secretRef:
                    name: rhdh-rhoai-connector-token
              image: quay.io/redhat-ai-dev/model-catalog-location-service@sha256:c4471e07be6e0dbe821613053e6264a552cacda7f8604dbf306e6ac9e81e8ab9
              imagePullPolicy: Always
              name: location
              ports:
                - containerPort: 9090
                  name: location
                  protocol: TCP
              volumeMounts:
                - mountPath: /opt/app-root/src/dynamic-plugins-root
                  name: dynamic-plugins-root
              workingDir: /opt/app-root/src
            - env:
                - name: NORMALIZER_FORMAT
                  value: JsonArrayFormat
                - name: STORAGE_TYPE
                  value: ConfigMap
                - name: BRIDGE_URL
                  value: http://localhost:9090
                - name: POD_IP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.podIP
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              envFrom:
                - secretRef:
                    name: rhdh-rhoai-connector-token
              image: quay.io/redhat-ai-dev/model-catalog-storage-rest@sha256:609f6866c7913a87c51912260803c219e564fa7dc90c2ff735ff6dfc5797bc3b
              imagePullPolicy: Always
              name: storage-rest
              volumeMounts:
                - mountPath: /opt/app-root/src/dynamic-plugins-root
                  name: dynamic-plugins-root
              workingDir: /opt/app-root/src
            - env:
                - name: NORMALIZER_FORMAT
                  value: JsonArrayFormat
                - name: POD_IP
                  valueFrom:
                    fieldRef:
                      fieldPath: status.podIP
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              envFrom:
                - secretRef:
                    name: rhdh-rhoai-connector-token
              image: quay.io/redhat-ai-dev/model-catalog-rhoai-normalizer@sha256:9f19742450a3a9c6d9c01d8341a20db7eb5a52a39348f488ae06b6aa49754a26
              imagePullPolicy: Always
              name: rhoai-normalizer
              volumeMounts:
                - mountPath: /opt/app-root/src/dynamic-plugins-root
                  name: dynamic-plugins-root
              workingDir: /opt/app-root/src
              args:
                - '--metrics-address=:8081'
  11. Enable Connector in your RHDH app-config.yaml file. In your Backstage `app-config.extra.yaml file, configure Entity Provider under the catalog.providers section:

    providers:
      modelCatalog:
        development:
          baseUrl: http://localhost:9090

    where:

    modelCatalog
    Specifies the name of the provider.
    development
    Defines future connector capability beyond a single baseUrl.
    baseUrl
    For Developer Preview, this value is the only one supported. Future releases might support external routes.
12.2.14.5.3. Populate the API Definition tab in RHDH API entities

Because RHOAI does not expose the OpenAPI specification by default, the AI platform engineer can take the following steps to provide this information:

Prerequisites

Procedure

  1. Retrieve OpenAPI JSON: Use a tool such as curl to fetch the specification directly from the running endpoint of the AI model server. The following command provides the precise endpoint (/openapi.json) and shows how to include a Bearer token if the model requires authentication for access.

    $ curl -k -H "Authorization: Bearer $MODEL_API_KEY" https://$MODEL_ROOT_URL_INCLUDING_PORT/openapi.json | jq > open-api.json
  2. Set Property in RHOAI.

    1. In the RHOAI dashboard, go to Model Registry and select the appropriate Model Version.

      Note

      Red Hat recommends using Model Version instead of Registered Model to maintain stability if the API changes between versions.

    2. In the Properties section, set a key/value pair where the key is API Spec and the value is the entire JSON content from the open-api.json file.
  3. Propagation: The OpenShift AI Connector for Red Hat Developer Hub periodically polls the RHOAI Model Registry, propagates this JSON, and renders the interactive API documentation in the Definition tab of the RHDH API entity.

12.3. Integrate CI/CD and infrastructure tools to visualize pipelines and workloads

12.3.1. Integrate CI/CD and infrastructure tools to visualize pipelines and workloads

Integrate CI/CD and infrastructure tools with Red Hat Developer Hub to visualize deployment pipelines, track build artifacts, and monitor Kubernetes workloads.

12.3.2. Track deployment history and rollouts with Argo CD

12.3.2.1. Track deployment history and rollouts with Argo CD

The Argo CD plugin provides a visual overview of the application's status, deployment details, commit message, author of the commit, container image promoted to environment and deployment history.

12.3.2.2. Enable the Argo CD plugin

The Argo CD plugin provides a visual overview of the application's status, deployment details, commit message, author of the commit, container image promoted to environment and deployment history.

Procedure

  1. Add Argo CD instance information to your app-config.yaml configmap as shown in the following example:

    argocd:
      appLocatorMethods:
        - type: 'config'
          instances:
            - name: argoInstance1
              url: https://argoInstance1.com
              username: ${ARGOCD_USERNAME}
              password: ${ARGOCD_PASSWORD}
            - name: argoInstance2
              url: https://argoInstance2.com
              username: ${ARGOCD_USERNAME}
              password: ${ARGOCD_PASSWORD}
    Note

    Avoid using a trailing slash in the url, as it might cause unexpected behavior.

  2. Add the following annotation to the entity's catalog-info.yaml file to identify the Argo CD applications.

    annotations:
      ...
      # The label that Argo CD uses to fetch all the applications. The format to be used is label.key=label.value. For example, rht-gitops.com/janus-argocd=quarkus-app.
    
      argocd/app-selector: '${ARGOCD_LABEL_SELECTOR}'
  3. (Optional) Add the following annotation to the entity's catalog-info.yaml file to switch between Argo CD instances as shown in the following example:

     annotations:
       ...
        # The Argo CD instance name used in `app-config.yaml`.
    
        argocd/instance-name: '${ARGOCD_INSTANCE}'
    Note

    If you do not set this annotation, the Argo CD plugin defaults to the first Argo CD instance configured in app-config.yaml.

  4. To enable the Argo CD plugin, set the disabled property to false in your dynamic-plugins.yaml file as follows:

    Important

    Argo CD contains multiple plugin options you can choose from for your Argo CD configuration:

    • Community Argo CD:

      • @backstage-community/plugin-argocd
      • @backstage-community/plugin-argocd-backend
    • Roadie Argo CD:

      • @roadiehq/backstage-plugin-argo-cd
      • @roadiehq/backstage-plugin-argo-cd-backend

    Community and Roadie plugins are comparable in functionality but have different features. For example, both versions feature scaffolder actions, however, their implementation is different: the Community version contains scaffolder actions by default, the Roadie version requires an additional plugin.

    The recommended combination is to use @backstage-community/plugin-argocd together with @backstage-community/plugin-argocd-backend.

    However, you can also combine @roadiehq/backstage-plugin-argo-cd together with @roadiehq/backstage-plugin-argo-cd-backend.

    Mixing Community and Roadie plugins is not recommended.

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-argo-cd-backend:<tag>
        disabled: false
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

12.3.2.3. Enable Argo CD Rollouts

Enable advanced deployment strategies such as blue-green and canary deployments by integrating Argo CD Rollouts with the Red Hat Developer Hub Kubernetes plugin.

The optional Argo CD Rollouts feature enhances Kubernetes by providing advanced deployment strategies, such as blue-green and canary deployments, for your applications. When integrated into the backstage Kubernetes plugin, it allows developers and operations teams to visualize and manage Argo CD Rollouts seamlessly within the Developer Hub interface.

Prerequisites

  • The Developer Hub Kubernetes plugin (@backstage/plugin-kubernetes) is installed and configured.

  • You have access to the Kubernetes cluster with the necessary permissions to create and manage custom resources and ClusterRoles.
  • The Kubernetes cluster has the argoproj.io group resources (for example, Rollouts and Analysis Runs) installed.

Procedure

  1. In the app-config.yaml file in your Developer Hub instance, add the following customResources component under the kubernetes configuration to enable Argo Rollouts and Analysis Runs:

    kubernetes:
      ...
      customResources:
        - group: 'argoproj.io'
          apiVersion: 'v1alpha1'
          plural: 'Rollouts'
        - group: 'argoproj.io'
          apiVersion: 'v1alpha1'
          plural: 'analysisruns'
  2. Grant ClusterRole permissions for custom resources.

    Note
    1. If the Developer Hub Kubernetes plugin is already configured, the ClusterRole permissions for Rollouts and AnalysisRuns might already be granted.
    2. Use the prepared manifest to give read-only ClusterRole access to both the Kubernetes and ArgoCD plugins.
    1. If the ClusterRole permission is not granted, use the following YAML manifest to create the ClusterRole:
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: backstage-read-only
    rules:
      - apiGroups:
          - argoproj.io
        resources:
          - rollouts
          - analysisruns
        verbs:
          - get
          - list
    1. Apply the manifest to the cluster using kubectl:

      $ kubectl apply -f <your_cluster_role_file>.yaml
    2. Ensure the ServiceAccount accessing the cluster has this ClusterRole assigned.
  3. Add annotations to catalog-info.yaml to identify Kubernetes resources for Backstage.

    1. For identifying resources by entity ID:

      annotations:
        ...
        backstage.io/kubernetes-id: <BACKSTAGE_ENTITY_NAME>
    2. (Optional) For identifying resources by namespace:

      annotations:
        ...
        backstage.io/kubernetes-namespace: <RESOURCE_NAMESPACE>
    3. For using custom label selectors, which override resource identification by entity ID or namespace:

      annotations:
        ...
        backstage.io/kubernetes-label-selector: 'app=my-app,component=front-end'
      Note

      Ensure you specify the labels declared in backstage.io/kubernetes-label-selector on your Kubernetes resources. This annotation overrides entity-based or namespace-based identification annotations, such as backstage.io/kubernetes-id and backstage.io/kubernetes-namespace.

  4. Add label to Kubernetes resources to enable Developer Hub to find the appropriate Kubernetes resources.

    1. Developer Hub Kubernetes plugin label: Add this label to map resources to specific Developer Hub entities.

      labels:
        ...
        backstage.io/kubernetes-id: <BACKSTAGE_ENTITY_NAME>
    2. GitOps application mapping: Add this label to map Argo CD Rollouts to a specific GitOps application

      labels:
        ...
        app.kubernetes.io/instance: <GITOPS_APPLICATION_NAME>
    Note

    If using the label selector annotation (backstage.io/kubernetes-label-selector), ensure the specified labels are present on the resources. The label selector will override other annotations such as kubernetes-id or kubernetes-namespace.

Verification

  1. Push the updated configuration to your GitOps repository to trigger a rollout.
  2. Open Red Hat Developer Hub interface and navigate to the entity you configured.
  3. Select the CD tab and then select the GitOps application. The side panel opens.
  4. In the Resources table of the side panel, verify that the following resources are displayed:

    • Rollouts
    • Analysis Runs (optional)
  5. Expand a rollout resource and review the following details:

    • The Revisions row displays traffic distribution details for different rollout versions.
    • The Analysis Runs row displays the status of analysis tasks that evaluate rollout success.

12.3.2.4. Use the Argo CD plugin

You can use the Argo CD plugin to visualize the Continuous Delivery (CD) workflows in OpenShift GitOps. This plugin provides a visual overview of the application’s status, deployment details, commit message, author of the commit, container image promoted to environment and deployment history.

Prerequisites

Procedure

  1. Select the Catalog tab and choose the component that you want to use.
  2. Select the CD tab to view insights into deployments managed by Argo CD.

    CD tab showing Argo CD deployments
  3. Select an appropriate card to view the deployment details (for example, commit message, author name, and deployment history).

    Sidebar showing deployment details
    1. Click the link icon ( Link icon ) to open the deployment details in Argo CD.
  4. Select the Overview tab and navigate to the Deployment summary section to review the summary of your application’s deployment across namespaces. Additionally, select an appropriate Argo CD app to open the deployment details in Argo CD, or select a commit ID from the Revision column to review the changes in GitLab or GitHub.

    Deployment summary showing application deployment across namespaces

12.3.3. Track build artifacts using the JFrog plugin

12.3.3.1. Track build artifacts using the JFrog plugin

Enable the JFrog Artifactory plugin to track and view build artifacts stored in your JFrog Artifactory instance.

12.3.3.2. Enable the JFrog Artifactory plugin

To enable the JFrog Artifactory plugin, set the disabled property to false.

Procedure

  • To enable the JFrog Artifactory plugin, set the disabled property to false in your dynamic-plugins.yaml file as follows:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-jfrog-artifactory:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

12.3.3.3. Configure the JFrog Artifactory plugin

Configure proxy settings and annotations to display container images stored in your JFrog Artifactory repository.

Procedure

  1. Set the proxy to the required JFrog Artifactory server in the app-config.yaml file as follows:

    proxy:
      endpoints:
        '/jfrog-artifactory/api':
          target: http://<hostname>:8082 # or https://<customer>.jfrog.io
          headers:
          # Authorization: 'Bearer <YOUR TOKEN>'
          # Change to "false" in case of using a self-hosted Artifactory instance with a self-signed certificate
          secure: true
  2. Add the following annotation to the entity’s catalog-info.yaml file to enable the JFrog Artifactory plugin features in RHDH components:

    metadata:
        annotations:
          'jfrog-artifactory/image-name': '<IMAGE-NAME>'

12.3.3.4. Use the JFrog Artifactory plugin

The JFrog Artifactory plugin displays information about your container images within the JFrog Artifactory registry.

Prerequisites

  • Your Developer Hub application is installed and running.
  • You have enabled the JFrog Artifactory plugin.

Procedure

  1. Open your Developer Hub application and select a component from the Catalog page.
  2. Go to the Image Registry tab.

    The Image Registry tab contains a list of container images within your JFrog Artifactory repository and related information, such as Version, Repositories, Manifest, Modified, and Size.

    Image Registry tab showing JFrog Artifactory container images

12.3.4. Manage identity data by integrating Keycloak

12.3.4.1. Manage identity data by integrating Keycloak

Configure schedule frequency, query parameters, and authentication methods for synchronizing Keycloak users and groups.

12.3.4.2. Enable the Keycloak plugin

Enable the Keycloak plugin to synchronize users and groups from your Red Hat Build of Keycloak realm into Red Hat Developer Hub.

Prerequisites

  • To enable the Keycloak plugin, you must set the following environment variables:

    • KEYCLOAK_BASE_URL
    • KEYCLOAK_LOGIN_REALM
    • KEYCLOAK_REALM
    • KEYCLOAK_CLIENT_ID
    • KEYCLOAK_CLIENT_SECRET

Procedure

  • The Keycloak plugin is pre-loaded in Developer Hub with basic configuration properties. To enable it, set the disabled property to false in your dynamic-plugins.yaml file as follows:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-catalog-backend-module-keycloak:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

12.3.4.3. Configure the Keycloak plugin

Configure schedule frequency, query parameters, and authentication methods for synchronizing Keycloak users and groups.

Procedure

  1. To configure the Keycloak plugin, add the following in your app-config.yaml file:

    schedule

    Configure the schedule frequency, timeout, and initial delay. The fields support cron, ISO duration, "human duration" as used in code.

         catalog:
           providers:
             keycloakOrg:
               default:
                 schedule:
                   frequency: { minutes: 1 }
                   timeout: { minutes: 1 }
                   initialDelay: { seconds: 15 }
    userQuerySize and groupQuerySize

    Optionally, configure the Keycloak query parameters to define the number of users and groups to query at a time. Default values are 100 for both fields.

       catalog:
         providers:
           keycloakOrg:
             default:
               userQuerySize: 100
               groupQuerySize: 100
    Authentication

    Communication between Developer Hub and Keycloak is enabled by using the Keycloak API. Username and password, or client credentials are supported authentication methods.

    The following table describes the parameters that you can configure to enable the plugin under catalog.providers.keycloakOrg.<ENVIRONMENT_NAME> object in the app-config.yaml file:

    NameDescriptionDefault ValueRequired

    baseUrl

    Location of the Keycloak server, such as https://localhost:8443/auth.

    ""

    Yes

    realm

    Realm to synchronize

    master

    No

    loginRealm

    Realm used to authenticate

    master

    No

    username

    Username to authenticate

    ""

    Yes if using password based authentication

    password

    Password to authenticate

    ""

    Yes if using password based authentication

    clientId

    Client ID to authenticate

    ""

    Yes if using client credentials based authentication

    clientSecret

    Client Secret to authenticate

    ""

    Yes if using client credentials based authentication

    userQuerySize

    Number of users to query at a time

    100

    No

    groupQuerySize

    Number of groups to query at a time

    100

    No

  2. When using client credentials

    1. Set the access type to confidential.
    2. Enable service accounts.
    3. Add the following roles from the realm-management client role:
  3. query-groups
  4. query-users
  5. view-users
  6. Optionally, if you have self-signed or corporate certificate issues, you can set the following environment variable before starting Developer Hub:

    NODE_TLS_REJECT_UNAUTHORIZED=0
    Warning

    Setting the environment variable is not recommended.

12.3.4.4. Keycloak plugin metrics

Monitor Keycloak fetch operations and diagnose issues by using OpenTelemetry metrics with Prometheus or Grafana.

The Keycloak backend plugin supports OpenTelemetry metrics that you can use to monitor fetch operations and diagnose potential issues.

12.3.4.4.1. Available Counters

Keycloak metrics:

Metric NameDescription

backend_keycloak_fetch_task_failure_count_total

Counts fetch task failures where no data was returned due to an error.

backend_keycloak_fetch_data_batch_failure_count_total

Counts partial data batch failures. Even if some batches fail, the plugin continues fetching others.

12.3.4.4.2. Labels

All counters include the taskInstanceId label, which uniquely identifies each scheduled fetch task. You can use this label to trace failures back to individual task executions.

Users can enter queries in the Prometheus UI or Grafana to explore and manipulate metric data.

In the following examples, a Prometheus Query Language (PromQL) expression returns the number of backend failures.

To get the number of backend failures associated with a taskInstanceId:

backend_keycloak_fetch_data_batch_failure_count_total{taskInstanceId="df040f82-2e80-44bd-83b0-06a984ca05ba"} 1

To get the number of backend failures during the last hour:

sum(backend_keycloak_fetch_data_batch_failure_count_total) - sum(backend_keycloak_fetch_data_batch_failure_count_total offset 1h)
Note

PromQL supports arithmetic operations, comparison operators, logical/set operations, aggregation, and various functions. Users can combine these features to analyze time-series data effectively.

Additionally, the results can be visualized using Grafana.

12.3.4.4.3. Export metrics

You can export metrics by using any OpenTelemetry-compatible backend, such as Prometheus.

12.3.4.5. Use Keycloak

The Keycloak backend plugin, which integrates Keycloak into Developer Hub, has the following capabilities:

  • Synchronization of Keycloak users in a realm.
  • Synchronization of Keycloak groups and their users in a realm.

After configuring the plugin successfully, the plugin imports the users and groups each time when started.

Note

If you set up a schedule, users and groups will also be imported.

Procedure

  1. In Red Hat Developer Hub, go to the Catalog page.
  2. Select User from the entity type filter to display the list of imported users.
  3. Browse the list of users displayed on the page.
  4. Select a user to view detailed information imported from Keycloak.
  5. To view groups, select Group from the entity type filter.
  6. Browse the list of groups shown on the page.
  7. From the list of groups, select a group to view the information imported from Keycloak.

12.3.5. View build artifacts using Nexus Repository Manager

12.3.5.1. View build artifacts using Nexus Repository Manager

Configure the Nexus Repository Manager plugin to display artifact information from your Nexus Repository Manager instance.

12.3.5.2. Enable the Nexus Repository Manager plugin

To enable the Nexus Repository Manager plugin, set the disabled property to false.

Procedure

  • To enable the Nexus Repository Manager plugin, set the disabled property to false in your dynamic-plugins.yaml file as follows:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-nexus-repository-manager:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

12.3.5.3. Configure the Nexus Repository Manager plugin

Configure the Nexus Repository Manager plugin to display artifact information from your Nexus Repository Manager instance.

Procedure

  1. Set the proxy to the required Nexus Repository Manager server in the app-config.yaml file as follows:

    proxy:
        '/nexus-repository-manager':
        target: 'https://<NEXUS_REPOSITORY_MANAGER_URL>'
        headers:
            X-Requested-With: 'XMLHttpRequest'
            # Uncomment the following line to access a private Nexus Repository Manager using a token
            # Authorization: 'Bearer <YOUR TOKEN>'
        changeOrigin: true
        # Change to "false" in case of using self hosted Nexus Repository Manager instance with a self-signed certificate
        secure: true
  2. Optional: Change the base URL of Nexus Repository Manager proxy as follows:

    nexusRepositoryManager:
        # default path is `/nexus-repository-manager`
        proxyPath: /custom-path
  3. Optional: Enable the following experimental annotations:

    nexusRepositoryManager:
        experimentalAnnotations: true
  4. Annotate your entity using the following annotations:

    metadata:
        annotations:
        # insert the chosen annotations here
        # example
        nexus-repository-manager/docker.image-name: `<ORGANIZATION>/<REPOSITORY>`,

12.3.5.4. Use the Nexus Repository Manager plugin

For components in the Red Hat Developer Hub catalog, you can view build artifacts from the Nexus Repository Manager.

Prerequisites

  • Your Developer Hub application is installed and running.
  • You have installed the Nexus Repository Manager plugin.

Procedure

  1. Open your Developer Hub application and select a component from the Catalog page.
  2. Go to the BUILD ARTIFACTS tab.

    The BUILD ARTIFACTS tab contains a list of build artifacts and related information, such as VERSION, REPOSITORY, REPOSITORY TYPE, MANIFEST, MODIFIED, and SIZE.

    Build Artifacts tab showing Nexus Repository Manager artifacts

12.3.6. Monitor continuous integration pipelines with Tekton

The Tekton plugin enables you to monitor CI/CD pipeline results across your Kubernetes or OpenShift clusters. It provides a high-level overview of all associated tasks, allowing you to track the real-time status of your application pipelines.

Prerequisites

  • You have installed and configured the @backstage/plugin-kubernetes and @backstage/plugin-kubernetes-backend dynamic plugins.
  • You have configured the Kubernetes plugin to connect to the cluster using a ServiceAccount.
  • The ClusterRole must be granted for custom resources (PipelineRuns and TaskRuns) to the ServiceAccount accessing the cluster.

    Note

    If you have the RHDH Kubernetes plugin configured, then the ClusterRole is already granted.

  • To view the pod logs, you have granted permissions for pods/log.
  • You can use the following code to grant the ClusterRole for custom resources and pod logs:

    kubernetes:
       ...
       customResources:
         - group: 'tekton.dev'
           apiVersion: 'v1'
           plural: 'pipelineruns'
         - group: 'tekton.dev'
           apiVersion: 'v1'
    
    
     ...
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: backstage-read-only
      rules:
        - apiGroups:
            - ""
          resources:
            - pods/log
          verbs:
            - get
            - list
            - watch
        ...
        - apiGroups:
            - tekton.dev
          resources:
            - pipelineruns
            - taskruns
          verbs:
            - get
            - list

    You can use the prepared manifest for a read-only ClusterRole, which provides access for both Kubernetes plugin and Tekton plugin.

  • Add the following annotation to the entity’s catalog-info.yaml file to identify whether an entity contains the Kubernetes resources:

    annotations:
      ...
    
      backstage.io/kubernetes-id: <BACKSTAGE_ENTITY_NAME>
  • You can also add the backstage.io/kubernetes-namespace annotation to identify the Kubernetes resources using the defined namespace.

    annotations:
      ...
    
      backstage.io/kubernetes-namespace: <RESOURCE_NS>
  • Add the following annotation to the catalog-info.yaml file of the entity to enable the Tekton related features in RHDH. The value of the annotation identifies the name of the RHDH entity:

    annotations:
      ...
    
      janus-idp.io/tekton : <BACKSTAGE_ENTITY_NAME>
  • Add a custom label selector, which RHDH uses to find the Kubernetes resources. The label selector takes precedence over the ID annotations.

    annotations:
      ...
    
      backstage.io/kubernetes-label-selector: 'app=my-app,component=front-end'
  • Add the following label to the resources so that the Kubernetes plugin gets the Kubernetes resources from the requested entity:

    labels:
      ...
    
      backstage.io/kubernetes-id: <BACKSTAGE_ENTITY_NAME>
    Note

    When you use the label selector, the mentioned labels must be present on the resource.

Procedure

  • To enable the Tekton plugin, set the disabled property to false in your dynamic-plugins.yaml file as follows:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-tekton:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

12.3.7. Use the Tekton plugin

You can use the Tekton plugin to visualize the results of CI/CD pipeline runs on your Kubernetes or OpenShift clusters. The plugin allows users to visually see high level status of all associated tasks in the pipeline for their applications.

You can use the Tekton front-end plugin to view PipelineRun resources.

Prerequisites

Procedure

  1. Open your RHDH application and select a component from the Catalog page.
  2. Go to the CI tab.

    The CI tab displays the list of PipelineRun resources associated with a Kubernetes cluster. The list contains pipeline run details, such as NAME, VULNERABILITIES, STATUS, TASK STATUS, STARTED, and DURATION.

    CI tab showing Tekton PipelineRun resources
  3. Click the expand row button besides PipelineRun name in the list to view the PipelineRun visualization. The pipeline run resource includes tasks to complete. When you hover the mouse pointer on a task card, you can view the steps to complete that particular task.

    Expanded PipelineRun visualization showing task steps

12.3.8. Visualize Kubernetes workloads and pod health with Topology

12.3.8.1. Visualize Kubernetes workloads and pod health with Topology

Visualize Kubernetes workloads like Deployments, Pods, and Virtual Machines by enabling the Topology plugin.

12.3.8.2. Install the Topology plugin

Visualize Kubernetes workloads like Deployments, Pods, and Virtual Machines by enabling the Topology plugin.

The Topology plugin enables you to visualize the workloads such as Deployment, Job, Daemonset, Statefulset, CronJob, Pods and Virtual Machines powering any service on your Kubernetes cluster.

Prerequisites

  • You have installed and configured the @backstage/plugin-kubernetes-backend dynamic plugins.
  • You have configured the Kubernetes plugin to connect to the cluster using a ServiceAccount.
  • The ClusterRole must be granted to ServiceAccount accessing the cluster.

    Note

    If you have the Developer Hub Kubernetes plugin configured, then the ClusterRole is already granted.

Procedure

  • The Topology plugin is pre-loaded in Developer Hub with basic configuration properties. To enable it, set the disabled property to false as follows:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-topology:__<tag>__
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

12.3.8.3. Configure the plugin

Grant read access to routes resource in ClusterRole to view OpenShift routes in the Topology plugin.

Procedure

  1. To view OpenShift routes, grant read access to the routes resource in the ClusterRole:

      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: backstage-read-only
      rules:
        ...
        - apiGroups:
            - route.openshift.io
          resources:
            - routes
          verbs:
            - get
            - list
  2. Also add the following in kubernetes.customResources property in your app-config.yaml file:

    kubernetes:
        ...
        customResources:
          - group: 'route.openshift.io'
            apiVersion: 'v1'
            	  plural: 'routes'
12.3.8.3.1. View pod logs

Grant ClusterRole permissions to pods and pods/log resources to view pod logs in the Topology plugin.

Procedure

  • To view pod logs, you must grant the following permission to the ClusterRole:

     apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: backstage-read-only
      rules:
        ...
        - apiGroups:
            - ''
          resources:
            - pods
            - pods/log
          verbs:
            - get
            - list
            - watch
12.3.8.3.2. View Tekton PipelineRuns

Grant ClusterRole access to Tekton resources to view PipelineRuns status in the Topology plugin.

Procedure

  1. To view the Tekton PipelineRuns, grant read access to the pipelines, pipelineruns, and taskruns resources in the ClusterRole:

     ...
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: backstage-read-only
      rules:
        ...
        - apiGroups:
            - tekton.dev
          resources:
            - pipelines
            - pipelineruns
            - taskruns
          verbs:
            - get
            - list
  2. To view the Tekton PipelineRuns list in the side panel and the latest PipelineRuns status in the Topology node decorator, add the following code to the kubernetes.customResources property in your app-config.yaml file:

    kubernetes:
        ...
        customResources:
          - group: 'tekton.dev'
            apiVersion: 'v1'
            plural: 'pipelines'
          - group: 'tekton.dev'
            apiVersion: 'v1'
            plural: 'pipelineruns'
          - group: 'tekton.dev'
            apiVersion: 'v1'
            plural: 'taskruns'
12.3.8.3.3. View virtual machines

Grant ClusterRole access to VirtualMachines resources to view virtual machine nodes in the Topology plugin.

Prerequisites

  • The OpenShift Virtualization operator is installed and configured on a Kubernetes cluster.

Procedure

  1. Grant read access to the VirtualMachines resource in the ClusterRole:

     ...
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: backstage-read-only
      rules:
        ...
        - apiGroups:
            - kubevirt.io
          resources:
            - virtualmachines
            - virtualmachineinstances
          verbs:
            - get
            - list
  2. To view the virtual machine nodes on the topology plugin, add the following code to the kubernetes.customResources property in the app-config.yaml file:

    kubernetes:
        ...
        customResources:
          - group: 'kubevirt.io'
            apiVersion: 'v1'
            plural: 'virtualmachines'
          - group: 'kubevirt.io'
            apiVersion: 'v1'
            plural: 'virtualmachineinstances'
12.3.8.3.4. Enable the source code editor

Enable the source code editor to allow developers to open source code directly from RHDH.

Procedure

  1. Grant read access to the CheClusters resource in the ClusterRole:

     ...
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: backstage-read-only
      rules:
        ...
        - apiGroups:
            - org.eclipse.che
          resources:
            - checlusters
          verbs:
            - get
            - list
  2. Add the following configuration to the kubernetes.customResources property in your app-config.yaml file:

     kubernetes:
        ...
        customResources:
          - group: 'org.eclipse.che'
            apiVersion: 'v2'
            plural: 'checlusters'

12.3.8.5. Use the Topology plugin

You can use the Topology plugin to view the workloads such as deployments or pods as nodes on the Kubernetes cluster.

Prerequisites

Procedure

  1. Open your RHDH application and select a component from the Catalog page.
  2. Go to the TOPOLOGY tab and you can view the workloads such as deployments or pods as nodes.

    Topology tab showing workload nodes
  3. Select a node and a pop-up appears on the right side that contains two tabs: Details and Resources.

    The Details and Resources tabs contain the associated information and resources for the node.

    Node details and resources tabs
  4. Click the Open URL button on the top of a node.

    Open URL button on a topology node

    Click the Open URL button to access the associated Ingresses and run your application in a new tab.

12.3.8.6. Enable users to use the Topology plugin

The Topology plugin is defining additional permissions. When Authorization in Red Hat Developer Hub is enabled, to enable users to use the Topology plugin, grant them:

  • The kubernetes.clusters.read and kubernetes.resources.read, read permissions to view the Topology panel.
  • The kubernetes.proxy use permission to view the pod logs.
  • The catalog-entity read permission to view the Red Hat Developer Hub software catalog items.

Procedure

  • Add the following permission policies to your rbac-policy.csv file to create a topology-viewer role that has access to the Topology plugin features, and add the role to the users requiring this authorization:

    g, user:default/<YOUR_USERNAME>, role:default/topology-viewer
    p, role:default/topology-viewer, kubernetes.clusters.read, read, allow
    p, role:default/topology-viewer, kubernetes.resources.read, read, allow
    p, role:default/topology-viewer, kubernetes.proxy, use, allow
    p, role:default/topology-viewer, catalog-entity, read, allow
    kubernetes.clusters.read and kubernetes.resources.read, read, allow
    Grants the user the ability to see the Topology panel.
    kubernetes.proxy, use, allow
    Grants the user the ability to view the pod logs.
    catalog-entity, read, allow
    Grants the user the ability to see the catalog item.

12.3.9. Configure the GitHub Events Module plugin

Configure GitHub webhooks to trigger real-time updates for GitHub Discovery and organizational data.

Learn how to configure Events Module for use with the RHDH GitHub Discovery feature and GitHub organization data.

Prerequisites

  • You have added your GitHub integration credentials in the app-config.yaml file.
  • You have defined the schedule.frequency in the app-config.yaml file as longer time period, such as 24 hours.
  • For GitHub Discovery only: You have enabled GitHub Discovery.
  • For GitHub Organizational Data only: You have enabled Github Authentication with user ingestion.

Procedure

  1. Add the GitHub Events Module to your dynamic-plugins.yaml configuration file as follows:

    data:
    dynamic-plugins.yaml: |
    includes:
    - dynamic-plugins.default.yaml
    plugins:
    - package: oci://registry.access.redhat.com/rhdh/backstage-plugin-events-backend-module-github:<tag>
    disabled: false

    where:

    <tag>
    Enter your RHDH version and the plugin version, in the format <rhdh-version>--<plugin-version>. To find these versions, complete the following steps:
  2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.10, use the format 1.10--<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  3. To create HTTP endpoints to receive events for the github, add the following to your app-config.yaml file:

    events:
      http:
       topics:
        - github
      modules:
        github:
          webhookSecret: ${GITHUB_WEBHOOK_SECRET}
    Important

    Secure your workflow by adding a webhook secret token to validate webhook deliveries.

  4. Create a GitHub webhook with the following specifications:

    • For GitHub Discovery Events: push, repository
    • For GitHub Organizational Data Events: organization, team and membership
    • Content Type: application/json
    • Payload URL: https://<my_developer_hub_domain>/api/events/http/github

      Note

      Payload URL is the URL exposed after configuring the HTTP endpoint.

Verification

  • Check the log for an entry that confirms that http endpoint was set up successfully to receive events from the GitHub webhook.

    Example of a log of successfully set up http endpoint
    {"level":"\u001b[32minfo\u001b[39m","message":"Registered /api/events/http/github to receive events","plugin":"events","service":"backstage","timestamp":"2025-11-03 02:19:12"}
  • For GitHub Discovery only:

    • Trigger a GitHub push event by adding, modifying or deleting the catalog-info.yaml file in the repository where you set up your webhook. A record of this event should appear in the pod logs of your RHDH instance.

      Example of a log with changes to catalog-info.yaml file
      {"level":"\u001b[32minfo\u001b[39m","message":"Processed Github push event: added 0 - removed 0 - modified 1","plugin":"catalog","service":"backstage","span_id":"47534b96c4afc654","target":"github-provider:providerId","timestamp":"2025-06-15 21:33:14","trace_flags":"01","trace_id":"ecc782deb86aed2027da0ae6b1999e5c"}
  • For GitHub Organizational Data only:

    • Newly added users and teams appear in the RHDH catalog.

12.4. Extend software templates with Kubernetes custom actions

12.4.1. Kubernetes custom actions in Red Hat Developer Hub

You can create and manage Kubernetes resources by using custom scaffolder actions in Red Hat Developer Hub templates. The Kubernetes custom actions plugin is preinstalled in a disabled state.

12.4.2. Enable Kubernetes custom actions plugin in Red Hat Developer Hub

Enable the preinstalled Kubernetes custom actions plugin by updating the dynamic plugins configuration.

In Red Hat Developer Hub, the Kubernetes custom actions are provided as a preinstalled plugin, which is disabled by default. You can enable the Kubernetes custom actions plugin by updating the disabled key value in your dynamic-plugins.yaml file.

Procedure

  • Add a package with the Kubernetes custom action plugin name and update the disabled field in your dynamic-plugins.yaml file to enable the plugin. For example:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-kubernetes:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    Note

    The default configuration for a plugin is extracted from the dynamic-plugins.default.yaml file, however, you can use a pluginConfig entry to override the default configuration.

12.4.3. Use Kubernetes custom actions plugin in Red Hat Developer Hub

Add Kubernetes actions to your custom templates to create namespaces and manage cluster resources.

In Red Hat Developer Hub, the Kubernetes custom actions enable you to run template actions for Kubernetes.

Procedure

  • To use a Kubernetes custom action in your custom template, add the following Kubernetes actions to your template:

    action: kubernetes:create-namespace
    id: create-kubernetes-namespace
    name: Create kubernetes namespace
    input:
      namespace: my-rhdh-project
      clusterRef: bar
      token: TOKEN
      skipTLSVerify: false
      caData: Zm9v
      labels: app.io/type=ns; app.io/managed-by=org;

Additional resources

12.4.4. Create a template using Kubernetes custom actions in Red Hat Developer Hub

Define a Template object with Kubernetes actions to automate namespace creation and resource management.

Procedure

  • To create a template, define a Template object as a YAML file.

    The Template object describes the template and its metadata. It also contains required input variables and a list of actions that are executed by the scaffolding service.

    apiVersion: scaffolder.backstage.io/v1beta3
    kind: Template
    metadata:
      name: create-kubernetes-namespace
      title: Create a kubernetes namespace
      description: Create a kubernetes namespace
    spec:
      type: service
      parameters:
        - title: Information
          required: [namespace, token]
          properties:
            namespace:
              title: Namespace name
              type: string
              description: Name of the namespace to be created
            clusterRef:
              title: Cluster reference
              type: string
              description: Cluster resource entity reference from the catalog
              ui:field: EntityPicker
              ui:options:
                catalogFilter:
                  kind: Resource
            url:
              title: Url
              type: string
              description: Url of the kubernetes API, will be used if clusterRef is not provided
            token:
              title: Token
              type: string
              ui:field: Secret
              description: Bearer token to authenticate with
            skipTLSVerify:
              title: Skip TLS verification
              type: boolean
              description: Skip TLS certificate verification, not recommended to use in production environment, default to false
            caData:
              title: CA data
              type: string
              ui:field: Secret
              description: Certificate Authority base64 encoded certificate
            labels:
              title: Labels
              type: string
              description: Labels to be applied to the namespace
              ui:widget: textarea
              ui:options:
                rows: 3
              ui:help: 'Hint: Separate multiple labels with a semicolon!'
              ui:placeholder: 'kubernetes.io/type=namespace; app.io/managed-by=org'
      steps:
        - id: create-kubernetes-namespace
          name: Create kubernetes namespace
          action: kubernetes:create-namespace
          input:
            namespace: ${ parameters.namespace }
            clusterRef: ${ parameters.clusterRef }
            url: ${ parameters.url }
            token: ${ secrets.token }
            skipTLSVerify: ${ parameters.skipTLSVerify }
            caData: ${ secrets.caData }
            labels: ${ parameters.labels }

12.4.5. Supported Kubernetes custom actions in Red Hat Developer Hub

Access parameter specifications and requirements for the kubernetes:create-namespace scaffolder action.

In Red Hat Developer Hub, you can use custom Kubernetes actions in Scaffolder templates.

Action: kubernetes:create-namespace
Creates a namespace for the Kubernetes cluster in the Developer Hub.
Parameter nameTypeRequirementDescriptionExample

namespace

string

Required

Name of the Kubernetes namespace

my-rhdh-project

clusterRef

string

Required only if url is not defined. You cannot specify both url and clusterRef.

Cluster resource entity reference from the catalog

bar

url

string

Required only if clusterRef is not defined. You cannot specify both url and clusterRef.

API url of the Kubernetes cluster

https://api.example.com:6443

token

String

Required

Kubernetes API bearer token used for authentication

 

skipTLSVerify

boolean

Optional

If true, certificate verification is skipped

false

caData

string

Optional

Base64 encoded certificate data

 

label

string

Optional

Labels applied to the namespace

app.io/type=ns; app.io/managed-by=org;

12.5. Integrate ServiceNow for incident management and scaffolder actions

12.5.1. ServiceNow custom actions in Red Hat Developer Hub

Integrate ServiceNow with Red Hat Developer Hub to manage ServiceNow records by using Scaffolder actions and view ServiceNow data on entity pages.

In Red Hat Developer Hub, you can use ServiceNow custom actions to fetch and register resources within the catalog.

The custom actions in Developer Hub help you automate the management of records. By using the custom actions, you can:

  • Create, update, or delete a record
  • Retrieve information about a single record or many records

The ServiceNow custom actions plugin is community-sourced.

12.5.2. ServiceNow entity linking methods

To view and manage ServiceNow incidents directly in Red Hat Developer Hub (RHDH), you must link an entity to your ServiceNow records. Linking ensures that incident data is accurately synchronized and visible within the relevant component or system.

Red Hat Developer Hub provides two methods for linking these entities. You can choose the method that best fits your organization’s security requirements and your ability to modify the ServiceNow schema.

12.5.2.1. Direct mapping (Backstage Entity ID column)

The default method requires adding a custom column named backstage_entity_id to your ServiceNow incident table. You then manually or programmatically assign the specific RHDH entity reference (for example, component:default/my-service) to this column in ServiceNow.

  • Advantages:

    • Highly secure and precise
    • Ensures data is only exposed to the intended entity
  • Limitations:

    • Requires a schema change in ServiceNow
    • Requires manual data entry for each incident

12.5.2.2. Flexible mapping (Custom column mapping)

The flexible mapping approach is an opt-in feature that allows you to use any existing column in your ServiceNow incident table to link to RHDH entities. Instead of creating a new column, you configure the ServiceNow plugin to look at an existing field (such as short_description, cmdb_ci, or a custom organizational ID) to match the entity.

  • Advantages:

    • Does not require ServiceNow schema changes
    • Faster to implement for organizations with strict ServiceNow governance
  • Limitations:

    • Requires careful configuration to ensure that the search criteria in the chosen column are unique enough to prevent displaying unrelated incidents

12.5.2.3. Comparison of linking methods

FeatureDirect mappingFlexible mapping

ServiceNow schema change

Required

Not required

Security level

High (strict matching)

Medium (dependent on column data)

Configuration complexity

Low (plugin side)

Medium (requires YAML mapping)

Ideal use case

New ServiceNow instances or high-security environments

Existing ServiceNow instances where schema changes are restricted

12.5.3. Enable ServiceNow custom actions plugin in Red Hat Developer Hub

To use ServiceNow custom actions, you must first activate the plugin.

Prerequisites

  • Red Hat Developer Hub is installed and running.
  • You have created a project in the Developer Hub.

Procedure

  1. Add a package with plugin name and update the disabled field in your dynamic-plugins.yaml file as follows:

    plugins:
      - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-servicenow:<tag>
        disabled: false

    where:

    <tag>

    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

    1. Find your Backstage version in the RHDH release notes preface.
    2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

      Tip

      To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    Note

    The default configuration for a plugin is extracted from the dynamic-plugins.default.yaml file, however, you can use a pluginConfig entry to override the default configuration.

  2. Set the following variables in your app-config.yaml file to access the custom actions:

    servicenow:
      # The base url of the ServiceNow instance.
      baseUrl: ${SERVICENOW_BASE_URL}
      # The username to use for authentication.
      username: ${SERVICENOW_USERNAME}
      # The password to use for authentication.
      password: ${SERVICENOW_PASSWORD}

12.5.4. Configure the ServiceNow plugin in the ConfigMap

Update the Red Hat Developer Hub ConfigMap to enable the ServiceNow backend, frontend, and Scaffolder actions. This configuration defines the connection parameters and UI components required to integrate ServiceNow with your software catalog.

Prerequisites

  • You have provisioned a custom configuration by following the steps in Provisioning and using your custom Developer Hub configuration, including the section on authoring a custom dynamic-plugins.yaml file.
  • You have administrator access to an Red Hat OpenShift Container Platform cluster.
  • Red Hat Developer Hub is installed on the cluster.

Procedure

  1. Open your Red Hat Developer Hub ConfigMap for editing.
  2. Add the ServiceNow backend and frontend plugin packages to the dynamic-plugins.yaml section, including the connection and UI configuration:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: rhdh-plugin-config
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          # -----------------------------------------------------------------
          # ... Your pre-existing custom dynamic plugins would be listed here
          # -----------------------------------------------------------------
    
          # ServiceNow Backend Plugin
          - package: 'oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-servicenow-backend:<tag>'
            disabled: false
            pluginConfig:
              servicenow:
                instanceUrl: ${SERVICENOW_BASE_URL}
                basicAuth:
                  username: ${SERVICENOW_USERNAME}
                  password: ${SERVICENOW_PASSWORD}
    
          # ServiceNow Scaffolder Module / Actions
          - package: 'oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-servicenow:<tag>'
            disabled: false
            pluginConfig:
              servicenow:
                baseUrl: ${SERVICENOW_BASE_URL}
                username: ${SERVICENOW_USERNAME}
                password: ${SERVICENOW_PASSWORD}
    
          # ServiceNow Frontend Plugin
          - package: 'oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-servicenow:<tag>'
            disabled: false

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  3. Find your Backstage version in the RHDH release notes preface.
  4. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  5. Save the changes to the ConfigMap.
  6. Wait for the RHDH Operator to redeploy the pods. The plugins are available once the pods are in a Running state.

12.5.6. Use ServiceNow scaffolder actions in software templates

Add ServiceNow actions to your software templates to automate the creation, retrieval, and modification of ServiceNow records during the software scaffolding process.

Prerequisites

  • You have configured the ServiceNow instance parameters in the Red Hat Developer HubConfigMap or app-config.yaml file.
  • You have the required permissions to edit Software Templates in the source repository.
  • You have registered the Software Template in the Red Hat Developer Hub catalog.

Procedure

  1. Open your software template YAML file.
  2. In the spec.steps section, add the ServiceNow action that corresponds to your goal.
  3. Define the tableName and the requestBody containing the fields to populate or modify. The following example demonstrates how to use the servicenow:now:table:createRecord action to generate an incident ticket:

    steps:
      - id: create-incident
        name: Create ServiceNow Incident
        action: servicenow:now:table:createRecord
        input:
          tableName: incident
          requestBody:
            short_description: "Printer is offline"
            description: "The office printer is not accessible via the network"
            severity: "3"
  4. Optional: To perform other operations, use the appropriate action ID and parameters:

    GoalAction IDKey Input Parameters

    Delete a record

    servicenow:now:table:deleteRecord

    tableName, sysId

    Modify a record

    servicenow:now:table:modifyRecord

    tableName, sysId, requestBody

    Retrieve a record

    servicenow:now:table:retrieveRecord

    tableName, sysId

    Update a record

    servicenow:now:table:updateRecord

    tableName, sysId, requestBody

    Tip

    To view the full schema and all available ServiceNow actions for your specific installation, navigate to Create > Installed Actions in the Red Hat Developer Hub interface.

12.5.7. ServiceNow configuration parameters

The ServiceNow integration requires specific parameters in your configuration files to establish a connection between Red Hat Developer Hub and your ServiceNow instances. Use these parameters to define authentication methods, instance URLs, and UI layouts.

12.5.7.1. ServiceNow backend and frontend configuration

Define the following parameters in the app-config.yaml file or the dynamic-plugins.yaml section of the Red Hat Developer Hub ConfigMap to enable the backend and frontend plugins.

ParameterDescriptionRequirement

instanceUrl

The base URL of your ServiceNow instance. For example, https://dev12345.service-now.com.

Required

basicAuth.username

The service account username for Basic authentication.

Optional

basicAuth.password

The service account password for Basic authentication.

Optional

oauth.grantType

The OAuth 2.0 grant type. Supports client_credentials or password.

Optional

oauth.clientId

The client ID for OAuth authentication.

Optional

oauth.clientSecret

The client secret for OAuth authentication.

Optional

12.5.7.2. ServiceNow scaffolder configuration

The ServiceNow Scaffolder module requires a separate configuration block. Note that this module uses baseUrl instead of instanceUrl.

ParameterDescriptionRequirement

baseUrl

The base URL of your ServiceNow instance.

Required

username

The service account username.

Required for Basic authentication

password

The service account password.

Required for Basic authentication

12.5.7.3. Authentication examples

The following examples demonstrate how to structure different authentication methods in your configuration.

12.5.7.4. Basic authentication example

servicenow:
  baseUrl: ${SERVICENOW_PROD_URL}
  username: ${SERVICENOW_USER}
  password: ${SERVICENOW_PASS}

12.5.7.5. OAuth with Client Credentials

servicenow:
  instanceUrl: ${SERVICENOW_INSTANCE_URL}
  oauth:
    grantType: client_credentials
    clientId: ${SERVICENOW_CLIENT_ID}
    clientSecret: ${SERVICENOW_CLIENT_SECRET}

12.5.7.6. OAuth with Password Grant

servicenow:
  instanceUrl: ${SERVICENOW_INSTANCE_URL}
  oauth:
    grantType: password
    clientId: ${SERVICENOW_CLIENT_ID}
    clientSecret: ${SERVICENOW_CLIENT_SECRET}
    username: ${SERVICENOW_USER}
    password: ${SERVICENOW_PASS}

12.5.7.7. Frontend UI configuration

The frontend plugin configuration defines how ServiceNow data appears on component entity pages.

dynamicPlugins:
  frontend:
    backstage-community.plugin-servicenow:
      entityTabs:
        - path: /servicenow
          title: ServiceNow
          mountPoint: entity.page.servicenow
      mountPoints:
        - mountPoint: entity.page.servicenow/cards
          importName: ServicenowPage
          config:
            layout:
              gridColumn: 1 / -1
              height: 75vh

12.5.8. Supported ServiceNow custom actions in Red Hat Developer Hub

The ServiceNow custom actions enable you to manage records in the Red Hat Developer Hub.

The custom actions support the following HTTP methods for API requests:

  • GET: Retrieves specified information from a specified resource endpoint
  • POST: Creates or updates a resource
  • PUT: Modify a resource
  • PATCH: Updates a resource
  • DELETE: Deletes a resource

    [GET] servicenow:now:table:retrieveRecord

    Retrieves information of a specified record from a table in the Developer Hub.

    The following table describes the input parameters:

    NameTypeRequirementDescription

    tableName

    string

    Required

    Name of the table to retrieve the record from

    sysId

    string

    Required

    Unique identifier of the record to retrieve

    sysparmDisplayValue

    enum("true", "false", "all")

    Optional

    Returns field display values such as true, actual values as false, or both. The default value is false.

    sysparmExcludeReferenceLink

    boolean

    Optional

    Set as true to exclude Table API links for reference fields. The default value is false.

    sysparmFields

    string[]

    Optional

    Array of fields to return in the response

    sysparmView

    string

    Optional

    Renders the response according to the specified UI view. You can override this parameter using sysparm_fields.

    sysparmQueryNoDomain

    boolean

    Optional

    Set as true to access data across domains if authorized. The default value is false.

    The following table describes the output parameters:

    NameTypeDescription

    result

    Record<PropertyKey, unknown>

    The response body of the request

    [GET] servicenow:now:table:retrieveRecords

    Retrieves information about multiple records from a table in the Developer Hub.

    The following table describes the input parameters:

    NameTypeRequirementDescription

    tableName

    string

    Required

    Name of the table to retrieve the records from

    sysparamQuery

    string

    Optional

    Encoded query string used to filter the results

    sysparmDisplayValue

    enum("true", "false", "all")

    Optional

    Returns field display values such as true, actual values as false, or both. The default value is false.

    sysparmExcludeReferenceLink

    boolean

    Optional

    Set as true to exclude Table API links for reference fields. The default value is false.

    sysparmSuppressPaginationHeader

    boolean

    Optional

    Set as true to suppress pagination header. The default value is false.

    sysparmFields

    string[]

    Optional

    Array of fields to return in the response

    sysparmLimit

    int

    Optional

    Maximum number of results returned per page. The default value is 10,000.

    sysparmView

    string

    Optional

    Renders the response according to the specified UI view. You can override this parameter using sysparm_fields.

    sysparmQueryCategory

    string

    Optional

    Name of the query category to use for queries

    sysparmQueryNoDomain

    boolean

    Optional

    Set as true to access data across domains if authorized. The default value is false.

    sysparmNoCount

    boolean

    Optional

    Does not run a select count(*) on the table. The default value is false.

    The following table describes the output parameters:

    NameTypeDescription

    result

    Record<PropertyKey, unknown>

    The response body of the request

    [POST] servicenow:now:table:createRecord

    Creates a record in a table in the Developer Hub.

    The following table describes the input parameters:

    NameTypeRequirementDescription

    tableName

    string

    Required

    Name of the table to save the record in

    requestBody

    Record<PropertyKey, unknown>

    Optional

    Field name and associated value for each parameter to define in the specified record

    sysparmDisplayValue

    enum("true", "false", "all")

    Optional

    Returns field display values such as true, actual values as false, or both. The default value is false.

    sysparmExcludeReferenceLink

    boolean

    Optional

    Set as true to exclude Table API links for reference fields. The default value is false.

    sysparmFields

    string[]

    Optional

    Array of fields to return in the response

    sysparmInputDisplayValue

    boolean

    Optional

    Set field values using their display value such as true or actual value as false. The default value is false.

    sysparmSuppressAutoSysField

    boolean

    Optional

    Set as true to suppress auto-generation of system fields. The default value is false.

    sysparmView

    string

    Optional

    Renders the response according to the specified UI view. You can override this parameter using sysparm_fields.

    The following table describes the output parameters:

    NameTypeDescription

    result

    Record<PropertyKey, unknown>

    The response body of the request

    [PUT] servicenow:now:table:modifyRecord

    Modifies a record in a table in the Developer Hub.

    The following table describes the input parameters:

    NameTypeRequirementDescription

    tableName

    string

    Required

    Name of the table to change the record from

    sysId

    string

    Required

    Unique identifier of the record to change

    requestBody

    Record<PropertyKey, unknown>

    Optional

    Field name and associated value for each parameter to define in the specified record

    sysparmDisplayValue

    enum("true", "false", "all")

    Optional

    Returns field display values such as true, actual values as false, or both. The default value is false.

    sysparmExcludeReferenceLink

    boolean

    Optional

    Set as true to exclude Table API links for reference fields. The default value is false.

    sysparmFields

    string[]

    Optional

    Array of fields to return in the response

    sysparmInputDisplayValue

    boolean

    Optional

    Set field values using their display value such as true or actual value as false. The default value is false.

    sysparmSuppressAutoSysField

    boolean

    Optional

    Set as true to suppress auto-generation of system fields. The default value is false.

    sysparmView

    string

    Optional

    Renders the response according to the specified UI view. You can override this parameter using sysparm_fields.

    sysparmQueryNoDomain

    boolean

    Optional

    Set as true to access data across domains if authorized. The default value is false.

    The following table describes the output parameters:

    NameTypeDescription

    result

    Record<PropertyKey, unknown>

    The response body of the request

    [PATCH] servicenow:now:table:updateRecord

    Updates a record in a table in the Developer Hub.

    The following table describes the input parameters:

    NameTypeRequirementDescription

    tableName

    string

    Required

    Name of the table to update the record in

    sysId

    string

    Required

    Unique identifier of the record to update

    requestBody

    Record<PropertyKey, unknown>

    Optional

    Field name and associated value for each parameter to define in the specified record

    sysparmDisplayValue

    enum("true", "false", "all")

    Optional

    Returns field display values such as true, actual values as false, or both. The default value is false.

    sysparmExcludeReferenceLink

    boolean

    Optional

    Set as true to exclude Table API links for reference fields. The default value is false.

    sysparmFields

    string[]

    Optional

    Array of fields to return in the response

    sysparmInputDisplayValue

    boolean

    Optional

    Set field values using their display value such as true or actual value as false. The default value is false.

    sysparmSuppressAutoSysField

    boolean

    Optional

    Set as true to suppress auto-generation of system fields. The default value is false.

    sysparmView

    string

    Optional

    Renders the response according to the specified UI view. You can override this parameter using sysparm_fields.

    sysparmQueryNoDomain

    boolean

    Optional

    Set as true to access data across domains if authorized. The default value is false.

    The following table describes the output parameters:

    NameTypeDescription

    result

    Record<PropertyKey, unknown>

    The response body of the request

    [DELETE] servicenow:now:table:deleteRecord

    Deletes a record from a table in the Developer Hub.

    The following table describes the input parameters:

    NameTypeRequirementDescription

    tableName

    string

    Required

    Name of the table to delete the record from

    sysId

    string

    Required

    Unique identifier of the record to delete

    sysparmQueryNoDomain

    boolean

    Optional

    Set as true to access data across domains if authorized. The default value is false.

12.6. Enable Ansible plugins for automation workflows

12.6.1. Enable Ansible plugins for automation workflows

Use the Ansible plugins for Red Hat Developer Hub to integrate Ansible Automation Platform capabilities into your developer portal.

12.6.2. Installing Ansible plugins for Red Hat Developer Hub

Access Ansible-specific portal experience with curated learning paths, push-button content creation, and integrated development tools.

Ansible plugins for Red Hat Developer Hub deliver an Ansible-specific portal experience with curated learning paths, push-button content creation, integrated development tools, and other opinionated resources.

12.6.3. Using Ansible plug-ins for Red Hat Developer Hub

Ansible plug-ins for Red Hat Developer Hub deliver an Ansible-specific portal experience with curated learning paths, push-button content creation, integrated development tools, and other opinionated resources.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

Chapter 13. Optimize

13.1. Optimize

Scale your Red Hat Developer Hub deployment for production workloads by configuring high availability, implementing database and cache redundancy, and optimizing plugin startup performance. Optimization tasks ensure your platform maintains reliable service as traffic and usage grow.

13.2. Scale system performance for growing traffic

13.2.1. Scale system performance for growing traffic

Prepare your Red Hat Developer Hub deployment to handle increasing user demand by planning high availability architecture, configuring redundant backend replicas, and caching dynamic plugins to reduce startup time.

13.2.2. Plan production scaling using high availability architecture

Achieving high availability in Red Hat Developer Hub requires implementing redundancy and failover for both the backend service and its data dependencies. This is accomplished through horizontal scaling, database replication, and shared caching to ensure continuous operation during component failures.

13.2.2.1. Deploy multiple stateless instances

Achieving high availability in Red Hat Developer Hub requires implementing redundancy and failover for both the backend service and its data dependencies. This is accomplished through horizontal scaling, database replication, and shared caching to ensure continuous operation during component failures.

13.2.2.1.1. Deploy multiple stateless instances

RHDH backend uses a stateless design to support horizontal scaling. PostgreSQL stores persistent data and the database manages sessions, allowing multiple backend instances to serve any request simultaneously. To improve performance, you can configure an optional logical cache by using Redis.

To maintain backend availability, observe the following architectural requirements:

Deploy multiple backend instances
Run at least two backend instances for basic HA.
Configure a load balancer
Use platform-provided load balancing, such as OpenShift Routes, Kubernetes Ingress, or cloud provider load balancers.
Enable health checks
Configure the load balancer to probe backend health and remove failed instances from rotation.
Disable session affinity (sticky sessions)
Database-backed sessions allow any instance to serve any request.
13.2.2.1.2. Implement database HA

RHDH operations rely on PostgreSQL for persistence. A database outage renders the deployment non-functional until the database is restored. For production deployments, you must configure PostgreSQL with high availability (primary-replica replication) to minimize downtime.

Important

If you use catalog providers exclusively, the database acts as an indexed cache. You do not require disaster recovery backups because you can repopulate catalog data from external sources of truth, such as Git repositories, CI/CD platforms, and monitoring tools.

13.2.2.1.3. Implement cache HA

Configuring Redis as a shared logical cache improves production performance by sharing cached data across multiple backend instances. A shared cache makes sure that all instances access the same processed data, such as rendered TechDocs.

If the logical cache fails, the platform remains functional, but you might experience the following symptoms:

  • Slower response times due to cache misses.
  • Increased database load because the backend must fetch data from PostgreSQL.
  • No impact on authentication or core functionality.

For maximum performance stability in production, configure Redis with high availability using Redis Sentinel for small deployments or Redis Cluster for larger deployments.

13.2.3. Configure high availability to maintain performance

Configure high availability to ensure continuous service accessibility by eliminating single points of failure through redundancy and failover mechanisms.

Red Hat Developer Hub supports HA deployments on the following platforms:

  • Red Hat OpenShift Container Platform
  • Azure Kubernetes Service
  • Elastic Kubernetes Service
  • Google Kubernetes Engine

The HA deployments enable more resilient and reliable service availability across supported environments.

In a single instance deployment, a failure makes the entire service unavailable. Software crashes, hardware issues, or other disruptions can interrupt development workflows and access to key resources.

With HA enabled, you can scale the number of backend replicas to introduce redundancy. This setup ensures that if one pod or component fails, others continue to serve requests without disruption. The built-in load balancer manages ingress traffic and distributes the load across the available pods. Meanwhile, the RHDH backend manages concurrent requests and resolves resource-level conflicts effectively.

As an administrator, you can configure high availability by adjusting replica values in your configuration file:

  • If you installed using the Operator, configure the replica values in your Backstage custom resource.
  • If you used the Helm chart, set the replica values in the Helm configuration.

13.2.3.1. Configure with the Operator

Configure high availability for Operator deployments by setting the replicas field to a value greater than 1 in the custom resource.

Procedure

  • In your Backstage custom resource (CR), set replicas to a value greater than 1.

    For example, to configure two replicas (one backup instance):

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: <your_yaml_file>
    spec:
      deployment:
        patch:
          spec:
            replicas: 2

13.2.3.2. Configure with the Helm chart

Configure high availability for Helm deployments by setting the replicas value to greater than 1 in the Helm configuration file.

Procedure

  • In your Helm chart configuration file, set replicas to a value greater than 1.

    For example, to configure two replicas (one backup instance):

    upstream:
      backstage:
        replicas: 2

13.2.4. Configure the dynamic plugins cache

The dynamic plugins cache reduces platform boot time by storing already-installed plugins and skipping redundant downloads when the configuration does not change.

When you enable dynamic plugins cache:

  • The system calculates a checksum of each plugin’s YAML configuration (excluding pluginConfig).
  • The system stores the checksum in a file named dynamic-plugin-config.hash within the plugin’s directory.
  • During boot, if a plugin’s package reference matches the earlier installation and the checksum does not change, the system skips the download.
  • The system automatically removes plugins that you disabled since the earlier boot.
Note

To enable the dynamic plugins cache in RHDH, the plugins directory dynamic-plugins-root must be a persistent volume.

13.2.4.1. Create PVC with Operator

Create a persistent volume claim for the dynamic plugin cache in Operator deployments by replacing the default dynamic-plugins-root volume.

Prerequisites

  • You have installed Red Hat Developer Hub on OpenShift Container Platform using the Red Hat Developer Hub Operator.
  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create the persistent volume definition and save it to a file, such as pvc.yaml. For example:

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: dynamic-plugins-root
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 5Gi
    Note

    This example uses ReadWriteOnce as the access mode which prevents many replicas from sharing the PVC across different nodes. To run many replicas on different nodes, depending on your storage driver, you must use an access mode such as ReadWriteMany.

  2. To apply this PVC to your cluster, run the following command:

    $ oc apply -f pvc.yaml
  3. Replace the default dynamic-plugins-root volume with a PVC named dynamic-plugins-root. For example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: developer-hub
    spec:
      deployment:
        patch:
          spec:
            template:
              spec:
                volumes:
                  - $patch: replace
                    name: dynamic-plugins-root
                    persistentVolumeClaim:
                      claimName: dynamic-plugins-root
    Note

    To avoid adding a new volume, you must use the $patch: replace directive.

13.2.4.2. Create PVC with Helm Chart

Create a persistent volume claim for the dynamic plugin cache in Helm deployments to persist the cache across pod restarts.

Prerequisites

  • You have installed Red Hat Developer Hub using the Helm chart.
  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create the persistent volume definition. For example:

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: dynamic-plugins-root
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 5Gi
    Note

    This example uses ReadWriteOnce as the access mode which prevents many replicas from sharing the PVC across different nodes. To run many replicas on different nodes, depending on your storage driver, you must use an access mode such as ReadWriteMany.

  2. To apply this PVC to your cluster, run the following command:

    $ oc apply -f pvc.yaml
  3. Configure the Helm chart to use the PVC. For example:

    upstream:
      backstage:
        extraVolumes:
          - name: dynamic-plugins-root
            persistentVolumeClaim:
              claimName: dynamic-plugins-root
          - name: dynamic-plugins
            configMap:
              defaultMode: 420
              name: '{{ printf "%s-dynamic-plugins" .Release.Name }}'
              optional: true
          - name: dynamic-plugins-npmrc
            secret:
              defaultMode: 420
              optional: true
              secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}'
          - name: dynamic-plugins-registry-auth
            secret:
              defaultMode: 416
              optional: true
              secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}'
          - name: npmcacache
            emptyDir: {}
          - name: temp
            emptyDir: {}
    Note

    When you configure the Helm chart to use the PVC, you must also include the extraVolumes section defined in the default Helm chart values.

13.2.4.3. Resolve plugin configuration errors

Troubleshoot and resolve configuration errors that prevent dynamic plugins from loading or operating correctly.

Procedure

  • TO DO: Update procedure steps

13.2.5. Enable the plugin assets cache

Use a Redis cache store to improve Developer Hub performance and reliability by caching plugin assets.

Prerequisites

  • You have installed Red Hat Developer Hub.
  • You have an active Redis server. For more information on setting up an external Redis server, see the official Redis documentation.

Procedure

  1. Enable the Developer Hub cache by defining Redis as the cache store type and entering your Redis server connection URL in your app-config.yaml file.

    app-config.yaml file fragment

    backend:
      cache:
        store: redis
        connection: redis://user:pass@cache.example.com:6379

  2. Enable the cache for TechDocs by adding the techdocs.cache.ttl setting in your app-config.yaml file. This setting specifies how long, in milliseconds, a statically built asset should stay in the cache.

    app-config.yaml file fragment

    techdocs:
      cache:
        ttl: 3600000

    Tip

    Optionally, enable the cache for unsupported plugins that support this feature. See the documentation for each plugin for details.

Chapter 14. Extend

14.1. Extend

Add new capabilities to Red Hat Developer Hub by installing, configuring, and developing dynamic plugins without rebuilding or restarting the core platform. Dynamic plugins enable teams to tailor the developer portal to specific organizational workflows while maintaining upgrade compatibility.

14.2. Manage the plugin ecosystem to add functionality without downtime

14.2.1. Manage the plugin ecosystem to add functionality without downtime

Discover, install, and manage dynamic plugins to extend Red Hat Developer Hub with new capabilities. Dynamic plugins load at runtime from a configured root directory, enabling platform teams to add functionality without rebuilding the application or scheduling downtime.

14.2.2. Install dynamic plugins

14.2.2.1. Install dynamic plugins

Install dynamic plugins by using the Operator or Helm chart to add preinstalled or external capabilities to Red Hat Developer Hub. The backend plugin manager scans a configured root directory for dynamic plugin packages and loads them at startup.

14.2.2.2. Dynamic Plugins

Red Hat Developer Hub implements a dynamic plugin system. You can install, configure, and load plugins at runtime without changing or rebuilding the application. You only need a restart. You can load these plugins from NPM, tarballs, or OCI compliant container images.

With dynamic plugins, instead of modifying the Backstage application itself, you create a dynamic-plugins.yaml file to specify the plugins that Red Hat Developer Hub will install and enable at startup. For example, the following configuration loads a plugin named plugin-name, which is stored in a Quay.io container image at quay.io/account-name/image-name:

dynamic-plugins.yaml fragment

plugins:
  - package: oci://quay.io/account-name/image-name:tag
    disabled: false
    pluginConfig: {}

14.2.2.3. Install with Operator

14.2.2.3.1. Install with Operator

Configure the Red Hat Developer Hub Operator custom resource to install dynamic plugins with dependency management and resource specifications. The Operator automates plugin lifecycle operations during deployments.

14.2.2.3.2. Install dynamic plugins with the Red Hat Developer Hub Operator

You can store the configuration for dynamic plugins in a ConfigMap object that your Backstage custom resource (CR) can reference.

Dynamic plugins might require you to configure certain Kubernetes resources. The documentation refers to these resources as plugin dependencies. For more information, see Dynamic plugins dependency management.

In Red Hat Developer Hub (RHDH), you can automatically create these resources when you apply the Backstage CR to the cluster.

Note

If the pluginConfig field references environment variables, you must define the variables in your <my_product_secrets> secret.

Procedure

  1. From the OpenShift Container Platform web console, select the ConfigMaps tab.
  2. Click Create ConfigMap.
  3. From the Create ConfigMap page, select the YAML view option in Configure via and edit the file, if needed.

    The following example shows a ConfigMap object using the GitHub dynamic plugin:

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic'
            disabled: false
            pluginConfig:
              catalog:
                providers:
                  github:
                    organization: "${GITHUB_ORG}"
                    schedule:
                      frequency: { minutes: 1 }
                      timeout: { minutes: 1 }
                      initialDelay: { seconds: 100 }
  4. Click Create.
  5. Go to the Topology view.
  6. Click the overflow menu for the Red Hat Developer Hub instance that you want to use and select Edit Backstage to load the YAML view of the Red Hat Developer Hub instance.

    Editing Backstage from the Topology view
  7. Add the dynamicPluginsConfigMapName field to your Backstage CR. For example:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh
    spec:
      application:
        dynamicPluginsConfigMapName: dynamic-plugins-rhdh
  8. Click Save.
  9. Navigate back to the Topology view and wait for the Red Hat Developer Hub pod to start.
  10. Click the Open URL icon to start using the Red Hat Developer Hub platform with the new configuration changes.

Verification

  • Ensure that the system loads the dynamic plugins configuration, by appending /api/dynamic-plugins-info/loaded-plugins to your Red Hat Developer Hub root URL and checking the list of plugins:

    The following example shows a list of plugins:

    [
      {
        "name": "backstage-plugin-catalog-backend-module-github-dynamic",
        "version": "0.5.2",
        "platform": "node",
        "role": "backend-plugin-module"
      },
      {
        "name": "backstage-plugin-techdocs",
        "version": "1.10.0",
        "role": "frontend-plugin",
        "platform": "web"
      },
      {
        "name": "backstage-plugin-techdocs-backend-dynamic",
        "version": "1.9.5",
        "platform": "node",
        "role": "backend-plugin"
      },
    ]

14.2.2.4. Dynamic plugin dependency requirements and resource specifications

Dynamic plugins configured for the Backstage custom resource (CR) might require Kubernetes resources called plugin dependencies, which RHDH creates automatically when you apply the CR.

14.2.2.4.1. Cluster level plugin dependencies configuration

You can configure plugin dependencies by including the required Kubernetes resources in the /config/profile/{PROFILE}/plugin-deps directory. You must add the required resources as Kubernetes manifests in YAML format in the plugin-deps directory.

Example showing how to add example-dep1.yaml and example-dep2.yaml as plugin dependencies:

config/
  profile/
    rhdh/
     kustomization.yaml
     plugin-deps/
        example-dep1.yaml
        example-dep2.yaml
Note
  • If a resource manifest does not specify a namespace, the Operator creates it in the namespace of the Backstage CR.
  • Resources can contain {{backstage-name}} and {{backstage-ns}} placeholders. The Operator replaces the {{backstage-name}} placeholder with the name of the Backstage CR, and replaces the {{backstage-ns}} placeholder with the namespace of the Backstage CR.

The kustomization.yaml file must contain the following lines:

configMapGenerator:
  - files:
      - plugin-deps/example-dep1.yaml
      - plugin-deps/example-dep2.yaml
    name: plugin-deps
14.2.2.4.2. Plugin dependencies infrastructure

To install infrastructural resources that plugin dependencies require, for example, other Operators or custom resources (CR), you can include these in the /config/profile/{PROFILE}/plugin-infra directory.

To create these infrastructural resources (along with the Operator deployment), use the make plugin-infra command.

Note

On a production cluster, use this command with caution as it might reconfigure cluster-scoped resources.

14.2.2.4.3. Plugin configuration

You must reference the plugin dependencies in the dependencies field of the plugin configuration when you apply the Backstage CR.

The Operator creates the resources that the files in the plugin-deps directory describe.

You can reference plugin dependencies in the dynamic-plugins ConfigMap that can either be part of the default profile configuration for all Backstage custom resources or part of the ConfigMap referenced in the Backstage CR. In Red Hat Developer Hub, you can include plugin dependencies in the dynamic plugin configuration.

Each dependencies.ref value can either match the full file name or serve as a prefix for the file name. The Operator creates the resources that the files in the plugin-deps directory describe that start with the specified ref value or exactly match it

Example showing how to add example-dep plugin dependency:

apiVersion: v1
kind: ConfigMap
metadata:
  name: default-dynamic-plugins
data:
  dynamic-plugins.yaml: |
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - disabled: false
        package: "path-or-url-to-example-plugin"
        dependencies:
          - ref: example-dep

14.2.2.5. Install with Helm Chart

14.2.2.5.1. Install with Helm Chart

Configure the Helm chart values file to install dynamic plugins during Red Hat Developer Hub deployment. The Helm chart approach provides fine-grained control over plugin packages and their initialization parameters.

14.2.2.5.2. Installing dynamic plugins using the Helm chart

You can deploy a Developer Hub instance by using a Helm chart, which is a flexible installation method. With the Helm chart, you can load dynamic plugins into your Developer Hub instance without having to recompile your code or rebuild the container.

To install dynamic plugins in Developer Hub using Helm, add the following global.dynamic parameters in your Helm chart:

  • plugins: the dynamic plugins list intended for installation. By default, the list is empty. You can populate the plugins list with the following fields:

    • package: a package specification for the dynamic plugin package that you want to install. You can use a package for either a local or an external dynamic plugin installation. For a local installation, use a path to the local folder containing the dynamic plugin. For an external installation, use a package specification from a public NPM repository.
    • integrity (required for external packages): an integrity checksum in the form of <alg>-<digest> specific to the package. Supported algorithms include sha256, sha384 and sha512.
    • pluginConfig: an optional plugin-specific app-config.yaml YAML fragment. See plugin configuration for more information.
    • disabled: disables the dynamic plugin if set to true. Default: false.
    • forceDownload: Set the value to true to force a reinstall of the plugin, bypassing the cache. The default value is false.
    • pullPolicy: Similar to the forceDownload parameter and is consistent with other image container platforms. You can use one of the following values for this key:

      • Always: This value compares the image digest in the remote registry and downloads the artifact if it has changed, even if you downloaded the plugin before.
      • IfNotPresent: This value downloads the artifact if it is not already present in the dynamic-plugins-root folder, without checking image digests.

        Note

        The pullPolicy setting is also applied to the NPM downloading method, although Always will download the remote artifact without a digest check. The existing forceDownload option remains functional, however, the pullPolicy option takes precedence. The forceDownload option might be deprecated in a future Developer Hub release.

  • includes: a list of YAML files using the same syntax.
Note

The system merges the plugins list in the includes file with the plugins list in the main Helm values. If both plugins lists mention a plugin package, the plugins fields in the main Helm values override the plugins fields in the includes file. The default configuration has the dynamic-plugins.default.yaml file, which has all of the dynamic plugins preinstalled in Developer Hub, whether enabled or disabled by default.

14.2.2.5.3. Example configurations

The following examples show how to configure the Helm chart for specific types of dynamic plugin installations.

Configuring a local plugin and an external plugin when the external plugin requires a specific configuration:

global:
  dynamic:
    plugins:
      - package: <alocal package-spec used by npm pack>
      - package: <external package-spec used by npm pack>
        integrity: sha512-<some hash>
        pluginConfig: ...

Disabling a plugin from an included file:

global:
  dynamic:
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: <some imported plugins listed in dynamic-plugins.default.yaml>
        disabled: true

Enabling a plugin from an included file:

global:
  dynamic:
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: <some imported plugin listed in dynamic-plugins.default.yaml>
        disabled: false

Enabling a plugin that an included file disables:

global:
  dynamic:
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: <some disabled plugin listed in dynamic-plugins.default.yaml>
        disabled: false # overrides disabled: true from the included file

14.2.2.6. Install in an air-gapped environment using the Helm chart

You can install external plugins in an air-gapped environment by setting up a custom NPM registry.

You can configure the NPM registry URL and authentication information for dynamic plugin packages by using a Helm chart. For dynamic plugin packages obtained through npm pack, you can use a .npmrc file.

Using the Helm chart, add the .npmrc file to the NPM registry by creating a secret. For example:

apiVersion: v1
kind: Secret
metadata:
  name: <release_name>-dynamic-plugins-npmrc
type: Opaque
stringData:
  .npmrc: |
    registry=<registry_link>
    //<registry_link>:_authToken=<auth_token>
          ...

Replace <release_name> with your Helm release name. This name is a unique identifier for each chart installation in the Kubernetes cluster.

14.2.2.7. Install in an air-gapped environment using the Operator

To install external dynamic plugins in an air-gapped environment, configure a custom NPM registry by mounting a secret into the Developer Hub Operator.

Prerequisites

  • An OpenShift Container Platform administrator has installed the Red Hat Developer Hub Operator.
  • You have set up a custom NPM registry that is accessible from within your cluster and contains the required dynamic plugin packages.

Procedure

  1. Create a secret containing your .npmrc configuration that points to your internal NPM registry:

    apiVersion: v1
    kind: Secret
    metadata:
      name: dynamic-plugins-npmrc
    type: Opaque
    stringData:
      .npmrc: |
        registry=https://<your_internal_registry>
        //<your_internal_registry>:_authToken=<your_auth_token>
  2. Apply the secret to your namespace:

    $ oc apply -f dynamic-plugins-npmrc.yaml -n my-rhdh-project
  3. Add the secret to the spec.application.extraFiles.secrets field in your Backstage custom resource, targeting the install-dynamic-plugins init container:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: my-rhdh
    spec:
      application:
        extraFiles:
          secrets:
            - name: dynamic-plugins-npmrc
              mountPath: /opt/app-root/src/.npmrc.dynamic-plugins
              containers:
                - install-dynamic-plugins

    The install-dynamic-plugins init container reads the .npmrc file from /opt/app-root/src/.npmrc.dynamic-plugins/.npmrc to resolve plugin packages from your internal registry.

  4. Apply the updated custom resource:

    $ oc apply -f my-rhdh.yaml -n my-rhdh-project

Verification

  • Verify that the init container used your custom registry by checking the init container logs:

    $ oc logs -c install-dynamic-plugins deploy/backstage-my-rhdh

14.2.2.8. Mirror dynamic plugins in disconnected environments

14.2.2.8.1. Mirror dynamic plugins in disconnected environments

Mirror dynamic plugin OCI artifacts to a local registry for deployments in restricted or air-gapped environments. Red Hat Developer Hub distributes plugins as Open Container Initiative (OCI) artifacts that must be accessible from within the cluster network.

14.2.2.8.2. Mirror to a partially disconnected environment

Use this procedure to mirror plugins from a catalog index to a partially disconnected environment.

Procedure

  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Mirror the plugin catalog index and all referenced plugin OCI artifacts to your target registry by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-registry <target_registry>

    where:

    <target_registry>

    Enter the URL of the target mirror registry, such as, registry.example.com.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

14.2.2.8.3. Mirror to a fully disconnected environment

This two-phase process exports plugins to disk from a connected host, transfers them to a restricted network, then imports them to your internal registry.

Procedure

  1. Download the plugin mirroring script by running the following command:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. Export the plugin catalog index and all referenced plugin OCI artifacts to disk by running the following command:

    $ bash mirror-plugins.sh \
      --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 \
      --to-dir <my_plugin_mirror_dir>

    where:

    <my_plugin_mirror_dir>

    Enter the absolute path to a directory where you want to export the plugin artifacts, for example, /home/user/rhdh-plugins-mirror.

    Note

    The script can take several minutes to complete. It mirrors the catalog index image and all plugin OCI artifacts that the index references.

  3. Transfer the directory specified by the --to-dir option to your disconnected environment.
  4. From a machine in your disconnected environment that has access to the target mirror registry, import the plugin artifacts by running the following command:

    $ bash mirror-plugins.sh \
      --from-dir <my_plugin_mirror_dir> \
      --to-registry <target_registry>

    where:

    <my_plugin_mirror_dir>
    Enter the path to the directory containing the exported plugin artifacts.
    <target_registry>
    Enter the URL of the target mirror registry, for example, registry.example.com.
14.2.2.8.4. Mirror specific plugins

Use this procedure to mirror specific plugins by specifying their OCI URLs directly.

Procedure

  1. Download the mirroring script:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. To mirror individual plugins by specifying their OCI URLs directly, run the mirroring script by using the bash command with the appropriate set of options:

    For example:

    bash mirror-plugins.sh \
        --plugins oci://quay.io/rhdh-plugin-catalog/backstage-community-plugin-quay:<tag> \
                  oci://quay.io/rhdh-plugin-catalog/backstage-community-plugin-github-actions:<tag> \
        --to-registry <my.registry.example.com>

    where:

    <tag>
    Enter your RHDH version and the plugin version, in the format <rhdh-version>--<plugin-version>. To find these versions, complete the following steps:
  3. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.10, use the format 1.10--<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

    where:

    --to-registry <my.registry.example.com>
    Enter the URL for the target mirror registry where you want to mirror the catalog index.
14.2.2.8.5. Mirror plugins from a file

Use this procedure to mirror plugins from a file containing a list of plugin URLs.

Procedure

  1. Create a text file listing the plugins to mirror (one per line), as follows:

    Example plugins.txt file:

    oci://quay.io/rhdh-plugin-catalog/backstage-community-plugin-quay:<tag>
    oci://quay.io/rhdh-plugin-catalog/backstage-community-plugin-github-actions:<tag>
    oci://quay.io/rhdh-plugin-catalog/backstage-community-plugin-azure-devops:<tag>

    where:

    <tag>
    Enter your RHDH version and the plugin version, in the format <rhdh-version>--<plugin-version>. To find these versions, complete the following steps:
  2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.10, use the format 1.10--<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  3. Download the mirroring script:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  4. Run the mirroring script by using the bash command with the appropriate set of options:

    For example:

    bash mirror-plugins.sh \
        --plugin-list plugins.txt \
        --to-registry <my.registry.example.com>

    where:

    --plugin-list plugins.txt
    A text file listing the plugins to mirror.
    --to-registry <my.registry.example.com>
    Enter the URL for the target mirror registry where you want to mirror the catalog index.
14.2.2.8.6. Combine plugin sources

You can combine any of the plugin sources (for example, catalog index, plugin list file, and direct URLs) in a single mirroring operation. The script automatically deduplicates plugins if the same plugin is present in many sources.

Procedure

  1. Download the mirroring script:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/.rhdh/scripts/mirror-plugins.sh
  2. To combine many plugin sources, run the mirroring script by using the bash command with the appropriate set of options:

    For example:

    bash mirror-plugins.sh \
        --plugin-index oci://registry.access.redhat.com/rhdh/plugin-catalog-index:1.9 \
        --plugin-list custom-plugins.txt \
        --plugins 'oci://registry.internal.example.com/custom/my-plugin:1.0' \
        --to-registry registry.example.com

    where:

    --plugin-list custom-plugins.txt
    A text file listing the plugins to mirror.
    --to-registry <my.registry.example.com>
    Enter the URL for the target mirror registry where you want to mirror the catalog index.

14.2.2.9. Example of installing a custom plugin in Red Hat Developer Hub

This example demonstrates how to package and install dynamic plugins by using the Backstage Entity Feedback community plugin that is not included in Red Hat Developer Hub pre-installed dynamic plugins.

Limitations:

  • You need to ensure that you build your custom plugin with a compatible version of Backstage. In Developer Hub, click Settings. Your custom plugin must be compatible with the Backstage Version (or the closest earlier version) that the Metadata section of Red Hat Developer Hub displays.

    For example, if you view the history of the backstage.json file for the Entity Feedback plugin, the 1fc87de commit is the closest earlier version to Backstage version of 1.39.1.

    backstage.json file history in GitHub

Prerequisites

  • Your local environment meets the following requirements:
  • Node.js: Version 22.x
  • Yarn: Version 4.x
  • git CLI
  • jq CLI: Command-line JSON processor
  • OpenShift CLI (oc): The client for interacting with your OpenShift cluster.
  • Container runtime: You need either podman or docker to package the plugin into an OCI image and to log in to registries.
  • Container registry access: Access to an OCI-compliant container registry, such as the internal OpenShift registry or a public registry such as Quay.io.

Procedure

  1. Clone the source code for the Entity Feedback plugin, as follows:

    $ git clone https://github.com/backstage/community-plugins.git
    $ cd community-plugins
  2. Prepare your environment to build the plugin by enabling Yarn for your Node.js installation, as follows:

    $ corepack enable yarn
  3. Install the dependencies, compile the code, and build the plugins, as follows:

    $ cd workspaces/entity-feedback
    $ yarn install
    $ yarn tsc
    $ yarn build:all
    Note

    After this step, with upstream Backstage, you publish the built plugins to a NPM or NPM-compatible registry. In this example, as you are building this plugin to support dynamic loading by Red Hat Developer Hub, you can skip the npm publish step that publishes the plugin to a NPM registry. Instead, you can package the plugin for dynamic loading and publish it as a container image on Quay.io or your preferred container registry.

  4. Prepare the Entity Feedback front-end plugin by using the Red Hat Developer Hub CLI. The following command uses the plugin files in the dist folder that the yarn build:all command generated, and creates a new dist-scalprum folder that has the necessary configuration and source files to enable dynamic loading:

    $ cd plugins/entity-feedback
    $ npx @red-hat-developer-hub/cli@latest plugin export

    When this command packages a front-end plugin, it uses a default Scalprum configuration if one is not found. The Scalprum configuration specifies the plugin entry point and exports, and then builds a dist-scalprum folder that has the dynamic plugin. The following example shows the default Scalprum configuration. However, you can add a scalprum key to the package.json file used by your plugin to set custom values, if necessary:

    {
      "name": "backstage-community.plugin-entity-feedback",
      "exposedModules": {
        "PluginRoot": "./src/index.ts"
      }
    }

    Red Hat Developer Hub uses the following plugin-manifest.json file to load the plugin. This file is in the dist-dynamic/dist-scalprum folder:

    {
      "name": "backstage-community.plugin-entity-feedback",
      "version": "0.6.0",
      "extensions": [],
      "registrationMethod": "callback",
      "baseURL": "auto",
      "loadScripts": [
        "backstage-community.plugin-entity-feedback.fd691533c03cb52c30ac.js"
      ],
      "buildHash": "fd691533c03cb52c30acbb5a80197c9d"
    }
  5. Package the plugin into a container image and publish it to Quay.io or your preferred container registry:

    $ export QUAY_USER=replace-with-your-username
    $ export PLUGIN_NAME=entity-feedback-plugin
    $ export VERSION=$(cat package.json | jq .version -r)
    
    $ npx @red-hat-developer-hub/cli@latest plugin package \
      --tag quay.io/$QUAY_USER/$PLUGIN_NAME:$VERSION
    
    $ podman login quay.io
    $ podman push quay.io/$QUAY_USER/$PLUGIN_NAME:$VERSION
  6. Repeat the same steps for the backend plugin. Backend plugins do not require Scalprum, and the export generates a dist-dynamic folder instead of a dist-scalprum folder:

    $ cd ../entity-feedback-backend/
    $ npx @red-hat-developer-hub/cli@latest plugin export
    
    $ export QUAY_USER=replace-with-your-username
    $ export PLUGIN_NAME=entity-feedback-plugin-backend
    $ export VERSION=$(cat package.json | jq .version -r)
    
    $ npx @red-hat-developer-hub/cli@latest plugin package \
      --tag quay.io/$QUAY_USER/$PLUGIN_NAME:$VERSION
    
    $ podman push quay.io/$QUAY_USER/$PLUGIN_NAME:$VERSION

    Those commands publish two container images to your container registry.

    The following image shows the container images published to Quay.io:

    Container images published to Quay.io

14.2.3. Install plugins using custom certificates to secure private registry connections

14.2.3.1. Install plugins using custom certificates to secure private registry connections

Install OCI plugins from internal registries served over HTTPS with corporate CA certificates. Custom certificate configuration ensures Red Hat Developer Hub trusts your private registry connections during plugin installation.

14.2.3.2. Install from secure container registries

Use this procedure to install plugins from OCI registries by configuring per-registry TLS certificates.

Procedure

  1. Create a ConfigMap from the CA certificate in the namespace where you are deploying your RHDH instance:

    oc create configmap registry-ca-crt --from-file=ca.crt
  2. Mount the CA certificate ConfigMap into your RHDH configuration:

    1. For a Helm chart installation, update your Helm chart configuration file, as follows:

      upstream:
        backstage:
          extraVolumes:
            # IMPORTANT: Due to a Helm limitation with arrays, you must also
            # include all the volumes defined in the default Helm Chart
            # before adding the new one
            # ...
            - name: registry-ca-crt
              configMap:
                name: registry-ca-crt
      
          initContainers:
            - name: install-dynamic-plugins
              # IMPORTANT: Due to a Helm limitation with arrays, you must also
              # include all the other fields defined in the default Helm Chart
              # ...
      
              volumeMounts:
                # IMPORTANT: Due to a Helm limitation with arrays, you must also
                # include all the volume mounts defined in the default Helm Chart
                # before adding the new one
                # ...
                - name: registry-ca-crt
                  # Hostname and port must match your target registry
                  mountPath: '/etc/containers/certs.d/reg.example.com:5000'
    2. For Operator-based installations, update your Backstage Custom Resource (CR), as follows:

      spec:
        application:
          extraFiles:
            configMaps:
              - name: registry-ca-crt
                # Hostname and port must match your target registry
                mountPath: '/etc/containers/certs.d/reg.example.com:5000'
                containers:
                  - install-dynamic-plugins

14.2.3.3. Install using trusted certificate authorities

Use this procedure to install plugins from OCI registries by mounting a CA bundle.

Procedure

  1. Create a ConfigMap from the CA bundle in the namespace where you are deploying your RHDH instance:

    oc create configmap registry-ca-bundle --from-file=ca-bundle.crt
  2. Mount the CA bundle ConfigMap into your RHDH configuration

    1. For a Helm chart installation, update your Helm chart configuration file, as follows:

      upstream:
        backstage:
          extraVolumes:
            # IMPORTANT: Due to a Helm limitation with arrays, you must also
            # include all the volumes defined in the default Helm Chart
            # before adding the new one
            # ...
            - name: registry-ca-bundle
              configMap:
                name: registry-ca-bundle
      
          initContainers:
            - name: install-dynamic-plugins
              # IMPORTANT: Due to a Helm limitation with arrays, you must also
              # include all the other fields defined in the default Helm Chart
              # ...
      
              volumeMounts:
                # IMPORTANT: Due to a Helm limitation with arrays, you must also
                # include all the volume mounts defined in the default Helm Chart
                # before adding the new one
                # ...
                - name: registry-ca-bundle
                  mountPath: /etc/pki/tls/certs/
    2. For Operator-based installations, update your Backstage Custom Resource (CR), as follows:

      spec:
        application:
          extraFiles:
            configMaps:
              - name: registry-ca-bundle
                mountPath: /etc/pki/tls/certs/
                containers:
                  # Note: Set to "*" instead if you want to mount it in all containers
                  - install-dynamic-plugins

14.2.3.4. Install with cluster-wide trust bundles

Use this procedure to install plugins from OCI registries in an OpenShift environment by using cluster-wide trusted CA bundles.

Prerequisites

  • Your cluster administrator must add the trusted corporate CA bundle to the cluster-wide configuration. For more information, see Security and compliance in the OpenShift Container Platform documentation.

Procedure

  1. Create an empty ConfigMap in the namespace where you are deploying your RHDH instance. You must add the config.openshift.io/inject-trusted-cabundle label to your ConfigMap, as follows:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: trusted-ca
      labels:
        config.openshift.io/inject-trusted-cabundle: "true"
  2. Wait for the cluster to inject the trusted CA bundle into the ConfigMap. You can verify with the following command:

    oc get cm trusted-ca

    You should see a block of certificates under the ca-bundle.crt key.

  3. Mount the ConfigMap into the /etc/pki/ca-trust/extracted/pem path of the RHDH init container.

    1. For a Helm chart installation, update your Helm chart configuration file, as follows:

      upstream:
        backstage:
          extraVolumes:
            # IMPORTANT: Due to a Helm limitation with arrays, you must also
            # include all the volumes defined in the default Helm Chart
            # before adding the new one
            # ...
            - name: trusted-ca
              configMap:
                name: trusted-ca
      
          initContainers:
            - name: install-dynamic-plugins
              # IMPORTANT: Due to a Helm limitation with arrays, you must also
              # include all the other fields defined in the default Helm Chart
              # ...
      
              volumeMounts:
                # IMPORTANT: Due to a Helm limitation with arrays, you must also
                # include all the volume mounts defined in the default Helm Chart
                # before adding the new one
                # ...
                - name: trusted-ca
                  mountPath: /etc/pki/ca-trust/extracted/pem
    2. For Operator-based installations, update your Backstage Custom Resource (CR), as follows:

      spec:
        application:
          extraFiles:
            configMaps:
              - name: trusted-ca
                mountPath: /etc/pki/ca-trust/extracted/pem
                containers:
                  # Note: Set to "*" instead if you want to mount it in all containers
                  - install-dynamic-plugins

14.2.4. Enable pre-loaded container plugins

The RHDH container image preinstalls a set of dynamic plugins to enhance functionality. However, due to mandatory configuration requirements, the image disables most of the plugins.

You can enable and configure the plugins in the RHDH container image. This includes how to manage the default configuration, set necessary environment variables, and ensure the proper functionality of the plugins within your application.

Important

Since RHDH 1.10, the latest version of the dynamic-plugins.default.yaml file exists in the plugin catalog index container image.

To retrieve the latest version of the dynamic-plugins.default.yaml file, run the following commands in your terminal:

$ unpack () {
  if [[ ! $1 ]]; then
    echo "Usage: unpack reg/org/container:tagorsha [file(s)-to-unpack-pattern]"
    echo "Example: unpack quay.io/rhdh/plugin-catalog-index:1.10 dynamic-plugins.default.yaml"
  else
    local FILES=""
    if [[ $2 ]]; then FILES="$2"; fi
    local IMAGE="$1"
    local DIR="${IMAGE//:/_}"
    DIR="/tmp/${DIR//\//-}"
    rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}")
    podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/" $FILES; podman rm $container_id; rm -f /tmp/image.tar
    echo "Unpacked $IMAGE into $DIR"
    cd $DIR;
    if [[ $FILES ]]; then ls -la $FILES; else tree -d -L 3 -I "usr|root|buildinfo"; fi
  fi
}

$ unpack registry.access.redhat.com/rhdh/plugin-catalog-index:1.10 dynamic-plugins.default.yaml

# For a pre-GA CI container:
$ unpack quay.io/rhdh/plugin-catalog-index:1.10 dynamic-plugins.default.yaml

Alternatively, you can use an oci:// plugin reference, and the special {{inherit}} tag will fetch the latest compatible plugin, including its default configuration, for your current RHDH version.

Prerequisites

  • You have deployed the RHDH application, and have access to the logs of the install-dynamic-plugins init container.
  • You have the necessary permissions to change plugin configurations and access the application environment.
  • You have identified and set the required environment variables referenced by the plugin’s default configuration. You must define these environment variables in the Helm Chart or Operator configuration.

Procedure

  1. Start your RHDH application and access the logs of the install-dynamic-plugins init container within the RHDH pod.
  2. Identify the Red Hat supported plugins that the system disables by default.
  3. If you need to provide additional configuration for the plugin, other than enabling it, copy the package configuration from the dynamic-plugins.default.yaml file you extracted above. For plugins which require no configuration, you can simply reference the plugin and set it to disabled:false as in the example below.
  4. To use the latest compatible plugin version, use the special tag {{inherit}}; this will also load the default configuration, which you can then override.
  5. Open the plugin configuration file (Custom Resource or ConfigMap) and locate the plugin entry you want to enable.

    The location of the plugin configuration file varies based on the deployment method. For more details, see Installing and viewing plugins in Red Hat Developer Hub.

  6. Change the disabled field to false and add the package name as follows:

    plugins:
      - package: oci://registry.access.redhat.com/rhdh/backstage-community-plugin-analytics-provider-segment:{{inherit}}
        disabled: false

    or using the deprecated wrapper syntax:

    plugins:
      - package: './dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment'
        disabled: false

    For more information about how to configure dynamic plugins in Developer Hub, see Configuring dynamic plugins.

Verification

  1. Restart the RHDH application and verify that the plugin is successfully activated and configured.
  2. Verify the application logs for confirmation and ensure the plugin is functioning as expected.

14.2.5. Browse and manage available plugins using the Extensions UI

14.2.5.1. Browse and manage available plugins using the Extensions UI

Browse, install, and manage available plugins through the Extensions interface in Red Hat Developer Hub. The Extensions feature provides a centralized UI to discover plugins that extend platform functionality and streamline development workflows.

14.2.5.2. Manage plugins

14.2.5.2.1. Manage plugins

Control access to plugin administration, configure persistent storage, and manage the plugin lifecycle through the Extensions UI. Role-based access control restricts who can install, enable, or disable plugins on the platform.

14.2.5.2.2. Control plugin administration access

You can add Extensions permissions by creating or updating and existing RBAC role. For more information about using RBAC to manage role-based controls, see Managing role-based access controls (RBAC) using the Red Hat Developer Hub Web UI.

Prerequisites

  • If RBAC is enabled, you have a role with the following permissions: policy.entity.create, policy.entity.update, policy.entity.read, catalog.entity.read.

Procedure

  1. Go to Administration at the bottom of the sidebar in the Developer Hub.

    The RBAC tab is displayed, showing all the created roles in the Developer Hub.

  2. Click Create to create a role.
  3. Enter the user name and description (optional) of role in the given fields and click Next.
  4. In Add users and groups, select the user name, and click Next.
  5. In Add permission policies, select Extensions from the plugins dropdown.
  6. Expand Extensions, select both the Create and Read permissions for the Extensions plugin and click Next.
  7. Click Create to create the role.

    Creating an RBAC role with Extensions permissions

Verification

After you refresh the RHDH application, when you select a plugin, the Actions drop-down is active. When you click the Actions drop-down, you can edit the plugin configuration, and enable or disable the plugin.

14.2.5.2.3. Configure persistent storage for plugin installations
Important

This feature is supported in development environments only. In a production environment, the interface prevents plugin installation and is not supported.

When you install a plugin using Extensions UI, the system saves the configuration to a persistent volume, preserving it across application restarts.

You must create a persistent volume claim (PVC) to ensure that the cache persists when you restart the RHDH application. For more information about using the dynamic plugins cache, see Using the dynamic plugins cache.

Prerequisites

  • You have created a persistent volume claim (PVC) for the dynamic plugins cache with the name dynamic-plugins-root.
  • You have installed Red Hat Developer Hub using the Helm chart or the Operator.
  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create the extensions configuration file and save it as dynamic-plugins.extensions.yaml. For example:

    includes:
      - dynamic-plugins.default.yaml
    
    plugins:
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-marketplace:
                translationResources:
                  - importName: marketplaceTranslations
                    ref: marketplaceTranslationRef
                    module: Alpha
                appIcons:
                  - name: pluginsIcon
                    importName: PluginsIcon
                dynamicRoutes:
                  - path: /extensions
                    importName: DynamicMarketplacePluginRouter
                    menuItem:
                      icon: pluginsIcon
                      text: Extensions
                      textKey: menuItem.extensions
                menuItems:
                  extensions:
                    parent: default.admin
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions-backend-dynamic
        disabled: false
        pluginConfig:
          extensions:
            installation:
              enabled: true
              saveToSingleFile:
                file: /opt/app-root/src/dynamic-plugins-root/dynamic-plugins.extensions.yaml

    where:

    translationResources
    Sets the extension point for localization.
  2. Copy the file to your cluster by running the following commands:

    oc get pods -n <your_namespace>
    
    oc cp ./dynamic-plugins.extensions.yaml <your_namespace>/<pod_name>:/opt/app-root/src/dynamic-plugins-root/dynamic-plugins.extensions.yaml
  3. Update your RHDH application to use this file:

    1. For operator-based installations:

      1. Update your Backstage CR to update the NODE_ENV environment variable to development, as follows:

        apiVersion: rhdh.redhat.com/v1alpha5
        kind: Backstage
        metadata:
          name: developer-hub
          namespace: rhdh
        spec:
          application:
            dynamicPluginsConfigMapName: dynamic-plugins-rhdh
            extraEnvs:
              envs:
                - name: NODE_ENV
                  value: "development"
              secrets:
                - name: secrets-rhdh
            extraFiles:
              mountPath: /opt/app-root/src
            route:
              enabled: true
          database:
            enableLocalDb: true
      2. Update your dynamic-plugins-rhdh config map to include your extensions configuration file, as follows:

        kind: ConfigMap
        apiVersion: v1
        metadata:
          name: dynamic-plugins-rhdh
          namespace: rhdh
        data:
         dynamic-plugins.yaml: |
           includes:
             - dynamic-plugins.default.yaml
             - /dynamic-plugins-root/dynamic-plugins.extensions.yaml
           plugins: []
    2. For Helm chart installations:

      1. Upgrade the Helm release to include your extensions configuration file and update the NODE_ENV environment variable to development:

        global:
          auth:
            backend:
              enabled: true
          clusterRouterBase: apps.<clusterName>.com
          dynamic:
            includes:
              - dynamic-plugins.default.yaml
              - /dynamic-plugins-root/dynamic-plugins.extensions.yaml
        upstream:
          backstage:
            extraEnvVars:
              - name: NODE_ENV
                value: development
      2. Click Upgrade

Verification

Enable a plugin by using the Extensions UI, restart your RHDH application, and refresh the UI to confirm that you enabled the plugin.

14.2.5.2.4. View plugins

You can view available plugins for your Red Hat Developer Hub application on the Extensions page.

Procedure

  1. Open your RHDH application and click Administration > Extensions.
  2. Go to the Catalog tab to view a list of available plugins and related information.

    Extensions Catalog
14.2.5.2.5. Search for plugins by name

You can use the search bar in the header to filter the Extensions plugin cards by name. For example, if you type “A” into the search bar, Extensions shows only the plugins that contain the letter “A”.

Procedure

  1. In the header search bar, enter a plugin name, such as "Dynatrace".

    Extensions catalog with a Dynatrace search
  2. Optional: Refine your search by selecting one of the following filters:
  3. Category
  4. Author
  5. Support type

Verification

  • The Extensions list updates to display only the plugins that match your search text and selected filters.
14.2.5.2.6. View installed plugins

Using the Dynamic Plugins Info front-end plugin, you can view plugins that your Red Hat Developer Hub application currently has installed. Red Hat Developer Hub enables the Dynamic Plugins Info plugin by default.

Procedure

  1. Open your Developer Hub application and click Administration > Extensions.
  2. Go to the Installed tab to view a list of installed plugins and related information.
14.2.5.2.7. Install and configure portal plugins

You can install and configure plugins by using Extensions.

Prerequisites

Procedure

  1. Navigate to Extensions.
  2. Select a plugin to install.
  3. Click the Install button.

    Installing a plugin from the Extensions page

    The code editor is displayed that displays the plugin default configuration.

  4. Update the plugin configuration, if necessary.

    Plugin configuration code editor
  5. Click Install
  6. To view the plugins that require a restart, click View plugins in the alert message.

    Alert showing plugins that require a restart
  7. Restart your RHDH application.

Verification

  1. After you restart your RHDH application, navigate to Extensions.
  2. Select the plugin that you have installed.
  3. The Actions button is displayed.
14.2.5.2.8. Validate plugin configurations locally

You can use RHDH Local to test installing plugins by using Extensions.

Important

Red Hat maintains RHDH Local as an open source project, but does not support it or subject it to any service level agreement (SLA). There is no official, or commercial support for RHDH Local. Use RHDH Local at your own risk.

RHDH Local is NOT a substitute for Red Hat Developer Hub. It’s intended use is for development and testing purposes only, not for production use.

RHDH Local is designed for individual developers try out various RHDH features, not for use by development teams as there is no out-of-the-box RBAC support.

Prerequisites

Procedure

  1. Update your dynamic-plugins.override.yaml file:

    includes:
      - dynamic-plugins.default.yaml
    
    plugins:
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-marketplace:
                translationResources:
                  - importName: marketplaceTranslations
                    ref: marketplaceTranslationRef
                    module: Alpha
                appIcons:
                  - name: pluginsIcon
                    importName: PluginsIcon
                dynamicRoutes:
                  - path: /extensions
                    importName: DynamicMarketplacePluginRouter
                    menuItem:
                      icon: pluginsIcon
                      text: Extensions
                      textKey: menuItem.extensions
                menuItems:
                  extensions:
                    parent: default.admin
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions-backend-dynamic
        disabled: false
        pluginConfig:
          extensions:
            installation:
              enabled: true
              saveToSingleFile:
                file: /opt/app-root/src/configs/dynamic-plugins/dynamic-plugins.override.yaml

    where:

    translationResources
    Sets the extension point for localization.
  2. Update your compose.yaml file:

    rhdh:
      container_name: rhdh
      environment:
        NODE_OPTIONS: "--inspect=0.0.0.0:9229"
        NODE_ENV: "development"

Verification

Enable a plugin by using the Extensions UI, restart your RHDH application, and refresh the UI to confirm that you enabled the plugin.

14.2.5.2.9. Enable and disable portal plugins

Use this procedure to enable or disable plugins through the Extensions interface.

Prerequisites

Procedure

  1. Navigate to Extensions.
  2. Select a plugin to enable or disable.
  3. Click the Enable/Disable slider.

    Enable and disable slider for a plugin
  4. To view the plugins that require a restart, click View plugins in the alert message.

    Alert showing plugins that require a restart
  5. Restart your RHDH application.

Verification

  1. After you restart your RHDH application, navigate to Extensions.
  2. Select the plugin that you have installed.
  3. Verify that the system updated the Enable/Disable slider.
14.2.5.2.10. Disable the Extensions UI

The Extensions feature is available by default. To remove the Extensions interface (Marketplace) from your instance, you must disable the relevant plugins.

Procedure

  • Edit your dynamic-plugins.yaml with the following content.

    plugins:
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions
        disabled: true
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-catalog-backend-module-extensions-dynamic
        disabled: true
      - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions-backend-dynamic
        disabled: true
    Note

    Disabling these plugins removes the Catalog and Installed tabs. You can still view a basic list of installed plugins by selecting Administration > Extensions.

14.2.6. Configure core front-end wiring for navigation and UI components

14.2.6.1. Configure core front-end wiring for navigation and UI components

Configure front-end plugins to customize icons, create navigation entries, and define dynamic routes for new plugin pages. Front-end wiring connects dynamic plugin components to the Red Hat Developer Hub user interface without modifying core application code.

14.2.6.2. Front-end plugin wiring

Front-end plugin wiring integrates dynamic front-end plugin components, such as new pages, UI extensions, icons, and APIs, into Red Hat Developer Hub.

Because the dynamic plugins load at runtime, the core application must discover and connect the exported assets of the plugin to the appropriate user interface systems and locations.

14.2.6.3. Requirements and workflows for front-end plugin wiring

14.2.6.3.1. Requirements and workflows for front-end plugin wiring

Understand why front-end plugin wiring is required and the consequences of skipping it. Front-end wiring ensures dynamic plugins integrate correctly with the Red Hat Developer Hub navigation, entity pages, and component framework.

14.2.6.3.2. Reasons for requiring front-end plugin wiring

Because dynamic front-end plugins load their code at runtime, the Developer Hub application requires explicit instructions to integrate the plugin components in the user interface (UI).

Front-end wiring provides the metadata and instructions necessary to bridge this gap, informing the applications on how to:

The wiring configuration, typically located in app-config.yaml or dynamic-plugins-config.yaml, gives the application the necessary metadata (including the component names, paths, and integration points) to render and use the plugin features.

14.2.6.3.3. Consequences of skipping front-end plugin wiring

If you skip front-end wiring, the system discovers the plugin but does not load it because front-end plugins require explicit configuration.

You can expect the following behavior when you skip front-end wiring:

Disabled functionality
The Backstage application cannot integrate or use the plugin exports.
Invisible components
New pages, sidebar links, or custom cards do not render in the application UI.
Unregistered APIs
Custom utility APIs or API overrides provided by the plugin are not registered in the application API system, which can cause plugins or components to fail.
Unused assets
Icons, translations, and themes are not registered or available for use.
Tip

If a plugin is not visible even with front-end wiring, the plugin is likely misconfigured. Troubleshoot the issue by checking the Console tab in the Developer Tools of your browser for specific error messages or warnings.

14.2.6.4. Dynamic front-end plugins for application integration

A dynamic front-end plugin requires front-end wiring when it exports a feature for integration into the main Backstage application UI. The following scenarios require wiring:

ScenarioWiring configurationDescription

Extending entity tabs

entityTabs

Add or customize a tab on the Catalog entity view.

Binding routes

routeBindings

Link a route in one plugin to an external route defined by another plugin.

Integrating custom APIs

apiFactories

Supply a custom utility API implementation or override an existing one.

Enabling new pages/Routes

dynamicRoutes

Add a new page and route to the application (for example, /my-plugin).

Extending existing pages/UI

mountPoints

Inject custom widgets, cards, listeners, or providers into existing pages (for example, the Catalog entity page).

Customizing sidebar navigation

dynamicRoutes.menuItem, menuItems

Add a new entry to the main sidebar or customize its order and nesting.

Adding icons/Theming

appIcons, themes

Add custom icons to the application catalog or define a new Backstage theme.

Scaffolder/TechDocs extensions

scaffolderFieldExtensions, techdocsAddons

Expose custom field extensions for the Scaffolder or new add-ons for TechDocs.

Translation resources

translationResources

Offer new translation files or override default plugin translations.

14.2.6.4.1. Example of Front-end wiring workflow

Front-end wiring configuration occurs in the app-config.yaml or a dedicated dynamic-plugins-config.yaml file. The dynamic plugin exposes components, routes, or APIs. For example, a module exports a plugin component.

The application administrator defines the wiring in the configuration file, using the plugin package name to register the exports, such as adding a new page with a sidebar link.

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin-package-name: # The plugin's unique package name
            dynamicRoutes: # Wiring for a new page/route
              - path: /my-new-page # The desired URL path
                importName: <my-plugin>PluginPage # The exported component name
                menuItem: # Wiring for the sidebar entry
                  icon: favorite # A registered icon name
                  text: My Custom Page

When the application loads, it performs the following steps:

  1. It parses the dynamic-plugins-config.yaml.
  2. It uses the <plugin_path_or_url> to download the plugin bundle using the dynamic loading mechanism.
  3. If the package exports the plugin object, the application adds it to the list provided to the Backstage createApp API, registering the plugin properly with the front-end application.
  4. It uses the configuration block (dynamicRoutes, menuItem) to:

    • Add an entry to the internal router mapping /my-new-page to the <my-plugin>PluginPage component.
    • Construct and render a new sidebar item labeled My Custom Page, pointing to the /my-new-page route.
Note

If the configuration is missing, steps 1 and 2 might still occur, but the application skips the final registration in step 3 and the wiring/rendering in step 4, and no UI changes occur.

14.2.6.5. Add custom icons to the internal icon catalog

You can use the internal catalog to fetch icons for configured routes with sidebar navigation menu entry.

Procedure

  • Add a custom icon to the internal icon catalog for use in the menu item of a plugin by using the appIcons configuration as shown in the following example:

    # dynamic-plugins-config.yaml
    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              <package_name>:  # The plugin package name.
                appIcons:
                  - name: <icon_name> # A unique icon name.
                    module: <module_name> # (Optional): Specifies the set of assets to access within the plugin. If not specified, the system uses the default PluginRoot module name.
                    importName: <custom_icon_name> # (Optional): Specifies which component should be rendered. If not specified, the system uses the default export.
    Important

    The package_name key must match the scalprum.name value in your plugin’s package.json.

    The module key must match the scalprum.exposedModules key in the plugin’s package.json file.

14.2.6.6. Define dynamic routes to create plugin pages

Use this procedure to configure dynamic routes for new plugin pages in the application.

Procedure

  1. Define each route by specifying a unique path and, if needed, an importName if it is different from the default export.
  2. Expose additional routes in a dynamic plugin by configuring dynamicRoutes in the dynamic-plugins-config.yaml file as shown in the following example:

    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              <package_name>: # The plugin package name
                dynamicRoutes:
                    # The unique path in the application. The path cannot override existing routes except the / home route.
                  - path: /<plugin_path>
                    # (Optional): Specifies the set of assets to access within the plugin. If not specified, the system uses the default PluginRoot module name.
                    module: CustomModule
                    # (Optional): Specifies which component should be rendered as a standalone page. If not specified, the system uses the default export.
                    importName: <plugin_page>
                    # Lets you extend the main sidebar navigation and point to a new route.
                    menuItem:
                      icon: # home | group | category | extension | school | <my_icon>
                      text: <plugin_label>
                      enabled: false
                    config: # (Optional): Passes props to a custom sidebar item
                      props: ...
    Important

    The package_name key must match the scalprum.name value in your plugin’s package.json.

    The module variable must match the scalprum.exposedModules key in the plugin’s package.json file.

    The menuItem accepts the following properties:

    text
    The label shown to the user.
    icon
    The Backstage system icon name.
    enabled
    Optional: When you set this to false, you can remove a menuItem from the sidebar.
    importName
    Optional: Specifies the name of an exported SidebarItem component. The component receives a to property as well as any properties specified in config.props.
  3. (Optional) To configure a custom SidebarItem to enhance experiences such as notification badges, ensure the component accepts the following properties:

    export type MySidebarItemProps = {
      to: string;
    };

    where:

    string

    Supplied by the sidebar during rendering as the path configured for the dynamicRoute.

    Example of a configuration with a specified custom SidebarItem component

    # dynamic-plugins-config.yaml
    plugins:
      - plugin: <plugin_path_or_url>
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              my-dynamic-plugin-package-name:
                dynamicRoutes:
                  - importName: CustomPage
                    menuItem:
                      config:
                        props:
                          text: Click Me!
                      importName: SimpleSidebarItem
                    path: /custom_page

14.2.6.7. Customize sidebar navigation menus

You can customize the order and parent-child relationships of plugin menu items in the main sidebar navigation by using the menu items configuration as shown in the following example:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin:
            menuItems:
              <menu_item_name>:
                icon: <icon_name>Icon
                title: <plugin_name> Plugin Page
                priority: 10
                parent: favorites
                enabled: false

where:

my-plugin
The plugin package name.
<menu_item_name>
The unique name in the main sidebar navigation. Represents either a standalone menu item or a parent menu item.
icon
Optional: The icon for the menu item, which refers to a Backstage system icon. If you have already defined the icon in the dynamicRoutes configuration under menuItem.icon, you can omit it in the menuItems configuration.
title
Optional: The display title of the menu item. If you have already defined the title in the dynamicRoutes configuration under menuItem.text, you can omit it in the menuItems configuration.
priority
Optional: The order in which menu items appear. The default priority is 0, which places the item at the bottom of the list.
parent
Optional: Defines the parent menu item to nest the current item under.
enabled
Optional: When you set this to false, you can remove a menuItem from the sidebar.
Important

If menu_item_name represents a plugin menu item, the name must match the corresponding path in dynamicRoutes. For example, if dynamicRoutes defines path: /my-plugin, the menu_item_name must be my-plugin.

Handling simple paths
  • For simple paths such as path: /my-plugin, the menu_item_name should be my-plugin.
Handling Complex Paths
  • For complex paths such as path: /metrics/users/info, the menu_item_name should represent the full path in dot notation (for example metrics.users.info).
  • Ignore trailing and leading slashes in paths as follows:

    • For path: /docs, the menu_item_name is docs.
    • For path: /metrics/users, the menu_item_name is metrics.users.
Note

Red Hat Developer Hub supports up to three levels of nested menu items.

14.2.6.8. Using mount points

Red Hat Developer Hub defines mount points as identifiers available across the application. You can use these points to extend existing pages with additional content.

14.2.6.9. Display the front-end plugin

Use this procedure to configure and display a front-end plugin in the Red Hat Developer Hub UI.

Procedure

  1. Update the pluginConfig section of your dynamic-plugins.yaml file to specify how to add the Entity Feedback to the Red Hat Developer Hub UI.

    dynamic-plugins.yaml file fragment

    - package: oci://quay.io/_<user_name>_/entity-feedback-plugin:0.5.0
      disabled: false
      pluginConfig:
        dynamicPlugins:
          frontend:
            backstage-community.plugin-entity-feedback:
              entityTabs:
                - mountPoint: entity.page.feedback
                  path: /feedback
                  title: Feedback
              mountPoints:
                - config:
                    layout:
                      gridColumn: 1 / -1
                  importName: StarredRatingButtons
                  mountPoint: entity.page.feedback/cards
                - config:
                    layout:
                      gridColumn: 1 / -1
                  importName: EntityFeedbackResponseContent
                  mountPoint: entity.page.feedback/cards
                - config:
                    layout:
                      gridColumnEnd:
                        lg: span 6
                        md: span 6
                        xs: span 6
                  importName: StarredRatingButtons
                  mountPoint: entity.page.overview/cards

    where:

    backstage-community.plugin-entity-feedback:entityTabs
    Enter the entityTabs array to define a new tab, named “Feedback” on the Entity Overview screen in Red Hat Developer Hub.
    frontend:mountPoints
    This array defines the following configurations to mount React components exposed by the plugin:
  2. This configuration adds the StarredRatingButtons component to the new Feedback tab defined in entityTabs.
  3. Similar to the StarredRatingButtons, this configuration mounts the EntityFeedbackResponseContent on the Feedback tab.
  4. This configuration adds the StarredRatingButtons to the default Overview tab for each entity.
  5. To complete installing the Entity Feedback plugins, you must redeploy your Red Hat Developer Hub instance.

Verification

When your new instance of Red Hat Developer Hub has started, you can check that your plugins install and enable by visiting the Administration > Extensions screen and searching for “entity” on the Installed tab.

Custom extensions in the Extensions page

When you click Catalog, you should see the new Feedback tab, and the StarredRatingButtons displayed, as follows:

Entity view showing the Feedback tab and StarredRatingButtons

Selecting a low star rating prompts the user to offer feedback, as follows:

Feedback overlay dialog prompting for user feedback
Note

The system does not save user feedback if you log in as the Guest user.

14.2.7. Configure route bindings and mount points for component integration

14.2.7.1. Configure route bindings and mount points for component integration

Bind dynamic plugins to existing routes and attach custom UI components to predefined mount points. Route bindings and mount points enable plugins to extend entity pages, application headers, and providers without modifying the core platform layout.

14.2.7.2. Bind dynamic plugins to existing routes

You can bind to existing plugins and their routes, and declare new targets sourced from dynamic plugins as shown in the following routeBindings configuration:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin:
            routeBindings:
              targets:
                - name: <plugin_name>Plugin
                  importName: <plugin_key>Plugin
                  module: CustomModule
              bindings:
                - bindTarget: "<plugin_name>Plugin.externalRoutes"
                  bindMap:
                    headerLink: "<plugin_name>Plugin.routes.root"

where:

my-plugin
The plugin package name.
targets
A new bind target.
name
Optional: Defaults to importName. Explicit name of the plugin that exposes the bind target.
importName
Required: Explicit import name that references a BackstagePlugin<{}> implementation.
module
Optional: Same as the key in scalprum.exposedModules in the package.json file of the plugin.
bindTarget
Required: One of the supported or imported bind targets.
bindMap
Required: A map of route bindings similar to bind function options.

To configure routeBindings, complete the following steps:

  1. Define new targets using routeBindings.targets. Set the required importName to a BackstagePlugin<{}> implementation.
  2. Declare route bindings using the routeBindings.bindings field by setting bindTarget to the name of the target to bind to. This is a dynamic or static target, such as:

    • catalogPlugin.externalRoutes
    • catalogImportPlugin.externalRoutes
    • techdocsPlugin.externalRoutes
    • scaffolderPlugin.externalRoutes

      You can extend existing pages with additional content by using mount points. The application defines these identifiers throughout the system.

14.2.7.3. Configure mount points to attach custom UI components

14.2.7.3.1. Configure mount points to attach custom UI components

Attach UI components to predefined locations in the Red Hat Developer Hub interface by using mount points. Mount points let plugins inject content into entity pages, application headers, listeners, and providers without modifying the core application code.

14.2.7.3.2. Customize the entity page

You can extend catalog components and additional views.

The available mount points include the following:

Mount pointDescriptionVisible even when you enable no plugins

admin.page.plugins

Administration plugins page

NO

admin.page.rbac

Administration RBAC page

NO

entity.context.menu

Catalog entity menu

YES for all entities

entity.page.overview

Catalog entity overview page

YES for all entities

entity.page.topology

Catalog entity Topology tab

NO

entity.page.issues

Catalog entity Issues tab

NO

entity.page.pull-requests

Catalog entity Pull Requests tab

NO

entity.page.ci

Catalog entity CI tab

NO

entity.page.cd

Catalog entity CD tab

NO

entity.page.kubernetes

Catalog entity Kubernetes tab

NO

entity.page.image-registry

Catalog entity Image Registry tab

NO

entity.page.monitoring

Catalog entity Monitoring tab

NO

entity.page.lighthouse

Catalog entity Lighthouse tab

NO

entity.page.api

Catalog entity API tab

YES for entity of kind: Component and spec.type: 'service'

entity.page.dependencies

Catalog entity Dependencies tab

YES for entity of kind: Component

entity.page.docs

Catalog entity Documentation tab

YES for entity that satisfies isTechDocsAvailable

entity.page.definition

Catalog entity Definitions tab

YES for entity of kind: Api

entity.page.diagram

Catalog entity Diagram tab

YES for entity of kind: System

search.page.types

Search result type

YES, default catalog search type is available

search.page.filters

Search filters

YES, default catalog kind and lifecycle filters are visible

search.page.results

Search results content

YES, default catalog search is present

Note

Mount points within a catalog such as entity.page. render as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.

Each entity.page. mount point has the following variations:

  • /context type that serves to create React contexts
  • /cards type for regular React components

The following is an example of the overall configuration structure of a mount point:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-plugin: # The plugin package name
            mountPoints: # (Optional): Uses existing mount points
              - mountPoint: <mountPointName>/[cards|context]
                module: CustomModule
                importName: <pluginName>PluginPage
                config: # (Optional): Lets you pass additional configuration to the component
                  layout: {} # Used only in /cards type
                  if:  # Used only in /cards type
                    allOf|anyOf|oneOf:
                      - isMyPluginAvailable
                      - isKind: component
                      - isType: service
                      - hasAnnotation: annotationKey
                  props: {} # React props passed to the component

Each mount point supports additional configuration:

  • layout: Used only in */cards type which renders visible content. Lets you pass MUI sx properties to the component. This is useful when you want to control the layout of the component. The entity.page.* mount points are rendered as CSS grid, so SX property lets you to control the grid layout and exact positioning of the rendered component.
  • props: React props passed to the component. Useful when you want to pass additional data to the component.
  • if: Used only in \*/cards type which renders visible content. Passed to <EntitySwitch.Case if={<here>}.

The available conditions include:

  • allOf: The configuration must meet all conditions
  • anyOf: The configuration must meet at least one condition
  • oneOf: The configuration must meet only one condition

Conditions are:

  • isKind: Accepts a string or a list of string with entity kinds. For example isKind: component renders the component only for entity of kind: Component.
  • isType: Accepts a string or a list of string with entity types. For example isType: service renders the component only for entities of spec.type: 'service'.
  • hasAnnotation: Accepts a string or a list of string with annotation keys. For example hasAnnotation: my-annotation renders the component only for entities that have defined metadata.annotations['my-annotation'].
  • Condition imported from the module of the plugin: Must be function name exported from the same module within the plugin. For example isMyPluginAvailable renders the component only if isMyPluginAvailable function returns true. The function must have the following signature: (e: Entity) ⇒ boolean.

The entity page supports adding more items to the menu at the top right of the page. The exported component is a form of dialog wrapper component that accepts an open boolean property and an onClose event handler property as shown in the following example:

export type SimpleDialogProps = {
  open: boolean;
  onClose: () => void;
};

You can configure the menu entry by using the props configuration entry for the mount point. The title and icon properties sets the text and icon of the menu item. You can use any system icon or icon added through a dynamic plugin. The following is an example configuration:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          my-dynamic-plugin-package:
            appIcons:
              - name: dialogIcon
                importName: DialogIcon
            mountPoints:
              - mountPoint: entity.context.menu
                importName: SimpleDialog
                config:
                  props:
                    title: Open Simple Dialog
                    icon: dialogIcon
14.2.7.3.3. Add application headers

You can customize global headers by specifying configurations in the app-config.yaml file as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin:  # The plugin package name
      mountPoints:
        - mountPoint: application/header # Adds the header as a global header
          importName: <header_component> # Specifies the component exported by the global header plugin
          config:
            position: above-main-content # Supported values: (`above-main-content`| above-sidebar`)
Note

To configure many global headers at different positions, add entries to the mountPoints field.

14.2.7.3.4. Add application listeners

You can add application listeners by using the application/listener mount point as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      mountPoints:
        - mountPoint: application/listener
          importName: <exported listener component>
Note

You can configure many application listeners by adding entries to the mountPoints field.

14.2.7.3.5. Add application providers

You can add application providers by using the application/provider mount point. You can use a mount point to configure a context provider as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      dynamicRoutes:
        - path: /<route>
          importName: Component # The component to load on the route
      mountPoints:
        - mountPoint: application/provider
          importName: <exported provider component>
Note
  1. You can configure many application providers by adding entries to the mountPoints field.
  2. The package_name key under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin. This ensures your dynamic plugin loads correctly at runtime.

14.2.7.4. Customize and extend catalog entity tabs

You can customize and extend the set of tabs by using the entityTabs configuration as in the following example:

# dynamic-plugins-config.yaml
plugins:
  - plugin: <plugin_path_or_url>
    disabled: false
    pluginConfig:
      dynamicPlugins:
        frontend:
          <package_name>: # The plugin package name
            entityTabs:
              # Specifies a new tab
              - path: /new-path
                title: My New Tab
                mountPoint: entity.page.my-new-tab
              # Changes an existing tab's title or mount point
              - path: /
                title: General
                mountPoint: entity.page.overview # Can be customized
                # Specifies the sub-path route in the catalog where this tab is available
              - path: "/pr"
                title: "Changed Pull/Merge Requests" # Specifies the title you want to display
                priority: 1
                # The base mount point name available on the tab
                mountPoint: "entity.page.pull-requests"
              - path: "/"
                title: "Changed Overview"
                mountPoint: "entity.page.overview"
                # Specifies the order of tabs. The tabs with higher priority values appear first
                priority: -6

Each entity tab entry requires the following attributes: * path: Specifies the sub-path route in the catalog where this tab is available. * title: The title displayed to the user. * mountPoint: The base mount point name available on the tab. This name is expanded to create two mount points per tab, one appended with /context and the second appended with /cards. * priority: (Optional): Determines the order of tabs. Tabs with higher priority values appear first. You can set a negative priority to hide default tabs.

You can configure dynamic front-end plugins to target the mount points exposed by the entityTabs configuration. The following are the default catalog entity routes in the default order:

RouteTitleMount PointEntity Kind

/

Overview

entity.page.overview

Any

/topology

Topology

entity.page.topology

Any

/issues

Issues

entity.page.issues

Any

/pr

CPull/Merge Requests

entity.page.pull-requests

Any

/ci

CI

entity.page.ci`

VAny

/cd

CD

entity.page.cd

Any

/kubernetes

Kubernetes

entity.page.kubernetes

Any

/image-registry

Image Registry

entity.page.image-registry

Any

/monitoring

Monitoring

entity.page.monitoring

Any

/lighthouse

Lighthouse

entity.page.lighthouse

Any

/api

Api

entity.page.api

kind: Service or kind: Component

/dependencies

Dependencies

entity.page.dependencies

kind: Component

/docs

Docs

entity.page.docs

Any

/definition

Definition

entity.page.definition

kind: API

/system

Diagram

entity.page.diagram

kind: System

Note

Mount points within Catalog such as `entity.page.*` render as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.

14.2.7.5. Customize the platform theme using front-end plugins

You can customize Developer Hub themes from a dynamic plugin with various configurations as shown in the following example:

import { lightTheme } from './lightTheme';
import { darkTheme } from './darkTheme';
import { UnifiedThemeProvider } from '@backstage/theme';
export const lightThemeProvider = ({ children }: { children: ReactNode }) => (
  <UnifiedThemeProvider theme={lightTheme} children={children} />
);
export const darkThemeProvider = ({ children }: { children: ReactNode }) => (
  <UnifiedThemeProvider theme={darkTheme} children={children} />
);

For more information about creating a custom theme, see creating a custom theme.

You can declare the theme by using the themes configuration as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      themes:
          #  are `light` or `dark`. Using 'light' overrides the app-provided light theme
        - id: light
          title: Light
          variant: light
          icon: someIconReference
          importName: lightThemeProvider
          # The theme name displayed to the user on the *Settings* page. Using 'dark' overrides the app-provided dark theme
        - id: dark
          title: Dark
          variant: dark
          icon: someIconReference # A string reference to a system or app icon
          # The name of the exported theme provider function, the function signature should match `({ children }: { children: ReactNode }): React.JSX.Element`
          importName: darkThemeProvider

14.2.8. Configure specialized front-end extensions for APIs and features

14.2.8.1. Configure specialized front-end extensions for APIs and features

Configure specialized front-end extensions including custom sign-in pages, Scaffolder field extensions, utility APIs, authentication provider settings, and TechDocs add-ons. These extensions enable advanced UI customization beyond standard route and mount point configuration.

14.2.8.2. Configure custom sign-in pages for authentication

In Red Hat Developer Hub (RHDH), the SignInPage component manages authentication flow. By default, Developer Hub uses a static SignInPage.

When you configure a custom SignInPage:

  • Only one signInPage is specified and used by the application.
  • The system loads the specified importName component from your dynamic plugin.
  • The component returns a configured SignInPage that connects the required authentication provider factories.
  • The optional module field specifies the set of assets that should be accessed within the dynamic plugin. By default, the system uses the PluginRoot module.
dynamicPlugins:
  frontend:
    <package_name>: # The plugin package name
      signInPage:
        importName: CustomSignInPage
Important

The package_name specified under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin to ensure the dynamic plugin loads correctly at runtime.

14.2.8.3. Add custom Scaffolder field extensions

With the Scaffolder component in Red Hat Developer Hub (RHDH), you can create software components by using templates through a guided wizard. You can extend the functionality of the Scaffolder by adding custom form fields as dynamic plugins by using the scaffolderFieldExtensions configuration.

With custom field extensions, you can add specialized form fields that capture domain-specific data during the scaffolding process, such as environment selectors, input validations, or repository checks.

When you configure custom Scaffolder field extensions:

  • The dynamic plugin exposes the field extension component using createScaffolderFieldExtension.
  • You can register multiple field extensions by listing each one in the configuration.
  • Each field extension requires a unique importName for registration. The name should reference the value returned by the scaffolder field extension API.
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      scaffolderFieldExtensions:
        - importName: MyNewFieldExtension # References the exported Scaffolder field extension component from your plugin
Note

The module field is optional and specifies which set of assets to access within the plugin. By default, the system uses the PluginRoot module, consistent with the scalprum.exposedModules key in the package.json file of your package.

14.2.8.4. Configure additional utility APIs

If a dynamic plugin exports the plugin object returned by createPlugin, the createApp API receives it. All API factories exported by the plugin are automatically registered and available in the front-end application.

You can add an entry to the dynamicPlugins.frontend configuration when a dynamic plugin has only API factories as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-dynamic-plugin-package-with-api-factories: {}

However, when the dynamic plugin is not exporting the plugin object, you must explicitly configure each API factory. Use the apiFactories configuration to register them with the createApp API as shown in the following example:

# app-config.yaml
dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      apiFactories:
        # (Optional): Specify the import name that references a `AnyApiFactory<{}>` implementation. (Defaults to `default` export)
        - importName: BarApi
          # (Optional): An argument which specifies the assets you want to access within the plugin. If not provided, the default module named `PluginRoot` is used
          module: CustomModule

An API factory from a dynamic plugin overrides the API factories that the Developer Hub application initializes when both specify the same API ref ID. A dynamic plugin can export AnyApiFactory<{}> to cater for some specific use case as shown in the following example:

export const customScmAuthApiFactory = createApiFactory({
  api: scmAuthApiRef,
  deps: { githubAuthApi: githubAuthApiRef },
  factory: ({ githubAuthApi }) =>
    ScmAuth.merge(
      ScmAuth.forGithub(githubAuthApi, { host: "github.someinstance.com" }),
      ScmAuth.forGithub(githubAuthApi, {
        host: "github.someotherinstance.com",
      }),
    ),
});

The corresponding configuration that overrides the default ScmAuth API factory that Developer Hub defaults to is as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin:  # The plugin package name
      apiFactories:
        - importName: customScmAuthApiFactory

14.2.8.5. Add custom authentication provider settings to verify identities

You can install new authentication providers from a dynamic plugin that either adds additional configuration support for an existing provider or adds a new authentication provider. The user settings section lists these providers under the Authentication Providers tab.

You can use the providerSettings configuration to add entries for an authentication provider from a dynamic plugin, as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      providerSettings:
        # The title for the authentication provider shown above the user's profile image if available
        - title: My Custom Auth Provider
          # The description of the authentication provider
          description: Sign in using My Custom Auth Provider
          # The ID of the authentication provider as provided to the `createApiRef` API call.
          provider: core.auth.my-custom-auth-provider
Note

provider looks up the corresponding API factory for the authentication provider to connect the provider’s Sign In/Sign Out button.

14.2.8.6. Configure custom TechDocs add-ons

If a plugin provides many add-ons, each techdocsAddon entry specifies a unique importName corresponding to the add-on. Front-end plugins expose the TechDocs add-on component by using the techdocsAddons configuration as shown in the following example:

dynamicPlugins:
  frontend:
    my-plugin: # The plugin package name
      techdocsAddons:
        - importName: ExampleAddon # The exported add-on component
          config:
            props: ... # (Optional): React props to pass to the add-on

14.2.9. Filter plugins by support badges

14.2.9.1. Filter plugins by support badges

Filter available plugins by support level and maturity badges to identify production-ready components. Support badges classify plugins by support tier and development maturity to help you assess production readiness.

14.3. Develop custom dynamic plugins to support custom workflows

14.3.1. Develop custom dynamic plugins to support custom workflows

Develop, package, and deploy custom dynamic plugins when standard plugins do not meet organizational requirements. Custom plugin development enables teams to extend Red Hat Developer Hub with bespoke functionality and business logic.

14.3.2. Prepare your development environment to write custom plugins

14.3.2.1. Prepare your development environment to write custom plugins

Set up the required development toolchain including Node.js, NPM, Yarn, and the Red Hat Developer Hub Plugin Factory to begin developing custom dynamic plugins.

14.3.2.2. The development toolchain

Before creating or converting plugins for Red Hat Developer Hub (RHDH), set up a local development toolchain to write, convert, and package plugins for deployment.

Required skills and languages: To develop dynamic plugins, you must have experience with the following:

JavaScript and TypeScript
Used for Backstage frontend and backend development.
React
Used for building frontend plugin components.
Node.js ecosystem
Includes package management (NPM/Yarn) and module handling.
14.3.2.2.1. The development toolchain

The following tools are required to initialize, build, and package your plugins:

Node.js (via NVM)

Node.js is the engine that runs JavaScript on your computer.

RHDH requires Node v22. Use Node Version Manager (NVM) to switch between Node versions and ensure compatibility with the RHDH backend system.

Yarn 4

Yarn is a package manager that handles all the library dependencies that your application needs.

The Backstage project structure is optimized for Yarn (specifically Yarn Classic 1.x) to manage workspaces and dependencies efficiently.

Containerization tools (Docker or Podman)

These tools used to run containers and package applications.

  • Packaging: Dynamic plugins are distributed as OCI images. Use Docker or Podman to package your derived plugin assets into an image that can be pushed to a registry, for example, Quay.io and sideloaded into RHDH.
RHDH plugin tools

These specialized tools convert standard plugins into the dynamic architecture required by RHDH.

  • RHDH Plugin Factory and rhdh-cli: These tools assist converting existing standard Backstage plugins into the RHDH dynamic plugin format.
  • rhdh-cli (@red-hat-developer-hub/cli): This command-line tool is critical for the export process. It allows you to run commands like export-dynamic-plugin, which repackages your code into a derived package containing the necessary configuration (like Scalprum for frontend) and dependency handling (bundling private dependencies versus sharing platform dependencies)

Additional resources

14.3.3. Develop and test new plugin components locally

14.3.3.1. Develop and test new plugin components locally

Create, implement, and test new plugin components in a local development environment before deploying to a cluster. Local development with a Backstage application enables rapid iteration and debugging of plugin functionality.

14.3.3.2. Determine RHDH version

To ensure your plugin uses dependencies compatible with the RHDH instance that it will run on, check the target RHDH version and identify the compatible Backstage version.

Table 14.1. RHDH compatibility matrix

RHDH versionBackstage versioncreate-app version

1.9

1.45.3

0.7.6

1.8

1.42.5

0.7.3

1.7

1.39.1

0.6.2

14.3.3.3. Create a new Backstage application

To ensure that you use the compatible version of the Backstage CLI to create your plugin, create a new Backstage application in your workspace by using the create-app command.

Prerequisites

  • Determine the create-app version based on the RHDH compatibility matrix.

Procedure

  1. Create a directory for your workspace:

    $ mkdir rhdh-plugin-dev
    $ cd rhdh-plugin-dev
  2. Initialize the Backstage application:

    $ npx @backstage/create-app@0.7.6 --path .

Verification

Your workspace should contain the following:

  1. packages/app/ folder
  2. packages/backend/ folder
  3. plugins/ folder
  4. package.json file containing the Backstage dependencies.

14.3.3.4. Create a new plugin

Use the yarn new command to create a new Backstage plugin in your application root folder with the appropriate folder structure and configuration files.

Prerequisites

  • You have created a Backstage application.

Procedure

  1. In your Backstage application root folder, create a new plugin by using the yarn new command, for example:

    $ cd rhdh-plugin-dev
    $ yarn new

    Output from the yarn new command:

    ? What do you want to create? (Use arrow keys)
    ❯ frontend-plugin - A new frontend plugin
      backend-plugin - A new backend plugin
      backend-plugin-module - A new backend module that extends an existing backend plugin
      plugin-web-library - A new web library plugin package
      plugin-node-library - A new Node.js library plugin package
      plugin-common-library - A new isomorphic common plugin package
      web-library - A library package, exporting shared functionality for web environments
  2. Select the type of plugin to create, for example, frontend-plugin.
  3. Enter the ID of the plugin, for example:

    ? What do you want to create? frontend-plugin - A new frontend plugin
    ? Enter the ID of the plugin [required] simple-example
  4. (Optional) To preview your plugin with RHDH styling, configure the RHDH theme package in the plugin:

    $ cd plugins/simple-example
    $ yarn add --dev @red-hat-developer-hub/backstage-plugin-theme

    Update dev/index.tsx file, as follows, to use RHDH themes:

    // Import the RHDH themes from the plugin
    import { getAllThemes } from '@red-hat-developer-hub/backstage-plugin-theme';
    // ...
    // ...
    createDevApp()
      // ...
      // ...
      // Add RHDH themes to the development harness
      .addThemes(getAllThemes())
      .render();
    Note

    This configuration is only for the local development harness (dev/index.tsx). When deployed to RHDH, the application provides theming automatically.

Verification

The system generates a new Backstage plugin using your provided ID, then automatically builds and integrates it into the application. The plugins/simple-example/ directory must exist with src/, dev/ folders, and a package.json file.

You can also serve the plugin in isolation by running yarn start in the plugin directory, for example:

$ cd plugins/simple-example
$ yarn start

14.3.3.5. Implement a plugin component

By default, the frontend plugin already has a sample page component defined in src/components/ExampleComponent/. This page is automatically registered in src/plugin.ts as SimpleExamplePage.

One of the common extensions is to create a new entity card component.

Procedure

  1. In the src/components/ directory create an ExampleCard sub-directory.
  2. Create an ExampleCard.tsx file, as follows:

    import React from 'react';
    import { InfoCard } from '@backstage/core-components';
    import { useEntity } from '@backstage/plugin-catalog-react';
    
    export const ExampleCard = () => {
      const { entity } = useEntity();
      return (
        <InfoCard title="Simple Example Info">
          <p>Entity: {entity.metadata.name}</p>
        </InfoCard>
      );
    };
  3. In the src/components/ExampleCard directory, create and edit the index.ts file, as follows:

    export { ExampleCard } from './ExampleCard';
  4. To register the new entity card component, edit the src/plugin.ts file to add the new component to the plugin, as follows:

    import { createComponentExtension } from '@backstage/core-plugin-api';
    
    // ...
    // ...
    export const ExampleCard = simpleExamplePlugin.provide(
      createComponentExtension({
        name: 'ExampleCard',
        component: {
          lazy: () =>
            import('./components/ExampleCard').then(m => m.ExampleCard),
        },
      }),
    );
  5. Export all components in src/index.ts so they can be loaded dynamically:

    export { simpleExamplePlugin, SimpleExamplePage, ExampleCard } from './plugin';

Verification

Your plugin should have the following new files:

  1. src/components/ExampleCard/ExampleCard.tsx
  2. src/components/ExampleCard/index.ts.

The src/plugin.ts should export ExampleCard, and src/index.ts should re-export it.

14.3.3.6. Test a plugin locally

You can test a plugin locally by using your Backstage application.

Note

You can also use RHDH Local to test your plugins by copying the generated dist-dynamic/ folder contents to the RHDH Local local-plugins folder. For more details, see Verify plugins locally.

For example, to test your component card locally in your Backstage application by using the development harness, update the dev/index.tsx file to include the new component card.

This file is the entry point for the Local Development Sandbox, it serves as a testing harness.

When you are developing a plugin, you do not need to boot up an entire Backstage (or RHDH) production-grade instance just to see a UI change. Instead, you use the Dev App which is a lightweight, stripped-down version of the Backstage frontend.

Primary functions of the Dev App:

Plugin isolation
It allows you to run your plugin in a standalone wrapper. This is what loads when you run yarn start from within the plugin directory.
Mocking the environment
Since the plugin usually expects to live inside a Backstage App, dev/index.tsx provides the necessary context:
Identity mocks
Simulating a logged-in user.
API mocks
Registering test versions of APIs (similar to a mock CatalogApi) so the plugin doesn’t try to call a real backend that isn’t there.
Route registration
It defines how the plugin is mounted within this mini-dev-app, usually using createDevApp().

Procedure

  1. Add Backstage dependencies:

    $ yarn add @backstage/catalog-model @backstage/plugin-catalog-react
  2. Edit your dev/index.tsx file, as follows:

    // ...
    // ...
    import { Entity } from '@backstage/catalog-model';
    import { EntityProvider } from '@backstage/plugin-catalog-react';
    import { Page, Header, Content } from '@backstage/core-components';
    import { Grid } from '@material-ui/core';
    import { ExampleCard } from '../src/plugin';
    
    
    // Mock entity for the component card
    const mockEntity: Entity = {
      apiVersion: 'backstage.io/v1alpha1',
      kind: 'Component',
      metadata: {
        name: 'example-service',
        description: 'An example service component for plugin development.',
        annotations: {
          'backstage.io/techdocs-ref': 'dir:.',
        },
      },
      spec: {
        type: 'service',
        lifecycle: 'production',
        owner: 'team-platform',
      },
    };
    
    // Create a page with the mock entity and the component card
    const entityPage = (
      <EntityProvider entity={mockEntity}>
        <Page themeId="service">
          <Header
            title={mockEntity.metadata.name}
            subtitle={`${mockEntity.kind} · ${mockEntity.spec?.type}`}
          />
          <Content>
            <Grid container spacing={3} alignItems="stretch">
              <Grid item md={6} xs={12}>
                <ExampleCard />
              </Grid>
            </Grid>
          </Content>
        </Page>
      </EntityProvider>
    );
    
    createDevApp()
      // ...
      // ...
      .addPage({
        element: entityPage,
        title: 'Entity Page',
        path: '/simple-example/entity',
      })
      // ...
      // ...
      .render();
  3. Run the development server:

    $ yarn start

Verification

Navigate to http://localhost:3000/simple-example/entity in your browser. You should see the Entity Page with your ExampleCard component displaying "Entity: example-service".

14.3.3.7. Integrate custom user interface components

Front-end plugin wiring integrates dynamic front-end plugin components, such as new pages, UI extensions, icons, and APIs, into Red Hat Developer Hub.

Because the dynamic plugins load at runtime, the core application must discover and connect the exported assets of the plugin to the appropriate user interface systems and locations.

Procedure

  • Register and configure dynamic front-end plugins in the dynamic-plugins.yaml file.

    Important

    If you are using RHDH Local for development and testing, use dynamic-plugins.override.yaml instead.

    This configuration determines how the plugin is integrated with the RHDH interface, such as adding routes, sidebar menu items, and mount points.

    dynamic-plugins.yaml example

    plugins:
      # Option 1: Load from an OCI image
      - package: oci://quay.io/<namespace>/simple-example:v0.1.0
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              # The package name must match package.json
              internal.backstage-plugin-simple-example:
                dynamicRoutes:
                  - path: /simple-example
                    # Must match the export in src/index.ts
                    importName: SimpleExamplePage
                    menuItem:
                      icon: extension
                      text: Simple Example
                mountPoints:
                  - mountPoint: entity.page.overview/cards
                    # Must match the export in src/index.ts
                    importName: ExampleCard
                    config:
                      layout:
                        gridColumnEnd: 'span 4'
                      if:
                        allOf:
                          - isKind: component
    
      # Option 2: Load from local directory (for local RHDH testing)
      # - package: ./local-plugins/simple-example
      #   disabled: false
      #   pluginConfig: ... (same as above)

Verification

After restarting RHDH, confirm that Simple Example appears in the sidebar menu. Click Simple Example and verify that the plugin page displays correctly. Navigate to a Component entity page and verify that the ExampleCard appears in the Overview tab.

Additional resources

14.3.4. Convert standard plugins into dynamic plugins using the Plugin Factory

14.3.4.1. Convert standard plugins into dynamic plugins using the Plugin Factory

Convert standard Backstage plugins into dynamic plugins by using the Dynamic Plugin Factory. The factory model automates the export and packaging process to produce runtime-loadable plugin packages compatible with Red Hat Developer Hub.

14.3.4.2. The dynamic plugin factory model

You can automate the conversion and packaging of standard Backstage plugins into RHDH dynamic plugins by using the RHDH Dynamic Plugin Factory tool.

Important

Red Hat maintains the Dynamic Plugin Factory as an open source project, but does not support it or subject it to any service level agreement (SLA).

Manually converting Backstage plugins to RHDH dynamic plugins requires configuring webpack, managing dependencies, and building container images. This process can be both time-consuming and error-prone. The Dynamic Plugin Factory automates this entire workflow, providing a reproducible way to convert plugins from source code to deployable containers without requiring deep knowledge of build tools.

This approach is particularly valuable when you are:

  • Converting multiple community plugins from the Backstage marketplace.
  • Testing custom plugin changes during active development.
  • Ensuring consistent builds across development teams.
  • Applying patches to plugin source code before building.
14.3.4.2.1. How the Dynamic Plugin Factory works

The core function of the Dynamic Plugin Factory tool is to streamline the dynamic plugin build process, offering the following capabilities:

Source repository management
Clones and checks out plugin source repositories.
Multi-workspace support
Exports plugins from multiple workspaces across different repositories in a single run.
Patch and overlay system
Applies custom modifications to plugin source code before exporting.
Dependency management
Automates yarn installation with TypeScript compilation, and automated private dependency handling for backend dynamic plugins.
Dynamic plugin packaging
Builds, exports and, packages plugins using the RHDH CLI.
Container image publishing
Optionally pushes to container registries such as Quay or OpenShift.

The Dynamic Plugin Factory tool provides a simplified, reproducible method for developers and platform engineers to create and test dynamic plugins. Using a pre-configured dynamic plugin factory container and documentation, the tool eases migration and testing.

Additional resources

14.3.4.3. Convert a custom plugin into a dynamic plugin

Use the RHDH CLI to convert a custom plugin into a dynamic plugin format and package it as a container image for deployment.

Procedure

  1. Use the RHDH CLI to prepare the plugin you want to export. The following command uses the plugin files in the dist folder that was generated by the yarn build:all command, and creates a dist-dynamic folder containing a dist-scalprum sub-folder that contains the necessary configuration and source files to enable dynamic loading:

    cd plugins/simple-example
    npx @red-hat-developer-hub/cli@latest plugin export

    When this command packages a frontend plugin, it uses a default Scalprum configuration if one is not found. The Scalprum configuration is used to specify the plugin entry point and exports, and then to build a dist-scalprum folder that contains the dynamic plugin. The default Scalprum configuration is suitable for most plugins.

  2. Package the plugin into a container image and publish it to Quay.io.

    export QUAY_USER=_<username>_
    export PLUGIN_NAME=simple-example
    export VERSION=$(cat package.json | jq .version -r)
    npx @red-hat-developer-hub/cli@latest plugin package --tag quay.io/$QUAY_USER/$PLUGIN_NAME:$VERSION
  3. Push to Quay.io

    podman push quay.io/$QUAY_USER/$PLUGIN_NAME:$VERSION

14.3.5. Package and deploy dynamic plugins as OCI images

14.3.5.1. Package and deploy dynamic plugins as OCI images

Package dynamic plugins as OCI images and deploy them to container registries for distribution. OCI packaging enables versioned, portable plugin artifacts that integrate with standard container workflows and air-gapped deployment strategies.

14.3.5.2. Deploy custom dynamic plugins

To add a custom dynamic plugin to Red Hat Developer Hub, update the dynamic-plugins.yaml file with the configuration generated by the RHDH CLI packaging command.

plugins:
  - package: oci://quay.io/<account-name>/<image-name>:_<tag>_
    disabled: false
    pluginConfig: {}
Note

If you are using RHDH Local for development and testing, use the dynamic-plugins.override.yaml file instead.

Procedure

  • Add the plugin configuration to the dynamic-plugins.yaml file.

    The following example integrates a plugin named simple-example with RHDH and includes the plugin-config that you must add to display a frontend plugin:

    plugins:
      # Option 1: Load from an OCI image
      - package: oci://quay.io/<namespace>/simple-example:v0.1.0
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              # The package name must match package.json (usually internal.backstage-plugin-<id>)
              internal.backstage-plugin-simple-example:
                dynamicRoutes:
                  - path: /simple-example
                    # Must match the export in src/index.ts
                    importName: SimpleExamplePage
                    menuItem:
                      icon: extension
                      text: Simple Example
                mountPoints:
                  - mountPoint: entity.page.overview/cards
                    # Must match the export in src/index.ts
                    importName: ExampleCard
                    config:
                      layout:
                        gridColumnEnd: 'span 4'
                      if:
                        allOf:
                          - isKind: component
    +
      # Option 2: Load from local directory (for local RHDH testing)
      # - package: ./local-plugins/simple-example
      #   disabled: false
      #   pluginConfig: ... (same as above)

    where

    frontend:dynamic-routes
    Enter the sidebar menu item and the plugin route.
    frontend:mountPoints

    Enter the configuration to mount components exposed by the plugin.

    Note

    Ensure that your container images are publicly accessible, or that you have configured a pull secret in your environment. A pull secret provides Red Hat Developer Hub with credentials to authenticate pulling your plugin container images from a container registry. For more details, see Loading a plugin packaged as an OCI image.

14.3.5.3. Add a custom dynamic plugin to Red Hat Developer Hub

Use this procedure to add custom dynamic plugins to Red Hat Developer Hub by updating the dynamic-plugins.yaml configuration file.

Procedure

  • To add your custom dynamic plugins to Red Hat Developer Hub, update the dynamic-plugins.yaml file by using the following configuration that the npx @red-hat-developer-hub/cli@latest plugin package command generates:

    plugins:
      - package: oci://quay.io/_<user_name>_/entity-feedback-plugin:0.5.0
        disabled: false
      - package: oci://quay.io/_<user_name>_/entity-feedback-plugin-backend:0.6.0
        disabled: false
    Note

    Ensure that your container images are publicly accessible, or that you have configured a pull secret in your environment. A pull secret provides Red Hat Developer Hub with credentials to authenticate pulling your plugin container images from a container registry.

14.3.5.4. Load a plugin packaged as a JavaScript package

Use this procedure to load a dynamic plugin from a JavaScript package into Red Hat Developer Hub.

Prerequisites

Procedure

  1. Run the following command to obtain the integrity hash from the NPM registry:

    $ npm view --registry <registry_link> <npm_package>@<version> dist.integrity
  2. Specify the package name, version, and its integrity hash in the dynamic-plugins.yaml file as follows:

    plugins:
      - disabled: false
        package: @example/backstage-plugin-myplugin@1.0.0
        integrity: sha512-9WlbgEdadJNeQxdn1973r5E4kNFvnT9GjLD627GWgrhCaxjCmxqdNW08cj+Bf47mwAtZMt1Ttyo+ZhDRDj9PoA==
  3. If you are using a custom NPM registry, create a .npmrc file with the registry URL and authentication details:

    registry=<registry_link>
    //<registry_link>:_authToken=<auth_token>
  4. When using OpenShift Container Platform or Kubernetes:

    1. Use the Helm chart to add the .npmrc file by creating a secret. For example:

      apiVersion: v1
      kind: Secret
      metadata:
        name: <release_name>-dynamic-plugins-npmrc
      type: Opaque
      stringData:
        .npmrc: |
          registry=<registry_link>
          //<registry_link>:_authToken=<auth_token>

      Replace <release_name> with your Helm release name. This name is a unique identifier for each chart installation in the Kubernetes cluster.

    2. For RHDH Helm chart, name the secret using the following format for automatic mounting:

      <release_name>-dynamic-plugins-npmrc

  5. To apply the changes, restart the RHDH application.

14.3.5.5. Load a plugin packaged as a TGZ file

Use this procedure to load a dynamic plugin from a TGZ file into Red Hat Developer Hub.

Prerequisites

Procedure

  1. Specify the archive URL and its integrity hash in the dynamic-plugins.yaml file using the following example:

    plugins:
      - disabled: false
        package: https://example.com/backstage-plugin-myplugin-1.0.0.tgz
        integrity: sha512-9WlbgEdadJNeQxdn1973r5E4kNFvnT9GjLD627GWgrhCaxjCmxqdNW08cj+Bf47mwAtZMt1Ttyo+ZhDRDj9PoA==
  2. To apply the changes, restart the RHDH application.

14.3.5.6. Create a JavaScript package with dynamic packages

Use this procedure to publish a dynamic plugin to a private NPM registry.

Warning

Do not publish the derived dynamic plugin JavaScript packages to the public NPM registry. If you must publish to the NPM registry, use a private registry.

Procedure

  1. Navigate to the dist-dynamic directory.
  2. Run the following command to publish the package to your private NPM registry:

    $ npm publish --registry <npm_registry_url>
    Tip

    You can add the following to your package.json file before running the export command:

    {
      "publishConfig": {
        "registry": "<npm_registry_url>"
      }
    }

    If you change publishConfig after exporting the dynamic plugin, re-run the plugin export command to ensure that the correct configuration is in the package.

14.3.5.7. Create a TGZ file with dynamic packages

Use this procedure to package a dynamic plugin as a TGZ file and host it on a web server.

Prerequisites

package-and-deploy-dynamic-plugins-as-oci-images

Procedure

  1. Navigate to the dist-dynamic directory.
  2. Run the following command to create a tgz archive:

    $ npm pack

    You can obtain the integrity hash from the output of the npm pack command by using the --json flag as follows:

    $ npm pack --json | head -n 10
  3. Host the archive on a web server accessible to your RHDH instance, and reference its URL in the dynamic-plugin-config.yaml file as follows:

    plugins:
      - package: https://example.com/backstage-plugin-myplugin-1.0.0.tgz
        integrity: sha512-<hash>
  4. Run the following command to package the plugins:

    $ npm pack --pack-destination ~/test/dynamic-plugins-root/
    Tip

    To create a plugin registry using HTTP server on OpenShift Container Platform, run the following commands:

    $ oc project my-rhdh-project
    $ oc new-build httpd --name=plugin-registry --binary
    $ oc start-build plugin-registry --from-dir=dynamic-plugins-root --wait
    $ oc new-app --image-stream=plugin-registry
  5. Configure your RHDH to use plugins from the HTTP server by editing the dynamic-plugin-config.yaml file:

    plugins:
      - package: http://plugin-registry:8080/backstage-plugin-myplugin-1.9.6.tgz

14.3.5.8. Create an OCI image with dynamic packages

Use this procedure to package a dynamic plugin as an OCI image and push it to a container registry.

Prerequisites

  • You have installed podman or docker.

Procedure

  1. Navigate to the plugin’s root directory (not the dist-dynamic directory).
  2. Run the following command to package the plugin into an OCI image:

    $ npx @red-hat-developer-hub/cli@latest plugin package --tag quay.io/example/image:v0.0.1

    In the earlier command, the --tag argument specifies the image name and tag.

  3. Ensure that your container runtime (podman or docker) is running and that you are logged in to the target image registry:

    $ podman login quay.io
  4. Run one of the following commands to push the image to a registry:

    $ podman push quay.io/example/image:v0.0.1
    $ docker push quay.io/example/image:v0.0.1

    The output of the package-dynamic-plugins command provides the plugin’s path for use in the dynamic-plugin-config.yaml file.

14.3.6. Verify plugins locally

RHDH Local enables you to test a dynamic plugin that you have built before publishing it to a registry.

During boot, the install-dynamic-plugins container reads the contents of the plugin configuration file and activates, configures, or downloads any plugins listed. RHDH Local supports two ways of specifying dynamic plugin configuration:

  • Default path: configs/dynamic-plugins/dynamic-plugins.yaml
  • User override path: configs/dynamic-plugins/dynamic-plugins.override.yaml

The dynamic-plugins.override.yaml configuration takes precedence over the dynamic-plugins.yaml configuration. You should not modify the default dynamic-plugins.yaml file, use the dynamic-plugins.override.yaml to override the default file settings.

In addition, the local-plugins directory is mounted into the install-dynamic-plugins container at /opt/app-root/src/local-plugins. Any plugins placed there can be activated or configured the same way without downloading.

Prerequisites

  • You have exported a custom plugin by using the npx @red-hat-developer-hub/cli@latest plugin export command that has generated a dist-dynamic directory containing the following:

    • dist-scalprum: A directory that contains the Webpack federated modules.
    • package.json: A modified version of your package.json file optimized for dynamic loading.

Procedure

  1. Copy the dist-dynamic directory directly into the local-plugins folder, for example:

    # Copy the dynamic distribution to {product-local-very-short}
    $ cp -r dist-dynamic/ <{product-very-short}_LOCAL_PATH>/local-plugins/example-plugin
    Note

    The local-plugins/simple-example/ directory in your RHDH Local installation should contain the plugin files from dist-dynamic directory, including the dist-scalprum directory and the package.json file

  2. Ensure that permissions allow the container to read the files.
  3. Configure your plugin in the configs/dynamic-plugins/dynamic-plugins.override.yaml file.

Additional resources

14.3.7. Export custom plugins in Red Hat Developer Hub

To use plugins in Red Hat Developer Hub, you can export plugins as derived dynamic plugin packages. These packages contain the plugin code and dependencies, ready for dynamic plugin integration into Developer Hub.

Prerequisites

  • You have installed the @red-hat-developer-hub/cli package. Use the latest version (@latest tag) for compatibility with the most recent features and fixes.

    Note

    Use the npx @red-hat-developer-hub/cli@latest plugin export command to export an existing custom plugin as a derived dynamic plugin package.

    You must use this command when you have the source code for a custom plugin and want to integrate it into RHDH as a dynamic plugin.

    The command processes the plugin’s source code and dependencies and generates the necessary output for dynamic loading by RHDH.

    For an example of using this command, see Example of installing a custom plugin in Red Hat Developer Hub.

  • You have installed and configured Node.js and NPM.
  • The custom plugin is compatible with your Red Hat Developer Hub version. For more information, see Version compatibility matrix.
  • The custom plugin must have a valid package.json file in its root directory, containing all required metadata and dependencies.

    Backend plugins

    To ensure compatibility with the dynamic plugin support and enable their use as dynamic plugins, existing backend plugins must be compatible with the new Backstage backend system. Additionally, these plugins must be rebuilt using a dedicated CLI command.

    You must export the new Backstage backend system entry point (created using createBackendPlugin() or createBackendModule()) as the default export from either the main package or an alpha package. Export as an alpha package if the plugin instance support still uses alpha APIs. This does not add any additional requirement on top of the standard plugin development guidelines of the plugin instance.

    The dynamic export mechanism identifies private dependencies and sets the bundleDependencies field in the package.json file. This export mechanism ensures that you publish the dynamic plugin package as a self-contained package, with its private dependencies bundled in a private node_modules folder.

    Certain plugin dependencies require specific handling in the derived packages, such as:

    • Shared dependencies: The RHDH application provides these dependencies and lists them as peerDependencies in the package.json file. The dynamic plugin package does not bundle shared dependencies. For example, by default, all @backstage scoped packages use sharing.

      You can use the --shared-package flag to specify shared dependencies that Red Hat Developer Hub application provides and that the dynamic plugin package does not bundle.

      To treat a @backstage package as private, use the negation prefix (!). For example, when a plugin depends on the package in @backstage that is not provided by the Red Hat Developer Hub application.

    • Embedded dependencies: The dynamic plugin package bundles these dependencies with their dependencies hoisted to the top level. By default, the package embeds packages with -node or -common suffixes.

      You can use the --embed-package flag to specify additional embedded packages. For example, packages from the same workspace that do not follow the default naming convention.

      The following is an example of exporting a dynamic plugin with shared and embedded packages:

      $ npx @red-hat-developer-hub/cli@latest plugin export --shared-package '!/@backstage/plugin-notifications/' --embed-package @backstage/plugin-notifications-backend

      In the earlier example:

    • The export treats the @backstage/plugin-notifications package as a private dependency and bundles it in the dynamic plugin package, despite being in the @backstage scope.
    • The export marks the @backstage/plugin-notifications-backend package as an embedded dependency and bundles it in the dynamic plugin package.
    Front-end plugins

    Front-end plugins can use scalprum for configuration. The CLI can generate this configuration automatically during the export process. When running the following command, the CLI logs the generated default configuration:

    $ npx @red-hat-developer-hub/cli@latest plugin export

    The following is an example of default scalprum configuration:

    "scalprum": {
      "name": "<package_name>",  // The Webpack container name matches the NPM package name, with "@" replaced by "." and "/" removed.
      "exposedModules": {
        "PluginRoot": "./src/index.ts"  // The default module name is "PluginRoot" and doesn't need explicit specification in the app-config.yaml file.
      }
    }

    You can add a scalprum section to the package.json file. For example:

    "scalprum": {
      "name": "custom-package-name",
      "exposedModules": {
        "BazModuleName": "./src/baz.ts",
        "QuxModuleName": "./src/qux.ts"
        // Define multiple modules here, with each exposed as a separate entry point in the Webpack container.
      }
    }

    Dynamic plugins might need adjustments for Developer Hub needs, such as static JSX for mountpoints or dynamic routes. These changes are optional but might be incompatible with static plugins.

    To include static JSX, define an additional export and use it as the dynamic plugin’s importName. For example:

    // For a static plugin
    $ export const EntityTechdocsContent = () => {...}
    
    // For a dynamic plugin
    $ export const DynamicEntityTechdocsContent = {
      element: EntityTechdocsContent,
      staticJSXContent: (
        <TechDocsAddons>
          <ReportIssue />
        </TechDocsAddons>
      ),
    };

Procedure

  • Use the plugin export command from the @red-hat-developer-hub/cli package to export the plugin:

    $ npx @red-hat-developer-hub/cli@latest plugin export

    Ensure that you run the earlier command in the root directory of the plugin’s JavaScript package (containing package.json file).

    The dist-dynamic subdirectory has the resulting derived package. The exported package name consists of the original plugin name with -dynamic appended.

    Warning

    Do not publish the derived dynamic plugin JavaScript packages to the public NPM registry. For more appropriate packaging options, see Section 14.3.5, “Package and deploy dynamic plugins as OCI images”. If you must publish to the NPM registry, use a private registry.

14.3.8. Override Core Backend Service Configuration

Customize core backend services by installing them as BackendFeatures using dynamic plugin functionality.

The Red Hat Developer Hub (RHDH) backend platform consists of several core services that are well encapsulated. The RHDH backend installs these default core services statically during initialization.

Customize a core service by installing it as a BackendFeature by using the dynamic plugin functionality.

Procedure

  1. Configure Developer Hub to allow a core service override, by setting the corresponding core service ID environment variable to true in the Developer Hub app-config.yaml configuration file.

    The following table describes the environment variables and their corresponding core service IDs:

    VariableOverrides the related service

    ENABLE_CORE_AUTH_OVERRIDE

    core.auth

    ENABLE_CORE_CACHE_OVERRIDE

    core.cache

    ENABLE_CORE_ROOTCONFIG_OVERRIDE

    core.rootConfig

    ENABLE_CORE_DATABASE_OVERRIDE

    core.database

    ENABLE_CORE_DISCOVERY_OVERRIDE

    core.discovery

    ENABLE_CORE_HTTPAUTH_OVERRIDE

    core.httpAuth

    ENABLE_CORE_HTTPROUTER_OVERRIDE

    core.httpRouter

    ENABLE_CORE_LIFECYCLE_OVERRIDE

    core.lifecycle

    ENABLE_CORE_LOGGER_OVERRIDE

    core.logger

    ENABLE_CORE_PERMISSIONS_OVERRIDE

    core.permissions

    ENABLE_CORE_ROOTHEALTH_OVERRIDE

    core.rootHealth

    ENABLE_CORE_ROOTHTTPROUTER_OVERRIDE

    core.rootHttpRouter

    ENABLE_CORE_ROOTLIFECYCLE_OVERRIDE

    core.rootLifecycle

    ENABLE_CORE_SCHEDULER_OVERRIDE

    core.scheduler

    ENABLE_CORE_USERINFO_OVERRIDE

    core.userInfo

    ENABLE_CORE_URLREADER_OVERRIDE

    core.urlReader

    ENABLE_EVENTS_SERVICE_OVERRIDE

    events.service

  2. Install your custom core service as a BackendFeature as shown in the following example:

    // Create the BackendFeature
    $ export const customRootHttpServerFactory: BackendFeature =
      rootHttpRouterServiceFactory({
        configure: ({ app, routes, middleware, logger }) => {
          logger.info(
            'Using custom root HttpRouterServiceFactory configure function',
          );
          app.use(middleware.helmet());
          app.use(middleware.cors());
          app.use(middleware.compression());
          app.use(middleware.logging());
          // Add a the custom middleware function before all
          // of the route handlers
          app.use(addTestHeaderMiddleware({ logger }));
          app.use(routes);
          app.use(middleware.notFound());
          app.use(middleware.error());
        },
      });
    
    // Export the BackendFeature as the default entrypoint
    $ export default customRootHttpServerFactory;

    In the previous example, as the BackendFeature overrides the default implementation of the HTTP router service, you must set the ENABLE_CORE_ROOTHTTPROUTER_OVERRIDE environment variable to true so that the Developer Hub does not install the default implementation automatically.

14.4. Manage containerized plugins securely by migrating to OCI artifacts

14.4.1. Manage containerized plugins securely by migrating to OCI artifacts

Migrate community and custom plugins to OCI artifact registries for improved security, versioning, and distribution. OCI-based plugin management replaces direct NPM registry access with container-native workflows that align with enterprise supply chain requirements.

14.4.2. Migrate community plugins to the GitHub Container Registry

14.4.2.1. Migrate community plugins to the GitHub Container Registry

Migrate community plugins from NPM registries to the GitHub Container Registry (GHCR) for OCI-based distribution. Container registry hosting enables consistent versioning and access control aligned with your existing container image workflows.

14.4.2.2. Update deployment configurations for OCI registry container images

Use this procedure to load a dynamic plugin from an OCI image into Red Hat Developer Hub.

Prerequisites

Procedure

  1. To retrieve plugins from an authenticated registry, such as a private repository, complete the following steps:

    Note

    If your OCI image is stored in a public registry, you can skip this step.

    1. Log in to the container image registry.

      podman login <registry>
    2. Verify the content of the auth.json file created after the login.

      cat ${XDG_RUNTIME_DIR:-~/.config}/containers/auth.json
    3. Create a secret file using the following example:

      oc create secret generic _<secret_name>_ --from-file=auth.json=${XDG_RUNTIME_DIR:-~/.config}/containers/auth.json 1
      • For an Operator-based deployment, replace <secret_name> with dynamic-plugins-registry-auth.
      • For a Helm-based deployment, replace <secret_name> with <Helm_release_name>-dynamic-plugins-registry-auth.
  2. Define the plugin with the oci:// prefix by using one of the following formats in your dynamic-plugins.yaml file:

    Standard definition

    Use the format oci://<image_name>:<tag>, as shown in the following example. The installation program automatically extracts the plugin path from the image metadata.

    Example configuration in dynamic-plugins.yaml file:

    plugins:
      - disabled: false
        package: oci://quay.io/example/image:v1.0.0
    Note

    You must package images with the @red-hat-developer-hub/cli to ensure the system applies the io.backstage.dynamic-packages annotation.

    You must define exactly one plugin from that OCI image in the configuration files. The system returns an error if the configuration files contain many plugins or no matching plugins.

    Using image digests

    To perform an integrity check, use the image digest in place of the tag in the dynamic-plugins.yaml file as shown in the following example:

    Example configuration in dynamic-plugins.yaml file:

    plugins:
      - disabled: false
        package: oci://quay.io/example/image@sha256:28036abec4dffc714394e4ee433f16a59493db8017795049c831be41c02eb5dc
    Using version inheritance

    To inherit a version from a base configuration file, for example, dynamic-plugins.default.yaml, use the {{inherit}} placeholder to inherit the v0.0.2 tag, as shown in the following example:

    Example configuration in dynamic-plugins.default.yaml file:

    plugins:
      - disabled: false
        package: oci://quay.io/example/image:v0.0.2

    Example configuration in dynamic-plugins.yaml file:

    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - disabled: false
        package: oci://quay.io/example/image:{{inherit}}
    Note

    An error occurs if you use {{inherit}} in the includes file itself or if no matching plugin key exists in the base configuration.

  3. To apply the changes, restart the RHDH application.

14.5. Enable and configure the Orchestrator extension

14.5.1. Enable and configure the Orchestrator extension

Enable the Orchestrator extension to automate infrastructure tasks by using serverless workflows in Red Hat Developer Hub. The Orchestrator integrates the OpenShift Serverless Logic Operator, SonataFlow runtime, and Data Index to deliver workflow orchestration within the developer portal.

14.5.2. Understand Orchestrator architecture

The Orchestrator architecture is composed of several components, each contributing to the running and management of workflows.

Red Hat Developer Hub (RHDH)

Serves as the primary interface. It contains the following subcomponents:

Orchestrator frontend plugins
Provide the interface for users to run and monitor workflows within RHDH.
Orchestrator backend plugins
Get workflow data into Developer Hub.
Notifications plugins
Inform users about workflow events.
OpenShift Serverless Logic Operator

Serves as the workflow engine, and its subcomponents handle running, executing and providing persistence for the workflows. The Red Hat Developer Hub Operator and the Red Hat Developer Hub Helm chart manage the following lifecycle of these subcomponents:

SonataFlow Runtime/Workflow Application
Functions as a deployed workflow. Operates as an HTTP server, handling requests for running workflow instances. It is managed as a Kubernetes (K8s) deployment by the Openshift Serverless Logic Operator.
Data Index Service
Serves as a repository for workflow definitions, instances, and associated jobs. It exposes a GraphQL API used by the Orchestrator backend plugin to retrieve workflow definitions and instances.
Job Service
Orchestrates scheduled tasks for workflows.
OpenShift Serverless
Provides serverless capabilities essential for workflow communication. It employs Knative eventing to interface with the Data Index service and uses Knative functions to introduce more complex logic to workflows.
PostgreSQL Server
Provides a database solution essential for data persistence within the Orchestrator ecosystem. The system uses PostgreSQL Server for storing both SonataFlow information and Developer Hub data.
OpenShift AMQ Streams (Strimzi/Kafka)

Provides enhanced reliability of the eventing system. Eventing can work without Kafka by using direct HTTP calls, however, this approach is not reliable.

Optional: The current deployment iteration does not natively integrate or include the AMQ Streams Operator. However, you can add the Operator post-install for enhanced reliability if you require it.

14.5.3. Getting started with Orchestrator

To start using Orchestrator in RHDH, you must install the required infrastructure components and configure your Backstage custom resource or Helm values file.

  • Install the required infrastructure components, such as OpenShift Serverless Operator, and OpenShift Serverless Logic Operator
  • Configure your Backstage custom resource (CR) or Helm values file for Orchestrator
Note

When using the RHDH Operator, you must first install the required infrastructure components. The Operator then provisions the dependent SonataFlow resources once the Orchestrator plugins are enabled in the Backstage CR.

When using the RHDH Helm chart, the required infrastructure components are installed automatically using the dedicated redhat-developer-hub-orchestrator-infra Helm chart before enabling the Orchestrator plugins in the main RHDH chart.

14.5.4. Orchestrator plugin dependencies for Operator installation

When you enable the Orchestrator plugin in your Backstage custom resource (CR), the Operator automatically provisions required dependencies.

  • A SonataflowPlatform CR
  • NetworkPolicies that allow traffic between infrastructure resources (Knative, Serverless Logic Operator), monitoring traffic, and intra-namespace traffic

The Orchestrator plugin requires these components to run. For example, to communicate with the SonataFlow platform, the Orchestrator plugin uses the sonataflow-platform-data-index-service, which is created by the SonataFlowPlatform CR.

Important

The SonataFlowPlatform CR contains Data Index service that requires PostgreSQL database as shown in the following example:

      persistence:
        postgresql:
          secretRef:
            name: backstage-psql-secret-{{backstage-name}}
            userKey: POSTGRES_USER
            passwordKey: POSTGRES_PASSWORD
          serviceRef:
            name: backstage-psql-{{backstage-name}} # # Namespace where the Backstage CR is created
            namespace: {{backstage-ns}} # Namespace where the Backstage (CR) is created
            databaseName: backstage_plugin_orchestrator

By default, the Orchestrator plugin dependencies use the following:

  • The PostgreSQL database named backstage_plugin_orchestrator created by Backstage
  • A Secret created by Backstage Operator for the PostgreSQL with POSTGRES_USER and POSTGRES_PASSWORD keys as the database credentials in the Backstage CR namespace.
  • A Service created by Backstage Operator for the PostgreSQL database with the name backstage-psql-{{backstage-name}} in the Backstage CR namespace.
Note

To enable the Backstage Operator to work with the SonataFlow platform, its ServiceAccount must have the appropriate permissions.

The Operator automatically creates the required Role and RoleBinding resource in profile/rhdh/plugin-rbac directory.

14.5.5. Configure Orchestrator plugins

To use the Orchestrator, enable the Orchestrator plugins for Red Hat Developer Hub that are disabled by default.

Orchestrator-frontend plugin
backstage-plugin-orchestrator
Provides the interface for users to run and monitor workflows within RHDH. You can run and track the execution status of processes.
Orchestrator-backend plugin
backstage-plugin-orchestrator-backend
Gets workflow data into Developer Hub making sure RHDH processes critical workflow metadata and runtime status fulfilling your need for visibility.
Orchestrator-form-widget
backstage-plugin-orchestrator-form-widgets
Provides custom widgets for the workflow execution form, allowing you to customize input fields and streamline the process of launching workflows.
Orchestrator-scaffolder-backend-module
scaffolder-backend-module-orchestrator
Provides callable actions from Scaffolder templates, such as orchestrator:workflow:run or orchestrator:workflow:get_params.

Prerequisites

  • You have installed the following operators:

    • OpenShift Serverless
    • OpenShift Serverless Logic (OSL)
  • (Optional) For managing the Orchestrator project, you have an instance of Argo CD or Red Hat OpenShift GitOps in the cluster. It is disabled by default.
  • (Optional) To use Tekton tasks and the build pipeline, you have an instance of Tekton or Red Hat OpenShift Pipelines in the cluster. These features are disabled by default.

Procedure

  1. Locate your Developer Hub configuration and enable the Orchestrator plugins and the supporting notification plugins.

    The {{inherit}} attribute in the package field automatically resolves to the default plugin version and configuration for your version of RHDH.

    plugins:
      - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{inherit}}"
        disabled: false
      - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{inherit}}"
        disabled: false
      - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{inherit}}"
        disabled: false
      - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{inherit}}"
        disabled: false
      - package: "./dynamic-plugins/dist/backstage-plugin-notifications"
        disabled: false
      - package: "./dynamic-plugins/dist/backstage-plugin-signals"
        disabled: false
      - package: "./dynamic-plugins/dist/backstage-plugin-notifications-backend-dynamic"
        disabled: false
      - package: "./dynamic-plugins/dist/backstage-plugin-signals-backend-dynamic"
        disabled: false
    Note

    If you need a specific plugin version, replace {{inherit}} with the version tag, for example: oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:1.3.0.

  2. Optional: Restrict where the Workflows tab appears.

    By default, the Workflows tab appears on all entity types. To display it only on specific entities, add the pluginConfig section with filtering conditions.

    plugins:
      - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{inherit}}"
        disabled: false
        pluginConfig:
          dynamicPlugins:
            frontend:
              red-hat-developer-hub.backstage-plugin-orchestrator:
                appIcons:
                  - importName: OrchestratorIcon
                    name: orchestratorIcon
                dynamicRoutes:
                  - importName: OrchestratorPage
                    menuItem:
                      icon: orchestratorIcon
                      text: Orchestrator
                      textKey: menuItem.orchestrator
                    path: /orchestrator
                entityTabs:
                  - path: /workflows
                    title: Workflows
                    titleKey: catalog.entityPage.workflows.title
                    mountPoint: entity.page.workflows
                mountPoints:
                  - mountPoint: entity.page.workflows/cards
                    importName: OrchestratorCatalogTab
                    config:
                      layout:
                        gridColumn: 1 / -1
                      if:
                        anyOf:
                          - IsOrchestratorCatalogTabAvailable

    Where:

    IsOrchestratorCatalogTabAvailable
    A condition function exported by the Orchestrator plugin that checks whether the entity has workflow-related data or annotations.
    layout.gridColumn
    Controls the grid layout positioning. The value 1 / -1 spans the full width of the grid.
    if.anyOf

    Specifies that the tab appears if any of the listed conditions are met. Add conditions like isKind: component to further restrict where the tab appears.

    Important

    Make sure the indentation is correct: if must be at the same level as layout under config, and conditions under anyOf must be indented two more levels. Incorrect indentation can cause the Workflows tab to appear on all entity types, including User and Group entities.

    To restrict the Workflows tab to only Component entities, modify the if condition:

                      if:
                        allOf:
                          - IsOrchestratorCatalogTabAvailable
                          - isKind: component

14.5.6. Enable the Orchestrator plugins using the Operator

You can enable the Orchestrator plugins in RHDH by configuring dynamic plugins in your Backstage custom resource (CR).

Prerequisites

  • You have installed RHDH on OpenShift Container Platform.
  • You have access to edit or create ConfigMaps in the namespace where the Backstage CR is deployed.

Procedure

  1. To enable the Orchestrator plugins with default settings, set disabled: false for the corresponding packages.

    The {{inherit}} attribute in the package field automatically resolves to the default plugin version and configuration for your version of RHDH.

    - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{inherit}}"
      disabled: false
    - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{inherit}}"
      disabled: false
      dependencies:
        - ref: sonataflow
    - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{inherit}}"
      disabled: false
    - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{inherit}}"
      disabled: false
    Note

    If you need a specific plugin version, replace {{inherit}} with the version tag, such as 1.3.0. When you use the Operator, the ref: sonataflow field installs the OpenShift Serverless and OpenShift Serverless Logic resources.

    The following example shows a complete configuration of the Orchestrator plugin dynamic-plugins config map:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: orchestrator-plugin
    data:
        dynamic-plugins.yaml: |
          includes:
            - dynamic-plugins.default.yaml
          plugins:
            - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{inherit}}"
              disabled: false
            - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{inherit}}"
              disabled: false
              dependencies:
                - ref: sonataflow
            - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{inherit}}"
              disabled: false
            - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{inherit}}"
              disabled: false
  2. (Optional) Configure backend authentication to allow Orchestrator components to communicate with the RHDH API.

    This step is required only when your workflow definitions include API calls to RHDH plugins, such as the notifications or scaffolding plugins.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config-rhdh
    data:
      app-config.yaml: |-
        backend:
          auth:
            externalAccess:
              - type: static
                options:
                  token: ${BACKEND_SECRET}
                  subject: orchestrator
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: backend-auth-secret
    stringData:
      # Run the following command to generate a secure random value:
      # node -p 'require("crypto").randomBytes(24).toString("base64")'
      BACKEND_SECRET: "<GENERATED_VALUE>"
    Important

    Replace <GENERATED_VALUE> with a securely generated random token. Do not use example or placeholder values in production environments.

  3. If you have configured backend authentication in the previous step, update your Backstage CR to reference the secret:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: orchestrator
    spec:
      application:
        appConfig:
          configMaps:
            - name: app-config-rhdh
        dynamicPluginsConfigMapName: orchestrator-plugin
        extraEnvs:
          secrets:
            - name: backend-auth-secret

Verification

  • In the RHDH console, confirm that the Orchestrator frontend and backend features are available.

14.5.7. Install components using the RHDH helper script

You can use the RHDH helper script plugin-infra.sh to quickly install the OpenShift Serverless infrastructure and OpenShift Serverless Logic infrastructure required by the Orchestrator plugin.

Warning

Do not use plugin-infra.sh in production.

Procedure

  1. Download the plugin-infra.sh script as shown in the following example:

    $ curl -sSLO https://raw.githubusercontent.com/redhat-developer/rhdh-operator/refs/heads/release-1.10/config/profile/rhdh/plugin-infra/plugin-infra.sh # Specify the Red Hat Developer Hub version in the URL or use main
  2. Run the script:

    $ ./plugin-infra.sh

14.5.8. Install Orchestrator components manually on OpenShift Container Platform

Use manual installation when you want full control of the setup process and component versions. Manual installation method focuses on setting up the underlying infrastructure.

Procedure

  1. Install the OpenShift Serverless components manually by following the instructions in the Red Hat OpenShift Serverless documentation.
  2. (Optional) If required, deploy a custom PostgreSQL database.

    Important

    Prevent workflow context from being lost when the Pod restarts by configuring workflow persistence. You can configure persistence at the namespace level by using the SonataFlowPlatform or SonataFlow custom resources (CR). For more information, check the Managing workflow persistence documentation.

14.5.9. Install Orchestrator software templates

To enable software templates on RHDH, you must install two additional Helm charts.

Prerequisites

  • You have installed RHDH and the Orchestrator plugin by using the Helm chart.
  • You have installed the redhat-developer-hub-orchestrator-infra chart.

Procedure

  1. Install the orchestrator-software-templates-infra chart.
  2. Install the orchestrator-software-templates chart.

14.5.10. Configure Orchestrator to connect to existing PostgreSQL infrastructure

Connect the Orchestrator plugins to your existing PostgreSQL database to leverage centralized database management and meet compliance requirements.

By default, when you enable the Orchestrator plugin by using the Operator, the dependencies: - ref: sonataflow field automatically provisions a SonataFlowPlatform custom resource (CR) and creates the required PostgreSQL database resources. The Operator uses specific naming patterns for these resources (such as backstage-psql-{{backstage-name}} for the service and backstage-psql-secret-{{backstage-name}} for the secret).

However, when you use an external PostgreSQL database that the Operator does not manage, these default resources and naming patterns do not exist. You must explicitly configure the SonataFlowPlatform CR to reference your external database resources and remove the automatic dependency provisioning.

Prerequisites

Procedure

  1. Create the backstage_plugin_orchestrator database on your external PostgreSQL server by applying the following job:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: create-sonataflow-database-developer-hub
    spec:
      ttlSecondsAfterFinished: 30
      activeDeadlineSeconds: 120
      template:
        spec:
          containers:
            - name: psql
              image: quay.io/fedora/postgresql-15:latest
              resources:
                limits:
                  cpu: "100m"
                  memory: "128Mi"
                requests:
                  cpu: "100m"
                  memory: "64Mi"
              securityContext:
                readOnlyRootFilesystem: true
                allowPrivilegeEscalation: false
                runAsNonRoot: true
                capabilities:
                  drop:
                    - ALL
              envFrom:
                - secretRef:
                    name: <SECRET-NAME-WITH-DB-CREDENTIALS>
              command: [ "sh", "-c" ]
              args:
                - |
                  set -e
                  # Check if the backstage_plugin_orchestrator database exists
                  DB_EXISTS=$(PGPASSWORD=${POSTGRES_PASSWORD} psql -h ${POSTGRES_HOST} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} -tAc "SELECT 1 FROM pg_database WHERE datname='backstage_plugin_orchestrator'" postgres)
                  if [ -z "$DB_EXISTS" ]; then
                    # Create the database if it does not exist
                    PGPASSWORD=${POSTGRES_PASSWORD} psql -h ${POSTGRES_HOST} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} -c "CREATE DATABASE backstage_plugin_orchestrator;" postgres
                  fi
          restartPolicy: Never
  2. Create a SonataFlowPlatform CR that references your external PostgreSQL service:

    apiVersion: sonataflow.org/v1alpha08
    kind: SonataFlowPlatform
    metadata:
      name: sonataflow-platform
    spec:
      monitoring:
        enabled: true
      services:
        dataIndex:
          enabled: true
          persistence:
            postgresql:
              secretRef:
                name: <SECRET-NAME-WITH-DB-CREDENTIALS>
                userKey: POSTGRES_USER
                passwordKey: POSTGRES_PASSWORD
              serviceRef:
                name: <SERVICE-NAME-TO-DB>
                namespace: <RHDH-NAMESPACE>
                databaseName: backstage_plugin_orchestrator
        jobService:
          enabled: true
          persistence:
            postgresql:
              secretRef:
                name: <SECRET-NAME-WITH-DB-CREDENTIALS>
                userKey: POSTGRES_USER
                passwordKey: POSTGRES_PASSWORD
              serviceRef:
                name: <SERVICE-NAME-TO-DB>
                namespace: <RHDH-NAMESPACE>
                databaseName: backstage_plugin_orchestrator
    Important

    Unlike the default configuration that uses the dependencies: - ref: sonataflow field to automatically provision database resources with specific naming patterns, this configuration explicitly references your external database Service and Secret. The SonataFlowPlatform CR will use these resources to connect to your external database instead of creating new database resources.

  3. Configure the Orchestrator plugins in your dynamic plugins config map to remove the default sonataflow dependency and explicitly reference the SonataFlowPlatform services:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: orchestrator-plugin
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          # Orchestrator plugins
          - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{inherit}}"
            disabled: false
          - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{inherit}}"
            disabled: false
            pluginConfig:
              orchestrator:
                dataIndexService:
                  url: http://<SERVICE-NAME-SONATAFLOW-PLATFORM-DATA-INDEX>
            dependencies: [{}]  # Empty array removes default 'ref: sonataflow' to prevent automatic database provisioning
          - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{inherit}}"
            disabled: false
            pluginConfig:
              orchestrator:
                dataIndexService:
                  url: http://<SERVICE-NAME-SONATAFLOW-PLATFORM-DATA-INDEX>
            dependencies: [{}]  # Empty array removes default 'ref: sonataflow' to prevent automatic database provisioning
          - package: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{inherit}}"
            disabled: false
  4. Update your Backstage CR to reference the orchestrator plugin config map and inject the database credentials secret:

    apiVersion: rhdh.redhat.com/v1alpha5
    kind: Backstage
    metadata:
      name: orchestrator
    spec:
      application:
        appConfig:
          configMaps:
            - name: app-config-rhdh
        dynamicPluginsConfigMapName: orchestrator-plugin
        extraEnvs:
          secrets:
            - name: <SECRET-NAME-WITH-DB-CREDENTIALS>

Verification

  1. Verify that the SonataFlowPlatform CR is running:

    $ oc get sonataflowplatform sonataflow-platform -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'
    True
  2. In the RHDH console, confirm that the Orchestrator frontend and backend features are available and can connect to your external database.

14.5.11. Configure Orchestrator to connect to existing PostgreSQL infrastructure using Helm

Connect the Orchestrator plugins to your existing PostgreSQL database when deploying with the Helm chart to leverage centralized database management and meet compliance requirements.

By default, when you enable the Orchestrator plugin by using the Helm chart with orchestrator.enabled=true, the chart automatically provisions a SonataFlowPlatform custom resource (CR) and creates the required PostgreSQL database resources. The chart uses the orchestrator.sonataflowPlatform values to configure these resources.

However, when you use an external PostgreSQL database that the Helm chart does not manage, you must explicitly configure the orchestrator.sonataflowPlatform values to reference your external database resources.

Prerequisites

Procedure

  1. Create the backstage_plugin_orchestrator database on your external PostgreSQL server by applying the following job:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: create-sonataflow-database-developer-hub
    spec:
      ttlSecondsAfterFinished: 30
      activeDeadlineSeconds: 120
      template:
        spec:
          containers:
            - name: psql
              image: quay.io/fedora/postgresql-15:latest
              resources:
                limits:
                  cpu: "100m"
                  memory: "128Mi"
                requests:
                  cpu: "100m"
                  memory: "64Mi"
              securityContext:
                readOnlyRootFilesystem: true
                allowPrivilegeEscalation: false
                runAsNonRoot: true
                capabilities:
                  drop:
                    - ALL
              envFrom:
                - secretRef:
                    name: <SECRET-NAME-WITH-DB-CREDENTIALS>
              command: [ "sh", "-c" ]
              args:
                - |
                  set -e
                  # Check if the backstage_plugin_orchestrator database exists
                  DB_EXISTS=$(PGPASSWORD=${POSTGRES_PASSWORD} psql -h ${POSTGRES_HOST} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} -tAc "SELECT 1 FROM pg_database WHERE datname='backstage_plugin_orchestrator'" postgres)
                  if [ -z "$DB_EXISTS" ]; then
                    # Create the database if it does not exist
                    PGPASSWORD=${POSTGRES_PASSWORD} psql -h ${POSTGRES_HOST} -p ${POSTGRES_PORT} -U ${POSTGRES_USER} -c "CREATE DATABASE backstage_plugin_orchestrator;" postgres
                  fi
          restartPolicy: Never
  2. Configure your external PostgreSQL database for Orchestrator in your Helm configuration file values.yaml:

    orchestrator:
      enabled: true
      sonataflowPlatform:
        externalDBsecretRef: <SECRET-NAME-WITH-DB-CREDENTIALS>
        externalDBName: backstage_plugin_orchestrator
        externalDBHost: <SERVICE-NAME-TO-DB>
        externalDBPort: "5432"

    Where:

    orchestrator.enabled
    Set to true to enable the Orchestrator plugin.
    orchestrator.sonataflowPlatform.externalDBsecretRef
    The secret name containing database credentials with POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, and POSTGRES_PORT keys.
    orchestrator.sonataflowPlatform.externalDBName
    The database name for Orchestrator data (must be backstage_plugin_orchestrator).
    orchestrator.sonataflowPlatform.externalDBHost
    The Kubernetes Service name pointing to your external database.
    orchestrator.sonataflowPlatform.externalDBPort

    The PostgreSQL port (typically 5432).

    Important

    Unlike the default configuration where the Helm chart automatically provisions database resources, this configuration explicitly references your external database Service and Secret. The SonataFlowPlatform CR will use these resources to connect to your external database instead of creating new database resources.

  3. Apply the configuration changes in your Helm configuration file values.yaml:

    $ helm upgrade -n <your_namespace> <your_deploy_name> openshift-helm-charts/redhat-developer-hub -f values.yaml --version 1.10.1

Verification

  1. Verify that the SonataFlowPlatform CR is running:

    $ oc get sonataflowplatform sonataflow-platform -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'
    True
  2. In the RHDH console, confirm that the Orchestrator frontend and backend features are available and can connect to your external database.

14.5.12. Compatibility guide for Orchestrator

To verify that your serverless workflows run reliably, use the validated Orchestrator plugin and infrastructure versions listed in the following table.

Important

Red Hat does not support or guarantee Orchestrator plugin functionality with unvalidated infrastructure versions. Use only the specific versions of OpenShift Serverless Logic (OSL) and other components listed in the following table.

The following table lists compatible Orchestrator and infrastructure versions:

Orchestrator plugin version

Red Hat Developer Hub (RHDH) version

OpenShift version

OpenShift Serverless Logic (OSL) version

OpenShift Serverless version

Orchestrator 1.5

1.5

4.14 - 4.18

OSL 1.35

1.35

Orchestrator 1.6

1.6

4.14 - 4.18

OSL 1.36

1.36

Orchestrator 1.7.1

1.7

4.16 - 4.19

OSL 1.36

1.36

Orchestrator 1.8.2

1.8

4.16 - 4.19

OSL 1.36

1.36

Orchestrator 1.10.0

1.10

4.18 - 4.21

OSL 1.38.0

1.37.1

Note

The Orchestrator plugin supports the same OpenShift Container Platform versions as RHDH. See the Life Cycle page.

14.5.13. Workflow review pages for your approval requirements

You can replace the default Orchestrator review page with a custom component to meet organizational standards, show warnings, require acknowledgment before run, or integrate with design systems in Red Hat Developer Hub.

Custom review pages are optional. If you do not implement a custom review component, the Orchestrator continues to use the default review page without any impact on functionality.

Use a custom review page when you need to perform the following actions:

  • Display workflow data in a specific layout that matches your organization’s documentation or approval standards.
  • Apply client-side checks or show warnings before the workflow runs.
  • Include additional context, such as help text or links to documentation, for reviewers.
  • Integrate with custom UI component libraries or design systems.

Custom review pages are compatible with existing workflows. The same workflow definitions, schemas, and data structures work with both default and custom review pages. You can switch between review page types without modifying your workflow configurations.

14.5.14. Build custom review pages for workflows

To build a custom review page that displays workflow data in a specific layout, or integrates with a design system, you must implement the getReviewComponent() method in the form API.

Prerequisites

  • You have configured the Orchestrator plugins in your Developer Hub instance.
  • You have a plugin or module that implements the OrchestratorFormApi interface from the orchestrator-form-api package.
  • You are familiar with React component development and TypeScript.

Procedure

  1. In your plugin that implements OrchestratorFormApi, import the required types:

    import type {
      OrchestratorFormApi,
      ReviewComponentProps,
    } from '@red-hat-developer-hub/backstage-plugin-orchestrator-form-api';
  2. Import the helper utilities from the orchestrator-form-react package:

    import {
      generateReviewTableData,
      schemaHasUiHiddenFields,
      ReviewHiddenParametersAlert,
      NestedReviewTable,
    } from '@red-hat-developer-hub/backstage-plugin-orchestrator-form-react';

    These utilities handle hidden fields, password masking, and nested data structures in your custom review page.

  3. Create your custom review page component:

    import React from 'react';
    import { Button, Box, Typography } from '@mui/material';
    
    export const CustomReviewPage = (props: ReviewComponentProps) => {
      const { busy, schema, data, handleBack, handleExecute } = props;
      const [showHiddenFields, setShowHiddenFields] = React.useState(false);
    
      const reviewData = React.useMemo(
        () => generateReviewTableData(schema, data, {
          includeHiddenFields: showHiddenFields
        }),
        [schema, data, showHiddenFields]
      );
    
      const hasHiddenFields = schemaHasUiHiddenFields(schema);
    
      return (
        <Box>
          <Typography variant="h5">Review Your Workflow Data</Typography>
    
          {hasHiddenFields && (
            <ReviewHiddenParametersAlert
              showHiddenFields={showHiddenFields}
              onShowHiddenFieldsChange={setShowHiddenFields}
            />
          )}
    
          <NestedReviewTable data={reviewData} />
    
          <Box sx={{ mt: 2, display: 'flex', gap: 1 }}>
            <Button onClick={handleBack} disabled={busy}>
              Back
            </Button>
            <Button
              variant="contained"
              onClick={handleExecute}
              disabled={busy}
            >
              Execute Workflow
            </Button>
          </Box>
        </Box>
      );
    };
  4. Add the getReviewComponent() method to your OrchestratorFormApi implementation:

    export class MyFormApi implements OrchestratorFormApi {
      getReviewComponent() {
        return CustomReviewPage;
      }
    
      // ... other OrchestratorFormApi methods
    }
  5. Register your custom form API with the Orchestrator plugin according to your plugin’s extension mechanism.

Verification

  1. Open the Orchestrator plugin in the Developer Hub web interface.
  2. Select a workflow and complete the workflow form.
  3. Proceed to the review step.
  4. Confirm that your custom review page displays with the correct layout and styling.
  5. Click Back and confirm that the workflow form is populated.
  6. Click Execute Workflow and verify that the workflow runs successfully.

Next steps

To revert to the default Orchestrator review page, return undefined from the getReviewComponent() method:

export class MyFormApi implements OrchestratorFormApi {
  getReviewComponent() {
    return undefined; // Uses default review page
  }
}

14.5.15. Custom review page API reference

The custom review page API provides the ReviewComponentProps interface, helper utilities for data processing, and UI components to implement custom review pages for Red Hat Developer Hub Orchestrator workflows.

14.5.15.1. ReviewComponentProps interface

Your custom review component receives the following properties through the ReviewComponentProps interface:

PropertyTypeDescription

busy

boolean

Indicates whether a workflow run is in progress. Disable action buttons when this value is true to prevent duplicate submissions.

schema

JSONSchema7

Defines field structure, titles, and UI hints such as hidden fields for the workflow form.

data

JsonObject

Contains the user-submitted form values structured according to the schema and awaiting review before the workflow runs.

handleBack

() ⇒ void

Returns to the previous step (same behavior as the default review page). This callback matches the default review page behavior.

handleExecute

() ⇒ void

Runs the workflow with the reviewed data. Call this function when the user clicks Run to start the workflow.

14.5.15.2. Helper utilities

The orchestrator-form-react package exports the following utilities to help you build custom review pages that handle data correctly:

FunctionSignatureDescription

generateReviewTableData

(schema: JSONSchema7, data: JsonObject, options?: {includeHiddenFields?: boolean}) ⇒ JsonObject

Processes form data for display. Respects ui:hidden fields, masks password fields, and structures nested data. Use this to prepare data for rendering in your custom review component.

schemaHasUiHiddenFields

(schema: JSONSchema7) ⇒ boolean

Returns true if the schema contains fields marked with ui:hidden in the UI schema. Use this to determine if the UI should display a toggle for hidden fields.

14.5.15.3. Helper components

The orchestrator-form-react package exports the following React components for use in custom review pages:

ComponentPropsDescription

NestedReviewTable

data: JsonObject

Renders form data in a nested table structure. Accepts data processed by generateReviewTableData() and displays it with proper formatting for nested objects and arrays.

ReviewHiddenParametersAlert

showHiddenFields: boolean, onShowHiddenFieldsChange: (includeHidden: boolean) ⇒ void

Displays an alert with a toggle switch for showing or hiding fields marked as ui:hidden in the schema. Use this component when schemaHasUiHiddenFields() returns true.

14.5.15.4. OrchestratorFormApi method

To provide a custom review page, implement the following method in your OrchestratorFormApi implementation:

MethodReturn TypeDescription

getReviewComponent()

React.ComponentType<ReviewComponentProps> | undefined

Returns your custom review page component, or undefined to use the default Orchestrator review page. The returned component must accept ReviewComponentProps as its props.

Chapter 15. Troubleshoot

15.1. Troubleshoot

Diagnose and resolve common issues with authentication, configuration, deployments, and integrations to maintain platform availability.

15.2. Troubleshoot user access and authentication issues to restore user entry

15.2.1. Troubleshoot user access and authentication issues to restore user entry

Resolve authentication and configuration issues that prevent users from accessing the platform.

15.2.2. Troubleshoot authentication issues

15.2.2.1. Troubleshoot authentication issues

Learn how to troubleshoot common authentication issues.

15.2.2.2. Reduce the size of issued tokens

If user identity tokens grow large and cause HTTP errors, you can use the omitIdentityTokenOwnershipClaim flag to remove the ent claim from the JWT payload and reduce token size.

Procedure

  • In the app-config.yaml file, set omitIdentityTokenOwnershipClaim to true as follows:

    auth:
      omitIdentityTokenOwnershipClaim: true

15.2.2.3. Troubleshoot unexpected session expiration

If sessions expire sooner than expected, check the following settings. The mechanism with the shortest timeout takes effect first.

Procedure

  1. Check the Identity Provider (IdP) session timeout: the IdP might have a shorter session lifetime than Developer Hub.
  2. Check the sessionDuration parameter for your authentication provider.
  3. Check the AutoLogout idleTimeoutMinutes setting, if auto-logout is enabled.

Additional resources

15.2.2.4. Troubleshoot missing session expiration warning

If users receive no warning before their session expires, auto-logout might not be enabled. Without auto-logout, sessions expire silently based on sessionDuration or IdP settings.

Procedure

  • To enable pre-expiration warnings, configure the auth.autologout settings in your app-config.yaml file.

15.2.2.5. Troubleshoot missing login redirect after session expiration

If users are not redirected to the login page after their session expires, verify the following.

Procedure

  1. Verify that your Developer Hub version includes the upstream session expiration fix.
  2. Verify that your authentication provider is correctly configured with valid metadataUrl, clientId, and clientSecret settings.

15.2.2.6. Troubleshoot login failed errors

When a user cannot sign in to Developer Hub, the sign-in page displays a "Login failed" error message. The following sections describe common login errors and their solutions.

15.2.2.6.1. Login failed: unable to resolve user identity
Login failed; caused by Error: Failed to sign-in, unable to resolve user identity. Please verify that your catalog contains the expected User entities that would match your configured sign-in resolver.

This error indicates that the user signing in does not match a user entity in the Developer Hub software catalog.

To resolve this issue:

  1. Check that the corresponding catalog provider plugin is set up correctly and is successfully syncing users and groups into the catalog.

    In the backend logs, look for a successful synchronization message such as:

    catalog info Read 114 GitHub users and 22 GitHub groups in 3.4 seconds. Committing...
    catalog info Committed 114 GitHub users and 22 GitHub groups in 0.0 seconds.
  2. If users and groups have been ingested into the catalog, verify that the sign-in resolver used (default or configured) matches the correct user attributes.
  3. Optionally, use guest login to look into the user entity in the catalog and verify the attributes.
15.2.2.6.2. Login failed: provider not configured to support sign-in
Login failed; caused by Error: The <providerId> provider is not configured to support sign-in.

This error indicates that the authentication provider has disableIdentityResolution set to true, meaning it is configured as an auxiliary provider, not for primary sign-in.

To resolve this issue:

  • In your app-config.yaml file, ensure that disableIdentityResolution is not set to true for your primary sign-in authentication provider.
15.2.2.6.3. Login failed: user profile does not contain an email
Login failed, user profile does not contain an email

This error indicates that the authentication client does not have permission to read the user’s email from the identity provider.

To resolve this issue:

  • Grant the necessary email-reading permissions to the authentication client in the identity provider.
  • Or, use a sign-in resolver that does not rely on email, such as preferredUsernameMatchingUserEntityName instead of emailMatchingUserEntityProfileEmail.

15.2.2.7. Troubleshoot catalog provider errors

Catalog provider plugins can fail to ingest users and groups into the Developer Hub software catalog. The following sections describe common catalog provider errors visible in the backend logs and their solutions.

15.2.2.7.1. LDAP: Malformed entity envelope
LdapOrgEntityProvider:default refresh failed, TypeError: Malformed entity envelope, TypeError: /metadata/name must NOT have fewer than 1 characters - limit: 1

This error occurs when a user being ingested from LDAP has no value for the name field, which is mapped to the uid LDAP attribute by default.

To resolve this issue:

  • Add a filter to the LDAP users configuration to exclude users without a uid:

    catalog:
      providers:
        ldapOrg:
          default:
            users:
              - dn: OU=Users,DC=example,DC=com
                options:
                  filter: (uid=*)

    For more information about LDAP user filters, see Enable user provisioning with LDAP.

15.2.2.7.2. GitHub: API rate limit exceeded
GithubMultiOrgEntityProvider:default refresh failed, HttpError: API rate limit exceeded

This error occurs when Developer Hub makes unauthenticated API calls to GitHub, which are limited to 60 requests per hour. Authenticated requests using a GitHub App get up to 5,000 requests per hour.

To resolve this issue:

  • Verify that the integrations.github section is configured in your app-config.yaml file with valid GitHub App credentials. For more information, see Import users and groups from GitHub.
15.2.2.7.3. GitLab: API rate limit exceeded

This error occurs when Developer Hub makes unauthenticated API calls to GitLab, which are subject to rate limits.

To resolve this issue:

  • Verify that the integrations.gitlab section is configured in your app-config.yaml file with a valid GitLab personal access token. For more information, see Configure the GitLab integration.

15.2.3. Troubleshoot configuration issues

15.2.3.1. Troubleshoot configuration issues

Resolve common configuration issues in Red Hat Developer Hub, such as Helm overwriting predefined array values.

15.2.3.2. Maintain dynamic plugin settings in Helm deployments

If you use Helm to install dynamic plugins, you might meet an issue where predefined values in fields with arrays are overwritten after you add new values. The issue affects fields such as:

  • extraEnvVars
  • extraVolumeMounts
  • extraVolumes

Fix this issue by duplicating the predefined values from RHDH Helm Chart’s values.yaml file into your own version of the file.

Procedure

  1. For extraEnvVars, add the following content to your values.yaml file:

    extraEnvVars:
          - name: BACKEND_SECRET
            valueFrom:
              secretKeyRef:
                key: backend-secret
                name: '{{ include "rhdh.backend-secret-name" $ }}'
          - name: POSTGRESQL_ADMIN_PASSWORD
            valueFrom:
              secretKeyRef:
                key: postgres-password
                name: '{{- include "rhdh.postgresql.secretName" . }}'
  2. For extraVolumeMounts, add the following content to your values.yaml file:

    extraVolumeMounts:
          - name: dynamic-plugins-root
            mountPath: /opt/app-root/src/dynamic-plugins-root
          - name: temp
            mountPath: /tmp
  3. For extraVolume, add the following content to your values.yaml file:

    extraVolumes:
          - name: dynamic-plugins-root
            ephemeral:
              volumeClaimTemplate:
                spec:
                  accessModes:
                    - ReadWriteOnce
                  resources:
                    requests:
                      storage: 5Gi

15.3. Troubleshoot plugin and workflow deployment errors to resume automation

15.3.1. Troubleshoot plugin and workflow deployment errors to resume automation

Diagnose and resolve deployment errors in plugins and serverless workflows to restore automation capabilities.

15.3.2. Troubleshoot pod startup failures

To ensure successful pod startup during a RHDH upgrade, update Orchestrator plugin versions to match the RHDH 1.8.6 configuration (version 1.8.12). This update enables the Orchestrator to automatically infer integrity hashes and prevents configuration errors.

Prerequisites

  • You have an Operator-backed instance of RHDH 1.8.5 with Orchestrator 1.8.9.
  • You encounter the following error when upgrading to RHDH 1.8.6:

    InstallException: No integrity hash provided for Package @redhat/backstage-plugin-orchestrator@1.8.9

Procedure

  1. Edit the dynamic-plugins ConfigMap to update the Orchestrator plugin version to 1.8.12:

    $ oc edit configmap dynamic-plugins-rhdh -n <your_namespace>
  2. Update the plugin versions in the ConfigMap:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: dynamic-plugins-rhdh
    data:
      dynamic-plugins.yaml: |
        includes:
          - dynamic-plugins.default.yaml
        plugins:
          - package: "@redhat/backstage-plugin-orchestrator@1.8.12"
            disabled: false
          - package: "@redhat/backstage-plugin-orchestrator-backend-dynamic@1.8.12"
            disabled: false
            dependencies:
              - ref: sonataflow
          - package: "@redhat/backstage-plugin-scaffolder-backend-module-orchestrator-dynamic@1.8.12"
            disabled: false
          - package: "@redhat/backstage-plugin-orchestrator-form-widgets@1.8.12"
            disabled: false
  3. Save and close the ConfigMap. The RHDH pods restart automatically.

Verification

  1. Monitor the status of the RHDH pods to ensure they restart:

    $ oc get pods -w
  2. Verify that all RHDH pods are in Running status with no errors.

15.3.3. Troubleshoot a pod startup failure after enabling a plugin

If the RHDH pod fails to start after enabling a plugin, you can inspect the pod logs and configure the required environment variables.

Procedure

  1. Inspect your RHDH pod logs to identify if the plugin requires specific environment variables or additional configuration, for example:

    Plugin '<PLUGIN_NAME>' threw an error during startup, waiting for X other plugins to finish before shutting down the process. Plugin '<PLUGIN_NAME>' startup failed; caused by Error: Missing required config value at '<concretePluginRequiredVariable.name>' in 'app-config.local.yaml' type="initialization"
  2. Verify the required configuration by inspecting the dynamic-plugins.default.yaml file that lists the required environment variables for each plugin. The variables for each plugin are in the format of ${PLUGIN_VARIABLE_NAME}.
  3. If any required environment variables are missing, set the environment variables by using a secret. For example:

    kind: Secret
    apiVersion: v1
    metadata:
      name: rhdh-secrets
      labels:
        backstage.io/kubernetes-id: developer-hub
    data:
      PLUGIN_VARIABLE_NAME: 'dummy-value'
    type: Opaque
  4. Mount the secret:

    1. If you deployed RHDH by using the Operator, update your Backstage CR, as follows:

      spec:
        application:
          extraEnvs:
            secrets:
              - name: rhdh-secrets
    2. If you deployed RHDH by using the Helm chart, in the upstream.backstage key in your Helm chart values, enter the name of the Developer Hub rhdh-secrets secret as the value for the extraEnvVarsSecrets field. For example:

      upstream:
        backstage:
          extraEnvVarsSecrets:
            - rhdh-secrets

15.3.4. Restore workflow visibility by removing duplicate entries

To restore clear workflow visibility in the Orchestrator UI, identify workflows that share the same ID and assign unique identifiers. When you deploy multiple versions with distinct IDs, you remove duplicate entries and maintain accurate workflow tracking.

Prerequisites

  • You have administrator access to the RHDH instance.
  • You have access to the workflow definitions and deployment manifests.

Procedure

  1. Identify duplicate workflows in the Orchestrator UI:

    1. Navigate to the Orchestrator plugin in RHDH.
    2. Review the workflow list for entries that appear multiple times with the same workflow name.
    3. Note the version information displayed in the version column of the workflow list and on the workflow details page to distinguish between duplicate entries.

      Note

      The version column displays metadata from the workflow definition, retrieved from the Data Index GraphQL schema. This information helps you identify which workflows share the same ID but does not prevent the duplicate entries. If a workflow definition does not specify a version, the field appears empty in the UI. Duplicate entries can occur when you deploy the same workflow ID to different runtime servers over time, because the Data Index records all executions.

  2. Verify the workflow IDs in your workflow definitions:

    1. Locate the workflow definition files (.sw.yaml or .sw.json files).
    2. Check the id field in each workflow definition.
    3. Identify workflows that use the same id value, even if they have different version values.
    4. Review the version field in each workflow definition to understand how workflows appear in the UI.

      Example of problematic workflow definitions:

      # First deployment
      id: customer-onboarding
      version: "1.0"
      name: Customer Onboarding
      
      # Second deployment (causes duplicate)
      id: customer-onboarding
      version: "2.0"
      name: Customer Onboarding
  3. Determine which workflow version to retain:

    1. Review the workflow instances and their execution history.
    2. Identify which version is currently in active use.
    3. Check for any running instances of older versions that must complete before removal.
  4. Update workflow definitions with unique IDs:

    1. For the new workflow version, modify the id field to include a version identifier:

      id: customer-onboarding-v2
      version: "2.0"
      name: Customer Onboarding
    2. Maintain the original workflow ID for the current deployment.
    3. Build and deploy the updated workflow definition.
  5. Remove outdated workflow deployments:

    1. After confirming the new workflow operates correctly, remove the old workflow deployment.
    2. Verify that all instances of the old workflow have completed.
    3. Delete the workflow resources from your cluster:

      oc delete sonataflow <old-workflow-name> -n <workflow-namespace>
      Note

      Deleting the workflow deployment removes it from the cluster but preserves historical execution records in the Data Index. Users can still view past workflow runs in RHDH.

  6. Clean historical data if necessary:

    If duplicate entries persist in the UI after you remove the workflow deployments, the Data Index database has historical records from earlier workflow executions. These records preserve the execution history of workflows that ran on different runtime servers over time.

    Important

    Back up your workflow execution records before you remove historical data from the Data Index database. Removing this data permanently prevents access to past execution records.

    1. Connect to the Data Index database to verify the duplicate entries.
    2. Query the workflow definitions to identify duplicate entries:

      SET search_path TO "sonataflow-platform-data-index-service";
      SELECT id, version, name FROM definitions;
    3. Evaluate whether to remove the historical data. You can keep the historical data to retain past workflow execution records, which allows you to view the execution history and results of completed workflow instances. Alternatively, contact your system administrator or Red Hat Support for guidance on safely removing historical duplicate entries from the Data Index without affecting active workflow operations.

Verification

  1. Navigate to the Orchestrator plugin in RHDH.
  2. Confirm that the UI shows only one entry for each workflow.
  3. Verify that the version information displays correctly for each workflow.
  4. Test workflow execution to confirm the correct version runs.

15.3.5. Troubleshooting workflow deployments

Identify and resolve issues related to plugin visibility, pipeline execution, or resource synchronization.

  1. Visibility issues

    Missing Orchestrator plugin
    If Orchestrator features do not appear in RHDH, make sure you have updated the RHDH Helm chart with the required plugins.
    Software templates not appearing
    Make sure the orchestrator-software-templates chart is installed and the orchestrator-auth-secret exists in the correct namespace.
  2. Pipeline failure (CI)

    GitHub or GitLab actions failure
    The GitOps automation includes a GitHub Action or GitLab CI step that creates a PipelineRun manifest from a PipelineRun template. Examine the failed GitHub or GitLab actions logs. Failures often occur due to invalid Git credentials or misconfigured runner permissions. You can also create the PipelineRun file manually to bypass automation issues.
    Build or push issues

    Check the CI tab in the RHDH Catalog.

    If RHDH does not display the status, use the OpenShift Container Platform console to monitor pipeline instances and triggered jobs. Navigate to Pipelines > PipelineRuns for detailed logs.

    If the Tekton pipeline fails during the build or push stages:

    • Verify that your Quay.io robot account has Write permissions.
    • Ensure the docker-registry-credentials secret exists in the rhdh namespace.
  3. Resource visibility and Sync issues (CD)

    Pipeline succeeds but workflows are missing

    If the CI pipeline succeeds but the workflow does not appear in the CD tab:

    • Make sure the target namespace is labeled for Argo CD:

      $ oc label ns <target_namespace> rhdh.redhat.com/argocd-namespace=true
    • Make sure the ArgoCD ServiceAccount has the required permissions to manage resources in the rhdh namespace.
    Argo CD sync failure
    If resources appear but remain in an OutOfSync state, click Refresh in the Argo CD UI or verify that the AppProject exists in the orchestrator-gitops namespace.
    PostgreSQL authentication failures in Argo CD

    If the Orchestrator fails to connect to the PostgreSQL database when you deploy by using Argo CD, the failure is often due to a mismatch in password generation.

    The Orchestrator Helm chart uses the Helm lookup function to check for an existing PostgreSQL secret. Because Argo CD uses helm template to render manifests, it cannot query the live cluster. Consequently, the chart generates a new, random password instead of retrieving the existing one, resulting in an authentication failure.

    To resolve this failure, you must complete the following steps:

    1. Create the database secret manually with the correct credentials:

      $ kubectl create secret generic <backstage-postgresql-svcbind-postgres> --from-literal=password=<your_password>
    2. Update your Helm configuration (for example, in values.yaml) to disable automatic service binding generation:

      upstream:
        postgresql:
          serviceBindings:
            enabled: false
          auth:
            username: postgres
            database: backstage
            existingSecret: backstage-postgresql-svcbind-postgres
            secretKeys:
              adminPasswordKey: password
              userPasswordKey: password
    3. Sync the application in Argo CD to apply the changes.

15.3.6. Diagnose serverless workflow issues

15.3.6.1. Diagnose serverless workflow issues

Use the following information to diagnose and resolve serverless workflow and visibility issues.

15.3.6.2. Troubleshoot HTTP error codes

Workflow operations fail when a service endpoint returns an HTTP error code. The user interface displays the HTTP code and error message.

The following table lists common HTTP errors encountered during workflow execution:

HTTP codeDescriptionPossible cause

401

Unauthorized access

The token, password, or username provided for the endpoint might be incorrect or expired.

403

Forbidden

The server understood the request but refused to process it due to insufficient permissions to a resource or action.

409

Conflict

The workflow attempted to create or update a resource (for example, Kubernetes or OpenShift resources) that already exists.

Additional resources

15.3.6.3. Troubleshoot common deployment errors

Use these steps to diagnose and resolve common workflow deployment, connectivity, or configuration failures.

Procedure

  1. If the workflow operation fails, examine the container log of the specific workflow instance to determine the cause by running the following command:

    $ oc logs my-workflow-xy73lj
  2. If the workflow fails to reach an HTTPS endpoint, check the pod log for an SSL certificate verification failure. This occurs if the target endpoint uses a Certificate Authority (CA) that the workflow cannot verify. The resulting error resembles the following:

    sun.security.provider.certpath.SunCertPathBuilderException - unable to find valid certification path to requested target
  3. To resolve the SSL certificate error, load the additional CA certificate into the running workflow container.

15.3.6.4. Troubleshoot cross-namespace configuration

Use this procedure to resolve configuration and deployment failures when SonataFlow workflows are installed in a namespace separate from the core services, or if the Data Index fails to connect to the PostgreSQL database.

Prerequisites

  • You have administrator privileges to access the OpenShift cluster.

Procedure

  1. Identify required namespaces.
  2. Retrieve the namespace value where RHDH is running using oc get backstage -A.
  3. Identify the SonataFlow Services Namespace by checking for either a sonataflowclusterplatform or sonataflowplatform instance.

    Note

    By default, the SonataFlow namespace must be the same as the RHDH namespace.

  4. If the workflow is deployed to a namespace outside the core SonataFlow services, configure network policies to permit the necessary inter-namespace traffic.

    # Example NetworkPolicy configuration to ingress traffic into the workflow namespace
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: {{ .Release.Name }}-allow-infra-ns-to-workflow-ns
      # SonataFlow and Workflows are using the RHDH target namespace.
      namespace: {{ .Release.Namespace | quote }}
    spec:
      podSelector: {}
      ingress:
        - from:
          - namespaceSelector:
              matchLabels:
                # Allow knative events to be delivered to workflows.
                kubernetes.io/metadata.name: knative-eventing
          - namespaceSelector:
              matchLabels:
                # Allow auxiliary knative function for workflow (such as m2k-save-transformation)
                kubernetes.io/metadata.name: knative-serving
          - namespaceSelector:
              matchLabels:
                # Allow communication between the serverless logic operator and the workflow namespace.
                kubernetes.io/metadata.name: openshift-serverless-logic
  5. Add SonataFlowClusterPlatform Custom Resource as shown in the following configuration:

    oc create -f - <<EOF
    apiVersion: sonataflow.org/v1alpha08
    kind: SonataFlowClusterPlatform
    metadata:
      name: cluster-platform
    spec:
      platformRef:
        name: sonataflow-platform
        namespace: $RHDH_NAMESPACE
  6. To allow communication between RHDH namespace and the workflow namespace, create the following network policies:

    1. Allow RHDH services to accept traffic from workflows. Create an additional network policy within the RHDH instance namespace as shown in the following configuration::

      oc create -f - <<EOF
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-external-workflows-to-rhdh
        # Namespace where network policies are deployed
        namespace: $RHDH_NAMESPACE
      spec:
        podSelector: {}
        ingress:
          - from:
            - namespaceSelector:
                matchLabels:
                  # Allow SonataFlow services to communicate with new/additional workflow namespace.
                  kubernetes.io/metadata.name: $ADDITIONAL_WORKFLOW_NAMESPACE
    2. Allow traffic from RHDH, SonataFlow and Knative. Create a network policy within the additional workflow namespace as shown in the following configuration:

      oc create -f - <<EOF
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-rhdh-and-knative-to-workflows
        namespace: $ADDITIONAL_WORKFLOW_NAMESPACE
      spec:
        podSelector: {}
        ingress:
          - from:
            - namespaceSelector:
                matchLabels:
                  # Allows traffic from pods in the RHDH namespace.
                  kubernetes.io/metadata.name: $RHDH_NAMESPACE
            - namespaceSelector:
                matchLabels:
                  # Allows traffic from pods in the Knative Eventing namespace.
                  kubernetes.io/metadata.name: knative-eventing
            - namespaceSelector:
                matchLabels:
                  # Allows traffic from pods in the Knative Serving namespace.
                  kubernetes.io/metadata.name: knative-serving
  7. (Optional) Create an allow-intra-namespace policy in the workflow namespace to enable unrestricted communication among all pods within that namespace.
  8. If workflow persistence is required, perform the following configuration steps:

    1. Create a dedicated PostgreSQL Secret containing database credentials within the workflow namespace as shown in the following configuration:

      oc get secret sonataflow-psql-postgresql -n <your_namespace> -o yaml > secret.yaml
      sed -i '/namespace: <your_namespace>/d' secret.yaml
      oc apply -f secret.yaml -n $ADDITIONAL_NAMESPACE
    2. Configure the workflow serviceRef property to correctly reference the PostgreSQL service namespace as shown in the following configuration:

      apiVersion: sonataflow.org/v1alpha08
      kind: SonataFlow
        ...
      spec:
        ...
        persistence:
          postgresql:
            secretRef:
              name: sonataflow-psql-postgresql
              passwordKey: postgres-password
              userKey: postgres-username
            serviceRef:
              databaseName: sonataflow
              databaseSchema: greeting
              name: sonataflow-psql-postgresql
              namespace: $POSTGRESQL_NAMESPACE
              port: 5432
      namespace
      Enter the namespace where the PostgreSQL server is deployed.
  9. If the sonataflow-platform-data-index-service cannot connect to the PostgreSQL database on startup, perform the following diagnostic checks:

    1. Verify that the PostgreSQL Pod has fully transitioned to a running and operational status. Allow additional time for database initialization before expecting related service pods (DataIndex, JobService) to establish a connection.
    2. If the PostgreSQL Server operates in a dedicated namespace (for example, outside RHDH), verify that network policies are configured to allow ingress traffic from the SonataFlow services namespace. Network policies might prevent the Data Index and Job Service pods from connecting to the database.

15.3.6.5. Troubleshoot missing workflows

You can perform the following checks to verify the workflow status and connectivity when the deployed workflow is missing from the RHDH Orchestrator UI.

Prerequisites

  • You have administrator privileges to access the OpenShift cluster where RHDH and SonataFlow services are running.

Procedure

  1. Verify if the workflow uses GitOps profile. The RHDH Orchestrator UI displays only the workflows that use this profile. Make sure the workflow definition and the SonataFlow manifests use the GitOps profile.
  2. Verify that the workflow pod has started and is ready. The readiness of a workflow pod depends on its successful registration with the Data Index. When a workflow initializes, it performs the following actions:

    1. It attempts to create its schema in the database (if persistence is active).
    2. It attempts to register itself to the Data Index. The workflow pod remains in an unready state until it successfully registers to the Data Index.

      Check the workflow deployment for additional status and error messages that might be unavailable in the pod log.

  3. Check if the workflow pod can reach the Data Index service. Connect to the workflows pod and send the following GraphQL request to the Data Index:

    curl -g -k  -X POST  -H "Content-Type: application/json" \
                        -d '{"query":"query{ ProcessDefinitions  { id, serviceUrl, endpoint } }"}' \
                        http://sonataflow-platform-data-index-service.<your_namespace>/graphql

    Use the Data Index service and namespace as defined in your environment. By default, this is the same namespace where RHDH is installed. If your SonataFlow resources are installed in a separate namespace, use <your_namespace>. Check if the RHDH pod can reach the workflow service by running the following command:

    curl http://<workflow_service>.<workflow_namespace>/management/processes
  4. Connect to the RHDH pod. Verify its connection to the Data Index service and inspect the RHDH pod logs for messages from the Orchestrator plugin.

    To inspect the logs, identify the RHDH pod and run the following oc logs command:

    oc get pods -n <your_namespace>
    oc logs <rhdh_pod_name> -n <your_namespace>

    You must find messages indicating it is attempting to fetch workflow information from the Data Index, similar to the following:

    {"level":"\u001b[32minfo\u001b[39m","message":"fetchWorkflowInfos() called: http://sonataflow-platform-data-index-service.<your_namespace>","plugin":"orchestrator","service":"backstage","span_id":"fca4ab29f0a7aef9","timestamp":"2025-08-04 17:58:26","trace_flags":"01","trace_id":"5408d4b06373ff8fb34769083ef771dd"}

    Notice the "plugin":"orchestrator" that can help to filter the messages.

  5. Make sure the Data Index properties are set in the -managed-props ConfigMap of the workflow as shown in the following configuration:

    kogito.data-index.health-enabled = true
    kogito.data-index.url = http://sonataflow-platform-data-index-service.<your_namespace>
    ...
    mp.messaging.outgoing.kogito-processdefinitions-events.url = http://sonataflow-platform-data-index-service.<your_namespace>/definitions
    mp.messaging.outgoing.kogito-processinstances-events.url = http://sonataflow-platform-data-index-service.<your_namespace>/processes
    Note

    The -managed-props ConfigMap is located in the same namespace as the workflow and is generated by the OpenShift Serverless Logic (OSL) Operator.

    These properties, along with similar settings for the Job Services, indicate that the (OSL) Operator successfully registered the Data Index service.

  6. Confirm that the workflow is registered in the Data Index database. Connect to the database used by the Data Index and run the following command from the PSQL instance pod:

    PGPASSWORD=<psql password> psql -h localhost -p 5432 -U < user> -d sonataflow

    Replace <psql password> and <user> with your database credentials.

    Run the following SQL commands to query the registered workflow definitions:

    sonataflow=# SET search_path TO "sonataflow-platform-data-index-service";
    sonataflow=# select id, name from definitions;

    You must see your workflows listed in the query results.

  7. Make sure you have enabled Data Index and Job Service in the SonataFlowPlatform custom resource (CR) as shown in the following configuration:

    services:
        dataIndex:
          enabled: true
        jobService:
          enabled: true

    If you fail to enable the Data Index and the Job Services in the SonataFlowPlatform custom resource (CR), the Orchestrator plugin fails to fetch the available workflows.

    Note

    You can also manually edit the SonataFlowPlatform CR instance to trigger the re-creation of workflow-related manifests.

  8. Configure role-based access control (RBAC) permissions to ensure workflows are visible in the Orchestrator UI.

    Note

    When the RBAC plugin is enabled, the Orchestrator UI does not display workflows by default. You must explicitly grant read permissions.

    1. Check your RHDH app-config.yaml file to confirm if the RBAC plugin is enabled.
    2. Confirm your user or role has the orchestrator.workflow permission with the read action.
    3. If this permission is missing, add the following to your RBAC CSV (rbac-policy.csv) file:

      p, role:default/workflowUser, orchestrator.workflow, read, allow
    4. Make sure policyFileReload is set to true in your configuration, or restart the RHDH application:

      permission:
        enabled: true
        rbac:
          policyFileReload: true

15.4. Troubleshoot AI and tool integrations to restore intelligent features

15.4.1. Troubleshoot AI and tool integrations to restore intelligent features

Diagnose and resolve issues with AI Connector and Model Context Protocol tools to restore intelligent platform features.

15.4.2. Troubleshoot AI Connector functionality

15.4.2.1. Troubleshoot AI Connector functionality

The connector system consists of the two dynamic plugins and the three OpenShift AI Connector sidecar containers. You must gather logs from these components and provide them to Red Hat Support for diagnostic analysis.

15.4.2.2. Troubleshoot Connector functionality

The connector system consists of the two dynamic plugins and the three OpenShift AI Connector for RHDH sidecar containers. You must gather logs from these components and provide them to Red Hat Support for diagnostic analysis.

The actual contents of the diagnostic data are not part of any product guaranteed specification, and can change at any time.

Note

During startup, you might see non-critical log errors, such as in cluster config error: open /var/run/secrets/kubernetes.io/serviceaccount/token: no such file or directory, in the sidecar logs. This error is expected during the initial setup and does not indicate a failure, provided the container eventually becomes healthy.

15.4.2.2.1. Verify dynamic plugin status

Validate that the dynamic plugins have been successfully installed into your RHDH project Pod by using the following command:

$ oc logs -c install-dynamic-plugins deployment/<your RHDH deployment>

In the install-dynamic-plugin logs, you can check the following installation logs for successful logs:

  • red-hat-developer-hub-backstage-plugin-catalog-backend-module-model-catalog (Entity Provider)
  • red-hat-developer-hub-backstage-plugin-catalog-techdoc-url-reader-backend (TechDoc URL Reader)
15.4.2.2.2. Inspect plugin logs

View the OpenShift AI Connector for Red Hat Developer Hub plugins in the backstage-backend container. Items to look for:

Plugin ComponentLogger Service TargetCommon Log Text

Model Catalog Entity Provider

ModelCatalogResourceEntityProvider

Discovering ResourceEntities from Model Server…​

Model Catalog TechDoc URL Reader

ModelCatalogBridgeTechdocUrlReader

ModelCatalogBridgeTechdocUrlReader.readUrl

To enable debug logging, set the LOG_LEVEL environment variable to debug on the backstage-backend container. For more information, see Monitoring and logging.

15.4.2.2.3. Inspect the OpenShift AI Connector for RHDH

The OpenShift AI Connector for RHDH sidecars manage the data fetching and storage:

  1. Check Cached Data (ConfigMap): The processed AI Model metadata is stored in a ConfigMap.

    $ oc get configmap bac-import-model -o json | jq -r '.binaryData | to_entries[] | "=== \(.key) ===\n" + (.value | @base64d | fromjson | .body | @base64d | fromjson | tostring)' | jq -R 'if startswith("=== ") then . else (. | fromjson) end'
  2. Check Location Service API: Confirm the location service is providing data to the RHDH Entity Provider.

    $ oc rsh -c backstage-backend deployment/<your RHDH deployment>
    $ curl http://localhost:9090/list
  3. Check Sidecar Container Logs:

    $ oc logs -c rhoai-normalizer deployment/<your {product-very-short} deployment>
    $ oc logs -c storage-rest deployment/<your {product-very-short} deployment>
    $ oc logs -c location deployment/<your {product-very-short} deployment>

15.4.2.3. Query model registries

To access the same RHOAI data as the connector, use curl to query the RHOAI model registry and model catalog APIs, ensuring the ServiceAccount token has correct access control:

  • Example showing how to fetch registered models

    $ curl -k -H "Authorization: Bearer $TOKEN" ${rhoai-short}_MODEL_REGISTRY_URL/api/model_registry/v1alpha3/registered_models | jq
  • Example showing how to fetch model versions

    $ curl -k -H "Authorization: Bearer $TOKEN" ${rhoai-short}_MODEL_REGISTRY_URL/api/model_registry/v1alpha3/model_versions | jq
  • Example showing how to fetch model artifacts

    $ curl -k -H "Authorization: Bearer $TOKEN" ${rhoai-short}_MODEL_REGISTRY_URL/api/model_registry/v1alpha3/model_artifacts | jq
  • Example showing how to fetch inference services

    $ curl -k -H "Authorization: Bearer $TOKEN" ${rhoai-short}_MODEL_REGISTRY_URL/api/model_registry/v1alpha3/inference_services | jq
  • Example showing how to fetch serving environments

    $ curl -k -H "Authorization: Bearer $TOKEN" ${rhoai-short}_MODEL_REGISTRY_URL/api/model_registry/v1alpha3/serving_environments | jq
  • Example showing how to fetch catalog sources

    $ curl -k -H "Authorization: Bearer $TOKEN" ${rhoai-short}_MODEL_CATALOG_URL/api/model_catalog/v1alpha1/sources | jq

15.4.3. Troubleshoot MCP server and client problems

15.4.3.1. Troubleshoot MCP server and client problems

Diagnose and resolve common issues with MCP server installation, client configuration, and tool execution in Red Hat Developer Hub.

15.4.3.2. Verify successful installation of MCP plugins

Verify MCP plugin installation by checking pod logs for successful plugin loading and MCP tool registration.

Procedure

  1. Log in to the OCP cluster running RHDH and go to your RHDH project using the following code:

    $ oc project my-rhdh-project
  2. Inspect the logs for the installation of the RHDH dynamic plugins using the following code:

    $ oc logs -c install-dynamic-plugins deployment/<my-product-deployment>

Verification

  1. You must see an entry for the MCP backend server plugin as shown in the following code:

    ..... prior logs ....
    ======= Installing dynamic plugin oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:<tag>
    	==> Copying image oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:<tag> to local filesystem
    	==> Successfully installed dynamic plugin oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:<tag>

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  2. Find your Backstage version in the RHDH release notes preface.
  3. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

  4. You must see entries for any of the MCP tool plugins you installed as shown in the following code:

    ..... prior logs ....
    ======= Installing dynamic plugin oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:<tag>
    	==> Copying image oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:<tag> to local filesystem
    	==> Successfully installed dynamic plugin oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:<tag>

    where:

    <tag>
    Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:
  5. Find your Backstage version in the RHDH release notes preface.
  6. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

15.4.3.3. Check MCP tool logs for status and errors

Review Backstage LoggerService logs for MCP tool execution status and error messages.

The Backstage LoggerService target name starts with the name of the MCP tool (either software-catalog-mcp-tool or techdocs-mcp-tool). The MCP tools generate a log by default. For example:

`[backend]: 2025-09-25T16:24:22.660Z software-catalog-mcp-tool info fetch-catalog-entities: Fetching catalog entities with options: kind="Component"`

If any errors occur in the MCP tools, check the logs.

15.4.3.4. Validate tool inputs using error messages

MCP tools provide optional error messages that communicate issues including input validation errors encountered during tool use.

The MCP tools response provides an optional error message that communicates any issues encountered during the use of the tool, including potential input validation errors.

15.4.3.5. Resolve unsupported tool calling errors

Resolve tool calling errors by confirming your AI model supports tool calls and switching to a compatible model if needed.

This error indicates that the model configured in your MCP client lacks the required functionality to handle tool calls. The error message appears similar to: Invalid request: model gemma3:27b does not support tool calls.

Procedure

  1. Consult your model documentation to confirm its support for tool calling.
  2. If the current model does not support tool calling, change the model that your MCP client uses to a tool-calling compatible model.

15.4.3.6. Resolve authentication issues

Verify authentication tokens and configuration settings when Model Context Protocol (MCP) clients connect to the server but do not display deployed tools.

If an MCP client connects to the server but cannot find deployed tools, verify the authentication status and endpoint resolution.

Procedure

  1. Check the token validation status in the Red Hat Developer Lightspeed for Red Hat Developer Hub interface:

    1. In the Red Hat Developer Lightspeed for Red Hat Developer Hub chat box, click the menu icon (Chatbot options) and select MCP settings.
    2. Locate the relevant server and check the status message displayed below the token field.
    3. If the status is Authorization failed. Try again, the token is incorrect, improperly formatted, or missing. You must verify the token value and ensure the server is enabled.
  2. Verify the authentication token configuration.

    1. Ensure a static token is configured for the RHDH MCP server.
    2. In your MCP client, verify that the token is set as the bearer token. The authorization header must use the Bearer <mcp_token> format.
  3. Check the MCP endpoint configuration.

    1. Confirm that the MCP server URL properly resolves correctly, particularly when using desktop clients.
    2. Use legacy SSE endpoint if your MCP client requires it instead of the Streamable endpoint. (For more details, see the Configuration topic).
  4. Verify the RHDH app-config.yaml file for formatting errors:

    1. Ensure there are no duplicate backend entries and that the YAML indentation is accurate.
    2. Confirm that the configuration for the static token and MCP plugin sources is nested under an existing backend field, if one is present. For a reference configuration, see Configure MCP in RHDH.

15.4.3.7. Resolve nonsensical MCP tool output

Improve MCP tool output quality by using larger models or models with larger context windows when nonsensical results occur.

Nonsensical output often occurs when smaller models or models with smaller context sizes cannot effectively manage repeated tool calls within the same context window.

Procedure

  1. Select an appropriate model for tool calling.

    1. Verify that the model has good support for tool calling.
    2. Make sure your model is not too small. We recommend a model with at least 7 billion parameters and a context window of 32k.
  2. Refine your queries.

    1. Use more well-defined queries that limit the amount of data returned in the response from the tool.
  3. If possible, increase the context window size of the model. We recommend at least 32k for these MCP tools.

Chapter 16. Reference

16.1. Reference

Quick-lookup reference information for Red Hat Developer Hub configuration syntax, permission policies, trace attributes, and Helm chart parameters.

Use this section to look up supported dynamic plugin parameters and configuration paths, permission policy strings and conditional rule schemas for RBAC, OpenTelemetry configuration properties and trace attributes for workflow observability, and Helm chart values for deployment customization.

16.2. Dynamic plugin parameter reference for configuration paths

16.2.1. Dynamic plugin parameter reference for configuration paths

Reference information about the dynamic plugins available in Red Hat Developer Hub, including preinstalled plugins, supported configuration paths, and support tiers.

Use this reference to look up plugin names, package identifiers, and configuration paths when installing, enabling, or customizing dynamic plugins in your Developer Hub deployment. Plugins are organized by support tier: generally available, Technology Preview, deprecated, and other installable plugins.

16.2.2. Preinstalled dynamic plugins reference

Red Hat Developer Hub is preinstalled with a selection of dynamic plugins.

The following 16 preinstalled dynamic plugins are enabled by default:

  • @backstage-community/plugin-analytics-provider-segment
  • @backstage-community/plugin-scaffolder-backend-module-regex
  • @backstage/plugin-techdocs-backend
  • @backstage/plugin-techdocs-module-addons-contrib
  • @backstage/plugin-techdocs
  • @red-hat-developer-hub/backstage-plugin-adoption-insights-backend
  • @red-hat-developer-hub/backstage-plugin-adoption-insights
  • @red-hat-developer-hub/backstage-plugin-analytics-module-adoption-insights
  • @red-hat-developer-hub/backstage-plugin-catalog-backend-module-extensions
  • @red-hat-developer-hub/backstage-plugin-dynamic-home-page
  • @red-hat-developer-hub/backstage-plugin-extensions-backend
  • @red-hat-developer-hub/backstage-plugin-extensions
  • @red-hat-developer-hub/backstage-plugin-global-header
  • @red-hat-developer-hub/backstage-plugin-lightspeed-backend
  • @red-hat-developer-hub/backstage-plugin-lightspeed
  • @red-hat-developer-hub/backstage-plugin-quickstart

The dynamic plugins that require custom configuration are disabled by default.

Upon application startup, for each plugin that is disabled by default, the install-dynamic-plugins init container within the Developer Hub pod log displays a message similar to the following:

======= Skipping disabled dynamic plugin ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic

To enable this plugin, add a package with the same name to the Helm chart and change the value in the disabled field to false. For example:

global:
  dynamic:
    includes:
      - dynamic-plugins.default.yaml
    plugins:
      - package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic
        disabled: false
Note

The default configuration for a plugin is extracted from the dynamic-plugins.default.yaml file, however, you can use a pluginConfig entry to override the default configuration.

16.2.3. Red Hat supported plugins and configuration paths reference

Red Hat provides full support for the following 31 dynamic plugins.

NamePluginVersionPath and required variables

Adoption Insights

@red-hat-developer-hub/backstage-plugin-adoption-insights

0.8.2

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-adoption-insights

Adoption Insights

@red-hat-developer-hub/backstage-plugin-adoption-insights-backend

0.8.2

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-adoption-insights-backend-dynamic

Analytics Module Adoption Insights

@red-hat-developer-hub/backstage-plugin-analytics-module-adoption-insights

0.8.2

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-analytics-module-adoption-insights-dynamic

Analytics Provider Segment

@backstage-community/plugin-analytics-provider-segment

1.27.0

./dynamic-plugins/dist/backstage-community-plugin-analytics-provider-segment

BACKSTAGE_VERSION

RHDH_VERSION

SEGMENT_TEST_MODE

SEGMENT_WRITE_KEY

Dynamic Home Page

@red-hat-developer-hub/backstage-plugin-dynamic-home-page

1.13.1

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page

GitHub Org

@backstage/plugin-catalog-backend-module-github-org

0.3.20

./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic

GITHUB_ORG

GITHUB_URL

GitHub

@backstage/plugin-catalog-backend-module-github

0.13.0

./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic

GITHUB_ORG

GitHub

@backstage/plugin-scaffolder-backend-module-github

0.9.7

./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-github-dynamic

GitLab Org

@backstage/plugin-catalog-backend-module-gitlab-org

0.2.19

./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-org-dynamic

GITLAB_HOST

GITLAB_ORG_GROUP

GitLab

@backstage/plugin-catalog-backend-module-gitlab

0.8.1

./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-gitlab-dynamic

GITLAB_DISCOVERY_GROUP

GITLAB_HOST

Global Header

@red-hat-developer-hub/backstage-plugin-global-header

1.21.6

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-header

Keycloak

@backstage-community/plugin-catalog-backend-module-keycloak

3.19.2

./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-keycloak-dynamic

KEYCLOAK_BASE_URL

KEYCLOAK_CLIENT_ID

KEYCLOAK_CLIENT_SECRET

KEYCLOAK_LOGIN_REALM

KEYCLOAK_REALM

Kubernetes

@backstage/plugin-kubernetes-backend

0.21.2

./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic

K8S_CLUSTER_NAME

K8S_CLUSTER_TOKEN

K8S_CLUSTER_URL

Kubernetes

@backstage-community/plugin-scaffolder-backend-module-kubernetes

2.17.1

./dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-kubernetes-dynamic

Ldap

@backstage/plugin-catalog-backend-module-ldap

0.12.3

./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-ldap-dynamic

LDAP_BIND_DN

LDAP_BIND_SECRET

LDAP_GROUPS_DN

LDAP_TARGET_URL

LDAP_USERS_DN

Lightspeed

@red-hat-developer-hub/backstage-plugin-lightspeed

2.8.5

oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-lightspeed@sha256:c68a58f268485e79e60a21e4f45e1c27b446bc17fcbb1af8a0e35b04d4f5cea7

Lightspeed

@red-hat-developer-hub/backstage-plugin-lightspeed-backend

2.8.5

oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-lightspeed-backend@sha256:3147f09ad990fbcd22a9f613d6982b4534b235a2c2d27684fc1834e196cd83ff

MS Graph

@backstage/plugin-catalog-backend-module-msgraph

0.9.1

./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-msgraph-dynamic

MICROSOFT_CLIENT_ID

MICROSOFT_CLIENT_SECRET

MICROSOFT_TENANT_ID

Orchestrator Form Widgets

@red-hat-developer-hub/backstage-plugin-orchestrator-form-widgets

1.10.7

oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets@sha256:5671a9d01cb98b7172019ddb3b524b5c8089a081273db00c9da24057f9bb8db3

Orchestrator

@red-hat-developer-hub/backstage-plugin-orchestrator

5.7.12

oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@sha256:a26989fc49b4f2ce58e4764e928eacff000d4dd9007d06c553ce2ff6fe60c41f

Orchestrator

@red-hat-developer-hub/backstage-plugin-orchestrator-backend

8.9.4

oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend@sha256:5e2e95950c3112a10c23c0fddae86b257d0cc16f9cde3dd2fc945b6a7be5f7c5

Quickstart

@red-hat-developer-hub/backstage-plugin-quickstart

1.9.6

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-quickstart

RBAC

@backstage-community/plugin-rbac

1.52.4

./dynamic-plugins/dist/backstage-community-plugin-rbac

Regex

@backstage-community/plugin-scaffolder-backend-module-regex

2.15.1

./dynamic-plugins/dist/backstage-community-plugin-scaffolder-backend-module-regex-dynamic

Signals

@backstage/plugin-signals-backend

0.3.13

./dynamic-plugins/dist/backstage-plugin-signals-backend-dynamic

Tech Radar

@backstage-community/plugin-tech-radar

1.17.0

./dynamic-plugins/dist/backstage-community-plugin-tech-radar

Tech Radar

@backstage-community/plugin-tech-radar-backend

1.16.0

./dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic

TECH_RADAR_DATA_URL

TechDocs Module Addons Contrib

@backstage/plugin-techdocs-module-addons-contrib

1.1.34

./dynamic-plugins/dist/backstage-plugin-techdocs-module-addons-contrib

TechDocs

@backstage/plugin-techdocs

1.17.2

./dynamic-plugins/dist/backstage-plugin-techdocs

TechDocs

@backstage/plugin-techdocs-backend

2.1.6

./dynamic-plugins/dist/backstage-plugin-techdocs-backend-dynamic

Topology

@backstage-community/plugin-topology

2.12.3

./dynamic-plugins/dist/backstage-community-plugin-topology

16.2.4. Technology Preview plugins

Red Hat provides Technology Preview support for the following 14 plugins.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

NamePluginVersionPath and required variables

ACR

@backstage-community/plugin-acr

1.24.1

./dynamic-plugins/dist/backstage-community-plugin-acr

Bulk Import

@red-hat-developer-hub/backstage-plugin-bulk-import

7.3.5

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import

Bulk Import

@red-hat-developer-hub/backstage-plugin-bulk-import-backend

7.3.5

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic

Extensions

@red-hat-developer-hub/backstage-plugin-extensions

0.17.1

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions

Extensions

@red-hat-developer-hub/backstage-plugin-catalog-backend-module-extensions

0.17.1

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-catalog-backend-module-extensions-dynamic

RHDH_EXTENSIONS_DIRECTORY

Extensions

@red-hat-developer-hub/backstage-plugin-extensions-backend

0.17.1

./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-extensions-backend-dynamic

RHDH_EXTENSIONS_INSTALL_EXPORT_PATH

GitLab

@backstage/plugin-scaffolder-backend-module-gitlab

0.11.4

./dynamic-plugins/dist/backstage-plugin-scaffolder-backend-module-gitlab-dynamic

Kubernetes

@backstage/plugin-kubernetes

0.12.17

./dynamic-plugins/dist/backstage-plugin-kubernetes

Notifications

@backstage/plugin-notifications

0.5.15

./dynamic-plugins/dist/backstage-plugin-notifications

Notifications

@backstage/plugin-notifications-backend-module-email

0.3.19

./dynamic-plugins/dist/backstage-plugin-notifications-backend-module-email-dynamic

EMAIL_HOSTNAME

EMAIL_PASSWORD

EMAIL_SENDER

EMAIL_USERNAME

Notifications

@backstage/plugin-notifications-backend

0.6.3

./dynamic-plugins/dist/backstage-plugin-notifications-backend-dynamic

Pingidentity

@backstage-community/plugin-catalog-backend-module-pingidentity

0.11.1

./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-pingidentity-dynamic

PING_IDENTITY_API_BASE_URL

PING_IDENTITY_AUTH_BASE_URL

PING_IDENTITY_CLIENT_ID

PING_IDENTITY_CLIENT_SECRET

PING_IDENTITY_ENV_ID

Scaffolder Relation Processor

@backstage-community/plugin-catalog-backend-module-scaffolder-relation-processor

2.14.2

./dynamic-plugins/dist/backstage-community-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic

Signals

@backstage/plugin-signals

0.0.29

./dynamic-plugins/dist/backstage-plugin-signals

16.2.5. Deprecated plugins

There are no deprecated plugins in this release of Red Hat Developer Hub (RHDH)

16.2.6. Other installable plugins

The following Technology Preview plugins are not preinstalled and must be installed from an external source.

Important

These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.

NamePluginVersionInstallation Details

Ansible Automation Platform Frontend

@ansible/plugin-backstage-rhaap

1.0.0

Learn more

Ansible Automation Platform

@ansible/plugin-backstage-rhaap-backend

1.0.0

Learn more

Ansible Automation Platform Scaffolder Backend

@ansible/plugin-scaffolder-backend-module-backstage-rhaap

1.0.0

Learn more

16.2.7. Red Hat community supported plugins

Red Hat provides community support for the following 45 dynamic plugins in ghcr.io.

Note

Replace <tag> with the version tag corresponding to your Developer Hub version. See Determining Tag Values

NameVersionPath and required variables

3Scale

3.13.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-3scale-backend:<tag>

THREESCALE_ACCESS_TOKEN

THREESCALE_BASE_URL

`

ArgoCD Backend

1.4.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd-backend:<tag>

ARGOCD_AUTH_TOKEN

ARGOCD_INSTANCE1_URL

ARGOCD_PASSWORD

ARGOCD_USERNAME

`

Auth Frontend

0.1.6

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-auth:<tag>

`

Azure DevOps Backend

0.27.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-azure-devops-backend:<tag>

AZURE_ORG

AZURE_TOKEN

`

Catalog Backend Module Azure DevOps Annotator Processor

0.18.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-catalog-backend-module-azure-devops-annotator-processor:<tag>

`

Catalog Backend Module Bitbucket Cloud

0.5.9

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-catalog-backend-module-bitbucket-cloud:<tag>

BITBUCKET_WORKSPACE

`

Catalog Backend Module Bitbucket Server

0.5.9

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-catalog-backend-module-bitbucket-server:<tag>

BITBUCKET_HOST

`

Datadog

2.7.2

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-datadog:<tag>

`

Dynatrace

10.17.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-dynatrace:<tag>

`

GitHub Actions

0.22.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-github-actions:<tag>

`

GitHub Deployments

0.18.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-github-deployments:<tag>

`

GitHub Discussions

0.10.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-github-discussions:<tag>

`

GitHub Discussions Search Backend Module

0.11.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-search-backend-module-github-discussions:<tag>

GITHUB_DISCUSSIONS_REPO_URL

`

GitHub Insights

3.5.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-github-insights:<tag>

`

GitHub Issues

0.21.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-github-issues:<tag>

`

GitHub Pull Requests

3.7.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-github-pull-requests:<tag>

`

GitHub Pull Requests Board

0.16.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-github-pull-requests-board:<tag>

`

GitLab Backend

7.0.1

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/immobiliarelabs-backstage-plugin-gitlab-backend:<tag>

GITLAB_HOST

GITLAB_TOKEN

`

JFrog Artifactory

1.28.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-jfrog-artifactory:<tag>

`

Jenkins Backend

0.27.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-jenkins-backend:<tag>

JENKINS_TOKEN

JENKINS_URL

JENKINS_USERNAME

`

Jenkins Scaffolder Backend Module

0.20.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-jenkins:<tag>

`

Jira

2.14.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-jira:<tag>

`

Lighthouse Backend

0.21.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-lighthouse-backend:<tag>

`

Nexus Repository Manager

1.23.2

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-nexus-repository-manager:<tag>

`

PagerDuty Backend

0.12.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/pagerduty-backstage-plugin-backend:<tag>

PAGERDUTY_API_BASE

PAGERDUTY_CLIENT_ID

PAGERDUTY_CLIENT_SECRET

PAGERDUTY_SUBDOMAIN

`

PagerDuty Entity Processor

0.3.10

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/pagerduty-backstage-plugin-entity-processor:<tag>

`

PagerDuty Scaffolder Actions

0.2.9

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/pagerduty-backstage-plugin-scaffolder-actions:<tag>

`

Quay Backend

1.14.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-quay-backend:<tag>

`

Roadie ArgoCD Backend

4.8.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-argo-cd-backend:<tag>

ARGOCD_AUTH_TOKEN

ARGOCD_INSTANCE1_URL

ARGOCD_PASSWORD

ARGOCD_USERNAME

`

Scaffolder Backend ArgoCD

1.8.1

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-scaffolder-backend-argocd:<tag>

ARGOCD_AUTH_TOKEN

ARGOCD_INSTANCE1_URL

ARGOCD_PASSWORD

ARGOCD_USERNAME

`

Scaffolder Backend Module AWS

2.8.2

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-scaffolder-backend-module-aws:<tag>

AWS_ACCESS_KEY_ID

AWS_SECRET_ACCESS_KEY

`

Scaffolder Backend Module Azure

0.2.19

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-scaffolder-backend-module-azure:<tag>

`

Scaffolder Backend Module Azure DevOps

0.23.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-azure-devops:<tag>

`

Scaffolder Backend Module Bitbucket Cloud

0.3.4

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-scaffolder-backend-module-bitbucket-cloud:<tag>

`

Scaffolder Backend Module Bitbucket Server

0.2.19

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-scaffolder-backend-module-bitbucket-server:<tag>

`

Scaffolder Backend Module DotNet

0.13.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-dotnet:<tag>

`

Scaffolder Backend Module Gerrit

0.2.19

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-scaffolder-backend-module-gerrit:<tag>

`

Scaffolder Backend Module Quay

2.18.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-quay:<tag>

`

Scaffolder Backend Module ServiceNow

2.15.1

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-servicenow:<tag>

SERVICENOW_BASE_URL

SERVICENOW_PASSWORD

SERVICENOW_USERNAME

`

Scaffolder Backend Module SonarQube

2.15.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-scaffolder-backend-module-sonarqube:<tag>

`

Scaffolder Backend Module Utils

4.1.2

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-scaffolder-backend-module-utils:<tag>

`

Search Backend Module Azure DevOps

0.5.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-search-backend-module-azure-devops:<tag>

AZURE_DEVOPS_BASE_URL

AZURE_DEVOPS_ORGANIZATION

AZURE_DEVOPS_PROJECT

AZURE_DEVOPS_TOKEN

AZURE_DEVOPS_WIKI_IDENTIFIER

`

Security Insights

3.3.1

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/roadiehq-backstage-plugin-security-insights:<tag>

`

SonarQube Backend

1.1.1

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-sonarqube-backend:<tag>

SONARQUBE_TOKEN

SONARQUBE_URL

`

Tekton

3.37.0

oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-tekton:<tag>

`

16.2.7.1. Troubleshooting

Plugin not loading

If a plugin fails to load, perform the following checks:

  1. Verify the ghcr.io path is correct and the image tag or digest exists.
  2. Confirm your cluster has network access to ghcr.io.
  3. Review Developer Hub logs for OCI pull errors.

Determining tag values

where:

<tag>

Enter your RHDH version of Backstage and the plugin version, in the format bs_<backstage-version>__<plugin-version> (note the double underscore delimiter). To find these versions, complete the following steps:

  1. Find your Backstage version in the RHDH release notes preface.
  2. Locate the plugin version in the Dynamic Plugins Reference guide. For example, for RHDH 1.9 based on Backstage 1.45.3, use the format bs_1.45.3__<plugin-version>.

    Tip

    To ensure environment stability, use a SHA256 digest instead of a version tag. See Determining SHA256 Digests.

Determining SHA256 digests

You can look up the SHA256 digest using the Skopeo CLI or by searching in the RHDH Plugin Export Overlays repository.

Skopeo CLI

Ensure you have skopeo and jq installed.

  1. Locate the plugin path in the Dynamic plugins reference.
  2. Run the following command, replacing the plugin path prefix oci:// with docker://:

    skopeo inspect docker://<plugin-path>:<tag> | jq '.Digest'

RHDH Plugin Export Overlays Repo

Go to the plugin packages list in the rhdh-plugin-export-overlays repository. Search for your plugin and select the tag that is associated with this release.

16.2.7.2. Additional resources

16.3. Permission policies and conditional rules reference for RBAC configurations

16.3.1. Permission policies and conditional rules reference for RBAC configurations

Reference information about permission policy types, available permissions, and conditional policy rules for RBAC configurations in Red Hat Developer Hub.

Use this reference to look up the permission strings required when defining RBAC policies for catalog, scaffolder, RBAC, Kubernetes, Extensions, and plugin resources. You can also look up conditional policy schemas and examples for defining fine-grained access rules with or without criteria.

16.3.2. Permission policies

16.3.2.1. Permission policies

Reference information about permission policy types and available permissions for catalog, scaffolder, RBAC, Kubernetes, Extensions, and plugin resources.

Developer Hub supports permission policies for controlling access to resources and functionalities. The following reference modules describe the available permission types and permissions for each plugin category.

16.3.2.2. Permission policy parameters and definitions

Reference information about resource type and basic permission types in Developer Hub.

Permission policies in Red Hat Developer Hub are a set of rules to govern access to resources or functionalities. These policies state the authorization level that is granted to users based on their roles. The permission policies are implemented to keep security and confidentiality within a given environment.

You can define the following types of permissions in Developer Hub:

  • resource type
  • basic

The distinction between the two permission types depends on whether a permission includes a defined resource type.

You can define the resource type permission by using either the associated resource type or the permission name as shown in the following example:

p, role:default/myrole, catalog.entity.read, read, allow
g, user:default/myuser, role:default/myrole

p, role:default/another-role, catalog-entity, read, allow
g, user:default/another-user, role:default/another-role

You can define the basic permission in Developer Hub using the permission name as shown in the following example:

p, role:default/myrole, catalog.entity.create, create, allow
g, user:default/myuser, role:default/myrole

16.3.2.3. Catalog permissions

Reference information about available catalog permissions for reading, creating, updating, and deleting catalog entities and locations.

NameResource typePolicyDescription

catalog.entity.read

catalog-entity

read

Enables a user or role to read from the catalog

catalog.entity.create

 

create

Enables a user or role to create catalog entities, including registering an existing component in the catalog

catalog.entity.refresh

catalog-entity

update

Enables a user or role to refresh a single or multiple entities from the catalog

catalog.entity.delete

catalog-entity

delete

Enables a user or role to delete a single or multiple entities from the catalog

catalog.location.read

 

read

Enables a user or role to read a single or multiple locations from the catalog

catalog.location.create

 

create

Enables a user or role to create locations within the catalog

catalog.location.delete

 

delete

Enables a user or role to delete locations from the catalog

16.3.2.4. Bulk import permission

Reference information about the bulk import permission for accessing bulk import endpoints.

NameResource typePolicyDescription

bulk.import

bulk-import

use

Enables the user to access the bulk import endpoints, such as listing all repositories and organizations accessible by the signed-in user (using SCM OAuth) and managing the import requests. Repositories already present in the software catalog are automatically hidden from this list.

Important

bulk.import permissions will fail to list repositories if GitHub or GitLab OAuth providers are not explicitly configured for the instance.

16.3.2.5. Scaffolder permissions

Reference information about scaffolder permissions for executing actions, reading templates, and managing scaffolder tasks.

NameResource typePolicyDescription

scaffolder.action.execute

scaffolder-action

use

Enables the execution of an action from a template

scaffolder.template.parameter.read

scaffolder-template

read

Enables a user or role to read a single or multiple one parameters from a template

scaffolder.template.step.read

scaffolder-template

read

Enables a user or role to read a single or multiple steps from a template

scaffolder.task.create

 

create

Enables a user or role to trigger software templates which create new scaffolder tasks

scaffolder.task.cancel

 

use

Enables a user or role to cancel currently running scaffolder tasks

scaffolder.task.read

 

read

Enables a user or role to read all scaffolder tasks and their associated events and logs

scaffolder.template.management

 

use

Enables a user or role to access front-end template management features, including editing, previewing, and trying templates, forms, and custom fields.

16.3.2.6. RBAC permissions

Reference information about RBAC permissions for reading, creating, updating, and deleting permission policies and roles.

NameResource typePolicyDescription

policy.entity.read

policy-entity

read

Enables a user or role to read permission policies and roles

policy.entity.create

 

create

Enables a user or role to create a single or multiple permission policies and roles

policy.entity.update

policy-entity

update

Enables a user or role to update a single or multiple permission policies and roles

policy.entity.delete

policy-entity

delete

Enables a user or role to delete a single or multiple permission policies and roles

16.3.2.7. Kubernetes permissions

Reference information about Kubernetes permissions for reading cluster details and resources and accessing proxy endpoints.

NameResource typePolicyDescription

kubernetes.clusters.read

 

read

Enables a user to read Kubernetes cluster details under the /clusters path

kubernetes.resources.read

 

read

Enables a user to read information about Kubernetes resources located at /services/:serviceId and /resources

kubernetes.proxy

 

use

Enables a user or role to access the proxy endpoint

16.3.2.8. Topology permissions

Reference information about Topology plugin permissions for reading Kubernetes cluster details and accessing proxy endpoints.

Note

Topology plugin does not have its own defined permissions. Kubernetes permissions are used instead.

NameResource typePolicyDescription

kubernetes.clusters.read

 

read

Enables a user to read Kubernetes cluster details under the /clusters path

kubernetes.resources.read

 

read

Enables a user to read information about Kubernetes resources located at /services/:serviceId and /resources

kubernetes.proxy

 

use

Enables a user or role to access the proxy endpoint, allowing the user or role to read pod logs and events within RHDH

16.3.2.9. Tekton permissions

Reference information about Tekton plugin permissions for reading Kubernetes cluster details and accessing proxy endpoints.

Note

Tekton plugin does not have its own defined permissions. Kubernetes permissions are used instead.

NameResource typePolicyDescription

kubernetes.clusters.read

 

read

Enables a user to read Kubernetes cluster details under the /clusters path

kubernetes.resources.read

 

read

Enables a user to read information about Kubernetes resources located at /services/:serviceId and /resources

kubernetes.proxy

 

use

Enables a user or role to access the proxy endpoint, allowing the user or role to read pod logs and events within RHDH

16.3.2.10. ArgoCD permissions

Reference information about ArgoCD plugin permissions for reading ArgoCD resources.

NameResource typePolicyDescription

argocd.view.read

 

read

Enables a user to read from the ArgoCD plugin

16.3.2.11. Quay permissions

Reference information about Quay plugin permissions for reading Quay resources.

NameResource typePolicyDescription

quay.view.read

 

read

Enables a user to read from the Quay plugin

16.3.2.12. Extensions permissions

Reference information about available Extensions permissions for reading and writing plugin configurations.

NameResource typePolicyDescription

extensions.plugin.configuration.read

extensions-plugin

read

Enables a user or role to view plugin configurations in Extensions

extensions.plugin.configuration.write

extensions-plugin

create

Enables a user or role to install, update, enable, or disable plugins by using Extensions

16.3.3. Conditional policy aliases and schemas

16.3.3.1. Conditional policy aliases and schemas

Reference information about conditional policy rules, schemas, and examples for defining conditions with or without criteria.

You can access API endpoints for conditional policies in Red Hat Developer Hub. The RBAC backend API constructs a condition JSON object based on the condition schema. In Red Hat Developer Hub, you can define conditional policies with or without criteria.

16.3.3.2. Conditional schemas

Reference information about the conditional policy API endpoint for retrieving available conditional rules and schemas.

You can access API endpoints for conditional policies in Red Hat Developer Hub. For example, to retrieve the available conditional rules, which can help you define these policies, you can access the GET [api/plugins/condition-rules] endpoint.

The api/plugins/condition-rules returns the condition parameters schemas, for example:

[
   {
      "pluginId": "catalog",
      "rules": [
         {
            "name": "HAS_ANNOTATION",
            "description": "Allow entities with the specified annotation",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "annotation": {
                     "type": "string",
                     "description": "Name of the annotation to match on"
                  },
                  "value": {
                     "type": "string",
                     "description": "Value of the annotation to match on"
                  }
               },
               "required": [
                  "annotation"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "HAS_LABEL",
            "description": "Allow entities with the specified label",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "label": {
                     "type": "string",
                     "description": "Name of the label to match on"
                  }
               },
               "required": [
                  "label"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "HAS_METADATA",
            "description": "Allow entities with the specified metadata subfield",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "key": {
                     "type": "string",
                     "description": "Property within the entities metadata to match on"
                  },
                  "value": {
                     "type": "string",
                     "description": "Value of the given property to match on"
                  }
               },
               "required": [
                  "key"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "HAS_SPEC",
            "description": "Allow entities with the specified spec subfield",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "key": {
                     "type": "string",
                     "description": "Property within the entities spec to match on"
                  },
                  "value": {
                     "type": "string",
                     "description": "Value of the given property to match on"
                  }
               },
               "required": [
                  "key"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "IS_ENTITY_KIND",
            "description": "Allow entities matching a specified kind",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "kinds": {
                     "type": "array",
                     "items": {
                        "type": "string"
                     },
                     "description": "List of kinds to match at least one of"
                  }
               },
               "required": [
                  "kinds"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         },
         {
            "name": "IS_ENTITY_OWNER",
            "description": "Allow entities owned by a specified claim",
            "resourceType": "catalog-entity",
            "paramsSchema": {
               "type": "object",
               "properties": {
                  "claims": {
                     "type": "array",
                     "items": {
                        "type": "string"
                     },
                     "description": "List of claims to match at least one on within ownedBy"
                  }
               },
               "required": [
                  "claims"
               ],
               "additionalProperties": false,
               "$schema": "http://json-schema.org/draft-07/schema#"
            }
         }
      ]
   }
   ... <another plugin condition parameter schemas>
]

The RBAC backend API constructs a condition JSON object based on the previous condition schema.

16.3.3.3. Conditional policy without criteria

Reference information about defining conditional policies without criteria to control access based on a single rule.

Consider a condition without criteria displaying catalogs only if user is a member of the owner group. To add this condition, you can use the catalog plugin schema IS_ENTITY_OWNER as follows:

{
  "rule": "IS_ENTITY_OWNER",
  "resourceType": "catalog-entity",
  "params": {
    "claims": ["group:default/team-a"]
  }
}

In the previous example, the only conditional parameter used is claims, which contains a list of user or group entity references.

You can apply the previous example condition to the RBAC REST API by adding additional parameters as follows:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/test",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["read"],
  "conditions": {
    "rule": "IS_ENTITY_OWNER",
    "resourceType": "catalog-entity",
    "params": {
      "claims": ["group:default/team-a"]
    }
  }
}

16.3.3.4. Conditional policy with criteria

Reference information about defining conditional policies with criteria to control access based on multiple rules combined with logical operators.

Consider a condition with criteria, which displays catalogs only if user is a member of owner group OR displays list of all catalog user groups.

To add the criteria, you can add another rule as IS_ENTITY_KIND in the condition as follows:

{
  "anyOf": [
    {
      "rule": "IS_ENTITY_OWNER",
      "resourceType": "catalog-entity",
      "params": {
        "claims": ["group:default/team-a"]
      }
    },
    {
      "rule": "IS_ENTITY_KIND",
      "resourceType": "catalog-entity",
      "params": {
        "kinds": ["Group"]
      }
    }
  ]
}
Note

Running conditions in parallel during creation is not supported. Therefore, consider defining nested conditional policies based on the available criteria.

+ Example of nested conditions:

+

{
  "anyOf": [
    {
      "rule": "IS_ENTITY_OWNER",
      "resourceType": "catalog-entity",
      "params": {
        "claims": ["group:default/team-a"]
      }
    },
    {
      "rule": "IS_ENTITY_KIND",
      "resourceType": "catalog-entity",
      "params": {
        "kinds": ["Group"]
      }
    }
  ],
  "not": {
    "rule": "IS_ENTITY_KIND",
    "resourceType": "catalog-entity",
    "params": { "kinds": ["Api"] }
  }
}

You can apply the previous example condition to the RBAC REST API by adding additional parameters as follows:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/test",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["read"],
  "conditions": {
    "anyOf": [
      {
        "rule": "IS_ENTITY_OWNER",
        "resourceType": "catalog-entity",
        "params": {
          "claims": ["group:default/team-a"]
        }
      },
      {
        "rule": "IS_ENTITY_KIND",
        "resourceType": "catalog-entity",
        "params": {
          "kinds": ["Group"]
        }
      }
    ]
  }
}

16.3.3.5. Conditional policy plugin examples

Reference information about conditional policy examples for Keycloak, Quay, and Extensions plugins demonstrating access control patterns.

The following examples can be used with Developer Hub plugins. These examples can help you determine how to define conditional policies:

Conditional policy defined for Keycloak plugin:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/developer",
  "pluginId": "catalog",
  "resourceType": "catalog-entity",
  "permissionMapping": ["update", "delete"],
  "conditions": {
    "not": {
      "rule": "HAS_ANNOTATION",
      "resourceType": "catalog-entity",
      "params": { "annotation": "keycloak.org/realm", "value": "<YOUR_REALM>" }
    }
  }
}

The previous example of Keycloak plugin prevents users in the role:default/developer from updating or deleting users that are ingested into the catalog from the Keycloak plugin.

Note

In the previous example, the annotation keycloak.org/realm requires the value of <YOUR_REALM>.

Conditional policy defined for Quay plugin:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/developer",
  "pluginId": "scaffolder",
  "resourceType": "scaffolder-action",
  "permissionMapping": ["use"],
  "conditions": {
    "not": {
      "rule": "HAS_ACTION_ID",
      "resourceType": "scaffolder-action",
      "params": { "actionId": "quay:create-repository" }
    }
  }
}

The previous example of Quay plugin prevents the role role:default/developer from using the Quay scaffolder action. Note that permissionMapping contains use, signifying that scaffolder-action resource type permission does not have a permission policy.

Conditional policy defined for Extensions plugin:

{
  "result": "CONDITIONAL",
  "roleEntityRef": "role:default/extensions-admin",
  "pluginId": "extensions",
  "resourceType": "extensions-plugin",
  "permissionMapping": ["create"],
  "conditions": {
    "rule": "HAS_NAME",
    "resourceType": "extensions-plugin",
    "params": { "pluginNames": ["<your_plugin_name>"] }
  }
}

The previous example of Extensions plugin restricts users in the role:default/extensions-admin to only installing or updating the specified plugin.

16.4. Trace attributes and OpenTelemetry configurations

16.4.1. Trace attributes and OpenTelemetry configurations

Reference information about OpenTelemetry configuration properties and trace attributes for serverless workflow observability in Red Hat Developer Hub.

Use this reference to look up configuration properties that control where traces are sent, sampling rates, and service names. You can also look up span attributes and lifecycle events that SonataFlow automatically generates for workflow executions, to build Jaeger queries, filter traces by workflow state, and track requests across service boundaries.

16.4.2. OpenTelemetry configurations

Configuration properties that control where traces are sent, how often they are sampled, and which service name appears in your monitoring dashboard. Reference this table to tune telemetry behavior for your environment.

PropertyDescriptionDefault

quarkus.otel.enabled

Enables or disables OpenTelemetry support.

false

quarkus.otel.service.name

Specify the service name that appears in the trace backend.

unset

quarkus.otel.exporter.otlp.endpoint

The URL of the OTLP-compatible collector.

http://localhost:4317

quarkus.otel.exporter.otlp.protocol

The transport protocol. Supported values are grpc or http/protobuf.

grpc

quarkus.otel.traces.sampler

The sampling strategy. For example, always_on, always_off, or parentbased_always_on.

parentbased_always_on

16.4.3. Trace attributes and lifecycle events

16.4.3.1. Trace attributes and lifecycle events

Reference information about span attributes and lifecycle events that SonataFlow automatically generates for workflow executions.

Use this data dictionary to build Jaeger queries, filter traces by workflow state, and track requests across service boundaries. This data allows you to track a workflow from start to finish, analyze external function calls, and correlate logs across asynchronous boundaries.

16.4.3.2. Trace attribute definitions and filtering keys

Automatic span attributes that identify workflow executions, instances, and states. Use these attributes in Jaeger queries to locate specific workflow runs, filter by version, or trace process instances through various execution states.

To locate specific workflow executions or trace a process through various states, use the automatic span attributes generated by SonataFlow. Each span includes the following specific attributes:

  • sonataflow.process.id: Indicates the ID of the workflow definition.
  • sonataflow.process.instance.id: Indicates the unique ID for the specific execution instance.
  • sonataflow.process.version: Indicates the version of the workflow definition.
  • sonataflow.workflow.state: Indicates the name of the current workflow state, for example, StartEvent.
  • sonataflow.process.instance.state: Indicates the current state of the process instance, such as ACTIVE, COMPLETED, ERROR, or SUSPENDED.
  • sonataflow.transaction.id: Indicates the ID used to correlate multiple workflows in a single business transaction.
  • sonataflow.tracker.*: Indicates custom attributes converted from X-TRACKER-* headers.
  • service.name and service.version: Indicates the service identification details from the configuration.

16.4.3.3. Process lifecycle events for timeline tracking

OpenTelemetry events that mark workflow execution milestones including start, completion, errors, and state transitions. Use these events to reconstruct the chronological order of workflow execution and identify when failures occurred.

To understand the exact chronological order of a workflow’s execution, look for OpenTelemetry events that are automatically generated at key lifecycle points. SonataFlow attaches the following events and their specific attributes to spans to mark execution milestones:

  • process.instance.start: Indicates the beginning of the execution. This event includes the process.instance.id, the trigger that started the process, and the reference.id.
  • process.instance.complete: Indicates the completion of the workflow. This event includes the process.instance.id, the final outcome, and the total duration.ms.
  • process.instance.error: Indicates a workflow failure. This event includes the process.instance.id, the error.message, and the error.type.
  • state.started and state.completed: Indicate the start and completion of individual workflow states. These events include an event.description that details the state execution.
  • log.message: Indicates the application log content within the trace span. This event provides the level, logger, message, thread.name, and thread.id.

16.4.3.4. Function call attributes for external integration debugging

HTTP and function-specific attributes attached to external service call spans. Use these attributes to debug REST API failures, identify slow external dependencies, and verify correct endpoint invocation in workflow integrations.

When a workflow invokes an external function, for example, a REST service, the function call spans are enriched with additional HTTP attributes:

  • sonataflow.function.name: The name of the function being called.
  • sonataflow.function.type: The type of function, such as rest or expression.
  • http.method: The HTTP method used for external REST calls.
  • http.url: The full target URL for the external call.
  • http.status_code: The resulting HTTP response code from the service.

16.4.3.5. Propagation headers

HTTP headers that SonataFlow extracts and propagates to maintain trace correlation across service boundaries. Use these headers to link workflow executions in distributed transactions and pass custom tracking context through service chains.

SonataFlow extracts and propagates the following headers to maintain observability across service boundaries:

  • X-TRANSACTION-ID: Correlates multiple workflow executions that belong to the same business transaction.
  • X-TRACKER-*: Sanitizes and converts any custom tracking context from headers into span attributes, such as sonataflow.tracker.*, to simplify querying.

16.5. Helm chart configuration parameters to define advanced deployment

16.5.1. Helm chart configuration parameters to define advanced deployment

Reference information about Helm chart configuration parameters for defining advanced Developer Hub deployments on Kubernetes and OpenShift clusters.

Use this reference to look up supported Helm keys, default values, and parameter override schemas when deploying or upgrading Red Hat Developer Hub. You can customize resource boundaries, networking parameters, and runtime configurations to establish a production-ready environment.

16.5.2. Helm chart configuration parameters

16.5.2.1. Helm chart configuration parameters

Use the overview of default Helm Chart values to configure and customize your RHDH deployment.

The values are organized into five main categories, which cover the key namespaces that organize the chart’s hierarchical configuration structure:

  • Global
  • Orchestrator
  • Route
  • Test
  • Upstream

16.5.2.2. Display a complete list of Helm Chart values with Helm CLI

Use the available options to configure Red Hat Developer Hub with Helm Charts: the Helm deployment method specific configuration files.

Procedure

  1. Pull the released RHDH Helm Chart, including all its dependencies:

    $ helm pull redhat-developer-hub \
      --repo https://charts.openshift.io \
      --version 1.10.1 \
      --untar
  2. View default values:

    1. View default values of the RHDH Chart.

      $ helm show values redhat-developer-hub
    2. View default values of the upstream Backstage Chart. The fields can be set under the upstream scope when deploying the RHDH Chart.

      $ helm show values redhat-developer-hub/charts/backstage
    3. Optional: View default values of the upstream PostgreSQL Chart, which is a dependency of the upstream Backstage Chart.

      Important

      Using the local PostgreSQL database is not recommended for production, as you should be using your own external database. However, it allows for visibility into the local database. For more information, see Configuring an external PostgreSQL instance using the Helm Chart.

      1. The fields can be set under the upstream.postgresql scope when deploying the RHDH Chart.

        $ helm show values redhat-developer-hub/charts/backstage/charts/postgresql

16.5.2.3. Root namespace value

Use the root namespace value to customize resource names.

Key

Description

Type

Default

nameOverride

Lets you customize resource names. Can be used at the root level and upstream level.

string

"developer-hub"

16.5.2.4. Global namespace values

Use the global namespace values to define cross-cutting configurations that affect multiple chart components.

KeyDescriptionTypeDefault

global.auth

Enables service authentication within Backstage instance.

object

{"backend":{"enabled":true,"existingSecret":"","value":""}}

global.auth.backend

Backend service to service authentication.

object

{"enabled":true,"existingSecret":"","value":""}

global.auth.backend.enabled

Enables backend service to service authentication. Generates a secret value unless configured otherwise.

bool

true

global.auth.backend.existingSecret

Uses an existing secret.

string

""

global.auth.backend.value

Uses a specified value.

string

""

global.catalogIndex

Catalog index configuration for automatic plugin discovery. The install-dynamic-plugins.py script pulls this image if the CATALOG_INDEX_IMAGE environment variable is set. The dynamic-plugins.default.yaml file is extracted and written to dynamic-plugins-root volume mount.

object

{"image":{"registry":"registry.redhat.io","repository":"rhdh/plugin-catalog-index@sha256","tag":"<digest>"}}

global.catalogIndex.image.registry

Catalog index image registry.

string

“registry.redhat.io”

global.catalogIndex.image.repository

Catalog index image repository.

string

“rhdh/plugin-catalog-index@sha256”

global.catalogIndex.image.tag

Catalog index image tag or digest.

string

“<digest>”

global.clusterRouterBase

Shorthand for users who do not want to specify a custom hostname. Used only with the default upstream.backstage.appConfig value and with OpenShift Container Platform Route enabled.

string

"apps.example.com"

global.dynamic.includes

Array of yaml files listing dynamic plugins to include with those listed in the plugin field. Relative paths are resolved from the working directory of the initContainer that install the plugins.

list

["dynamic-plugins.default.yaml"]

global.dynamic.includes[0]

List of dynamic plugins included inside the RHDH container image.

string

"dynamic-plugins.default.yaml"

global.dynamic.plugins

List of dynamic plugins. Every plugin package can be defined as an OCI artifact, NPM or local package reference.

This list can potentially override the list of plugins in include files.

list

[]

global.host

Custom hostname shorthand that overrides global.clusterRouterBase, upstream.ingress.host, route.host, and url values in upstream.backstage.appConfig.

string

""

global.imagePullSecrets

Global Docker registry secret names as an array.

list

[]

global.imageRegistry

Global Docker image registry.

string

""

16.5.2.5. Orchestrator namespace values

Use orchestrator namespace values to configure the orchestrator subsystem.

KeyDescriptionTypeDefault

orchestrator.enabled

Enables orchestrator integration.

bool

false

orchestrator.plugins

List of orchestrator plugins and their configuration.

list

default list of orchestrator plugins to enable when orchestrator.enabled is set to true

orchestrator.serverlessLogicOperator.enabled

Enables serverlessLogicOperator configuration.

bool

true

orchestrator.sonataflowPlatform.createDBJobImage

Image for the container used by the create-db job.

string

"{{ .Values.upstream.postgresql.image.registry }}/{{ .Values.upstream.postgresql.image.repository }}:{{ .Values.upstream.postgresql.image.tag }}"

orchestrator.sonataflowPlatform.dataIndexImage

Image for the container used by the SonataFlow data index.

Note

This is an optional image for disconnected environments.

string

""

orchestrator.sonataflowPlatform.eventing.broker.name

Specifies which broker to integrate into SonataFlow event-driven workflows.

string

""

orchestrator.sonataflowPlatform.eventing.broker.namespace

Specifies the Kubernetes namespace that contains the broker resource to integrate into SonataFlow event-driven workflows.

string

""

orchestrator.sonataflowPlatform.externalDBHost

Host for the user-configured external database.

string

""

orchestrator.sonataflowPlatform.externalDBName

Name for the user-configured external database.

string

""

orchestrator.sonataflowPlatform.externalDBPort

Port for the user-configured external database.

string

""

orchestrator.sonataflowPlatform.externalDBsecretRef

Name for the user-created secret to connect an external database.

string

""

orchestrator.sonataflowPlatform.initContainerImage

Image for the init container used by the create-db job.

string

"{{ .Values.upstream.postgresql.image.registry }}/{{ .Values.upstream.postgresql.image.repository }}:{{ .Values.upstream.postgresql.image.tag }}"

orchestrator.sonataflowPlatform.jobServiceImage

Image for the container used by the SonataFlow jobs service.

Note

This is an optional value used for disconnected environments.

string

""

orchestrator.sonataflowPlatform.monitoring.enabled

Controls if monitoring is enabled for SonataFlow when using the Orchestrator.

bool

true

orchestrator.sonataflowPlatform.resources.limits.cpu

Sets the maximum CPU allocation for SonataFlow’s build resources.

string

"500m"

orchestrator.sonataflowPlatform.resources.limits.memory

Sets the maximum memory allocation for SonataFlow’s build resources.

string

"1Gi"

orchestrator.sonataflowPlatform.resources.requests.cpu

Sets the minimum CPU allocation for SonataFlow’s build resources.

string

"250m"

orchestrator.sonataflowPlatform.resources.requests.memory

Sets the minimum memory allocation for SonataFlow’s build resources.

string

"64Mi"

16.5.2.6. Route namespace values

Use route namespace values to configure OpenShift Container Platform route-specific settings.

KeyDescriptionTypeDefault

route

OpenShift Route parameters.

object

{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}

route.annotations

Route-specific annotations.

object

{}

route.enabled

Enables the creation of the route resource.

bool

true

route.host

Sets the host attribute to a custom value. If not set, the value is generated by OpenShift.

Important

Make sure the value matches your baseUrl.

string

"{{ .Values.global.host }}"

route.path

Path that the router watches for to route traffic to the service.

string

"/"

route.tls

Route TLS parameters.

object

{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"}

route.tls.caCertificate

Optional value. Cert authority certificate contents.

string

""

route.tls.certificate

Certificate contents.

string

""

route.tls.destinationCACertificate

CA certificate contents of the final destination. Used by routers for health checks on the secure connection.

Important

Provide this file path if you use reencrypt termination. If not specified, the router might provide its own destination CA and perform hostname validation using the short service name (service.namespace.svc), which lets infrastructure generated certificates to be verified automatically.

string

""

route.tls.enabled

Enable TLS configuration for the host defined with the route.host parameter.

bool

true

route.tls.insecureEdgeTerminationPolicy

Indicates the desired behavior for insecure connections to a route.

string

"Redirect"

route.tls.key

Key file contents.

string

""

route.tls.termination

Specifies TLS termination.

string

"edge"

route.wildcardPolicy

Wildcard policy for the route.

string

"None"

16.5.2.7. Test namespace values

Use test namespace values to configure parameters that run when tests are initiated with helm test to verify RHDH Helm release.

TestDescriptionObjectDefault

test

Tests pod parameters.

object

{"enabled":true,"image":{"registry":"quay.io","repository":"curl/curl","tag":"latest"},"injectTestNpmrcSecret":false}

test.enabled

Enables the test-connection pod used for testing the release using helm test.

bool

true

test.image.registry

Tests connection pod image registry.

string

"quay.io"

test.image.repository

Test connection pod image repository.

Note

The image must contain both the sh and curl binaries.

string

"curl/curl"

test.image.tag

Tests connection pod image tag.

Note

The image must contain both the sh and curl binaries.

string

"latest"

test.injectTestNpmrcSecret

Injects a fake dynamic plugins npmrc secret. Only relevant when test.enabled field is set to true.

Important

This value is only used for testing purposes and should not be used in production.

bool

false

16.5.2.8. Upstream namespace values

Use the upstream namespace values for configurations that are passed to the upstream Backstage Helm chart.

Important

Specific upstream namespace values are also used in the global configuration of RHDH. Changing these values in the upstream namespace can override the global configuration.

KeyDescriptionTypeDefault

upstream

Upstream Backstage chart configuration.

object

OpenShift-compatible settings

upstream.backstage.extraVolumes[0]

Ephemeral volume that contains the dynamic plugins installed by the initContainer at start.

object

{"ephemeral":{"volumeClaimTemplate":{"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"5Gi"}}}}},"name":"dynamic-plugins-root"}

upstream.backstage.extraVolumes[0].ephemeral.volumeClaimTemplate.spec.resources.requests.storage

Size of the ephemeral volume that contains the dynamic plugins.

string

"5Gi"

upstream.backstage.initContainers[0].image

Image used by the initContainer to install dynamic plugins into the dynamic-plugins-root volume mount.

string

value of ‘upstream.backstage.image’

16.5.2.9. Additional upstream Backstage Chart values

Add the following Backstage Chart values to the upstream namespace to customize your RHDH configuration further.

KeyDescriptionTypeDefault

upstream.backstage

Backstage parameters.

object

see below

upstream.backstage.affinity

Pod assignment affinity.

object

{}

upstream.backstage.annotations

Additional custom annotations for the Deployment resource.

object

{}

upstream.backstage.appConfig

Generates a ConfigMap and configures it in the Backstage pods.

object

{“auth”: {“providers”: {}}, “app”: {“baseUrl”: 'https://{{- include "rhdh.hostname" . }}'}, “backend”: {“baseUrl”: 'https://{{- include "rhdh.hostname" . }}', “cors”: {“origin”: 'https://{{- include "rhdh.hostname" . }}'}, “database”: {“connection”: {“password”: “${POSTGRESQL_ADMIN_PASSWORD}”, “user”: “postgres”}}, “auth”: {“externalAccess”: [{“type”: “legacy”, “options”: {“subject”: “legacy-default-config”, “secret”: “${BACKEND_SECRET}”}}]}}}

upstream.backstage.args

Backstage container command arguments.

list

[“--config”, “dynamic-plugins-root/app-config.dynamic-plugins.yaml”]

upstream.backstage.autoscaling

Autoscaling configuration.

object

{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}

upstream.backstage.command

Backstage container command.

list

[]

upstream.backstage.containerPorts

Deployment container ports.

object

{"backend":7007}

upstream.backstage.containerSecurityContext

Container security settings.

object

{“readOnlyRootFilesystem”: true, “allowPrivilegeEscalation”: false, “capabilities”: {“drop”: [“ALL”]}, “runAsNonRoot”: true, “seccompProfile”: {“type”: “RuntimeDefault”}}}

upstream.backstage.extraAppConfig

Extra app configuration files to inline into command arguments.

list

[]

upstream.backstage.extraContainers

Deployment sidecars.

list

[]

upstream.backstage.extraEnvVars

Backstage container environment variables.

list

[{“name”: “BACKEND_SECRET”, “valueFrom”: {“secretKeyRef”: {“key”: “backend-secret”, “name”: '{{ include "rhdh.backend-secret-name" $ }}'}}}, {“name”: “POSTGRESQL_ADMIN_PASSWORD”, “valueFrom”: {“secretKeyRef”: {“key”: “postgres-password”, “name”: '{{- include "rhdh.postgresql.secretName" . }}'}}]}]

upstream.backstage.extraEnvVarsCM

Backstage container environment variables from existing ConfigMaps.

list

[]

upstream.backstage.extraEnvVarsSecrets

Backstage container environment variables from existing secrets.

list

[]

upstream.backstage.extraPorts

Backstage container additional ports.

list

[{“name”: “http-metrics”, “port”: 9464, “targetPort”: 9464}]

upstream.backstage.extraVolumeMounts

Backstage container additional volume mounts.

list

[{“name”: “dynamic-plugins-root”, “mountPath”: “/opt/app-root/src/dynamic-plugins-root”}, {“name”: “extensions-catalog”, “mountPath”: “/extensions”}, {“name”: “temp”, “mountPath”: “/tmp”}]

upstream.backstage.extraVolumes

Backstage container additional volumes.

list

[{“name”: “dynamic-plugins-root”, “ephemeral”: {“volumeClaimTemplate”: {“spec”: {“accessModes”: [“ReadWriteOnce”], “resources”: {“requests”: {“storage”: “5Gi”}}}}}}]

upstream.backstage.hostAliases

Host Aliases for the pod.

list

[]

upstream.backstage.image.digest

Backstage image digest. Takes precedence over image tag.

Important

The image digest must match the repository used for RHDH.

string

""

upstream.backstage.image.pullPolicy

Specifies the image pull policy.

string

""

upstream.backstage.image.pullSecrets

Specifies an array of imagePullSecrets.

Important

Secrets must be manually created in the namespace.

list

[]

upstream.backstage.image.registry

Backstage image registry.

string

"registry.redhat.io"

upstream.backstage.image.repository

Backstage image repository.

string

"rhdh/rhdh-hub-rhel9@sha256"

upstream.backstage.image.tag

Backstage image tag.

Note

It is recommended to use immutable tags.

string

"digest"

upstream.backstage.initContainers

Backstage container init containers.

list

[]

upstream.backstage.installDir

Directory containing the backstage installation.

Important

Before using this value, check that there are no restrictions placed on customizing installDir.

string

"/opt/app-root/src"

upstream.backstage.livenessProbe

Liveness probe.

object

{“failureThreshold”: 3, “httpGet”: {“path”: “/.backstage/health/v1/liveness”, “port”: “backend”, “scheme”: “HTTP”}, “periodSeconds”: 10, “successThreshold”: 1, “timeoutSeconds”: 4}

upstream.backstage.nodeSelector

Node labels for pod assignment.

object

{}

upstream.backstage.pdb

Pod disruption budget configuration.

object

{"create":false,"maxUnavailable":"","minAvailable":""}

upstream.backstage.podAnnotations

Annotations added to the backend deployment pods.

object

{“checksum/dynamic-plugins”: “{{- include "common.tplvalues.render" ( dict "value" .Values.global.dynamic "context" $)

upstream.backstage.podLabels

Labels added to the backend deployment pods.

object

{}

upstream.backstage.podSecurityContext

Pod security settings. They apply to all containers in the pod.

Important

Before using this value, check the OpenShift security policy.

object

{}

upstream.backstage.readinessProbe

Readiness probe.

object

{“failureThreshold”: 3, “httpGet”: {“path”: “/.backstage/health/v1/readiness”, “port”: “backend”, “scheme”: “HTTP”}, “periodSeconds”: 10, “successThreshold”: 2, “timeoutSeconds”: 4}

upstream.backstage.replicas

Number of deployment replicas.

int

1

upstream.backstage.resources

Resource requests and limits.

object

{“resources”: {“requests”: {“cpu”: “250m”, “memory”: “1Gi”}, “limits”: {“cpu”: “1000m”, “memory”: “2.5Gi”, “ephemeral-storage”: “5Gi”}}}

upstream.backstage.revisionHistoryLimit

Defines the count of deployment revisions to be kept.

Note

For GitOps deployment, the count might be set to 0.

int

10

upstream.backstage.startupProbe

Startup probe.

object

{“httpGet”: {“path”: “/.backstage/health/v1/liveness”, “port”: “backend”, “scheme”: “HTTP”}, “initialDelaySeconds”: 30, “timeoutSeconds”: 4, “periodSeconds”: 20, “successThreshold”: 1, “failureThreshold”: 3}

upstream.backstage.tolerations

Node tolerations for server scheduling to nodes with taints.

list

[]

upstream.backstage.topologySpreadConstraints

Topology spread constraints for pod assignment.

list

[]

upstream.clusterDomain

Default Kubernetes cluster domain.

Important

Use this value only if the underlying Backstage chart exposes and uses it.

string

"cluster.local"

upstream.commonAnnotations

Annotations to add to all deployed objects.

object

{}

upstream.commonLabels

Labels to add to all deployed objects.

object

{}

upstream.diagnosticMode

Enables diagnostic mode in the deployment.

object

{"args":["infinity"],"command":["sleep"],"enabled":false}

upstream.diagnosticMode.args

Arguments to override all containers in the deployment.

list

["infinity"]

upstream.diagnosticMode.command

Command to override all containers in the deployment.

list

["sleep"]

upstream.diagnosticMode.enabled

Enables diagnostic mode.

bool

false

upstream.extraDeploy

Array of extra objects to deploy with the release.

list

[]

upstream.fullnameOverride

String to fully override common.names.fullname.

string

""

upstream.ingress

Ingress parameters.

object

{“host”: “{{ .Values.global.host }}”}

upstream.ingress.annotations

Additional annotations for the Ingress resource.

object

{}

upstream.ingress.className

Name of the IngressClass cluster resource that defines which controller implements the resource, such as nginx.

string

""

upstream.ingress.enabled

Enables the creation of the Ingress resource.

bool

false

upstream.ingress.extraHosts

List of additional hostnames to be covered with this Ingress record, such as CNAME.

list

[]

upstream.ingress.extraTls

The TLS configuration for additional hostnames to be covered with this Ingress record.

list

[]

upstream.ingress.host

Hostname to be used to expose the route to access the Backstage application, such as backstage.IP.nip.io.

string

"{{ .Values.global.host }}"

upstream.ingress.path

Path to be used to expose the full route to access the Backstage application, such as backstage.IP.nip.io.

string

"/"

upstream.ingress.tls

Ingress TLS parameters.

object

{"serviceMonitor": {"enabled": false, "path": "/metrics", "port": "http-metrics"}}

upstream.ingress.tls.enabled

Enables TLS configuration for the host defined at ingress.host parameter.

bool

false

upstream.ingress.tls.secretName

The name to which the TLS Secret is called.

string

""

upstream.kubeVersion

Overrides Kubernetes version.

string

""

upstream.metrics

Metrics configuration.

object

{"serviceMonitor": {"enabled": false, "path": "/metrics", "port": "http-metrics"}}

upstream.metrics.serviceMonitor

Prometheus Operator ServiceMonitor configuration.

object

{"enabled": false, "path": "/metrics", "port": "http-metrics"}

upstream.metrics.serviceMonitor.annotations

ServiceMonitor annotations.

object

{}

upstream.metrics.serviceMonitor.enabled

Creates a ServiceMonitor resource for Prometheus Operator.

Important

Before you enable this value, you must install Prometheus Operator in your cluster.

bool

false

upstream.metrics.serviceMonitor.interval

ServiceMonitor scrape interval.

string

nil

upstream.metrics.serviceMonitor.labels

Additional ServiceMonitor labels.

object

{}

upstream.metrics.serviceMonitor.path

ServiceMonitor endpoint path.

Important

The /metrics endpoint is not present in a freshly scaffolded Backstage application.

string

"/metrics"

upstream.metrics.serviceMonitor.port

ServiceMonitor endpoint port.

Important

If you use OpenTelemetry, the port must be explicitly specified. The default port for OpenTelemetry is 9464.

string

"http-metrics"

upstream.nameOverride

String to partially override common.names.fullname.

string

"developer-hub"

upstream.networkPolicy.egressRules.customRules

Additional custom egress rules.

list

[]

upstream.networkPolicy.egressRules.denyConnectionsToExternal

Denies external connections.

Important

Do not enable this value when working with external databases.

bool

false

upstream.networkPolicy.enabled

Specifies if a NetworkPolicy is created.

bool

false

upstream.networkPolicy.ingressRules.customRules

Additional custom Ingress rules.

list

[]

upstream.networkPolicy.ingressRules.namespaceSelector

Namespace selector label allowed to access the Backstage instance.

object

{}

upstream.networkPolicy.ingressRules.podSelector

Pod selector label allowed to access the Backstage instance.

object

{}

upstream.postgresql

PostgreSQL chart configuration.

object

see below

upstream.postgresql.architecture

PostgreSQL architecture.

string

"standalone"

upstream.postgresql.auth

Authentication details of the PostgreSQL database.

object

{“secretKeys”: {“adminPasswordKey”: “postgres-password”, “userPasswordKey”: “password”}}

upstream.postgresql.auth.existingSecret

Name of existing secret used for PostgreSQL credentials.

string

""

upstream.postgresql.auth.password

Password created by custom user.

string

""

upstream.postgresql.auth.secretKeys

The secret keys PostgreSQL looks for to retrieve the relevant password.

object

{"adminPasswordKey":"admin-password","replicationPasswordKey":"replication-password","userPasswordKey":"user-password"}

upstream.postgresql.auth.secretKeys.adminPasswordKey

The key in the existing secret where PostgreSQL looks for the admin password.

string

"postgres-password"

upstream.postgresql.auth.secretKeys.replicationPasswordKey

The key in the existing secret where PostgreSQL looks for the replication password.

string

"replication-password"

upstream.postgresql.auth.secretKeys.userPasswordKey

The key in the existing secret where PostgreSQL looks for the user password.

string

"password"

upstream.postgresql.auth.username

Creates a name for a custom user.

string

"bn_backstage"

upstream.postgresql.enabled

Enables the PostgreSQL helm chart.

Note

PostgreSQL has many values you can use in RHDH. However, using your own external database is recommended for production.

bool

true

upstream.postgresql.image

Changes default PostgreSQL image location.

object

{"registry":"registry.redhat.io","repository":"rhel9/postgresql-15@sha256"}

upstream.service

Service parameters.

object

see below

upstream.service.annotations

Additional custom annotations for Backstage service.

object

{}

upstream.service.clusterIP

Backstage service cluster IP.

string

""

upstream.service.externalTrafficPolicy

Backstage service external traffic policy.

string

"Cluster"

upstream.service.extraPorts

Extra ports to expose in the Backstage service. Typically used with the sidecar value.

list

[{"extraPorts": {"name": "http-metrics", "port": "9464", "targetPort": "9464"}}]

upstream.service.ipFamilies

IP families.

list

[]

upstream.service.ipFamilyPolicy

IP family policy.

string

""

upstream.service.loadBalancerIP

Backstage service Load Balancer IP.

string

""

upstream.service.loadBalancerSourceRanges

Load Balancer sources.

list

[]

upstream.service.nodePorts

Node port for the Backstage client connections.

Note

Choose a port between 30000-32767.

object

{"backend":""}

upstream.service.ports

Backstage SVC port for client connections.

object

{"backend":7007,"name":"http-backend","targetPort":"backend"}

upstream.service.ports.name

Backstage SVC port name.

string

"http-backend"

upstream.service.ports.targetPort

Backstage SVC target port referencing receiving pod container port.

string

"backend"

upstream.service.sessionAffinity

Controls where client requests go: either the same pod or round-robin.

string

"None"

upstream.service.type

Kubernetes service type.

string

"ClusterIP"

upstream.serviceAccount

Service account configuration.

object

see below

upstream.serviceAccount.annotations

Additional custom annotations for the ServiceAccount.

object

{}

upstream.serviceAccount.automountServiceAccountToken

Auto-mounts the service account token in the pod.

bool

true

upstream.serviceAccount.create

Enable the creation of a ServiceAccount for Backstage pods.

bool

false

upstream.serviceAccount.labels

Additional custom labels for the ServiceAccount.

object

{}

upstream.serviceAccount.name

Name of the ServiceAccount to use.

Note

If you do not set this value and serviceAccount.create is set to true, a name is generated.

string

""

16.5.2.10. Resource limits for installing Red Hat Developer Hub with the Orchestrator plugin when using Helm

When installing Red Hat Developer Hub (RHDH) with the Orchestrator plugin using Helm, the chart defines default CPU and memory limits for the SonataFlowPlatform component.

These limits are enforced by the cluster so that pods do not exceed their allocated resources.

  1. Default resource limits
ResourceDefault value

CPU limits

500m

Memory limits

1Gi

  1. You can override these values in any of the following ways:

    • With values.yaml
    • With --set flags
  2. Override defaults with values.yaml as shown in the following example:

    orchestrator:
      enabled: true
      sonataflowPlatform:
      resources:
          limits:
            cpu: "500m"
            memory: "1Gi"
  3. Override with --set as shown in the following example:

    $ helm upgrade --install <release_name>  openshift-helm-charts/redhat-developer-hub \
      --set orchestrator.enabled=true \
      --set orchestrator.sonataflowPlatform.resources.requests.cpu=500m \
      --set orchestrator.sonataflowPlatform.resources.requests.memory=128Mi \
      --set orchestrator.sonataflowPlatform.resources.limits.cpu=1 \
      --set orchestrator.sonataflowPlatform.resources.limits.memory=2Gi
    Note

    The --set setting is applicable only when orchestrator.enabled is true. By default, it is set to false.

16.5.3. Display a complete list of Orchestrator infrastructure values with Helm CLI

Use the available options to configure Orchestrator infrastructure with Helm Chart: the Helm deployment method specific configuration files.

Procedure

  1. Pull the released RHDH Orchestrator Infrastructure Helm Chart, including all its dependencies:

    helm pull redhat-developer-hub-orchestrator-infra
      --repo https://charts.openshift.io
      --version 1.10.1
  2. Display the configurable infrastructure values from the chart:

    helm show values redhat-developer-hub-orchestrator-infra \
      --repo https://charts.openshift.io \
      --version 1.10.1

16.5.4. Orchestrator infrastructure Helm Chart values

Use these Helm Chart values to deploy the Orchestrator infrastructure on OpenShift Container Platform.

KeyDescriptionTypeDefault

serverlessLogicOperator.enabled

Specifies if operator is deployed by the Helm chart.

bool

true

serverlessLogicOperator.subscription.namespace

Specifies the namespace where the operator is deployed.

string

"openshift-serverless-logic"

serverlessLogicOperator.subscription.spec.channel

Specifies the channel of an operator package to subscribe to.

string

"alpha"

serverlessLogicOperator.subscription.spec.installPlanApproval

Specifies if update should be installed automatically.

string

"Manual"

serverlessLogicOperator.subscription.spec.name

Name of the operator package.

string

"logic-operator"

serverlessLogicOperator.subscription.spec.source

Name of the catalog source.

string

"redhat-operators"

serverlessLogicOperator.subscription.spec.sourceNamespace

Name of the catalog source namespace.

string

"openshift-marketplace"

serverlessLogicOperator.subscription.spec.startingCSV

Specifies the initial version of the operator.

Important

The version must match the custom resource definitions (CRDs) installed by the chart.

string

"logic-operator.v1.38.0"

serverlessOperator.enabled

Specifies if the operator is deployed by the chart.

bool

true

serverlessOperator.subscription.namespace

Specifies the namespace where the operator is deployed.

string

"openshift-serverless"

serverlessOperator.subscription.spec.channel

Specifies the channel of an operator package to subscribe to.

string

"stable"

serverlessOperator.subscription.spec.installPlanApproval

Specifies if the update is installed automatically.

string

"Manual"

serverlessOperator.subscription.spec.name

Name of the operator package.

string

"serverless-operator"

serverlessOperator.subscription.spec.source

Name of the catalog source.

string

"redhat-operators"

serverlessOperator.subscription.spec.sourceNamespace

Name of the catalog source namespace.

string

"openshift-marketplace"

tests.enabled

Specifies if the test pod used for testing the release with helm test is created.

bool

true

tests.image

Test pod image.

string

"bitnami/kubectl:latest"

Legal Notice

Copyright © 2026 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.