Swiss...
Zero-Trust Architecture for Regulated SaaS: Building Verify-Everything Infrastructure on Swiss Servers
Perimeter security assumes your internal network is safe. It is not. Here is how to implement zero-trust architecture on Swiss managed infrastructure for GDPR and FADP-regulated SaaS and fintech workloads — with actual configurations, not vendor slideware.
September 10, 2026
by SwissLayer 18 min read
Zero-Trust Architecture for Regulated SaaS on Swiss Infrastructure

The perimeter security model is dead. It has been dying for years, but regulated SaaS and fintech companies are the ones paying the price when it finally fails. You build a firewall, segment your VLANs, lock down SSH — and then a compromised service account moves laterally through your internal network because every system behind the firewall trusts every other system by default.

Zero-trust architecture flips this assumption. Nothing is trusted by default — not the network, not the device, not the user, not even the application making the request. Every access decision is authenticated, authorised, and continuously verified. For companies operating under GDPR, the Swiss FADP, or financial regulations like FINMA and DORA, this is not a nice-to-have security upgrade. It is increasingly the minimum standard that auditors and regulators expect.

This guide covers how to implement zero-trust architecture on dedicated Swiss infrastructure for regulated SaaS and fintech workloads. We will work through the five pillars of zero trust — identity, device, network, application, and data — with specific configurations for each. No vendor lock-in, no proprietary magic boxes. Just open-source tools, standard Linux capabilities, and architectural patterns that satisfy both security best practice and regulatory compliance requirements.

Why Perimeter Security Fails Regulated Workloads

Traditional network security operates on a castle-and-moat model: strong perimeter defences, relatively permissive internal access. You put a firewall at the edge, run an IDS, maybe segment production from staging, and call it done. Traffic inside the perimeter is implicitly trusted.

This model breaks down for regulated SaaS companies in three specific ways:

Lateral movement after initial compromise. Most breaches do not start with a frontal assault on your firewall. They start with a phished credential, a vulnerable dependency, a misconfigured API endpoint. Once an attacker has a foothold inside your perimeter, the implicit trust model gives them free movement. A compromised web application can query your database directly. A breached CI/CD runner can SSH into production. A stolen service account token can access every microservice in your cluster.

For a GDPR-regulated SaaS platform, lateral movement means a single compromised component can lead to a full data breach — not just the data that component directly handles, but everything else accessible from the same network segment. Under GDPR Article 33, that is a 72-hour notification to your supervisory authority. Under NIS2, it is a 24-hour early warning. Under Swiss FADP Article 24, it is notification to the FDPIC "as soon as possible." Each regulation measures breach severity by the scope of data affected — and perimeter-only security maximises that scope.

Regulatory expectations have evolved. GDPR Article 25 requires "data protection by design and by default." Article 32 requires "appropriate technical and organisational measures" including "the ability to ensure the ongoing confidentiality, integrity, availability and resilience of processing systems." Regulators and auditors increasingly interpret "appropriate measures" through the lens of zero trust. When the NIST Zero Trust Architecture framework (SP 800-207) became a de facto standard in 2020, it shifted auditor expectations. If you are running a flat network with perimeter-only controls for a fintech platform processing EU customer data, the question is not whether your security is adequate — it is whether you can defend that position under audit.

Multi-tenancy amplifies the risk. SaaS platforms serve multiple customers on shared infrastructure. A security boundary failure does not just affect one customer — it potentially exposes every tenant's data. For SaaS companies serving regulated industries (healthcare, finance, legal), this creates contractual liability on top of regulatory exposure. Your enterprise customers' compliance teams are asking about your internal network security, and "we have a firewall" is not an acceptable answer in 2026.

The Five Pillars of Zero Trust on Bare Metal

Zero trust is often presented as a product you buy. It is not. It is an architectural pattern that you implement across five pillars: identity, device, network, application, and data. On managed Swiss infrastructure, you have the advantage of working with dedicated hardware where you control every layer of the stack — no shared hypervisors, no cloud provider abstractions between you and the metal.

Here is how each pillar translates to concrete infrastructure configuration.

Pillar 1: Identity — Every Request Carries Proof

In a zero-trust model, identity is the primary security boundary. Not the network, not the IP address — the cryptographically verified identity of the entity making the request. This applies to human users, service accounts, automated processes, and machine-to-machine communication.

Human identity: SSH certificate authority

Password-based SSH is obviously out. Key-based SSH is better, but it has a key management problem: authorised_keys files scattered across servers, no expiration, no revocation without touching every machine. For regulated workloads, SSH certificates solve this cleanly:

# Set up an SSH Certificate Authority
# This replaces authorized_keys with short-lived, centrally managed certificates

# 1. Generate the CA key pair (do this once, store the private key securely)
ssh-keygen -t ed25519 -f /etc/ssh/ca_user_key -C "SSH User CA"

# 2. Configure sshd to trust the CA
# /etc/ssh/sshd_config
echo "TrustedUserCAKeys /etc/ssh/ca_user_key.pub" >> /etc/ssh/sshd_config

# 3. Sign a user's public key with a 12-hour validity window
ssh-keygen -s /etc/ssh/ca_user_key \
  -I "engineer-alice-2026-09-10" \
  -n deploy_svc,audit_svc \
  -V +12h \
  -z $(date +%s) \
  alice_ed25519.pub

# The resulting certificate (alice_ed25519-cert.pub) is valid for 12 hours,
# restricted to the deploy_svc and audit_svc principals,
# and includes a unique serial number for audit trail purposes.

Short-lived certificates eliminate the key revocation problem entirely. A compromised key is only valid for hours, not forever. For compliance, every certificate issuance is a logged event with the user's identity, the principals granted, and the validity window — a complete audit trail without parsing authorised_keys files across your fleet.

Service identity: mutual TLS everywhere

Human users are not the only entities that need identity verification. In a microservices architecture, services communicate constantly — API calls, database connections, cache lookups, queue consumers. In a perimeter model, these connections rely on network position for trust: "if it can reach port 5432, it is allowed." Zero trust requires that every service proves its identity on every connection.

Mutual TLS (mTLS) is the standard approach. Each service gets a certificate issued by your internal CA, and both sides of every connection verify the other's certificate:

# Internal PKI setup with step-ca (open-source ACME CA)
# Install step CLI and step-ca
wget https://dl.smallstep.com/cli/docs-ca-install/latest/step-ca_amd64.deb
dpkg -i step-ca_amd64.deb

# Initialise the CA
step ca init --name="Internal Zero Trust CA" \
  --dns="ca.internal.example.com" \
  --address=":8443" \
  --provisioner="admin@example.com"

# Issue a certificate for a service (24-hour validity)
step ca certificate "api-gateway.internal" \
  api-gateway.crt api-gateway.key \
  --not-after=24h

# Nginx upstream with mTLS verification
# /etc/nginx/conf.d/api-upstream.conf
upstream backend_api {
    server 10.20.0.10:8443;
}

server {
    listen 8443 ssl;
    server_name api-gateway.internal;

    # Server certificate (proves identity to clients)
    ssl_certificate /etc/ssl/services/api-gateway.crt;
    ssl_certificate_key /etc/ssl/services/api-gateway.key;

    # Client certificate verification (proves client identity to us)
    ssl_client_certificate /etc/ssl/internal-ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    # Only allow specific service identities
    if ($ssl_client_s_dn !~ "CN=(payment-svc|order-svc|admin-dashboard)") {
        return 403;
    }

    location / {
        proxy_pass https://backend_api;
        # Pass verified client identity to upstream
        proxy_set_header X-Client-Certificate-CN $ssl_client_s_dn;
    }
}

With mTLS, a compromised service cannot impersonate another service. Even if an attacker gains code execution on your web tier, they cannot connect to your database tier without a valid certificate for a service identity that the database is configured to accept. The blast radius shrinks from "everything on the network" to "whatever this specific service identity is authorised to access."

Machine identity: hardware-bound tokens

On dedicated Swiss servers, you have access to hardware security features that cloud VMs abstract away. TPM 2.0 modules (present on modern server hardware) can attest to the machine's boot state and bind cryptographic keys to specific hardware:

# TPM-based machine identity attestation
# Verify the server booted with expected firmware and configuration

# Read Platform Configuration Registers (PCRs)
# PCR 0: BIOS/firmware measurement
# PCR 7: Secure Boot state
tpm2_pcrread sha256:0,1,2,3,4,5,6,7

# Create a machine identity key bound to the TPM
tpm2_createprimary -C e -g sha256 -G ecc256 -c primary.ctx
tpm2_create -C primary.ctx -g sha256 -G ecc256 \
  -u machine_id.pub -r machine_id.priv \
  -L sha256:0,7  # Key is sealed to boot state

# Export the public key for registration with your identity provider
tpm2_readpublic -c machine_id.ctx -o machine_id.pem -f pem

This gives you a machine identity that cannot be extracted or cloned — the private key exists only inside the TPM. For compliance purposes, this provides hardware-rooted proof that a specific server, with a specific boot configuration, made a specific request. It is the strongest form of device authentication available, and it is something you get on dedicated hardware that you cannot replicate on shared cloud instances.

Pillar 2: Device — Trust the Machine, Not the Network

Zero trust requires verifying not just who is making a request, but what device they are making it from. A valid user credential on a compromised device is still a security risk. For server-to-server communication, device trust is about ensuring the machine itself has not been tampered with.

Measured boot and integrity verification

# Integrity Measurement Architecture (IMA) — runtime file integrity
# Enable IMA in the kernel boot parameters
# /etc/default/grub
GRUB_CMDLINE_LINUX="ima_policy=tcb ima_hash=sha256"

# After reboot, IMA measures every file executed or opened
# View the measurement log
cat /sys/kernel/security/ima/ascii_runtime_measurements | head -20

# Create a custom IMA policy for zero-trust verification
# /etc/ima/ima-policy
# Measure all executables
measure func=BPRM_CHECK mask=MAY_EXEC
# Measure all libraries
measure func=FILE_MMAP mask=MAY_EXEC
# Measure all configuration files in critical paths
measure func=FILE_CHECK mask=MAY_READ uid=0 fowner=0
# Appraise — reject execution if measurement fails
appraise func=BPRM_CHECK fowner=0 appraise_type=imasig

IMA creates a chain of measurements from boot through runtime. Every binary executed, every library loaded, every configuration file read by root is measured and recorded. If someone modifies a system binary or injects a malicious library, the measurement changes and the system can detect — or in appraise mode, prevent — the execution.

For regulated SaaS workloads, this provides continuous integrity verification that satisfies GDPR Article 32's "integrity of processing systems" requirement and supports NIS2's security monitoring obligations.

Endpoint compliance checks for admin access

For human administrators connecting to your infrastructure, device posture matters. A zero-trust access policy should verify the connecting device before granting access:

# WireGuard VPN with device posture check
# Access to management network requires:
# 1. Valid WireGuard key (identity)
# 2. Device compliance attestation (device posture)

# Server-side: WireGuard config with per-peer allowed IPs
# /etc/wireguard/wg-mgmt.conf
[Interface]
Address = 10.30.0.1/24
ListenPort = 51820
PrivateKey = [SERVER_PRIVATE_KEY]
PostUp = iptables -A FORWARD -i wg-mgmt -j ACCEPT
PostDown = iptables -D FORWARD -i wg-mgmt -j ACCEPT

# Engineer Alice — full management access
[Peer]
PublicKey = [ALICE_PUBLIC_KEY]
AllowedIPs = 10.30.0.10/32
# PresharedKey adds a second layer of key material
PresharedKey = [ALICE_PSK]

# Engineer Bob — read-only monitoring access
[Peer]
PublicKey = [BOB_PUBLIC_KEY]
AllowedIPs = 10.30.0.11/32
PresharedKey = [BOB_PSK]

# Post-connection device compliance script
# /etc/wireguard/posture-check.sh
#!/bin/bash
PEER_IP=$1

# Check if peer's compliance attestation is current (max 4 hours old)
ATTESTATION_FILE="/var/compliance/peers/${PEER_IP}/latest.json"
if [ ! -f "${ATTESTATION_FILE}" ]; then
    echo "DENY: No compliance attestation for ${PEER_IP}"
    # Block peer at firewall
    iptables -I FORWARD -s "${PEER_IP}" -j DROP
    exit 1
fi

ATTESTATION_AGE=$(( $(date +%s) - $(stat -c %Y "${ATTESTATION_FILE}") ))
if [ "${ATTESTATION_AGE}" -gt 14400 ]; then
    echo "DENY: Attestation expired for ${PEER_IP} (age: ${ATTESTATION_AGE}s)"
    iptables -I FORWARD -s "${PEER_IP}" -j DROP
    exit 1
fi

echo "ALLOW: ${PEER_IP} attestation valid"

Pillar 3: Network — Micro-Segmentation Beyond VLANs

Traditional network segmentation puts your web servers in one VLAN and your databases in another. Zero-trust micro-segmentation goes further: every workload gets its own security boundary, and traffic between workloads is explicitly authorised based on identity, not network position.

nftables for workload-level segmentation

On bare metal, nftables gives you the control to implement per-service network policies without the overhead of a service mesh:

#!/usr/sbin/nft -f
# Zero-trust nftables ruleset — default deny, explicit allow per service pair

flush ruleset

table inet zero_trust {
    # Track connection states
    chain input {
        type filter hook input priority 0; policy drop;

        # Allow established connections (responses to allowed outbound)
        ct state established,related accept

        # Loopback
        iif lo accept

        # SSH from management VPN only
        ip saddr 10.30.0.0/24 tcp dport 22 accept

        # Prometheus metrics scraping (from monitoring tier only)
        ip saddr 10.40.0.0/24 tcp dport 9100 accept  # node_exporter
        ip saddr 10.40.0.0/24 tcp dport 9187 accept  # postgres_exporter

        # Service-specific ingress (example: API gateway)
        ip saddr 10.10.0.0/24 tcp dport 8443 accept   # from load balancer tier

        # Log and drop everything else
        log prefix "ZT-INPUT-DROP: " counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;

        ct state established,related accept

        # Explicit service-to-service rules
        # API gateway -> Backend API
        ip saddr 10.10.0.5 ip daddr 10.20.0.10 tcp dport 8443 accept

        # Backend API -> PostgreSQL
        ip saddr 10.20.0.10 ip daddr 10.20.0.20 tcp dport 5432 accept

        # Backend API -> Redis cache
        ip saddr 10.20.0.10 ip daddr 10.20.0.30 tcp dport 6379 accept

        # Payment service -> Payment API (and nothing else)
        ip saddr 10.20.0.15 ip daddr 10.20.0.10 tcp dport 8443 accept
        ip saddr 10.20.0.15 ip daddr 10.20.0.20 tcp dport 5432 accept

        # Log all denied forward traffic — this is your anomaly detection feed
        log prefix "ZT-FORWARD-DROP: " counter drop
    }

    chain output {
        type filter hook output priority 0; policy drop;

        ct state established,related accept
        oif lo accept

        # DNS resolution
        tcp dport 53 accept
        udp dport 53 accept

        # NTP
        udp dport 123 accept

        # HTTPS outbound (for package updates, OCSP, etc.)
        tcp dport 443 accept

        # Explicit outbound rules per service
        # PostgreSQL -> backup target
        ip saddr 10.20.0.20 ip daddr 10.50.0.5 tcp dport 22 accept

        log prefix "ZT-OUTPUT-DROP: " counter drop
    }
}

The critical detail is the policy drop on every chain. Nothing passes unless explicitly allowed. The log entries on dropped traffic feed your SIEM and become your anomaly detection system — any service attempting a connection that is not in your explicit allow list is either misconfigured or compromised.

For compliance auditors, this ruleset is documentation. It shows exactly which services can communicate with which other services, on which ports, in which direction. That is a concrete answer to "how do you prevent lateral movement?" — far more convincing than "we have network segmentation."

DNS-based service discovery with policy enforcement

In a zero-trust network, services should not be able to discover other services by scanning the network. DNS becomes both a service discovery mechanism and a policy enforcement point:

# CoreDNS with policy-based resolution
# /etc/coredns/Corefile

internal.example.com {
    file /etc/coredns/zones/internal.zone
    
    # ACL: only specific source IPs can resolve specific services
    acl {
        # API gateway can resolve backend services
        allow net 10.10.0.5/32 type A name backend-api.internal.example.com
        allow net 10.10.0.5/32 type A name payment-svc.internal.example.com
        
        # Backend API can resolve database and cache
        allow net 10.20.0.10/32 type A name postgres-primary.internal.example.com
        allow net 10.20.0.10/32 type A name redis-cache.internal.example.com
        
        # Payment service — restricted resolution
        allow net 10.20.0.15/32 type A name postgres-primary.internal.example.com
        
        # Monitoring — can resolve everything (read-only scraping)
        allow net 10.40.0.0/24
        
        # Deny all other internal DNS queries
        block
    }
    
    log
    errors
}

. {
    forward . 1.1.1.1 8.8.8.8
    cache 300
}

A compromised service that cannot resolve other services' DNS names has a much harder time moving laterally, even if it manages to bypass network-level controls. This defence-in-depth approach — network rules block the connection AND DNS prevents discovery — is characteristic of mature zero-trust implementations.

Pillar 4: Application — Verify Every API Call

Identity-verified, device-attested, network-authorised traffic still needs application-level verification. A legitimate service with a valid certificate can still make unauthorised requests if your application layer does not enforce its own access policies.

Request-level authorisation with Open Policy Agent

Open Policy Agent (OPA) provides a declarative policy engine that can enforce access decisions at the application layer, independent of network position:

# OPA policy for API access control
# /etc/opa/policies/api-access.rego

package api.authz

import future.keywords.if
import future.keywords.in

default allow := false

# Allow read access to account data for the owning tenant
allow if {
    input.method == "GET"
    input.path[0] == "api"
    input.path[1] == "v1"
    input.path[2] == "accounts"
    input.tenant_id == input.resource_tenant_id
}

# Allow payment service to create transactions (service-to-service)
allow if {
    input.method == "POST"
    input.path[0] == "api"
    input.path[1] == "v1"
    input.path[2] == "transactions"
    input.caller_identity == "payment-svc.internal"
    input.caller_certificate_valid == true
}

# Block cross-tenant data access (GDPR tenant isolation)
deny if {
    input.tenant_id != input.resource_tenant_id
    not input.caller_identity in admin_identities
}

# Require MFA for sensitive operations
require_mfa if {
    input.path[2] == "users"
    input.method in ["DELETE", "PUT"]
}

require_mfa if {
    input.path[2] == "billing"
    input.method == "POST"
}

admin_identities := {"admin-dashboard.internal", "compliance-audit.internal"}

OPA policies are version-controlled, testable, and auditable. When a compliance officer asks "how do you prevent cross-tenant data access?" you can show them the exact policy, the test suite that validates it, and the decision logs that prove it is enforced in production.

JWT-based request authentication with short-lived tokens

# Nginx JWT validation for API requests
# Every request must carry a valid, non-expired JWT

# /etc/nginx/conf.d/jwt-validation.conf

# JWT validation using nginx-jwt module
map $http_authorization $jwt_token {
    ~^Bearer\s+(.+)$ $1;
    default "";
}

server {
    listen 8443 ssl;

    # mTLS (service identity) + JWT (request authorisation)
    ssl_client_certificate /etc/ssl/internal-ca.crt;
    ssl_verify_client on;

    location /api/ {
        # Validate JWT signature, expiration, and issuer
        auth_jwt "Zero Trust API";
        auth_jwt_key_file /etc/nginx/jwt-keys/signing-key.jwk;

        # Enforce maximum token lifetime (15 minutes)
        auth_jwt_claim_set $jwt_exp exp;
        auth_jwt_claim_set $jwt_iat iat;

        # Pass identity claims to upstream for OPA evaluation
        proxy_set_header X-JWT-Subject $jwt_claim_sub;
        proxy_set_header X-JWT-Tenant $jwt_claim_tenant_id;
        proxy_set_header X-JWT-Scope $jwt_claim_scope;
        proxy_set_header X-Client-CN $ssl_client_s_dn;

        proxy_pass https://backend_api;
    }
}

The combination of mTLS (service identity) and JWT (request authorisation) creates two independent verification layers. Even if an attacker steals a JWT, they cannot use it without a valid client certificate. Even if they compromise a service certificate, they cannot make authorised requests without a valid JWT scoped to the specific operation.

Pillar 5: Data — Encrypt, Classify, Control

The final pillar — and arguably the most important for GDPR and FADP compliance — is data-level zero trust. The principle: data should be protected independently of the infrastructure it sits on. Even if every other control fails, data-level protections should prevent unauthorised access.

Encryption at every layer

# Full-stack encryption for zero-trust data protection

# Layer 1: Disk encryption (data at rest)
# LUKS2 with hardware-bound key
cryptsetup luksFormat --type luks2 \
  --cipher aes-xts-plain64 \
  --key-size 512 \
  --hash sha512 \
  --pbkdf argon2id \
  /dev/sda2

# Layer 2: Database-level encryption (column-level for PII)
# PostgreSQL with pgcrypto
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- Encrypt sensitive columns with tenant-specific keys
CREATE TABLE customer_data (
    id UUID DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,
    -- Non-sensitive: stored plaintext for indexing
    customer_ref VARCHAR(64) NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now(),
    -- PII: encrypted with tenant-specific key
    full_name BYTEA,          -- pgp_sym_encrypt(name, tenant_key)
    email BYTEA,              -- pgp_sym_encrypt(email, tenant_key)
    phone BYTEA,              -- pgp_sym_encrypt(phone, tenant_key)
    -- Financial: encrypted with stricter key rotation
    account_number BYTEA,     -- pgp_sym_encrypt(acct, financial_key)
    -- Searchable hash for lookup without decryption
    email_hash VARCHAR(128)   -- SHA-256 of normalised email
);

-- Encrypt on insert
INSERT INTO customer_data (tenant_id, customer_ref, full_name, email, email_hash)
VALUES (
    $1, $2,
    pgp_sym_encrypt($3, get_tenant_key($1)),
    pgp_sym_encrypt($4, get_tenant_key($1)),
    encode(digest(lower(trim($4)), 'sha256'), 'hex')
);

Column-level encryption with tenant-specific keys provides the strongest isolation guarantee for multi-tenant SaaS. Even if an attacker gains database access, they get encrypted blobs, not personal data. Each tenant's data requires a separate key to decrypt, so a single key compromise does not expose all tenants.

This directly addresses GDPR Article 32(1)(a) — "encryption of personal data" — at the most granular level possible. It also satisfies the Swiss FADP's Article 8 requirement for appropriate technical measures proportional to the sensitivity of the data.

Data classification and access logging

# Automated data access logging for compliance evidence
# Every data access is logged with full context

# PostgreSQL audit logging via pgAudit
# postgresql.conf
shared_preload_libraries = 'pgaudit'
pgaudit.log = 'read, write, ddl'
pgaudit.log_catalog = off
pgaudit.log_level = log
pgaudit.log_parameter = on
pgaudit.log_statement_once = off

# Custom audit trigger for PII access
CREATE OR REPLACE FUNCTION audit_pii_access()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO pii_access_log (
        access_time,
        table_name,
        operation,
        row_id,
        tenant_id,
        accessing_user,
        client_ip,
        application_name
    ) VALUES (
        now(),
        TG_TABLE_NAME,
        TG_OP,
        COALESCE(NEW.id, OLD.id),
        COALESCE(NEW.tenant_id, OLD.tenant_id),
        current_user,
        inet_client_addr(),
        current_setting('application_name', true)
    );
    RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

-- Apply to all tables containing PII
CREATE TRIGGER audit_customer_data_access
    AFTER SELECT OR INSERT OR UPDATE OR DELETE ON customer_data
    FOR EACH ROW EXECUTE FUNCTION audit_pii_access();

PII access logging is not optional under zero trust — it is the mechanism that proves your access controls are working. When an auditor asks "who accessed customer X's data in the last 90 days?" you should be able to answer with a query against your audit log, not a manual investigation.

Continuous Verification: The Heartbeat of Zero Trust

Zero trust is not a one-time configuration. It is continuous verification — ongoing assessment that the trust assumptions you are making are still valid. Certificates can be compromised. Configurations can drift. Access patterns can change.

Continuous compliance monitoring

#!/bin/bash
# Zero-trust posture assessment — runs every 6 hours via cron
# /etc/cron.d/zt-posture-check

REPORT="/var/compliance/zero-trust/posture-$(date +%Y%m%d-%H%M).json"
VIOLATIONS=0

echo "{" > "${REPORT}"
echo "  \"timestamp\": \"$(date -Iseconds)\"," >> "${REPORT}"
echo "  \"hostname\": \"$(hostname -f)\"," >> "${REPORT}"
echo "  \"checks\": [" >> "${REPORT}"

# Check 1: No password authentication on SSH
SSH_PASSWD=$(sshd -T 2>/dev/null | grep "passwordauthentication yes" | wc -l)
if [ "${SSH_PASSWD}" -gt 0 ]; then
    echo "    {\"check\": \"ssh_no_password\", \"status\": \"FAIL\"}," >> "${REPORT}"
    VIOLATIONS=$((VIOLATIONS + 1))
else
    echo "    {\"check\": \"ssh_no_password\", \"status\": \"PASS\"}," >> "${REPORT}"
fi

# Check 2: All listening services use TLS
PLAINTEXT_PORTS=$(ss -tlnp | grep -v "127.0.0.1\|::1" | grep -v ":443\|:8443\|:22\|:9100" | wc -l)
if [ "${PLAINTEXT_PORTS}" -gt 0 ]; then
    echo "    {\"check\": \"no_plaintext_services\", \"status\": \"FAIL\", \"detail\": \"${PLAINTEXT_PORTS} plaintext services\"}," >> "${REPORT}"
    VIOLATIONS=$((VIOLATIONS + 1))
else
    echo "    {\"check\": \"no_plaintext_services\", \"status\": \"PASS\"}," >> "${REPORT}"
fi

# Check 3: nftables default-deny is active
NFT_DEFAULT=$(nft list chain inet zero_trust input 2>/dev/null | grep "policy drop" | wc -l)
if [ "${NFT_DEFAULT}" -eq 0 ]; then
    echo "    {\"check\": \"nftables_default_deny\", \"status\": \"FAIL\"}," >> "${REPORT}"
    VIOLATIONS=$((VIOLATIONS + 1))
else
    echo "    {\"check\": \"nftables_default_deny\", \"status\": \"PASS\"}," >> "${REPORT}"
fi

# Check 4: Disk encryption active
ENCRYPTED=$(lsblk -o NAME,TYPE,FSTYPE | grep -c "crypt")
if [ "${ENCRYPTED}" -eq 0 ]; then
    echo "    {\"check\": \"disk_encryption\", \"status\": \"FAIL\"}," >> "${REPORT}"
    VIOLATIONS=$((VIOLATIONS + 1))
else
    echo "    {\"check\": \"disk_encryption\", \"status\": \"PASS\", \"volumes\": ${ENCRYPTED}}," >> "${REPORT}"
fi

# Check 5: Certificate expiry check (services)
EXPIRING=0
for CERT in /etc/ssl/services/*.crt; do
    EXPIRY=$(openssl x509 -enddate -noout -in "${CERT}" 2>/dev/null | cut -d= -f2)
    EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s 2>/dev/null)
    NOW_EPOCH=$(date +%s)
    HOURS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 3600 ))
    if [ "${HOURS_LEFT}" -lt 48 ]; then
        EXPIRING=$((EXPIRING + 1))
    fi
done
if [ "${EXPIRING}" -gt 0 ]; then
    echo "    {\"check\": \"certificate_expiry\", \"status\": \"WARN\", \"expiring_soon\": ${EXPIRING}}," >> "${REPORT}"
else
    echo "    {\"check\": \"certificate_expiry\", \"status\": \"PASS\"}," >> "${REPORT}"
fi

# Check 6: IMA integrity violations
IMA_VIOLATIONS=$(dmesg | grep -c "integrity.*FAILED" 2>/dev/null || echo 0)
if [ "${IMA_VIOLATIONS}" -gt 0 ]; then
    echo "    {\"check\": \"ima_integrity\", \"status\": \"FAIL\", \"violations\": ${IMA_VIOLATIONS}}," >> "${REPORT}"
    VIOLATIONS=$((VIOLATIONS + 1))
else
    echo "    {\"check\": \"ima_integrity\", \"status\": \"PASS\"}," >> "${REPORT}"
fi

# Check 7: Audit logging running
AUDITD_RUNNING=$(systemctl is-active auditd 2>/dev/null)
if [ "${AUDITD_RUNNING}" != "active" ]; then
    echo "    {\"check\": \"audit_logging\", \"status\": \"FAIL\"}" >> "${REPORT}"
    VIOLATIONS=$((VIOLATIONS + 1))
else
    echo "    {\"check\": \"audit_logging\", \"status\": \"PASS\"}" >> "${REPORT}"
fi

echo "  ]," >> "${REPORT}"
echo "  \"total_violations\": ${VIOLATIONS}" >> "${REPORT}"
echo "}" >> "${REPORT}"

# Alert on violations
if [ "${VIOLATIONS}" -gt 0 ]; then
    curl -s -X POST "${ALERTING_WEBHOOK}" \
      -H "Content-Type: application/json" \
      -d "{\"text\": \"Zero-trust posture check: ${VIOLATIONS} violations on $(hostname -f)\"}"
fi

This script is your continuous compliance engine. Every six hours, it verifies that your zero-trust controls are still in place. The JSON output feeds your compliance dashboard and provides time-stamped evidence for auditors. If a configuration drifts — someone enables password authentication on SSH, a certificate is about to expire, a firewall rule changes — you catch it within hours, not at your next annual audit.

Mapping Zero Trust to Regulatory Requirements

For compliance teams who need to map your zero-trust implementation to specific regulatory controls, here is how the five pillars align with the frameworks that matter for regulated SaaS and fintech:

GDPR alignment:

Article 25 (Data protection by design): Zero trust is data protection by design. The architecture is built around the assumption of compromise, with controls that protect data independently of any single security boundary.
Article 32 (Security of processing): mTLS, column-level encryption, access logging, integrity monitoring, and continuous posture assessment collectively satisfy the "appropriate technical measures" standard — and go beyond what most auditors expect under "state of the art."
Article 33/34 (Breach notification): Comprehensive logging and anomaly detection enable faster breach detection, reducing the gap between compromise and notification.
Article 5(1)(f) (Integrity and confidentiality): The combination of encryption at every layer, identity verification on every request, and continuous integrity monitoring directly implements this principle.

Swiss FADP alignment:

Article 8 (Data security): Zero trust provides defence-in-depth that satisfies the "appropriate technical and organisational measures" requirement at multiple levels simultaneously.
Article 7 (Data protection by design and default): mTLS, tenant isolation, and default-deny network policies implement data protection by default — systems are restricted unless explicitly permitted, not permissive unless explicitly restricted.

FINMA/DORA alignment (for fintech):

ICT risk management: Continuous posture assessment, hardware-rooted machine identity, and measured boot directly address ICT risk management requirements.
Operational resilience: Micro-segmentation limits blast radius. A compromised service does not take down the platform because each service operates within its own trust boundary.
Third-party risk: Zero trust applied to your hosting provider relationship — verifying the provider's security posture, not just trusting their ISO certificate — aligns with DORA's ICT third-party risk management requirements.

The Swiss Infrastructure Advantage for Zero Trust

Implementing zero trust on managed Swiss infrastructure gives you specific advantages that are difficult to replicate on hyperscale cloud platforms:

Hardware access. Zero trust at the hardware layer — TPM-based machine identity, measured boot, IMA — requires access to the physical hardware security features. On cloud VMs, the hypervisor abstracts these away. On a Swiss dedicated server, you have direct access to TPM modules, hardware security features, and BIOS/UEFI configuration. Your machine identity is rooted in hardware you control, not in a cloud provider's attestation service.

Network control. Micro-segmentation on dedicated hardware means you control the network stack end to end. No cloud provider VPC abstractions, no shared network fabric with other tenants, no NAT gateways that obscure traffic patterns. Your nftables rules operate on real network interfaces with real IP addresses, making your security policy transparent and auditable.

Jurisdictional clarity. Zero trust eliminates many cross-border data flow concerns because data is encrypted everywhere — at rest, in transit, and at the application layer. But for regulated workloads, the physical location of the decryption keys and the legal jurisdiction governing access to them still matters. Swiss jurisdiction under the FADP provides a legal framework that regulators recognise: no mandatory backdoors, no mass surveillance programmes with legal compulsion to provide access, and an adequacy decision that simplifies GDPR data transfer compliance.

Supply chain simplicity. A managed infrastructure provider operating from Swiss data centres with a transparent sub-processor list is a simpler supply chain link to verify than a hyperscale cloud with dozens of sub-services, each with their own compliance posture. For NIS2 Article 21(2)(d) supply chain security requirements, fewer links in the chain means fewer risks to assess and fewer potential failure points.

Common Mistakes When Implementing Zero Trust

Having worked with teams implementing zero-trust architectures on dedicated infrastructure, these are the mistakes that cost the most time and credibility:

Trying to do everything at once. Zero trust is a journey, not a weekend project. Start with identity (SSH certificates + mTLS for your most critical service path) and build out. Trying to implement all five pillars simultaneously leads to half-implemented controls that provide a false sense of security.

Ignoring the monitoring tier. Teams implement strict controls on production traffic but leave monitoring systems with broad access. Your Prometheus instance that scrapes every service, your log aggregator that receives data from every host, your alerting system that can page anyone — these are high-value targets. Apply zero-trust principles to your monitoring infrastructure, not just your application infrastructure.

Certificate management without automation. mTLS is powerful, but it creates an operational burden: every certificate must be issued, rotated, and revoked. Without automation (like step-ca or HashiCorp Vault PKI), certificate management becomes a manual process that scales poorly and fails catastrophically when someone forgets to renew a cert at 3 AM.

Policy-as-code without testing. OPA policies are code. They need tests. A misconfigured policy can lock out legitimate users or — worse — silently allow unauthorised access. Write unit tests for your authorisation policies with the same rigour you apply to your application code.

Forgetting egress controls. Most zero-trust implementations focus on ingress — who can access what. But egress controls are equally important for preventing data exfiltration. If a compromised service can make arbitrary outbound HTTPS connections, it can exfiltrate data to any endpoint on the internet. Default-deny outbound, with explicit allow rules for known-good destinations, closes this gap.

Practical Starting Point

If you are running regulated SaaS or fintech workloads and want to start implementing zero trust, here is a pragmatic sequence that delivers security value at each step without requiring a full architecture overhaul:

Week 1: Deploy SSH certificate authority. Eliminate authorized_keys files. Set certificate validity to 12 hours. This immediately reduces your credential exposure window from "forever" to "hours."
Week 2: Implement default-deny nftables with explicit service-to-service rules. Log all denied traffic. This gives you micro-segmentation and anomaly detection in one step.
Week 3: Deploy mTLS on your most critical service path (typically API gateway to primary backend). Use step-ca with automated certificate rotation. This eliminates the highest-risk implicit trust relationship.
Week 4: Enable comprehensive audit logging (auditd + pgAudit). Deploy the continuous posture assessment script. This gives you the compliance evidence layer that makes the previous controls auditable.
Month 2: Extend mTLS to all internal service communication. Implement OPA for application-layer authorisation. Deploy column-level encryption for PII.
Month 3: Add device posture verification for admin access. Implement TPM-based machine identity. Deploy IMA for runtime integrity verification.

Each step is independently valuable. You do not need to complete the full roadmap to improve your security posture and regulatory compliance position. A partially implemented zero-trust architecture with SSH certificates, micro-segmentation, and audit logging is already far ahead of a perimeter-only model — and it gives you concrete, auditable controls to demonstrate to regulators and customers.

The Honest Assessment

Zero trust is harder to implement than perimeter security. It requires more configuration, more automation, more operational discipline. Every new service needs certificates. Every new connection needs a firewall rule. Every new access pattern needs a policy update. The operational overhead is real.

But for regulated SaaS and fintech companies, the alternative is worse. A single lateral movement incident on a perimeter-secured network can expose every tenant's data, trigger multiple regulatory notifications, and undermine the trust that your business is built on. Zero trust limits the blast radius, accelerates detection, and provides the auditable evidence trail that regulators demand.

The infrastructure foundation matters. Dedicated Swiss servers give you the hardware access, network control, and jurisdictional clarity that zero trust requires at every layer. The FADP provides the legal framework. FINMA-grade security expectations provide the cultural foundation. And the technical controls — mTLS, micro-segmentation, hardware-rooted identity, continuous verification — provide the concrete implementation that turns "we take security seriously" into "here is exactly how our systems verify every request, and here are the logs that prove it."

Start small. Start with identity. Build out systematically. And document everything — because in regulated environments, a security control that exists but cannot be demonstrated under audit is a security control that does not count.