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.aidor@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:
- Hold a GCP IAM role granting
roles/iap.tunnelResourceAccessoron the VM resource. - 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'→ onlydor@dtectvision.aiandroee@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.secretAccessorconfirmed 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.aiholds project-roles/owneron the GCP project but has no org-level role on the parent organization857403431877(verified 2026-05-02 whengcloud scc manage services list --organization=857403431877returnedPERMISSION_DENIED, and again 2026-05-03 whengcloud organizations get-iam-policy 857403431877returnedPERMISSION_DENIEDforresourcemanager.organizations.getIamPolicy). Roee'sadmin.google.comlogin 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 whetherdor@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.comdeveloper 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.aiaccount is ever locked out, suspended, or recovered. Both identities now grant the same access; both are logged separately in audit trails. Right-sizing the broadcompute.admin/storage.admingrants 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-osloginis 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 runspm2 resurrectat 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-keysmetadata 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 productionroeeuser — which would mean shared- account access without sudo. Pending operator review. - ~~Leftover "test condition" IAM binding on
iap.tunnelResourceAccessorfor. ~~ Resolved 2026-05-03. The redundant conditional binding (titlethinkpad-only, descriptiontest condition, expression scoped to thethinkpad-n2-std8instance) was removed viagcloud 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 grantroles/resourcemanager.organizationAdminto 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.