GATE - iam-data-access — Runbook
iam-data-access is the composite Lookup + Update gRPC service in the GATE/IAM
monorepo (gitlab-org/auth/iam): it serves
identity/access relationship reads (Lookup API) and writes (Update API) on one shared
gRPC port, backed by a Yugabyte data store (see the
YugabyteDB Aeon runbook for the DB side). It is deployed via
Runway
under the service ID iam-data-gke-grpc.
Use this when something is wrong or a consumer reports errors calling into IAM. Sections are ordered for an incident: triage first, then observability, alerts, troubleshooting, and escalation. The Reference section at the bottom covers environments, Vault paths, and config file locations.
1. Quick triage (start here)
Section titled “1. Quick triage (start here)”- Scope: staging or production? (Runway service ID either way:
iam-data-gke-grpc) - Health: kubelet already probes
Healthcontinuously (liveness/readiness), so a one-off manual call mostly just re-checks what Kubernetes already knows. Instead, watch the probe heartbeat itself: same production/staging A steady stream ofHealthcalls means probes are succeeding; gaps or errors mean they’re not. (A manual external call is still useful for testing the full client→gateway→pod path specifically — see 4.1.) - Deployment status: check the
Runway deployment pipeline
for the latest run. A green “Upload Resource Manifests” job is not a successful
deploy — it only publishes a Flux OCI artifact; Flux reconciles it async on the GKE
cluster. To confirm the actual pod state — see
4.1:
kubectl get pod -n iam-data-gke-grpc. - Client vs. service: is only one caller failing (suspect auth, not this service) or is everyone failing (suspect deployment or the backing DB)?
- Logs: production · staging (Grafana Explore, health checks excluded; see Observability to adjust the query).
- Recent change: check the
security-mirror main pipeline
for a recent Runway trigger, and recent MRs on
gitlab-org/auth/iam— did a deploy or config change trigger this? If so, assess a rollback (4.5). - Capture: exact error text (gRPC status + message), affected RPC, timestamps, env — you’ll need these for escalation.
Then jump to the matching section: Observability · Alerts · Troubleshooting · Incident response · Reference.
2. Observability
Section titled “2. Observability”Start here: production logs ·
staging logs — Grafana
Explore, health checks excluded. These are also the service catalog’s logging links for
iam-data-gke-grpc.
To adjust the query: datasource ClickHouse - Runway Production → table
observability → query type logs.
- Primary filter:
ServiceName = 'iam-iam-data-gke-grpc-iam-data-gke-grpc' - Other useful fields:
SeverityText(info/warn/error),Attributes['env'](staging/production),Attributes['cloud.runtime'](gke),k8s.pod.name,k8s.deployment.name,k8s.namespace.name,k8s.cluster.name. - Example filter:
WHERE ServiceName = 'iam-data-gke-grpc' AND SeverityText = 'error' AND Attributes['env'] = 'production'.
Metrics
Section titled “Metrics”- Shows the default
runway-k8s-archetypeSLIs: apdex/error-rate/RPS fromrunway_lb_*(frontend/backend load-balancer metrics), plus saturation (CPU/memory/HPA). - No custom application metrics (RPC-level latency/error-rate, DB-query timing) are
emitted today — only the generic Runway LB/saturation metrics above. Separate
iam-update/iam-readSLIs need that instrumentation to exist first.
Health / readiness
Section titled “Health / readiness”gRPC Health RPC per sub-service (gitlab.iam.lookup.v1.LookupService/Health,
gitlab.iam.update.v1.UpdateService/Health), served on the same port as regular gRPC
traffic (:5005) — there is no separate metrics/health port for this service.
3. Alerts
Section titled “3. Alerts”The Runway metrics-catalog entry for iam-data-gke-grpc provides the default
runway-k8s-archetype alerts via Alertmanager/Slack/incident.io:
- SLO violation alerts: apdex, error rate, traffic cessation — based on the
generic
runway_lb_*SLI (no RPC-method-level breakdown yet, see Metrics). - Saturation alerts: CPU, memory, HPA utilization.
- Default severity is S4 (Slack
#feed_alerts-general); S1/S2 pages on-call. See alert routing conventions.
These alert on service-level symptoms only — they won’t catch an iam-update-only or
iam-read-only regression while the other half of the composite service looks healthy.
For that, also watch consumer-side symptoms: GitLab Rails-side errors on calls into
IAM, or reports from teams integrating with the Lookup/Update APIs.
4. Troubleshooting
Section titled “4. Troubleshooting”4.1 Service unreachable / deployment unhealthy
Section titled “4.1 Service unreachable / deployment unhealthy”Symptoms: connection refused/timeouts on all RPCs (including Health), or a
deploy that “succeeded” in CI but nothing changed.
-
Check the Runway deployment pipeline — a green “Upload Resource Manifests” job only publishes a Flux OCI artifact; Flux reconciles it asynchronously on the target GKE cluster.
-
Check deployment health; two options:
- Via kubectl:
- Use
kubectlvia the KAS proxy onops.gitlab.net— see Connecting with kubectl for setup (glab cluster agent update-kubeconfig, pointed at the right agent — find it on the kas-clusters agents page). - Then
kubectl get pod -n iam-data-gke-grpcto see actual pod status/restarts/events.
- Use
- Via GCP console: Go to deployment details
- Via kubectl:
-
Check logs for crash/startup errors (bad
CONFIG_TOML, missing Vault secret — see 4.4). -
To test the full external path (client → gateway → pod) rather than just pod-level health, call the
HealthRPC directly — exempt from both auth layers, so no token needed:Terminal window # production: iam-data-gke-grpc.svc.gitlab.net# staging: staging.iam-data-gke-grpc.svc.gitlab.netbuf build -o - | grpcurl -protoset /dev/stdin \-d '{}' <host>:443 gitlab.iam.lookup.v1.LookupService/HealthUseful when the health-check heartbeat in logs looks fine (pod is healthy) but callers still can’t reach the service — points at routing/gateway rather than the pod itself.
4.2 Authentication failures (Unauthenticated / 401)
Section titled “4.2 Authentication failures (Unauthenticated / 401)”Symptoms: calls fail with opaque Unauthenticated (gRPC) or 401 (HTTP); Health
still works (it’s exempt from both auth layers).
Two independent layers, both required on every protected RPC:
| Layer | Checks | Failure mode |
|---|---|---|
Service token (pkg/serviceauth) | Shared secret sent in the gitlab-iam-data-access-token header — wrong header name is rejected the same as no token | Opaque Unauthorized, never says missing vs. wrong |
End-user JWT (pkg/userauth) | authorization: Bearer <jwt>; aud claim must match expected_audiences | Structured VerifyError/FailReason (audience mismatch, expired, key not found) |
- Confirm the caller is using the
gitlab-iam-data-access-tokenheader specifically (per-service header names are intentional — sending it under another service’s header name gets the same opaque rejection). - Confirm the JWT’s
audclaim matches this service’s configuredexpected_audiences. - Service token value: Vault-managed (see Vault paths).
- Full details:
docs/service-access.mdin theiamrepo.
4.3 Backing database issues
Section titled “4.3 Backing database issues”iam-data-access is backed by a YugabyteDB Aeon cluster. Connection failures,
latency, connection-pool exhaustion, node/cluster health — all covered in the
YugabyteDB Aeon runbook, not duplicated here.
4.4 Config/secrets issues
Section titled “4.4 Config/secrets issues”Symptoms: service fails to start, or starts with wrong config (wrong DB host, CORS rejecting a valid origin, wrong OAuth issuer).
- Runway can’t mount configMap volumes, so non-secret config is passed inline as a
CONFIG_TOMLenv var (.runway/values-{staging,production}.yaml) — the container entrypoint writes it to disk and pointsCONFIG_FILE_PATHat it. - Secrets are injected as individual env vars from Vault via Runway’s
secretEnvFrom(workloadSecrets: [yugabyte, service-token]in.runway/deployment.yaml). A missing secret shows as its config-file placeholder value (VAULT_MANAGED) leaking through unchanged — check the Vault paths below. - Confirm expected values against Vault paths and the environment’s
CONFIG_TOMLblock in.runway/values-<env>.yaml.
4.5 Bad deploy / need rollback
Section titled “4.5 Bad deploy / need rollback”- Production deploys are manual-gated (
runway_manual_production_deploy: true) — staging auto-deploys on every release tag. - Chart version is pinned per deploy
(
oci://registry.gitlab.com/gitlab-org/auth/iam/chart/iam:<ChartVersion>in.runway/deployment.yaml) — a rollback is re-triggering the Runway deployment pipeline against the previous known-good tag. - See
docs/release.mdin theiamrepo for the full release/deploy flow.
5. Incident response & escalation
Section titled “5. Incident response & escalation”5.1 Severity
Section titled “5.1 Severity”| Severity | Example | Action |
|---|---|---|
| S1 / Critical | Production unreachable for all callers; data corruption via Update API | Page on-call; declare incident |
| S2 / High | Partial outage (e.g. one RPC failing); elevated error rate reported by a consumer team | Page on-call |
| S3 / Moderate | Single-pod issue self-healing; staging-only issue blocking a release | Investigate same business day |
| S4 / Low | Smoke-test flakiness, minor config drift, capacity planning | Routine MR / follow-up |
Staging issues are normally ≤ S3 unless they block a release.
5.2 First responder checklist
Section titled “5.2 First responder checklist”See Quick triage. Mitigate what’s in our control (rollback, config/secret fix); escalate deployment/cluster-level issues to Runway.
5.3 Internal escalation
Section titled “5.3 Internal escalation”- On-call escalation: https://app.incident.io/gitlab/on-call/escalation-paths/01KCQ3V11Z5MXPYSWEG4F368CV
- Owning team:
group::authentication - Incident channel:
#g_authentication
5.4 Runway / Infra escalation
Section titled “5.4 Runway / Infra escalation”- Ask in
#f_runwayfor deployment/cluster-level issues (Flux reconciliation, pod crash diagnosis, PSC/network issues) — the Runway team owns the platform. - Read-only
kubectlaccess for non-Infra engineers is now available for both staging and production — see Connecting with kubectl.
5.5 What we handle vs. what Runway/Infra handles
Section titled “5.5 What we handle vs. what Runway/Infra handles”| We handle | Runway/Infra handles |
|---|---|
| App config, Vault secret values, service-token/JWT config | Cluster health, Flux reconciliation, autoscaling |
| Deploy trigger (release tags, manual production approval) | GKE node/pod infrastructure, PSC networking |
| App-level bugs, DB query issues (see Aeon runbook) | Platform-level metrics/logs pipeline (ClickHouse, Mimir) |
6. Reference: environments, access & config
Section titled “6. Reference: environments, access & config”Environments
Section titled “Environments”There are two distinct entrypoints into this service — which one a caller uses depends on whether it runs in the same GKE cluster as this service:
| Env | Runway service ID | env label | Public entrypoint | Internal entrypoint | OAuth issuer |
|---|---|---|---|---|---|
| Staging (gstg) | iam-data-gke-grpc | staging | staging.iam-data-gke-grpc.svc.gitlab.net:443 | direct pod IPs (designed, not yet exercised — see below) | https://staging.gitlab.com |
| Production (gprd) | iam-data-gke-grpc | production | iam-data-gke-grpc.svc.gitlab.net:443 | direct pod IPs (designed, not yet exercised — see below) | https://gitlab.com |
Public entrypoint (Cloudflare zone): .runway/deployment.yaml sets
loadBalancing.externalLoadBalancer.enabled and .cloudflareSetting.enabled to
true, which provisions a dedicated Cloudflare zone per environment — production at
iam-data-gke-grpc.svc.gitlab.net, staging at staging.iam-data-gke-grpc.svc.gitlab.net.
These front the same GKE external load balancer Runway provisions from the GCP origin
(<workload-name>[.staging].runway.gitlab.net). This path is for callers outside
this service’s GKE cluster — e.g. the main GitLab.com GKE clusters, which run
separately from Runway’s. No auth header is required to reach the host itself — the
service’s own two-layer auth
still applies once connected.
Internal entrypoint (direct pod IPs via Headless Service): the intent
is that other services co-located in the same GKE cluster — e.g. Artifact Registry,
which does run in the same staging cluster (runway-gke-stg-us-east1) — skip the
public internet entirely and reach this service’s pods directly via in-cluster
Service discovery (plain Kubernetes DNS, not a Private Service Connect setup),
rather than the external load balancer/Cloudflare path above.
Vault paths
Section titled “Vault paths”Secrets are injected via Runway’s secretEnvFrom; deep links to the output secrets:
- Yugabyte creds: staging · production
- Service token: same Runway KV mount,
env/<env>/service/iam-data-gke-grpc/service-token(seeworkloadSecretsin.runway/deployment.yaml).
Config file locations (in gitlab-org/auth/iam)
Section titled “Config file locations (in gitlab-org/auth/iam)”.runway/deployment.yaml— Runway manifest,workloadSecrets, load-balancer/Cloudflare config..runway/fairway.yaml— image, container port (5005), probes, scaling (minInstances/maxInstances), resource requests/limits..runway/values-staging.yaml/.runway/values-production.yaml— per-envsecretEnvFrom+ inlineCONFIG_TOML.configs/base.toml— shared defaults ([services.data-access] grpc_address = ":5005").pkg/config/loader.go— layered TOML loader + env-var override mechanics.
Making changes / deploy pipeline
Section titled “Making changes / deploy pipeline”- Release flow, mirrors, and manual-production-gate details:
docs/release.md. - Actual Runway staging/production deploy jobs run in the separate Infra-owned project —
deployments pipeline list,
not in
iam’s own CI. Staging auto-deploys on release tag; production requires manual approval.
Related links
Section titled “Related links”gitlab-org/auth/iam— repo rootdocs/service-access.md— service-token + JWT auth modeldocs/relationships-api.md— Lookup/Update API & data model- YugabyteDB Aeon runbook — backing database