Harbor is an open source container registry from the CNCF. It secures artifacts with role based access control, scans images for vulnerabilities, and supports replication across registries. Teams use it to manage images for Kubernetes and Docker at scale.
The Harbor Backstage plugin brings that data into your developer portal. It adds a page and a small widget to each service so you can see repositories that belong to the component. You can review tags and digests, confirm the latest push, and check scan status when scans run in Harbor. This keeps build, security, and release context in one place for the team.Typical use cases include verifying what is running before a rollout, spotting images that need rebuilds after a scan, and giving service owners a clear view without opening the registry UI. Platform and security teams get the same picture with less switching.
One company using the plugin is Digitalist Open Cloud. They maintain a fork to keep it current with newer Backstage releases.
Installation Instructions
These instructions apply to self-hosted Backstage only. To use this plugin on Roadie, visit the docs.
Install the frontend package
yarn --cwd packages/app add @bestsellerit/backstage-plugin-harbor
Register the plugin in your app
Add the plugin export.
// packages/app/src/plugins.ts
export { plugin as harbor } from '@bestsellerit/backstage-plugin-harbor'
Add the Harbor page to the service entity page
Import the components. Add a route so users can open the Harbor page from the entity sidebar.
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react'
import { EntityLayout, EntityPageLayout } from '@backstage/plugin-catalog'
import {
HarborPage,
HarborWidget,
isHarborAvailable,
} from '@bestsellerit/backstage-plugin-harbor'
const serviceEntityPage = (
<EntityPageLayout>
{/* other routes */}
<EntityLayout.Route path="/harbor" title="Harbor" if={isHarborAvailable}>
<HarborPage />
</EntityLayout.Route>
</EntityPageLayout>
)
Show the Harbor widget on the overview
Place the widget in the overview content.
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react'
import Grid from '@material-ui/core/Grid'
import { EntitySwitch } from '@backstage/plugin-catalog'
import {
HarborWidget,
isHarborAvailable,
} from '@bestsellerit/backstage-plugin-harbor'
const overviewContent = (
<Grid container spacing={6} alignItems="stretch">
{/* other content */}
<EntitySwitch>
<EntitySwitch.Case if={isHarborAvailable}>
<Grid item>
<HarborWidget />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
</Grid>
)
Install the backend for the legacy backend system
Add the backend package to the backend workspace.
yarn --cwd packages/backend add @container-registry/backstage-plugin-harbor-backend
Create the router factory.
// packages/backend/src/plugins/harbor.ts
import { createRouter } from '@container-registry/backstage-plugin-harbor-backend'
import { PluginEnvironment } from '../types'
export default async function createPlugin(env: PluginEnvironment) {
return await createRouter({
logger: env.logger,
config: env.config,
discovery: env.discovery,
tokenManager: env.tokenManager,
})
}
Wire the router into the backend.
// packages/backend/src/index.ts
import harbor from './plugins/harbor'
// inside the main function after creating the env
const harborEnv = useHotMemoize(module, () => createEnv('harbor'))
// inside the router setup
apiRouter.use('/harbor', await harbor(harborEnv))
Add the required config. Fill in the values for your Harbor instance and credentials. Keep the same keys so the plugin can read them.
# app-config.yaml
harbor:
baseUrl: https://harbor.example.com
username: ${HARBOR_USERNAME} # or a robot account
password: ${HARBOR_PASSWORD} # or a robot token
# tlsInsecure: false
# any other keys supported by the backend plugin
Export secrets as env vars in your backend process or set them in your secrets store.
export HARBOR_USERNAME=robot$backstage
export HARBOR_PASSWORD=your_token_here
Install the backend for the new backend system
Add the backend package.
yarn --cwd packages/backend add @container-registry/backstage-plugin-harbor-backend
Register the backend plugin feature.
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults'
import { harborPlugin } from '@container-registry/backstage-plugin-harbor-backend'
const backend = createBackend()
backend.add(harborPlugin())
backend.start()
Use the same config keys in app config.
# app-config.yaml
harbor:
baseUrl: https://harbor.example.com
username: ${HARBOR_USERNAME}
password: ${HARBOR_PASSWORD}
Add entity metadata
Make sure your entities contain the data that the plugin checks through isHarborAvailable. Add the needed annotations in the entity yaml.
# catalog-info.yaml
metadata:
name: my-service
annotations:
# add Harbor related annotations here
# example keys depend on your setup
spec:
type: service
owner: team-a
lifecycle: production
Things to Know
The Harbor Dashboard appears as a new tab on the catalog entity page:
A Harbor widget is also available to display a summary of vulnerabilities in your component’s Docker image. This widget can be added to any tab on the entity page:
The plugin will only display information about images in Harbor if a vulnerability scan has been run on the image. You can enable automatic scanning on image push in Harbor project settings:
Authentication
The plugin connects to Harbor with a username and password that is stored in app-config.yaml
. Credentials can be defined directly in the YAML file or passed in via environment variables like this:
harbor:
baseUrl: https://demo.goharbor.io
username:
$env: HARBOR_USERNAME
password:
$env: HARBOR_PASSWORD
Consider creating a dedicated Harbor user for the connection from Backstage.
Don’t have Harbor setup yet?
A demo of Harbor is available at demo.goharbor.io. The demo allows you to create an account and push images. All accounts and images are automatically purged on a regular basis. This is a great and easy way to experiment with Harbor in Backstage.
Changelog
The Harbor plugin has not seen any significant changes since a year ago.
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.