Skip to content

Privileged Access

Statement

Privileged access to ClaimGuard production infrastructure — the GCP project, the production VM, and the data services attached to them — is limited to the founder set, gated through Google's Identity-Aware Proxy (IAP) for shell access, and recorded in an immutable 400-day-retained audit log for every privileged action. Former collaborators have been fully removed from project-level IAM. Right- sizing of active developers' broad project roles is explicitly deferred to avoid disrupting sibling research workloads on the shared GCP project; that work is queued.

Implementation

Project-level owner set

The two principals holding roles/owner on the GCP project are:

  • roee@dtectvision.ai
  • dor@dtectvision.ai

This is the post-cleanup state, verified 2026-04-29:

$ gcloud projects get-iam-policy <project> \
    --flatten='bindings[].members' \
    --filter='bindings.role:roles/owner' \
    --format='value(bindings.members)'
user:dor@dtectvision.ai
user:roee@dtectvision.ai

Three former-collaborator accounts had owner or storage.admin grants before the IAM cleanup pass and are now fully removed:

Removed Bindings dropped
Departed principal A roles/owner, roles/storage.admin
Departed principal B roles/owner, roles/storage.admin, roles/compute.osAdminLogin
Departed principal C 8 bindings including roles/aiplatform.admin, roles/artifactregistry.admin, roles/compute.admin, roles/iam.serviceAccountUser, roles/storage.admin

The most security-relevant removal was roles/compute.osAdminLogin on departed principal B — that role granted sudo-SSH into every VM in the project. The full per-binding command record (with named principals) is retained internally and is available on NDA request.

Administrative SSH

Administrative SSH to the production VM is gated through GCP's Identity-Aware Proxy. There is no public SSH endpoint, no jump host, and no shared bastion VM. The only TCP/22 firewall rule on the VPC is scoped to Google's IAP source range (Google's IAP source range).

To reach the VM, an operator must:

  1. Hold a GCP IAM role granting roles/iap.tunnelResourceAccessor on the VM resource.
  2. Use gcloud compute ssh ... --tunnel-through-iap.

This means no separate VM credentials (passwords, SSH keys, etc.) are required — IAP authenticates the operator via their Google identity. Removing a person's GCP access removes their VM access in a single action, not two.

The legacy world-open SSH rules (a legacy SSH firewall rule, the default SSH firewall rule) were deleted on 2026-04-28 (an early plan step). See Network security for the firewall side of the same control.

Service account

The application's runtime service account, the workload service account, is least-privilege:

  • Project-level: roles/logging.logWriter, roles/monitoring.metricWriter.
  • Per secret (roles/secretmanager.secretAccessor): three runtime secrets only.
  • No project-Editor. No project-level secret accessor. No GCS bindings (until content-provenance service migrates from its static JSON key — see Secrets management).

The VM runs under this SA as of 2026-05-02. Plan step the SA-swap step was executed in a maintenance window combined with the Secure Boot step (Secure Boot enable). Verification:

$ gcloud compute instances describe <vm> \
    --zone=europe-west1-b --project=<project> \
    --format='value(serviceAccounts[0].email,
                    shieldedInstanceConfig.enableSecureBoot)'
<sa>@<project>.iam.gserviceaccount.com    True

A boot-disk snapshot (a pre-change snapshot) was taken before the swap as a failsafe and remains in place during the soak period. Smoke tests passed (Node /health → 200 with DB connection + Secret Manager fetches working under the new SA; the application processes online; zero secretmanager/permission denied patterns in 200 lines of post-restart logs).

Audit trail

Every privileged action — IAM mutations, VM lifecycle events, firewall rule changes, service account key operations, secret access — is recorded in the project's _Required Cloud Logging bucket with 400-day immutable retention (locked: true). See Audit logging for the audit-log control.

Multi-factor authentication

All members of the owner set use Google Workspace accounts with mandatory MFA enforced at the Workspace policy level. Sign-in to the Google Cloud Console and gcloud CLI both require MFA via the Workspace identity. Personal @gmail.com collaborator accounts are no longer present in the project after the IAM cleanup pass with one exception (see "Known gaps").

Workstation hygiene

GCP credentials on operator laptops are stored via gcloud auth login (short-lived ID tokens, refreshable). Long-lived JSON service account keys for human use are not provisioned. The one static JSON key present in the production environment is for a non-human Python workload (a static service-account JSON key used by the content-provenance service tool) and is queued for migration to ADC.

Status

partial — verified 2026-05-02.

What's in place:

  • Owner set is the founder pair; former collaborators fully removed. Verified 2026-04-30 via gcloud projects get-iam-policy <project> --filter='bindings.role:roles/owner' → only dor@dtectvision.ai and roee@dtectvision.ai.
  • Administrative SSH is gated through IAP; no public SSH path exists.
  • Least-privilege application service account provisioned and in use. The VM was swapped from the default compute SA → the workload service account on 2026-05-02 (combined the SA-swap step + the Secure Boot step maintenance window). Per-secret roles/secretmanager.secretAccessor confirmed on all three the runtime secrets (the JWT secret, the database URL secret, an internal-services API-key secret). Spot-check of the upload bucket returned no binding for the SA — consistent with "no GCS bindings yet" above. The the long-retention audit log bucket audit-export bucket was added 2026-05-01 with a sink-writer Object Creator binding; see Audit logging.
  • Shielded VM Secure Boot is on (enableSecureBoot=True) alongside the SA swap, the Secure Boot step.
  • Every privileged action audit-logged for 400 days, immutable.
  • MFA on all owner accounts via Google Workspace.

Known gaps

  • No identified Workspace super-admin / org-admin within the active founder pair (under investigation). roee@dtectvision.ai holds project-roles/owner on the GCP project but has no org-level role on the parent organization 857403431877 (verified 2026-05-02 when gcloud scc manage services list --organization=857403431877 returned PERMISSION_DENIED, and again 2026-05-03 when gcloud organizations get-iam-policy 857403431877 returned PERMISSION_DENIED for resourcemanager.organizations.getIamPolicy). Roee's admin.google.com login on 2026-05-03 was rejected with "Sign in with an administrator account" — confirming no Workspace admin role on the active account. Investigation in progress to determine whether dor@dtectvision.ai (CEO, the only other project owner) holds the role or whether the original Workspace super-admin account is no longer active. If neither, recovery via Google Workspace support (DNS-TXT domain proof + business documentation, per https://support.google.com/a/answer/9223976 ) is the remediation path. Until resolved, org-scope operations (SCC tier management, org policies, org-level IAM grants) cannot be performed by either current operator. Tracked as an active SOC 2 finding; a second org-admin seat will be added once the first is re-established.
  • Active developers retain broad project roles. a personal-account principal, , , , hold project-level roles (e.g., roles/storage.admin, roles/compute.admin, roles/artifactregistry.admin) inherited from prior workflows. Right-sizing was deferred per founder request to avoid disrupting in-flight ML work on sibling research workloads in the shared GCP project. See Cloud provider for why the multi-tenant project makes this a delicate cleanup.
  • One personal @gmail.com developer account intentionally retained alongside the new Workspace identity (migration completed 2026-05-04). was granted the identical set of 10 project roles as the existing a personal-account principal on 2026-05-03; the developer confirmed on 2026-05-04 that all workflows function against the new identity. Per operator decision the old a personal-account principal bindings are NOT being removed — they are retained intentionally as a fallback identity in case the new @dtectvision.ai account is ever locked out, suspended, or recovered. Both identities now grant the same access; both are logged separately in audit trails. Right-sizing the broad compute.admin / storage.admin grants down to per-instance / per-bucket scopes (e.g., compute.instanceAdmin.v1) on either identity remains a follow-up.
  • OS Login is not yet enforced. enable-oslogin is not set on the project. SSH still uses metadata-keyed access on top of IAP. Enabling OS Login is the OS Login step, deferred from the 2026-05-02 window because it requires dev-team coordination (re-keying their laptops + osLogin grant management).
  • pm2 startup-on-reboot was missing until 2026-05-02. The pm2 daemon now has a systemd unit (<PM2_SYSTEMD_UNIT>) that runs pm2 resurrect at boot; a fresh dump was saved post-Tier-D. Future reboots will auto-restore the application processes; the previous 47h-uptime baseline had hidden the gap.
  • No just-in-time elevation. Owner-level access is granted, not requested. JIT elevation (e.g., a "request access for 30 minutes" flow) is a roadmap item.
  • Stale home directories for departed users still exist on the VM. They no longer have IAM access (and therefore can't log in), but the dirs persist with whatever data was left. Cleanup is deferred to the OS Login step (OS Login enable) when the metadata-key model is retired. (The corresponding project-level ssh-keys metadata entries for these users were removed 2026-05-02 — see the HARDENING-LOG entry "Stale SSH metadata keys for removed users — cleaned up".)
  • Several roee-username metadata keys carry comment fields naming other people's Windows machines (COMFYUI-RDP\roee@<sibling research fleet>rdp, DESKTOP-42HMUQN\Orel_Shalem, PILAN\ilans@pilan, DTECT1\dtect_dev1@dtect1). Two interpretations: (a) Roee generated them on shared/RDP machines, or (b) other operators have SSH access AS the production roee user — which would mean shared- account access without sudo. Pending operator review.
  • ~~Leftover "test condition" IAM binding on iap.tunnelResourceAccessor for .~~ Resolved 2026-05-03. The redundant conditional binding (title thinkpad-only, description test condition, expression scoped to the thinkpad-n2-std8 instance) was removed via gcloud projects remove-iam-policy-binding <project> --member=user:<developer Workspace identity> --role=roles/iap.tunnelResourceAccessor --condition-from-file=<yaml>. ilan's unconditional binding for the same role remains (which is the correct posture for his actual access pattern). Verified post-removal via the same scoped query that surfaced it.

Roadmap

  • the OS Login step — enable OS Login on the production VM (last item of the the SA-swap + Secure Boot + OS Login maintenance window; the first two landed 2026-05-02). Needs dev-team coordination for re-keying.
  • Org-admin owner documentation + second seat — confirm the Workspace super-admin owner of dtectvision.ai, document the delegation chain, and grant roles/resourcemanager.organizationAdmin to a second principal so the org-level control plane has a second seat (currently a single point of failure).
  • the IAM cleanup pass-step3 — right-size active developers' broad project roles, contingent on the dedicated-project move (the dedicated-project step) so per-workload role granularity is actually meaningful.
  • the dedicated-project step — move ClaimGuard to a dedicated GCP project. Proper SOC 2 isolation fix.
  • JIT access — evaluate Google Workspace's privileged-access manager or third-party tooling for time-bounded role grants.
  • Periodic access review — quarterly review of project IAM and Workspace group memberships, with sign-off recorded.