| name | bc-gov-emerald |
| description | BC Government Emerald OpenShift platform mechanics: namespace conventions, AVI InfraSettings route annotations, DataClass pod labels, Helm openshift mode, StorageClass, and DNS split-tunneling. Use when creating or reviewing Helm charts, Routes, or deployment manifests targeting Emerald specifically. For zone/classification decisions see bc-gov-sdn-zones; for NetworkPolicy YAML patterns see bc-gov-networkpolicy. |
BC Gov Emerald Platform Standards
Emerald-specific mechanics only. Platform-independent concepts live in companion skills:
- Zone model, ISCF classification, internet egress constraints →
bc-gov-sdn-zones
- NetworkPolicy YAML patterns and two-policy rule →
bc-gov-networkpolicy
- End-to-end network architecture reasoning →
bc-gov-network-architect agent
Namespace Convention
<license>-dev ← development
<license>-test ← staging / QA
<license>-prod ← production
<license>-tools ← CI/CD tooling, Artifactory, Vault
AVI InfraSettings — Route Annotation
Controls which VIP pool handles the Route. Get this wrong and traffic silently drops.
| Annotation value | VIP | When to use |
|---|
dataclass-medium | Private VIP — VPN only | ✅ All internal workloads (default) |
dataclass-high | Private VIP — sensitive data | Higher-trust internal workloads |
dataclass-public | Public internet VIP | Internet-facing routes with public exposure |
dataclass-low | ⚠️ NO VIP on Emerald | NEVER USE — DNS resolves but ERR_EMPTY_RESPONSE |
metadata:
annotations:
aviinfrasetting.ako.vmware.com/name: "dataclass-medium"
AKO re-adds this annotation within ~15 seconds if removed — always keep it in Helm values.
DataClass Pod Label
Pod DataClass label must match the AVI annotation suffix.
podLabels:
DataClass: "Medium"
Mismatch rule: DataClass: Low + dataclass-medium route → SDN silently drops traffic.
Required pod labels (enforced by ag-devops Datree + Conftest)
Every Deployment/StatefulSet pod template must carry all three labels. Missing any will cause the ag-devops policy gate to deny the manifest.
podLabels:
DataClass: "Medium"
owner: "<team-or-ticket>"
environment: "development"
When using ag-template.deployment, set ModuleValues.dataClass (renders DataClass) and add owner/environment via a LabelData fragment:
{{- define "myapp.labels" -}}
owner: jag-pssg-team
environment: development
{{- end }}
Internet-Ingress label
podLabels:
Internet-Ingress: "DENY"
For the full ISCF → DataClass mapping and zone egress constraints, see bc-gov-sdn-zones.
NetworkPolicy Model
Emerald default-denies both Ingress AND Egress. See bc-gov-networkpolicy for full YAML
patterns, the two-policy rule, DNS egress, CIDR egress, and the debugging checklist.
Quick reminder of the flows that need policies on Emerald:
| Flow | Policy needed |
|---|
| Router → Frontend | Ingress on Frontend |
| Router → API | Ingress on API |
| Frontend → API | Ingress on API + Egress from Frontend |
| API → DB | Ingress on DB + Egress from API |
| Any pod → DNS | Egress UDP+TCP 53 on every pod |
Route Edge Termination (Conftest hard-deny)
ag-devops Conftest denies edge-terminated Routes unless the Route has either:
- Label
app.kubernetes.io/component: frontend, or
- Annotation
isb.gov.bc.ca/edge-termination-approval: "<ticket>"
Passthrough (spec.tls.termination: passthrough) and re-encrypt termination are not affected.
metadata:
labels:
app.kubernetes.io/component: frontend
annotations:
isb.gov.bc.ca/edge-termination-approval: "ISB-12345"
PriorityClass (Polaris priorityClassNotSet check)
Every Deployment and StatefulSet must reference a PriorityClass. Polaris issues a failure if spec.template.spec.priorityClassName is unset. Define one PriorityClass per application group in the chart:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: <app>-priority
value: 1000000
globalDefault: false
Then in each workload:
spec:
template:
spec:
priorityClassName: <app>-priority
OpenShift Mode in Helm (global.openshift: true)
Set this in every Helm chart's values.yaml targeting Emerald:
global:
openshift: true
Effect:
- Deployment/Job pod
securityContext does not pin runAsUser/runAsGroup — OpenShift SCC assigns runtime UID/GID
- Adds
checkov.io/skip999: CKV_K8S_40=... annotation to suppress Checkov false-positive
- Still enforces
runAsNonRoot, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, capabilities drop ALL
⚠️ Omitting global.openshift: true when using the ag-helm library chart causes the
deployment template to pin runAsUser: 10001 which may conflict with the namespace's SCC.
StorageClass
Choose based on access mode and workload type:
| StorageClass | Access mode | Best for |
|---|
netapp-file-standard | RWX (multi-pod) | Shared file storage, build artefacts, config mounts |
netapp-block-standard | RWO (single-pod) | Databases, stateful workloads requiring higher IOPS |
storageClassName: netapp-file-standard
storageClassName: netapp-block-standard
netapp-block-standard is single-pod (RWO) — do not use for workloads that require
concurrent access from multiple pods.
DNS Split-Tunneling
Route hostnames (*.apps.emerald.devops.gov.bc.ca) resolve only via BC Gov VPN DNS.
Local / home DNS returns NXDOMAIN. Ensure VPN client routes this domain through VPN DNS
before debugging route connectivity issues.