Naming Conventions

The naming patterns used across the CompTech v6 fleet — clusters, Vault paths, MinIO buckets, ESO bindings, Argo CD Applications, GitLab repos, Quay robot tokens, and platform-gitops branches.

Naming is the cheapest form of design. The patterns on this page exist so that an operator who has never seen a particular cluster, division, or tenant can read a single resource name and know what it is, where it belongs, and what it is allowed to talk to. The patterns are not aesthetic; they encode the ownership boundaries from ADR 0015 (federated GitOps) and ADR 0024 (OpenShift-only repo boundary), and the multi-tenant secret model from issue #174 (per-division Vault tenancy).

If you are introducing a new resource, a new tenant, or a new cluster, follow these patterns. If a pattern does not exist for what you are doing, that is a signal to write an ADR before naming things — not to invent a new convention quietly.

Cluster names

Active fleet:

ClusterRoleNaming components
hub-dc-v6active management hub<role>-<datacenter>-<generation>
spoke-dc-v6active workload cluster<role>-<datacenter>-<generation>

Reserved (not yet built; ADR 0022):

ClusterRoleStatus
hub-dr-v6future v6 management DRreserved name, no manifests
spoke-dr-v6future v6 workload DRreserved name, no manifests

Generation suffix. The -v6 suffix is the rebuild generation. Pre-v6 names (hub-dc, spoke-dc, hub-dr, spoke-dr) refer to the decommissioned cluster set; they may appear in historical reports but must not appear in new manifests, plans, scripts, runbooks, or session reports (ADR 0022).

Role prefixes. hub-* is a management cluster — runs RHACM, MCE, OpenShift GitOps, gitops-addon, ACS Central. Storage-light by ADR 0004; LVMS only, no ODF. spoke-* is a workload cluster — runs ODF, ESO, tenant workloads, LokiStack, TempoStack, OADP, the ACS Sensor.

Datacenter token. dc is the primary datacenter; dr is the disaster-recovery datacenter. Today the lab has one DC and reserves dr names; the pre-v6 DR was decommissioned and v6 DR is not built.

Cluster ingress hostnames follow the cluster name: *.apps.<cluster>.sub.comptech-lab.com. So spoke ingress is *.apps.spoke-dc-v6.sub.comptech-lab.com and the spoke console is console-openshift-console.apps.spoke-dc-v6.sub.comptech-lab.com. The cluster API is api.<cluster>.sub.comptech-lab.com:6443.

Host names and IP allocation

The lab uses a private RFC1918 /16 divided into role-bands. Specific addresses are kept in the private connection-details/ runbooks; this page documents only the allocation pattern, never an individual address.

Allocation pattern (general):

BandUsed byNotes
.x (low)Edge and infrastructure VMsDNS, HAProxy edge, GitLab, MinIO, Nexus, Vault, Jenkins, SigNoz
.y (mid)OpenShift node networksPer-cluster API and ingress VIPs
.z (high)Workers, dynamic hostsPhysical workers gold-1, gold-2, gpu-01

The hostname convention for platform VMs is <service>.sub.comptech-lab.com for the LAN-internal authoritative name (e.g., pdns.local, nexus-mirror.sub.comptech-lab.com, gitlab.apps.sub.comptech-lab.com). Edge-exposed HTTPS hostnames live under *.apps.sub.comptech-lab.com even though they are platform VMs and not OpenShift routes — HAProxy fronts them with the LE wildcard for that domain.

The monitoring track adds a parallel *.mon.sub.comptech-lab.com domain for the LGTM testing VM (grafana.mon.sub.comptech-lab.com, etc.). This split keeps the testing observability stack out of the *.apps.* namespace.

Vault paths

Per-division application tenancy under KV-v2 mount secret/:

secret/apps/
  <division>/                  # e.g. platform, payments, retail
    <app>/                     # e.g. open-liberty-readiness-probe
      <env>/                   # dev, stage, prod
        <key>                  # individual secret entries

Examples (illustrative, not live values):

secret/apps/platform/eso-smoke/dev/hello
secret/apps/payments/checkout-api/prod/db.password
secret/apps/retail/storefront-api/stage/api.token

KV-v2 access paths:

OperationPath
Readsecret/data/apps/<division>/<app>/<env>/<key>
List metadatasecret/metadata/apps/<division>/<app>/<env>/
Updatesecret/data/apps/<division>/<app>/<env>/<key>

Platform-scoped Vault paths (cluster operators, not tenant apps) live under a separate subtree (ocp/platform/*, ocp/<cluster>/*) and are bound to the platform ESO ClusterSecretStore, not the per-tenant SecretStore.

Why this shape: one path subtree per division means a leaked role only ever exposes one division’s secrets; the Vault role’s namespace glob refuses to issue a token to any namespace outside that division’s prefix. See Credential Custody Rules for the full bridge from path → role → policy → tenant SecretStore.

Vault role and policy names

Per-cluster, per-division roles under the cluster’s Kubernetes auth mount:

auth/kubernetes-<cluster>/role/apps-<cluster>-<division>

Examples:

auth/kubernetes-spoke-dc-v6/role/apps-spoke-dc-v6-platform
auth/kubernetes-spoke-dc-v6/role/apps-spoke-dc-v6-payments

ACL policy per division (cluster-agnostic):

apps-<division>-read

The role binds a single policy to a service-account / namespace selector:

{
  "bound_service_account_names":      ["app-eso"],
  "bound_service_account_namespaces": ["apps-<division>-*"],
  "token_policies":                   ["apps-<division>-read"],
  "token_ttl":                        "1h",
  "token_max_ttl":                    "4h",
  "audience":                         "vault"
}

app-eso is the per-tenant ServiceAccount, created in each apps-<division>-<app> namespace by the tenant template — not to be confused with the platform-scoped external-secrets-operator-controller-manager SA used by the cluster ClusterSecretStore.

Tenant namespace names

Tenant application namespaces use the prefix apps-<division>-<app>:

apps-platform-eso-smoke
apps-platform-readiness-probe
apps-payments-checkout-api
apps-retail-storefront-api

Why the prefix: the Vault role’s bound_service_account_namespaces glob is apps-<division>-*, so any namespace that doesn’t start with apps-<division>- is structurally locked out of that division’s Vault role. The naming is the access boundary.

Platform-owned (non-tenant) namespaces are prefixed by purpose:

PrefixPurposeExamples
openshift-*OCP system + Red Hat operatorsopenshift-gitops, openshift-storage, openshift-pipelines
open-cluster-management*RHACM hub-side resourcesopen-cluster-management, open-cluster-management-agent
stackroxACS Sensor namespace on spokesstackrox
external-secretsESO operatorexternal-secrets
cert-managercert-manager operatorcert-manager
(cluster-name)-managed-clusterHub-side namespace per spokespoke-dc-v6-managed-cluster

MinIO bucket and prefix names

The active developer-evidence bucket is developer-ci-evidence with prefixes per evidence kind:

developer-ci-evidence/
  builds/      # build artifacts (90-day retention)
  trivy/       # scan reports (180-day retention)
  sbom/        # SBOM JSON (365-day retention)
  releases/    # release evidence (365-day retention)
  smoke/       # smoke-test probe data (30-day retention)

Lifecycle policies are attached at the prefix level so that retention is by evidence type rather than by application — the same bucket is shared across CI jobs and divisions.

For platform backup/restore, per-cluster buckets:

oadp-backups-<cluster>           # OADP / Velero
acm-backups-<cluster>            # ACM DataProtectionApplication
vault-snapshots                  # Vault raft snapshots
loki-storage-<cluster>           # LokiStack chunks/index
tempo-storage-<cluster>          # TempoStack traces

Bucket access is per-bucket least-privilege MinIO users — there is no shared “operator” account used across multiple buckets.

OBC (ObjectBucketClaim) names and the bridge to operand secrets

NooBaa-backed OBCs on the spoke create an Object Bucket and a Secret containing AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY plus a ConfigMap with the endpoint. The LokiStack and TempoStack operators expect a different secret shape (endpoint/bucketnames/access_key_id/access_key_secret). The bridge is an ESO ExternalSecret using the kubernetes provider that reads the OBC Secret + ConfigMap and templates the operand Secret.

OBC names follow purpose:

loki-obc           -> loki-storage      (operand-shaped Secret)
tempo-obc          -> tempo-storage     (operand-shaped Secret)
quay-obc           -> quay-storage      (operand-shaped Secret)

See the OBC operand-secret bridge incident page for the canonical example.

ESO Secret-store and ExternalSecret names

The platform-scoped ClusterSecretStore (used by cluster operators):

vault-cluster        # ClusterSecretStore at clusters/<cluster>/secrets/eso/clustersecretstore-vault.yaml

The per-tenant SecretStore (used by tenant apps):

vault-apps           # SecretStore inside each apps-<division>-<app> namespace

ExternalSecret resources reference their store by kind + name:

spec:
  secretStoreRef:
    kind: SecretStore        # or ClusterSecretStore for platform-scoped
    name: vault-apps

ExternalSecret names usually match the target K8s Secret name they materialize:

ExternalSecret: pull-secret-app-registry  ->  Secret: pull-secret-app-registry
ExternalSecret: db-credentials            ->  Secret: db-credentials

Argo CD Application names

Top-level Applications follow <cluster>-<purpose>:

hub-dc-v6-bootstrap           # hub Argo's first Application; bootstraps the rest
spoke-dc-v6-cluster-config    # spoke Argo's bootstrap; reconciles the spoke overlay

ApplicationSets generated by ACM placement use <applicationset>-<cluster> where the cluster is the placement decision:

platform-operators-spoke-dc-v6
platform-storage-spoke-dc-v6
platform-observability-spoke-dc-v6

Tenant-scoped Applications inside <division>-gitops use <division>-<app>-<env>:

platform-eso-smoke-dev
payments-checkout-api-prod
retail-storefront-api-stage

AppProject names are usually <scope> (platform, tenant-<division>, system) and bound to allowed source repos + destination namespaces.

Platform-gitops branch names

Branches in comptech-platform/openshift-ops/openshift-platform-gitops use a phase-or-issue prefix:

main                                 # protected, MR-only
<phase-tag>                          # e.g. dev-ocp-0.4
<phase>-<purpose>                    # e.g. pci-3-hardening-tailored-profile
<issue-number>-<purpose>             # e.g. 153-routes-crd-cleanup

Phase tags come from the milestone/phase chain (PCI-0, PCI-1, PCI-1.13, PCI-2, …, DEV-OCP-0.4, OBS-1, etc.). The branch name is set when the phase issue is opened and stays consistent through the MR. Once the MR merges, the branch is deleted on the GitLab side; the merge commit on main carries the phase tag in its message.

The MR title convention echoes the branch:

<phase-or-issue>: <one-line summary>           # MR title

Example titles from the recent rebuild:

PCI-3: tailored profile + hardening manifests
DEV-OCP-0.4: per-division Vault tenancy (apps-* namespaces)
OBS-1: LokiStack + TempoStack OBC bridges via ESO kubernetes provider
153: remove stale routes.route.openshift.io CRD on hub

GitLab repo names

Group layout (ADR 0015):

comptech-platform/
  openshift-ops/
    openshift-platform-gitops          # the OpenShift platform repo
    openshift-cluster-build            # cluster install inputs (planned)

  infra-ops/
    vm-platform-ops                    # HAProxy, PDNS, GitLab, Jenkins, Nexus, Vault, ... (planned)

  platform-services/
    platform-tools-iac                 # shared infra modules (planned)
    platform-tools-config              # tool config via APIs / JCasC / Ansible (planned)

  tenant-registry/
    openshift-tenants                  # approved tenant metadata (optional split)

divisions/
  <division>/
    <division>-apps-monorepo           # application source per division
    <division>-gitops                  # deployment intent per division

GitLab role-group names

Role groups follow ct-<scope>-<role>:

ct-gitlab-admins
ct-openshift-platform-maintainers
ct-openshift-platform-reviewers
ct-infra-platform-maintainers
ct-infra-platform-reviewers
ct-cicd-platform-maintainers
ct-security-reviewers
ct-auditors
ct-<division>-app-maintainers
ct-<division>-developers
ct-<division>-release-approvers

The ct- prefix is “CompTech.” <scope> is the operational domain. <role> is the role within that scope. Adding a user directly to a project rather than to a role group is treated as drift.

Quay robot token names (per-tenant Tekton push)

For tenants pushing application images through Tekton on the spoke, the convention is per-tenant Quay robot tokens delivered as dockerconfigjson Secrets in openshift-pipelines:

Vault path:     secret/apps/<division>/<app>/ci/quay-robot
Vault role:     apps-<cluster>-<division>             # the existing per-division role
SecretStore:    vault-apps (in openshift-pipelines, scoped via tenant overlay)
Secret name:    quay-robot-team-<team>                # the materialized dockerconfigjson

The shared push-image-quay Tekton Task accepts the Secret name as a parameter, so each tenant overlay supplies its own robot token without per-task duplication.

Nexus user / role names

Service accounts on Nexus are scoped, not shared:

AccountRolePermissions
adminfull adminbreak-glass only
jenkinsbotnexus-jenkins-ciread on docker-group; browse+read+add+edit+delete on docker-dev-hosted; no access to ocp-mirror
(per-division CI accounts, when created)per-division rolescoped to that division’s repository path

The deletion right on docker-dev-hosted is intentional and bounded — Jenkins removes tags it created when a downstream pipeline stage fails. It is not permission to mutate OpenShift platform mirror content.

Catalog source names

Mirrored OperatorHub catalog sources on the spoke:

cs-redhat-operator-index-v4-20          # Red Hat operator catalog (OCP 4.20)
cs-certified-operator-index-v4-20       # certified operator catalog (OCP 4.20)
clustercatalog-redhat-operator-index-v4-20      # OLM v1 ClusterCatalog
clustercatalog-certified-operator-index-v4-20   # OLM v1 ClusterCatalog

The -v4-20 suffix is the OpenShift minor version. When the cluster moves to OCP 4.21, the catalog name changes to -v4-21 and the GitOps overlay refreshes the digest along with the name.

Image registry hostnames

Three Nexus Docker endpoints, three purposes:

HostnamePurposeBacked by
mirror-registry.apps.sub.comptech-lab.comOpenShift platform mirror (oc mirror --v2 target)Nexus hosted repo ocp-mirror
docker-group.apps.sub.comptech-lab.comDeveloper / Jenkins base-image pullsNexus group repo docker-group
app-registry.apps.sub.comptech-lab.comCI-produced application image pushesNexus hosted repo docker-dev-hosted

Hard rule: apps never push to mirror-registry; never pull base images from app-registry; never push to docker-group. Three endpoints, three change windows, three ACL surfaces.

Image tag conventions

Application images use immutable tags:

<repo>:<env>-<git-sha>           # preferred
<repo>:build-YYYYMMDD-HHMMSS     # build-id fallback
<repo>:<jenkins-build-number>    # short fallback
<repo>@sha256:<digest>           # canonical reference for promotion

latest is forbidden in any OpenShift manifest or Compose file. Promotion is by digest, not by re-tagging; build once, promote across devuatstagingprod by referring to the same @sha256:... digest in each environment overlay.

Summary

The naming patterns are deliberately repetitive so an operator can read a single name and triangulate every other name. A namespace called apps-payments-checkout-api implies:

  • division payments;
  • application checkout-api;
  • Vault path secret/apps/payments/checkout-api/<env>/...;
  • Vault role apps-<cluster>-payments;
  • ACL policy apps-payments-read;
  • ESO SecretStore named vault-apps inside the namespace;
  • GitLab repo divisions/payments/payments-gitops (deployment intent);
  • Argo Application payments-checkout-api-<env>;
  • Quay robot token Secret at secret/apps/payments/checkout-api/ci/quay-robot.

When something doesn’t follow the pattern, that is the signal to investigate before adopting the exception.

References

  • connection-details/vault-app-secrets.md — per-division Vault tenancy convention
  • connection-details/platform-admin-handoff.md — cluster names, operator inventory
  • connection-details/gitlab-operator-guide.md — GitLab group + role-group layout
  • connection-details/nexus.md — Nexus endpoint naming
  • connection-details/minio.md — bucket/prefix layout
  • adr/0015-federated-gitops-repo-architecture.md
  • adr/0019-nexus-only-image-supply-chain.md
  • adr/0022-v6-fleet-membership.md
  • adr/0024-openshift-only-platform-gitops-boundary.md

Last reviewed: 2026-05-11