Skip to main content

Installation

Requirements

ComponentMinimum versionNeeded for
SKE Operatorv0.32.1Installing the portal-controller integration type
Portal Controllerv0.2.0This integration
Portal Patch0.7.0Declarative customization, optional
@syntasso/plugin-ske-backendv0.21.0Backstage portals
@syntasso/plugin-ske-frontendv0.18.0Backstage portals

Install the Portal Controller

The Portal Controller is installed and upgraded by the SKE Operator from a single SKEIntegration resource of spec.type: portal-controller. Only one SKEIntegration of this type may exist on a platform at a time.

apiVersion: platform.syntasso.io/v1alpha1
kind: SKEIntegration
metadata:
name: portal-controller
spec:
type: portal-controller
version: v0.2.0
portals: []

Applying the resource installs the Portal Controller Deployment, the PortalCustomization Custom Resource Definition, and the RBAC and Service Account it runs as, into the kratix-platform-system namespace.

Connect a portal

Each entry under spec.portals describes one portal:

FieldRequiredMeaning
nameyesIdentifies the portal. Must be unique within type, so you can have two Backstage portals, but not two both named prod.
typeyesThe portal type this entry targets, for example backstage or cortex.
urldepends on typeThe portal's base URL. Required for Cortex, unused by Backstage.
secretRefdepends on typeNames the portal's credential Secret. Required for Cortex, unused by Backstage.
configdepends on typeSettings for this portal only. The keys differ per type.
adapterConfignoAdapter image, pull secrets and generate flags.

You can declare more than one portal, of the same or different types, on the same SKEIntegration. What each field needs varies by type:

Credential Secret handling

The Portal Controller does not create or manage a portal's credential Secret, and not every portal needs one. Backstage does not, since it never calls a live API.

Where a portal's secretRef is set, create the Secret yourself in kratix-platform-system before installing or upgrading, with the credential under a token key:

apiVersion: v1
kind: Secret
metadata:
name: cortex-token
namespace: kratix-platform-system
type: Opaque
stringData:
token: <cortex-api-token>

The operator validates only that a referenced Secret exists, not that it contains a usable credential. If it is missing, the SKEIntegration reports IntegrationDeploymentReady: False until you create it.

Once installed, the credential is injected directly into the sync pipeline's writer container, and for Cortex the status exporter, using a secret key reference. It is never written to a shared volume and never reaches the generate or configure stages.

Bind a Promise to a portal

A Promise, or a Resource request, opts into a portal with a label:

metadata:
labels:
kratix.io/portal-backstage: "true" # opt in to the default portal of type "backstage"

If you have more than one portal of the same type, name the one you want with an instance suffix:

metadata:
labels:
kratix.io/portal-backstage.prod: "true" # opt in to the portal named "prod"
note

On a Promise, only the presence of the label matters. Its value is not read, so kratix.io/portal-backstage: "false" still opts the Promise in. To opt a Promise out, remove the label.

Opting a single Resource out

Resource requests inherit their Promise's labels. To keep one request out of the portal, set the same label to the string "false" on that request:

metadata:
labels:
kratix.io/portal-backstage: "false" # this request only, on an opted-in Promise

The request is skipped silently, with no entity generated and no condition reported. Use the same key the Promise resolved to, including the instance suffix if it used one.

Binding status

A Promise reports how its binding resolved on the PortalBindingReady condition:

ReasonMeaning
BindingResolvedThe label resolved to exactly one portal
AmbiguousPortalInstanceMore than one portal of the type exists and no instance was named
PortalConnectionNotFoundThe named instance does not match a configured portal
PortalIntegrationNotFoundNo portal-controller SKEIntegration is installed
CustomizationNotFoundThe named PortalCustomization does not exist
AmbiguousCustomizationMore than one PortalCustomization label is present

Once bound, each sync reports on a per-type condition, BackstagePortalSynced or CortexPortalSynced:

ReasonMeaning
EntitySyncedThe entity shipped successfully
SyncInProgressThe sync Job is running
GenerateOrWriteFailedThe Job failed before shipping the entity
PromiseHasNoAPIThe Promise has no spec.api to render into an entity

On success the Promise is annotated with kratix.io/portal-<type>-entity-url, pointing at the entity in the portal.

Adapter image resolution

By default, a backstage or cortex portal uses the adapter bundled inside the Portal Controller's own image, at the version set on spec.version. Most platforms never change this.

To pin a different adapter image for one portal, for example to roll a fix out to a single portal before the rest, set adapterConfig.image to a single image reference (repo:tag or repo@sha256, there is no separate version field):

portals:
- name: prod
type: backstage
adapterConfig:
image: ghcr.io/syntasso/ske-portal-controller:v0.2.1

Other adapterConfig fields

FieldApplies toMeaning
imageall portalsAdapter image override
imagePullSecretsall portalsExtra pull secret names, always merged with syntasso-registry
generate.argsall portalsFlags passed verbatim to the generate stage
exporter.deploymentSpecCortex portalsOverlay merged into the status exporter's Deployment

Portal-wide generate flags

adapterConfig.generate.args is a list of flags passed verbatim to the adapter's generate stage for that portal. Every Promise and Resource routed through the portal gets the same behaviour, so this is a portal-wide setting, not a per-Promise one:

FlagPortal typeEffect
--single-spec-pagebackstageMerges the generated Template's spec form pages into one, instead of one page per top-level spec property
--fixed-namespace=<value>cortexHard-codes the namespace on the generated create workflow and hides the namespace input. Must be a valid DNS-1123 label
portals:
- name: prod
type: cortex
# ... url, secretRef, config as below
adapterConfig:
generate:
args:
- "--fixed-namespace=team-a"

Portal Patch offers per-Promise equivalents of both, through the singleSpecPage and hideNamespaceManifest recipes. Use the flags when you want the behaviour everywhere on a portal, and a recipe when you want it for particular Promises.

warning

Do not put credentials in generate.args. Unlike a secretRef credential, which is injected into the writer container as a secret key reference, these flags are passed as container arguments and are visible to anyone with read access to the Job in kratix-platform-system.

Air-gapped environments

Mirror the following images into your own registry:

ImageNeeded for
ghcr.io/syntasso/ske-portal-controller:<version>The controller and its bundled adapter, one image
ghcr.io/syntasso/portal-patch:<version>Only if you use Portal Patch recipes
Any adapterConfig.imageOnly if you override the adapter image
Any PortalCustomization container imageYour own configure containers

The Kratix pipeline adapter image is also required, but it is part of the SKE platform install rather than this integration.

Point the operator at your registry with its image registry configuration, the same way as other SKE components. Pull secrets come from adapterConfig.imagePullSecrets, which is always merged with syntasso-registry.