Google BeyondCorp Zero Trust: Setup & Architecture Guide
Replace your VPN with GCP BeyondCorp zero trust access. Step-by-step IAP setup, access level design, device posture policies, and a phased migration plan from VPN.

What is Google BeyondCorp?
BeyondCorp is Google's implementation of zero-trust security that eliminates the need for a traditional VPN. Instead of trusting users based on network location, BeyondCorp verifies every request based on user identity, device health, and context—allowing secure access to applications from any network without routing through a corporate VPN.
Introduction
BeyondCorp is Google's implementation of zero trust security, built on the principle that trust should not be granted based on network location. Instead of using VPNs to create a trusted network perimeter, BeyondCorp evaluates every request based on user identity, device trust, and contextual signals. Google has used this model internally for over a decade, and GCP's BeyondCorp Enterprise makes it available to all organizations.
In production deployments, BeyondCorp reduces VPN-related support tickets by 80%, eliminates lateral movement risk from compromised VPN credentials, and provides granular access logs that VPNs cannot deliver. This article covers the implementation architecture, access level design, and migration strategy from VPN to zero trust.
BeyondCorp vs. Traditional VPN
| Aspect | Traditional VPN | BeyondCorp Zero Trust |
|---|---|---|
| Trust model | Network perimeter | Per-request evaluation |
| Access granularity | All-or-nothing network access | Per-application, per-action |
| Device posture | Optional (if NAC deployed) | Required for every request |
| User experience | VPN client required | Browser-native |
| Lateral movement | Full network access after VPN | No network-level access |
| Scalability | VPN concentrator bottleneck | Google's edge network |
| Logging | Connection-level | Request-level (URL, user, device) |
| Maintenance | VPN infrastructure upkeep | Managed service |
BeyondCorp Components
| Component | Function | GCP Service |
|---|---|---|
| Identity Provider | Authenticate users | Cloud Identity / Workspace |
| Device Trust | Verify device posture | Endpoint Verification |
| Access Context | Define access conditions | Access Context Manager |
| Policy Engine | Evaluate access requests | Identity-Aware Proxy (IAP) |
| Access Gateway | Enforce policies at edge | Cloud Load Balancer + IAP |
| Connector | Reach on-premises apps | IAP Connector / Cloud VPN |
| Logging | Audit all access | Cloud Audit Logs |
Implementation: Identity-Aware Proxy (IAP)
Enable IAP for a Cloud Run Service
# Deploy application
gcloud run deploy internal-app \
--image gcr.io/my-project/internal-app:latest \
--region us-central1 \
--no-allow-unauthenticated
# Enable IAP on the backend service (requires HTTPS LB)
gcloud compute backend-services update internal-app-backend \
--iap=enabled \
--global
# Grant access to specific users/groups
gcloud iap web add-iam-policy-binding \
--resource-type=backend-services \
--service=internal-app-backend \
--member="group:engineering@example.com" \
--role="roles/iap.httpsResourceAccessor"
Terraform: Full IAP Setup
# IAP-protected backend service
resource "google_compute_backend_service" "internal_app" {
name = "internal-app-backend"
protocol = "HTTP"
port_name = "http"
timeout_sec = 30
health_checks = [google_compute_health_check.default.id]
backend {
group = google_compute_region_network_endpoint_group.app.id
}
iap {
oauth2_client_id = google_iap_client.app.client_id
oauth2_client_secret = google_iap_client.app.secret
}
log_config {
enable = true
}
}
# IAP access policy
resource "google_iap_web_backend_service_iam_binding" "access" {
project = var.project_id
web_backend_service = google_compute_backend_service.internal_app.name
role = "roles/iap.httpsResourceAccessor"
members = [
"group:engineering@example.com",
"group:product@example.com"
]
condition {
title = "require_corporate_device"
description = "Only allow access from managed corporate devices"
expression = "\"accessPolicies/${var.access_policy_id}/accessLevels/corporate_device\" in request.auth.access_levels"
}
}
# IAP OAuth client
resource "google_iap_client" "app" {
display_name = "Internal App"
brand = google_iap_brand.default.name
}
resource "google_iap_brand" "default" {
support_email = "support@example.com"
application_title = "Internal Applications"
project = var.project_number
}
Access Levels with Context
Device-Based Access Levels
# Managed device with encryption
resource "google_access_context_manager_access_level" "managed_device" {
parent = "accessPolicies/${var.access_policy_id}"
name = "accessPolicies/${var.access_policy_id}/accessLevels/managed_device"
title = "Managed Corporate Device"
basic {
conditions {
device_policy {
require_screen_lock = true
require_admin_approval = true
require_corp_owned = true
allowed_encryption_statuses = ["ENCRYPTED"]
allowed_device_management_levels = ["COMPLETE"]
os_constraints {
os_type = "DESKTOP_MAC"
minimum_version = "14.0.0"
}
os_constraints {
os_type = "DESKTOP_WINDOWS"
minimum_version = "10.0.19044"
}
os_constraints {
os_type = "DESKTOP_CHROME_OS"
require_verified_chrome_os = true
}
}
}
}
}
# Time-based access (business hours only for sensitive apps)
resource "google_access_context_manager_access_level" "business_hours" {
parent = "accessPolicies/${var.access_policy_id}"
name = "accessPolicies/${var.access_policy_id}/accessLevels/business_hours"
title = "Business Hours Access"
custom {
expr {
expression = "request.time.getHours('America/New_York') >= 8 && request.time.getHours('America/New_York') <= 18 && request.time.getDayOfWeek('America/New_York') >= 1 && request.time.getDayOfWeek('America/New_York') <= 5"
title = "Business hours (M-F, 8AM-6PM ET)"
}
}
}
# Geo-based access restriction
resource "google_access_context_manager_access_level" "allowed_countries" {
parent = "accessPolicies/${var.access_policy_id}"
name = "accessPolicies/${var.access_policy_id}/accessLevels/allowed_countries"
title = "Allowed Countries"
basic {
conditions {
regions = ["US", "CA", "GB", "DE", "FR"]
}
}
}
Combining Access Levels
# High-security access: managed device + allowed country + business hours
resource "google_access_context_manager_access_level" "high_security" {
parent = "accessPolicies/${var.access_policy_id}"
name = "accessPolicies/${var.access_policy_id}/accessLevels/high_security"
title = "High Security Combined"
basic {
combining_function = "AND"
conditions {
required_access_levels = [
google_access_context_manager_access_level.managed_device.name,
google_access_context_manager_access_level.allowed_countries.name,
google_access_context_manager_access_level.business_hours.name
]
}
}
}
IAP for On-Premises Applications
Use IAP Connector to extend zero trust to on-premises or other-cloud applications:
# Deploy IAP connector in your VPC
gcloud compute instances create iap-connector \
--zone=us-central1-a \
--machine-type=e2-medium \
--image-family=debian-12 \
--image-project=debian-cloud \
--metadata=startup-script='#!/bin/bash
# Install IAP connector agent
curl -sSL https://dl.google.com/cloudconnector/download | bash
/opt/google/cloudconnector/bin/connector \
--project=my-project \
--region=us-central1 \
--backend-address=http://internal-app.corp.local:8080'
Access Logging and Audit
Every IAP-protected request generates detailed audit logs:
# Query access logs
gcloud logging read \
'resource.type="iap_tunnel" OR resource.type="gce_backend_service"
AND protoPayload.methodName="AuthorizeUser"' \
--project=my-project \
--limit=50 \
--format="table(
timestamp,
protoPayload.authenticationInfo.principalEmail,
protoPayload.requestMetadata.callerIp,
protoPayload.request.httpRequest.url,
protoPayload.response.status)"
Access Analytics
| Metric | Value | Insight |
|---|---|---|
| Unique users/day | 450 | Active workforce accessing apps |
| Denied requests/day | 120 | Policy violations (investigate patterns) |
| Device compliance failures | 35/day | Need device management follow-up |
| After-hours access attempts | 20/day | Evaluate if policy is too strict |
| Geo-blocked requests | 15/day | Travel exceptions or threats |
| Average authentication latency | 180ms | IAP overhead per request |
VPN to BeyondCorp Migration Strategy
Phased Migration Plan
| Phase | Duration | Action | Risk |
|---|---|---|---|
| 1. Inventory | 2 weeks | Catalog all VPN-accessed applications | None |
| 2. Pilot | 4 weeks | Migrate 2-3 low-risk internal tools | Low |
| 3. Expand | 8 weeks | Migrate all web applications | Medium |
| 4. Enforce | 4 weeks | Require device compliance | Medium |
| 5. Decommission | 2 weeks | Shut down VPN for migrated apps | Low |
# Phase 2: Set up IAP for pilot application
# Keep VPN running as fallback
# Phase 3: Monitor both access paths
gcloud logging read \
'resource.type="iap_tunnel" AND
protoPayload.authenticationInfo.principalEmail!=""' \
--format="csv(timestamp,protoPayload.authenticationInfo.principalEmail)" \
> iap-access.csv
# Compare with VPN logs to verify all users migrated
Cost Comparison
| Component | VPN (per 500 users) | BeyondCorp (per 500 users) |
|---|---|---|
| Infrastructure | $2,000-5,000/mo (VPN appliances) | $0 (IAP included) |
| Licensing | $5-15/user/mo | $6/user/mo (BeyondCorp Enterprise) |
| Support tickets | ~40/month (VPN issues) | ~8/month |
| IT admin time | 20 hrs/month | 5 hrs/month |
| Monthly total | $5,500-12,500 | $3,000 |
Frequently Asked Questions
What is Google BeyondCorp?
BeyondCorp is Google's zero trust security model that eliminates reliance on VPNs by evaluating every access request based on user identity, device trust, and contextual signals rather than network location. Google used it internally for over a decade before making it available as BeyondCorp Enterprise on GCP, where it is implemented primarily through Identity-Aware Proxy (IAP).
How is BeyondCorp different from a VPN?
A VPN grants full network access once connected (all-or-nothing), while BeyondCorp evaluates every individual request against identity, device posture, and context policies. BeyondCorp provides per-application granularity, request-level logging, browser-native access without a client, and eliminates lateral movement risk. It also scales on Google's edge network rather than through VPN concentrator bottlenecks.
What does BeyondCorp Enterprise cost?
BeyondCorp Enterprise costs approximately $6 per user per month. Compared to traditional VPN infrastructure ($5-15/user/month in licensing plus $2,000-5,000/month in hardware for 500 users), organizations typically see 50-75% cost savings when factoring in reduced support tickets and eliminated VPN hardware maintenance.
How do I migrate from VPN to BeyondCorp?
Migrate in five phases over 4-5 months: inventory all VPN-accessed applications (2 weeks), pilot with 2-3 low-risk internal tools (4 weeks), expand to all web applications (8 weeks), enforce device compliance requirements (4 weeks), and finally decommission VPN for migrated apps (2 weeks). Keep VPN running as a fallback during early phases.
Key Takeaways
- BeyondCorp eliminates VPN dependency by evaluating every request based on identity, device trust, and context rather than network location.
- Identity-Aware Proxy adds ~180ms latency per request which is imperceptible for web applications and far better than VPN tunnel overhead.
- Device posture enforcement catches 35+ compliance failures daily that would otherwise grant full network access through a VPN.
- Combine multiple access levels (device trust + geography + time) for defense-in-depth that prevents access even with stolen credentials.
- Migrate from VPN to BeyondCorp in phases over 4-5 months, starting with low-risk internal tools and expanding to all web applications.
- IAP provides request-level logging showing exactly who accessed which URL from which device, far more granular than VPN connection logs.
- Cost savings of 50-75% compared to enterprise VPN infrastructure when factoring in reduced support burden and eliminated VPN hardware.
Recommended reading

Per-Team Cost Allocation in Shared Kubernetes Clusters: From Chaos to Clarity
Implementing accurate per-namespace cost allocation in multi-tenant Kubernetes clusters, covering request vs. usage attribution, shared resource amortization, and building showback dashboards that drive accountability.

Measuring and Eliminating Toil: From 40% to 12% of Engineering Time
A systematic approach to identifying, measuring, and automating toil—the repetitive operational work that scales linearly with service growth and prevents engineers from doing creative work.

Serverless Postgres in Production: Branching, Scale-to-Zero, and the End of Database Provisioning
Running Neon serverless Postgres in production for 8 months — covering database branching workflows, scale-to-zero economics, connection pooling, and migration from RDS.

Comments
No comments yet. Be the first to share your thoughts.