Skip to content
Unverified — AI-generated content. Help verify this page

Zero Trust Principles

Why Principles Matter

Zero Trust is not a product — it's an architectural philosophy. Without clearly understood principles, organizations buy "Zero Trust" products that are just rebranded VPNs or firewalls. The principles provide a framework for evaluating every architectural decision against the core tenet: never trust, always verify.

The Five Core Principles

First Principles

Principle 1: Verify Explicitly

Every access request must be authenticated and authorized based on all available data points:

Decision=f(identity,location,device,service,classification,anomalies)

This is fundamentally different from traditional security where authentication happens once at the perimeter and subsequent requests are trusted:

TraditionalZero Trust
Authenticate at VPN loginAuthenticate every request
Trust based on network locationTrust based on identity + context
Session = unlimited accessSession = scoped, time-limited access
Binary: inside/outsideContinuous: trust score

Principle 2: Use Least Privilege Access

Access should be just enough, just in time:

  • Just Enough Access (JEA): Grant the minimum permissions needed for the task
  • Just In Time (JIT): Grant access only when needed, automatically revoke when done
  • Risk-based policies: Higher-risk operations require stronger authentication

Principle 3: Assume Breach

Design every system assuming that attackers are already inside the network:

AssumptionImplication
Attackers are inside the networkEncrypt all internal traffic
Any credential could be compromisedUse short-lived tokens, require MFA
Any device could be compromisedVerify device health continuously
Any service could be compromisedImplement micro-segmentation
Any data could be exfiltratedClassify and monitor data access

Principle 4: Encrypt Everything

No traffic — internal or external — should be unencrypted:

All trafficmTLSEncrypted

This means:

  • Service-to-service: mTLS with short-lived certificates
  • User-to-service: TLS 1.3 with strong cipher suites
  • Data at rest: AES-256-GCM with managed keys
  • Databases: TLS for connections, encryption at rest
  • Even localhost: TLS for loopback connections in high-security environments

Principle 5: Continuously Monitor and Validate

Authentication is not a one-time event — it's continuous:

Core Mechanics

BeyondCorp Architecture Deep Dive

Google's BeyondCorp is built on several interconnected systems:

Key BeyondCorp innovations:

  1. No VPN: All applications are accessed through an internet-facing proxy
  2. Device inventory: Every device is tracked and must have a valid certificate
  3. Trust tiers: Devices are classified into trust tiers based on their security posture
  4. Access levels: Applications define required trust levels, not network locations

Implementation: Policy Decision Point

typescript
interface PolicyRule {
  id: string;
  description: string;
  resource: string; // glob pattern
  conditions: PolicyCondition[];
  effect: 'allow' | 'deny';
  priority: number;
}

interface PolicyCondition {
  field: string;
  operator: 'equals' | 'notEquals' | 'greaterThan' | 'in' | 'contains';
  value: unknown;
}

class PolicyDecisionPoint {
  private rules: PolicyRule[] = [];

  addRule(rule: PolicyRule): void {
    this.rules.push(rule);
    this.rules.sort((a, b) => b.priority - a.priority);
  }

  evaluate(request: {
    identity: Record<string, unknown>;
    device: Record<string, unknown>;
    context: Record<string, unknown>;
    resource: string;
    action: string;
  }): { allowed: boolean; matchedRule?: string; reason: string } {
    const allSignals = {
      ...request.identity,
      ...request.device,
      ...request.context,
      resource: request.resource,
      action: request.action,
    };

    for (const rule of this.rules) {
      // Check if rule applies to this resource
      if (!this.matchGlob(request.resource, rule.resource)) continue;

      // Evaluate all conditions
      const allConditionsMet = rule.conditions.every((cond) =>
        this.evaluateCondition(allSignals, cond)
      );

      if (allConditionsMet) {
        return {
          allowed: rule.effect === 'allow',
          matchedRule: rule.id,
          reason: `Matched rule: ${rule.description}`,
        };
      }
    }

    // Default deny
    return { allowed: false, reason: 'No matching policy rule (default deny)' };
  }

  private evaluateCondition(
    signals: Record<string, unknown>,
    condition: PolicyCondition
  ): boolean {
    const actualValue = signals[condition.field];
    switch (condition.operator) {
      case 'equals': return actualValue === condition.value;
      case 'notEquals': return actualValue !== condition.value;
      case 'greaterThan': return (actualValue as number) > (condition.value as number);
      case 'in': return (condition.value as unknown[]).includes(actualValue);
      case 'contains': return String(actualValue).includes(String(condition.value));
      default: return false;
    }
  }

  private matchGlob(path: string, pattern: string): boolean {
    const regexStr = pattern
      .replace(/\*/g, '.*')
      .replace(/\?/g, '.');
    return new RegExp(`^${regexStr}$`).test(path);
  }
}

// Example policies
const pdp = new PolicyDecisionPoint();

pdp.addRule({
  id: 'deny-unmanaged-confidential',
  description: 'Deny unmanaged devices from accessing confidential resources',
  resource: '/api/confidential/*',
  conditions: [
    { field: 'deviceManaged', operator: 'equals', value: false },
  ],
  effect: 'deny',
  priority: 100,
});

pdp.addRule({
  id: 'require-mfa-admin',
  description: 'Require MFA for admin actions',
  resource: '/api/admin/*',
  conditions: [
    { field: 'authMethod', operator: 'in', value: ['mfa', 'passkey', 'certificate'] },
    { field: 'role', operator: 'equals', value: 'admin' },
  ],
  effect: 'allow',
  priority: 90,
});

pdp.addRule({
  id: 'allow-authenticated-internal',
  description: 'Allow authenticated users to access internal resources',
  resource: '/api/internal/*',
  conditions: [
    { field: 'authenticated', operator: 'equals', value: true },
    { field: 'trustScore', operator: 'greaterThan', value: 50 },
  ],
  effect: 'allow',
  priority: 50,
});

Edge Cases & Failure Modes

Legitimate Access Denied

Zero Trust policies can be too restrictive, blocking legitimate users:

ScenarioCauseMitigation
New deviceNot yet in inventorySelf-enrollment with step-up auth
TravelingUnusual locationGeo-aware policies with exceptions
After hoursTime-based restrictionsEmergency access procedures
VPN split tunnelMixed network signalsDon't rely solely on network location

Policy Conflicts

When multiple policies apply:

Rule 1: ALLOW engineers to access /api/code/* (priority 50)
Rule 2: DENY unpatched devices from /api/* (priority 100)

Engineer with unpatched device accessing /api/code/build:
→ Rule 2 wins (higher priority) → DENIED

TIP

Always use a default deny posture. Only explicitly allowed access is permitted. This ensures that policy gaps result in denied access rather than unauthorized access.

Performance Characteristics

Policy Evaluation at Scale

MetricValueNotes
Policy evaluation time< 1msIn-memory rule engine
p99 latency (with context lookup)5–15msCached identity/device data
Throughput (single node)50K decisions/secCPU-bound
Policy rules supported10K+Indexed by resource path

Mathematical Foundations

Trust Score as a Weighted Sum

S=i=1nwisi

where wi are weights and si are individual signal scores:

SignalWeightScore RangeDescription
Auth method strength0.250–100Password=30, MFA=70, Passkey=95
Device compliance0.250–100Managed+patched+encrypted=100
Session freshness0.150–100Decays linearly with age
Network context0.100–100Corporate=90, Home=60, Public=30
Behavioral anomaly0.150–100Normal=90, Unusual=40, Alert=10
Risk intelligence0.100–100Based on threat feeds
If Sθresource, access is granted

where θresource is the minimum trust score for the resource's sensitivity level.

Real-World War Stories

War Story

Microsoft's Zero Trust Journey

Microsoft began its Zero Trust transformation in 2017, migrating from a VPN-centric model to identity-based access for 200,000+ employees and 600,000 devices. The migration took 3 years and involved:

  1. Enrolling all devices in Microsoft Endpoint Manager
  2. Deploying conditional access policies in Azure AD
  3. Removing VPN requirements for 95% of applications
  4. Implementing continuous access evaluation

Key metric: security incidents related to lateral movement decreased by 80% after implementing micro-segmentation and identity-based access.

Lesson: Zero Trust at scale requires executive sponsorship, a phased approach, and tolerance for temporary productivity disruptions during migration.

War Story

A Hospital's Zero Trust Emergency Access Problem

A hospital implemented Zero Trust with strict device compliance requirements. During a ransomware attack, the IT team needed to use personal devices and temporary workstations to restore systems. The Zero Trust policies blocked these unmanaged devices, slowing the recovery.

Resolution: They implemented "break-glass" accounts with separate emergency access policies that could be activated by two authorized administrators simultaneously. These accounts had full logging and automatic deactivation after 4 hours.

Decision Framework

Zero Trust Implementation Roadmap

Advanced Topics

Open Policy Agent (OPA) for Zero Trust

rego
# Zero Trust access policy in Rego (OPA)
package zerotrust.access

default allow = false

# Allow if all conditions are met
allow {
    input.identity.authenticated == true
    trust_score >= required_score
    device_compliant
}

trust_score = score {
    identity_score := identity_weight * auth_strength
    device_score := device_weight * device_health
    context_score := context_weight * context_trust
    score := identity_score + device_score + context_score
}

auth_strength = 95 { input.identity.auth_method == "passkey" }
auth_strength = 70 { input.identity.auth_method == "mfa" }
auth_strength = 30 { input.identity.auth_method == "password" }

device_compliant {
    input.device.managed == true
    input.device.disk_encrypted == true
    input.device.patch_level != "behind-2+"
}

required_score = 85 { input.resource.sensitivity == "restricted" }
required_score = 70 { input.resource.sensitivity == "confidential" }
required_score = 50 { input.resource.sensitivity == "internal" }
required_score = 20 { input.resource.sensitivity == "public" }

identity_weight = 0.4
device_weight = 0.35
context_weight = 0.25

device_health = 100 { input.device.compliance_status == "compliant" }
device_health = 50 { input.device.compliance_status == "unknown" }
device_health = 0 { input.device.compliance_status == "non-compliant" }

context_trust = 90 { input.context.network_type == "corporate" }
context_trust = 60 { input.context.network_type == "home" }
context_trust = 30 { input.context.network_type == "public" }

Zero Trust for APIs

typescript
// API gateway implementing Zero Trust
import { Request, Response, NextFunction } from 'express';

interface ZeroTrustAPIConfig {
  requireMTLS: boolean;
  requiredScopes: string[];
  sensitivityLevel: 'public' | 'internal' | 'confidential' | 'restricted';
  rateLimitPerIdentity: number;
  allowedClientCertificates?: string[]; // Allowed SPIFFE IDs
}

function zeroTrustAPI(config: ZeroTrustAPIConfig) {
  return async (req: Request, res: Response, next: NextFunction) => {
    // 1. Verify mTLS identity
    if (config.requireMTLS) {
      const clientCert = (req.socket as any).getPeerCertificate();
      if (!clientCert || !clientCert.subject) {
        res.status(401).json({ error: 'mTLS client certificate required' });
        return;
      }
      const spiffeId = extractSPIFFEId(clientCert);
      if (config.allowedClientCertificates && !config.allowedClientCertificates.includes(spiffeId)) {
        res.status(403).json({ error: 'Client not authorized' });
        return;
      }
    }

    // 2. Verify JWT/bearer token
    const token = extractBearerToken(req);
    if (!token) {
      res.status(401).json({ error: 'Authentication required' });
      return;
    }

    // 3. Verify scopes
    const tokenScopes = decodeTokenScopes(token);
    const hasRequiredScopes = config.requiredScopes.every(s => tokenScopes.includes(s));
    if (!hasRequiredScopes) {
      res.status(403).json({ error: 'Insufficient scopes' });
      return;
    }

    // 4. Apply rate limit per identity
    const identity = extractIdentity(token);
    const limited = await checkRateLimit(identity, config.rateLimitPerIdentity);
    if (limited) {
      res.status(429).json({ error: 'Rate limit exceeded' });
      return;
    }

    next();
  };
}

Cross-References

"What I cannot create, I do not understand." — Richard Feynman