Sections

  • Prerequisite
  • Hello World - Backstage
  • Backstage with LDAP integration - For Authentication
  • Remote Location - Manage your configuration with GitOps style
  • Custom Backstage UI
  • First Backstage plugin
  • Backstage Scaffolder - Golden Path
  • Prepare for Certified Backstage Associate Exam
  • Conclusion

Prerequisite

  • I assume you already have a local backstage instance running. So I don't need to repeat most of the content that already appear in https://backstage.io/docs/ with well-structured documents!
  • Basics of GitOps and other knowledge like Dockerfile, GitLab CI
  • Need an instance of LDAP for authentication because I will use it in this article.
  • You don't really need to know JavaScript, Typescript... AI(ChatGPT/Claude/Gemini/Deepseek/Grok....) are your friends!

Hello World - Backstage

  • Backstage is an open source framework for building developer portals. I know there are a lot of alternatives for Backstage, but I like Backstage since it is open source, and it is a great way to build internal developer portal in my opinion!
  • So a Backstage project will have a workspace with backend (packages/backend) and frontend (packages/app).
  • Configuration Central: app-config.yaml, everything you need to config for Backstage is here.

Backstage with LDAP integration - For Authentication

Before we start, in this article I don't use database to store, only use default in-memory configuration!

So, what do we want to do first after having Backstage running on port 3000? It is authentication! So I'm going to do with LDAP, if you want to set up LDAP with docker-compose for quick testing, take a look here https://github.com/BlackMetalz/docker-compose/tree/main/ldap-osixia

After set up, we are having LDAP users and LDAP credential for set up with following setting in app-config.yaml.

auth:
  environment: development
  providers:
    ldap:
      development:
        cookies:
          secure: false
          field: 'backstage-token'
        # ⚠️ FIX: ldapAuthenticationOptions cần có ldapOpts.url như một object
        ldapAuthenticationOptions:
          userSearchBase: 'ou=users,dc=kienlt,dc=local'
          usernameAttribute: 'uid'
          adminDn: 'cn=admin,dc=kienlt,dc=local'
          adminPassword: '${LDAP_ADMIN_PASSWORD}'
          # QUAN TRỌNG: ldapOpts phải là object với url bên trong
          ldapOpts:
            url: 'ldap://localhost:389'
            tlsOptions:
              rejectUnauthorized: false
catalog:
  providers:
    ldapOrg:
      default:
        target: ldap://localhost:389
        bind:
          dn: cn=admin,dc=kienlt,dc=local
          secret: admin
        # QUAN TRỌNG: Thêm schedule để fix lỗi startup
        schedule:
          frequency: PT1H
          timeout: PT15M
          initialDelay: PT30S
        users:
          - dn: ou=users,dc=kienlt,dc=local
            options:
              filter: (uid=*)
              scope: one
              attributes: ['*', '+']
            map:
              rdn: uid
              name: uid
              description: description
              displayName: cn
              email: mail
        groups:
          - dn: ou=groups,dc=kienlt,dc=local
            options:
              filter: (objectClass=groupOfNames)
              scope: one
              attributes: ['*', '+']
            map:
              rdn: cn
              name: cn
              description: description
              displayName: cn
              members: member

Oh shiet, I almost forget that we have to install plugin, from root folder of Backstage, where we run command yarn start to start Backstage

# Install frontend plugin
yarn workspace app add @immobiliarelabs/backstage-plugin-ldap-auth

# Install backend plugin
yarn workspace backend add @immobiliarelabs/backstage-plugin-ldap-auth-backend

# Install catalog sync
yarn workspace backend add @backstage/plugin-catalog-backend-module-ldap

We should verify installed packages to make sure it is installed!

grep -r "ldap" packages/*/package.json
packages/app/package.json:    "@immobiliarelabs/backstage-plugin-ldap-auth": "^4.3.1",
packages/backend/package.json:    "@backstage/plugin-catalog-backend-module-ldap": "^0.12.0",
packages/backend/package.json:    "@immobiliarelabs/backstage-plugin-ldap-auth-backend": "^4.3.1",

After that, modify some required files to enable login page, they are all in this commit

  • packages/app/src/App.tsx
  • packages/backend/src/index.ts

And the result

alt text

Use example LDAP user for login, and we have this (Forget about components, I will talk about them later soon!)

alt text

So we already set up authentication for Backstage, but yes only authentication, authorization not include in this introduction article!


Remote Location - Manage your configuration with GitOps style

In this section, we are going to ingest Components/API from remote location, the idea is make it like GitOps style, central location, single source of truth for Components/API.

You can take a look in this commit for more detail.

catalog:
  locations:
    # Central catalog repository providing the single source of truth for all entities.
    - type: url
      target: https://gitlab.com/kienlt-backstage/backstage-catalog/blob/main/locations.yaml
      rules:
        - allow: [Component, API, Group, Resource, Location, Template]

Custom Backstage UI

For example, I want to add new button in sidebar. I can do it via like this commit

import ExtensionIcon from '@material-ui/icons/Extension';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
+ import LibraryAdd from '@material-ui/icons/LibraryAdd';
import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';
import {
        <SidebarItem icon={ExtensionIcon} to="api-docs" text="APIs" />
        <SidebarItem icon={LibraryBooks} to="docs" text="Docs" />
        <SidebarItem icon={CreateComponentIcon} to="create" text="Create..." />
+        <SidebarItem icon={LibraryAdd} to="catalog-import" text="Import Catalog" />
        {/* End global nav */}
        <SidebarDivider />
        <SidebarScrollWrapper>

The result, it will create a button to location defined in to property, sound easy right?

alt text

Other example I want to show that is custom thing show in tab CI/CD inside a component:

alt text

And here is how I do it via this commit

It needs a plugin. Install the required plugin this way:

yarn workspace backend add @immobiliarelabs/backstage-plugin-gitlab

First Backstage plugin

This took a lot of my time for a simple plugin. So I will introduce proxy configuration in this section as well. You know when we call content from frontend, It will not work because of CORS, that is why we need to use proxy, and proxy in this scenario is our backend. Here is how we config our proxy:

proxy:
  endpoints:
    '/zenquotes':
      target: 'https://zenquotes.io/api'
      changeOrigin: true
      # This is the crucial part that preserves the path
      pathRewrite:
        '^/api/proxy/zenquotes': ''
  ### Example for how to add a proxy endpoint for the frontend.
  ### A typical reason to do this is to handle HTTPS and CORS for internal services.
  # endpoints:
  #   '/test':
  #     target: 'https://example.com'
  #     changeOrigin: true

And the commit for the plugin with big help of AI (Gemini in this scenario)

I even learned how to publish the package to npmjs.com haha. Here is the package link: https://www.npmjs.com/package/@kienlt/backstage-plugin-random-quote

And it's source code: https://gitlab.com/kienlt-backstage/backstage-plugin-random-quote. You can take a look with commit to see some pain I go through to make it works. And the result of simple plugin (Random Quote).

alt text


Backstage Scaffolder - Golden Path

The idea was from my previous leader back in 2022-2023, we are trying to find a solution for automation that have a form to create full CI/CD deployment. User(Developer) only need to enter which language, service type (api/website). Kinda like some simple information and the backend will process from A->Z that create best practice example code include Dockerfile and other components based service type. At that time, I understood the idea but could not make it work.

Until today, I'm learning Backstage and remember the past, ohh, Backstage Software Template (Backstage Scaffolder) is the solution for that issue.

Here is how it implemented via commit

We need GitLab Token with following information (For Demo):

alt text

And update in app-config.yaml for scan.

catalog:
  providers:
    gitlab:
      # A unique name for this provider
      kienlt-group:
        host: gitlab.com
        # The GitLab group to scan for projects
        group: 'kienlt-backstage'
        # Skip personal projects
        skipPersonalProjects: true
        schedule:
          frequency: { minutes: 5 }
          timeout: { minutes: 3 }

And yeah, with catalog-info.yaml located inside Skeleton folder, it will not make any senses for GitOps. But this article I just want to show some basic of Backstage and what's capable of!

Here is the Demo after we implement Backstage Scaffolder

alt text

We will choose NodeJS Express Service from backstage-catalog repo, enter some required field

alt text

alt text

alt text

And here is the result after we create

alt text

It already imported to Software Catalog page

alt text

And public demo repo: https://gitlab.com/kienlt-backstage/blackmetalz.github.io

Sound great right?


Prepare for Certified Backstage Associate Exam

A lot of things I haven't introduced in this Section was:

  • Techdocs: How document as code working.
  • Tech builder: How document build and generation.
  • Search: How we search component/catalog/document.
  • Relation between kind Component and API.
  • What is the lifecycle?
  • And many things more, but they can be found in here. The mock exam to prepare for Certified Backstage Associate exam!

https://www.udemy.com/course/certified-backstage-associate-exam-practice-questions

I used that to prepare for the exam and scored 83/100 in real test!


Conclusion

  • Backstage is not easy.
  • Don't use it if you don't have issue like Spotify or your infrastructure is not big enough because it will consume very very big human resource to implement!

When Backstage is overkill:

  • Maintaining Backstage itself requires significant effort (upgrades, plugin compatibility, custom development)
  • ROI isn't worth it for small teams where everyone already knows each other and where services live
  • Confluence/Notion + GitLab/GitHub wiki might be sufficient

When you actually need it:

  • 50+ microservices that no one can remember entirely
  • Multiple teams with frequent developer onboarding
  • Need to standardize Golden Paths for creating new services
  • "Who owns this service?" becomes a daily question

Resource I used to create this Article:


Published

Category

Knowledge Base

Tags

Contact