Harbor is your private container registry, running on the service cluster at registry.<CUSTOMER_ID>.truefullstaq.cloud. Every image you run on the production cluster should live here, not on Docker Hub or another public registry. Harbor also scans your images for known vulnerabilities (CVEs).

Throughout this page, replace <CUSTOMER_ID> with your 5-digit ID (e.g. 01234) and <project> with your Harbor project name.

# Signing in to the UI

Open https://registry.<CUSTOMER_ID>.truefullstaq.cloud and click Login via OIDC Provider to sign in with TrueFullstaq SSO. This is where you browse repositories, read scan results, and create robot accounts.

# Projects

Harbor organises images into projects (think: one per team or application). A project holds repositories (<project>/<image>), each with tags. Images you push must go into a project you have access to. If you need a new project created, ask your TrueFullstaq engineer, or create one in the UI if your account permits.

# Logging in with Docker

To push from your laptop or a CI runner you need a CLI secret, because OIDC accounts can’t use your SSO password directly for Docker:

  1. UI → click your username (top right) → User Profile.
  2. Copy the CLI secret (regenerate it any time from the same screen).
  3. Log in:
docker login registry.01234.truefullstaq.cloud
# Username: your SSO username
# Password: the CLI secret from your profile

Podman/nerdctl work the same way: podman login registry.01234.truefullstaq.cloud.

# Pushing an image

# Build
docker build -t my-app:latest .

# Tag for Harbor: registry / project / image : tag
docker tag my-app:latest registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2

# Push
docker push registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2

Use immutable tags (e.g. v1.4.2 or a git SHA) rather than latest. ArgoCD deploys whatever tag is in your manifest, and fixed tags make rollbacks and audits unambiguous.

# Pulling an image

On the production cluster, Kubernetes pulls from Harbor automatically using the image pull secret provisioned in your namespace. Just reference the full image path in your manifest:

spec:
  containers:
    - name: my-app
      image: registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2

If your namespace does not yet have a pull secret, ask your TrueFullstaq engineer, or create one from a robot account (below):

kubectl create secret docker-registry harbor-pull \
  --docker-server=registry.01234.truefullstaq.cloud \
  --docker-username='robot$my-project+ci' \
  --docker-password='<robot-token>' \
  -n my-namespace

Then reference it:

spec:
  imagePullSecrets:
    - name: harbor-pull
  containers:
    - name: my-app
      image: registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2

To pull locally for testing: docker pull registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2.

# Robot accounts for CI/CD

Don’t bake personal credentials into pipelines. Use a robot account scoped to a project:

  1. UI → your project → Robot Accounts+ New Robot Account.
  2. Name it (e.g. ci), set an expiry, grant Push and Pull on repositories.
  3. Copy the generated token now; it is shown only once.

The robot’s username is robot$<project>+<name> (note the $). Quote it to stop your shell expanding $:

docker login registry.01234.truefullstaq.cloud \
  --username 'robot$my-project+ci' \
  --password '<robot-token>'

Store the token in OpenBao and surface it to your pipeline via the External Secrets Operator, and never commit it to Git.

# Hosting Helm charts (OCI)

Harbor stores Helm charts as OCI artifacts. A chart lives in your project just like a container image, at registry.<CUSTOMER_ID>.truefullstaq.cloud/<project>/<chart> with the chart version as its tag, so you push and pull charts over the same registry endpoint as your images.

# Pushing a chart

# Log in (robot account or your CLI secret, same as for images)
helm registry login registry.01234.truefullstaq.cloud \
  --username 'robot$my-project+ci' \
  --password '<robot-token>'

# Package and push. The chart name + version become the repo path + tag:
helm package ./my-chart            # -> my-chart-0.0.370.tgz
helm push my-chart-0.0.370.tgz oci://registry.01234.truefullstaq.cloud/my-project
# -> registry.01234.truefullstaq.cloud/my-project/my-chart:0.0.370

# Deploying a chart with ArgoCD

1. Register the repository as type helm with Enable OCI turned on, over the HTTP/HTTPS connection method. Set the Repository URL to the registry host + project, with no oci:// prefix and without the chart name:

Field Value
Type helm
Repository URL registry.01234.truefullstaq.cloud/my-project
Enable OCI ✅ checked
Username robot$my-project+ci
Password <robot-token>

Declaratively, that repository is a Secret in ArgoCD’s namespace on the service cluster:

apiVersion: v1
kind: Secret
metadata:
  name: harbor-helm
  namespace: argo                                     # ArgoCD's namespace
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  name: harbor-helm
  type: helm
  enableOCI: "true"
  url: registry.01234.truefullstaq.cloud/my-project   # host + project; no oci://, no chart name
  username: 'robot$my-project+ci'
  password: '<robot-token>'

2. Reference the chart from your Application. Point source.repoURL at the same URL, name the chart in chart, and the version in targetRevision:

spec:
  project: project-customer
  source:
    repoURL: registry.01234.truefullstaq.cloud/my-project   # same URL as the repo Secret
    chart: my-chart                                         # i.e. <project>/my-chart in Harbor
    targetRevision: 0.0.370                                 # a fixed version, or a range like 0.0.*
    helm:
      valuesObject: {}                                      # optional values overrides
  destination:
    server: https://87.233.10.20:6443                       # your production cluster
    namespace: my-app
  syncPolicy:
    automated: { prune: true, selfHeal: true }
    syncOptions: [ CreateNamespace=true ]

ArgoCD pulls registry.01234.truefullstaq.cloud/my-project/my-chart:0.0.370, which is repoURL + chart + targetRevision joined together.

# Vulnerability scanning

Harbor scans every pushed image. To review results: UI → your project → Repositories → select a repository → a tag → Vulnerabilities. You’ll see CVEs by severity with fixed versions where available.

# Trigger/refresh a scan from the CLI is done in the UI; to check a digest locally you can
# inspect the manifest, but scan results live in the Harbor UI.

Depending on your project’s policy, pulls of images with Critical CVEs may be blocked (“Prevent vulnerable images from running”). If a deploy fails to pull for this reason, rebuild on a patched base image and push a new tag.

# Housekeeping

  • Tag retention / cleanup: old tags accumulate. Configure retention rules under your project → Policy → Tag Retention to keep, say, the last 10 tags per repo.
  • Garbage collection (reclaiming disk from deleted tags) runs on a schedule managed by TrueFullstaq, so you don’t need to trigger it.