Customer Snapshot
| Attribute | Details |
|---|---|
| Industry | FinTech / SaaS |
| Cloud Environment | GCP (70%), Azure (30%) |
| Workloads | GKE for most services, plus a fleet of VMs |
| VM Platforms | GCP Compute Engine, Azure Virtual Machines |
| Access Method Before | SSH with shared keys, standing bastion access |
| Console Access | 10–15 people with cloud and host access |
| Communication | Slack |
| Compliance | ISO 27001, SOC 1, SOC 2, GDPR |
| Primary Interest | Time-bound, recorded VM access across both clouds |
The Situation: GKE Gets the Attention, VMs Carry the Risk
This FinTech runs most of its services on GKE, so Kubernetes naturally gets the lion’s share of the security conversation. But underneath the orchestration layer sits a fleet of virtual machines that quietly carries a disproportionate amount of risk: GCP Compute Engine instances and Azure Virtual Machines running databases, batch jobs, legacy services, build agents, and the occasional “we’ll containerise it later” workload that has been running for two years.
VMs are where engineers go when something breaks in a way kubectl cannot fix. They SSH in to inspect logs, restart a stuck process, run a migration, or debug a networking issue. And because that access is occasional but urgent, it tends to be governed worst of all. The team’s reality looked familiar:
- SSH with shared keys distributed across the team, sitting on laptops indefinitely.
- Standing bastion access that, once granted, was never revisited.
- No record of which human SSH’d into which host, when, or what they did once inside.
- The same key granting access to development and production hosts because splitting them was more work than anyone had time for.
For a company under ISO 27001, SOC 1, SOC 2, and GDPR, with VMs that touch financial data and production systems, this was the softest part of an otherwise maturing security posture — and the part an auditor’s “show me who accessed production hosts in the last 90 days” question lands on hardest.
The Core Tension
VM access is occasional, urgent, and spread across two different clouds with two different native access models — GCP’s OS Login and IAM, and Azure’s SSH extensions and RBAC. Securing it properly usually means either standing up a heavyweight bastion architecture per cloud (operational burden the team cannot carry) or living with shared keys and standing access (the risk they already have). The team needed a third option: time-bound, approved, recorded host access that works identically across GCP and Azure, with no standing credentials and no new bastion to maintain.
Where the Gaps Were
Shared SSH Keys That Never Expire
The most immediate exposure. SSH keys were generated once, distributed to whoever needed host access, and never rotated — because rotating them means re-distributing to everyone and breaking whatever automation depends on them. So the keys accumulate on laptops, in dotfiles, in password managers, and occasionally in a repository where they should never have been committed.
A single stolen laptop or leaked key is a direct path to production hosts. And because the keys are shared, even if the team detects misuse, they cannot tell which holder of the key was responsible. The credential proves access to a machine, not to a person.
Standing Bastion Access With No Expiry
Where the team used a bastion host to reach private VMs, access to the bastion itself became standing. Once an engineer could reach the bastion, they could reach everything behind it, indefinitely. The bastion solved the network-reachability problem and created a new access-governance problem: a single always-on entry point into the production network, protected by credentials that never changed and were held by more people than anyone could list from memory.
No Attribution, No Recording
When an engineer SSH’d into a production VM and ran commands, nothing recorded who they were or what they did. The host’s own logs, if shipped anywhere, showed a shared username. There was no session recording, no command history tied to a named human, and no way to reconstruct — during an incident or an audit — the sequence of actions taken on a production machine. “Who restarted that service at 2 AM and what else did they touch?” had no answer.
Two Clouds, Two Access Models, Double the Work
GCP and Azure handle host access differently. GCP has OS Login, IAM roles, and IAP-based tunnelling; Azure has its own SSH extensions, Just-in-Time VM access through Defender, and RBAC. Managing both meant maintaining two separate access workflows, two sets of policies, and two audit sources — for a two-person security team that could not afford to be experts in both clouds’ native access tooling simultaneously. Azure’s native JIT VM access, in particular, is scoped to Azure alone and does not extend to the GCP side where most of the fleet lives.
How Cloudanix Addresses This Situation
Cloudanix VM JIT replaces standing SSH access, shared keys, and always-on bastions with time-bound, approved, session-recorded host access — delivered through one engine that works identically across GCP Compute Engine and Azure Virtual Machines.
One-Click, Time-Bound Host Access
-
Engineer requests VM access via Slack or the Cloudanix Console, selecting the host (or group of hosts), the access level, and the duration, with a reason or incident ID attached.
-
Approval routes by sensitivity. Access to a development host can auto-approve; access to a production VM carrying financial data requires an approver. For on-call incidents, a PagerDuty-triggered auto-approval can grant access immediately so a live incident is never blocked waiting on a human.
-
Access is granted for the window only. The engineer connects to the host and works normally — the same SSH-based workflow they already know. No new client to learn.
-
No standing key ever lives on the laptop. Access is brokered per session with short-lived credentials, so there is no durable key to steal, leak, or forget to rotate.
-
When the timer expires, access is revoked automatically. No manual cleanup, no “we forgot to remove that engineer’s key,” no standing bastion session left open.
Session Recording for Every VM Session
This is the control the team most lacked. VM JIT records the session — the commands run and the actions taken on the host — and ties the recording to the specific human, the approved request, and the time window. Recordings land in the customer’s own cloud storage, never in Cloudanix infrastructure, and are linked to the request and approval that authorised them.
For incident response, this turns “who touched this host and what did they do?” into a replayable timeline. For ISO 27001 and SOC 2 audits, it turns “we have SSH access controls” into “here is the recorded, attributed session for every production host access in the audit period, each one time-bound and auto-revoked.”

Private VMs Without a Standing Bastion
For VMs in private subnets, Cloudanix reaches the host through a scoped, outbound connection into the customer’s own VPC — so engineers get access to private instances without maintaining an always-on bastion with standing credentials. The network-reachability problem is solved per session, not by a permanent entry point that itself becomes a target. The private VM stays private; the access is ephemeral.
One Engine Across GCP and Azure
The decisive advantage for this profile: the same VM JIT workflow covers GCP Compute Engine and Azure Virtual Machines through one policy model, one Slack approval flow, and one audit trail. The team does not maintain GCP’s native access tooling and Azure’s separately. A request for a production host in GCP and a request for a production host in Azure look identical to the engineer and to the approver, and both produce the same attributed, recorded, auto-expiring session. For a two-person security function spanning two clouds, that single workflow is the difference between a sustainable control and one that erodes under operational pressure.
Part of One Access Lifecycle, Not a Point Tool
VM JIT is one surface of the same engine that governs this team’s GKE clusters, cloud consoles across GCP and Azure, and MySQL databases. The request → approve → time-boxed grant → auto-revoke lifecycle is identical everywhere, so the team builds the governance model once and applies it to every surface. An engineer requesting SSH to a VM, kubectl to a cluster, or a database session uses the same Slack flow and generates the same quality of audit trail.

Platform Impact
| Dimension | Before | After (VM JIT) |
|---|---|---|
| SSH keys | Shared, long-lived, on laptops | None — brokered per session |
| Bastion access | Standing, always-on | Scoped, per-session reachability |
| Attribution | Shared username | Every session stamped to a real human |
| Session recording | None | Full recording linked to request + identity |
| Private VM access | Standing bastion with broad reach | Ephemeral outbound tunnel into the VPC |
| GCP vs Azure | Two native access models to manage | One engine, one workflow across both |
| Revocation | Manual, often skipped | Automatic at expiry |
| Compliance evidence | Little to none | Recorded, attributed, time-bound per access |
Why VM Access Deserves the Same Rigor as Everything Else
It is tempting, in a GKE-first shop, to treat VMs as a legacy afterthought. But the hosts engineers SSH into are frequently the ones running databases, holding credentials, or sitting closest to production data — which makes them a high-value target precisely because they are governed loosely. A shared SSH key is, in practice, often the weakest credential in an otherwise well-run estate: it never expires, it names no person, and it tends to grant more reach than any single task requires.
Bringing VM access under the same time-bound, recorded, auto-revoking model as the rest of the platform closes that gap without asking engineers to change how they work. They still SSH in and do their job. What changes is that the access expires, the session is recorded, and the audit trail names a person instead of a key. For a FinTech under four compliance frameworks across two clouds, that is how the softest part of the access surface finally gets the same treatment as the loudest.
Key Outcomes
- ✅ No Standing SSH Keys: Host access brokered per session; nothing durable to steal or leak.
- ✅ Session Recording: Every VM session recorded and tied to a named human, in your own storage.
- ✅ One Engine, Two Clouds: Identical workflow across GCP Compute Engine and Azure VMs.
- ✅ No Always-On Bastion: Private VMs reached through scoped, ephemeral tunnels.
- ✅ Auto-Revocation: Access disappears at expiry — no manual cleanup.
- ✅ Incident-Ready Approvals: PagerDuty-triggered auto-approval so live incidents are never blocked.
- ✅ Audit Evidence by Default: Attributed, time-bound, recorded access for ISO 27001 and SOC 2.
Securing SSH Access to Production VMs Across GCP and Azure?
If your engineers still reach production hosts with shared SSH keys and standing bastion access — and you cannot prove who did what on which machine — Cloudanix VM JIT gives them the same SSH workflow with time-bound, approved, session-recorded access, across GCP and Azure, with no standing credentials and no bastion to maintain.
Book a Free Assessment to see VM JIT working across your GCP and Azure instances — including private hosts — in a single session.
Related Resources
- Implementing JIT Access in AWS, Azure & GCP: Complete Guide
- Kubernetes JIT for GKE Clusters: Eliminating Standing Access
- What is Zero Standing Privilege?
- PAM for Cloud Infrastructure: Why Traditional PAM Falls Short
- Azure JIT Access: Extending Zero Standing Privilege Across Multi-Cloud Environments
- Why Intune Is Not PAM for Cloud: JIT Access & GDPR Compliance