Container Registry in CI/CD pipelines
This guide covers authenticating to Thalassa Cloud Container Registry from CI/CD pipelines. Prefer OIDC workload identity so pipelines never store long-lived registry secrets. Access credentials remain available when federation is not an option.
Credential scopes
Access credentials must include a container registry scope:
| Scope | Access | Typical use |
|---|---|---|
containerRegistry | Push and pull | Build pipelines that push images |
containerRegistry:all | Push and pull | Same as above |
containerRegistry:pull | Pull only | Deploy pipelines and promotion stages |
Create separate credentials for build and deploy stages. Deploy pipelines should use pull-only scope.
User sessions and IAM policies can also grant push and pull on registry resources. See Access control for policy-based access.
When using OIDC token exchange, grant the federated identity the same registry scopes (containerRegistry or containerRegistry:pull) and ensure the service account has the required IAM roles.
OIDC workload identity (recommended)
For GitLab CI, GitHub Actions, and other OIDC-capable platforms, exchange a short-lived CI identity token for a Thalassa Cloud access token, then log in to the registry with username sts_token. No client secret is stored in CI variables.
Prerequisites:
- Create a service account with registry push (or pull) permissions.
- Configure an identity provider and federated identity so your pipeline can impersonate that service account.
- Store only non-secret identifiers as CI variables: organisation ID and service account ID.
GitLab CI example
variables:
THALASSA_API: "https://api.thalassa.cloud"
# Set THALASSA_ORGANISATION_ID and THALASSA_SERVICE_ACCOUNT_ID as CI/CD variables
build:
image: docker:24
services:
- docker:24-dind
id_tokens:
THALASSA_ID_TOKEN:
aud: https://api.thalassa.cloud
before_script:
- apk add --no-cache curl jq
- |
if [ -z "$THALASSA_ORGANISATION_ID" ] || [ -z "$THALASSA_SERVICE_ACCOUNT_ID" ]; then
echo "THALASSA_ORGANISATION_ID and THALASSA_SERVICE_ACCOUNT_ID must be set"
exit 1
fi
THALASSA_ACCESS_TOKEN=$(curl -s -X POST "${THALASSA_API}/oidc/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "subject_token=${THALASSA_ID_TOKEN}" \
-d "subject_token_type=urn:ietf:params:oauth:token-type:id_token" \
-d "organisation_id=${THALASSA_ORGANISATION_ID}" \
-d "service_account_id=${THALASSA_SERVICE_ACCOUNT_ID}" \
-d "access_token_lifetime=7200s" | jq -r '.access_token')
echo "$THALASSA_ACCESS_TOKEN" | docker login registry.nl-01.thalassa.cloud \
-u sts_token --password-stdin
script:
- docker build -t registry.nl-01.thalassa.cloud/acme-platform/my-app:$CI_COMMIT_SHA .
- docker push registry.nl-01.thalassa.cloud/acme-platform/my-app:$CI_COMMIT_SHAFull federation setup for GitLab is covered in Configuring Workload Identity Federation for GitLab CI. For GitHub Actions, see GitHub Actions.
Docker login with access credentials
Most CI systems support running docker login before push or pull:
docker login registry.nl-01.thalassa.cloud \
-u "$REGISTRY_USERNAME" \
-p "$REGISTRY_PASSWORD"Store REGISTRY_USERNAME and REGISTRY_PASSWORD as protected CI variables.
Build and push workflow
A typical build pipeline with static credentials:
# Authenticate
docker login registry.nl-01.thalassa.cloud \
-u "$REGISTRY_USERNAME" \
-p "$REGISTRY_PASSWORD"
# Build
docker build -t my-app:$CI_COMMIT_SHA .
# Tag with registry path
docker tag my-app:$CI_COMMIT_SHA \
registry.nl-01.thalassa.cloud/acme-platform/my-app:$CI_COMMIT_SHA
docker tag my-app:$CI_COMMIT_SHA \
registry.nl-01.thalassa.cloud/acme-platform/my-app:latest
# Push
docker push registry.nl-01.thalassa.cloud/acme-platform/my-app:$CI_COMMIT_SHA
docker push registry.nl-01.thalassa.cloud/acme-platform/my-app:latestTag images with commit SHA or build ID for traceability. Avoid overwriting latest in production namespaces without a promotion step.
Pull-only deploy workflow
Deploy pipelines that only need to verify or promote images:
docker login registry.nl-01.thalassa.cloud \
-u "$REGISTRY_USERNAME" \
-p "$REGISTRY_PASSWORD"
docker pull registry.nl-01.thalassa.cloud/acme-platform/my-app:$IMAGE_TAGUse a credential with containerRegistry:pull scope, or an OIDC federated identity limited to pull.
Service accounts
For long-running automation, create a service account and either:
- Impersonate it via OIDC token exchange (recommended for CI), or
- Create an access credential scoped to the minimum required registry permissions
Bind registry:developer or a custom IAM policy for API-level namespace management if the pipeline also creates namespaces.
Recommended practices
| Practice | Rationale |
|---|---|
| Prefer OIDC over static secrets | Removes long-lived registry credentials from CI |
| Separate build and deploy identities | Limit blast radius if a deploy credential leaks |
| Pull-only for deploy | Prevents accidental image overwrites from deploy pipelines |
| Tag with immutable identifiers | SHA or build ID enables rollback and audit |
| Use retention policies | Automatically prune CI-generated tags to control storage costs |
Related documentation
- Getting started — Manual push workflow
- Workload Identity Federation — OIDC setup for GitLab, GitHub Actions, and generic providers
- Kubernetes — Deploy pulled images to clusters
- Namespace configuration — Retention rules for CI tags
- Billing — Storage and transfer metering
- Pricing — Public tariffs and cost calculator