Trust No One, Not Even localhost
The biggest lie in systems administration is the concept of the "Trusted LAN." We grew up believing that once a packet passed the edge firewall, it was safe. We configured database listeners on private IPs and assumed only our app servers would touch them. We were wrong.
In 2024, the internal network is just a slightly quieter part of the public internet. If an attacker exploits a deserialization vulnerability in your frontend, they are now inside your "trusted" zone. If you are relying on IP whitelisting alone, you are already breached; you just don't know it yet.
This is where Zero Trust shifts from marketing buzzword to architectural necessity. It is not a product you buy; it is a discipline. It means authentication and authorization for every single flow, regardless of network location. Below, I will detail how we architect this for high-security Norwegian workloads using standard Linux tools available in Ubuntu 24.04 LTS, focusing on mTLS, WireGuard, and SSH Certificates.
1. The Identity Layer: Kill Static SSH Keys
Most DevOps teams still manage static SSH keys like it's 2015. You paste a public key into ~/.ssh/authorized_keys and forget about it. When an engineer leaves, do you rotate every key on every server? Probably not.
The Zero Trust approach uses an SSH Certificate Authority (CA). The server trusts a CA, not individual user keys. Users exchange their credentials (via OIDC or MFA) for a short-lived certificate.
Pro Tip: Store your CA private key offline or in a hardware security module (HSM). If that key leaks, your entire fleet is compromised.
Here is how you generate a CA and sign a user key for a 4-hour validity window:
# 1. Generate the CA keys (do this once, securely)
ssh-keygen -t ed25519 -f /etc/ssh/user_ca -C "CoolVDS_Internal_CA"
# 2. Configure the server to trust this CA
echo "TrustedUserCAKeys /etc/ssh/user_ca.pub" >> /etc/ssh/sshd_config
# 3. Sign a user's public key (valid for 4 hours only)
ssh-keygen -s /etc/ssh/user_ca \
-I user_id_123 \
-n john_doe \
-V +4h \
-z 1 \
user_key.pub
Now, SSH access is ephemeral. Even if a developer's laptop is stolen tomorrow, the certificate they have today is useless.
2. The Transport Layer: mTLS Everywhere
Encryption in transit is non-negotiable. But HTTPS usually only validates the server to the client. In a Zero Trust environment, the server must also validate the client. This is Mutual TLS (mTLS).
If you are running a microservices architecture on CoolVDS NVMe instances, you cannot rely on unencrypted HTTP over the private network. Packet sniffing on a compromised node reveals everything.
We use Nginx to enforce mTLS. This ensures that even if someone plugs into your switch or spoofs an IP, they cannot talk to the application without a valid client certificate signed by your internal PKI.
Nginx mTLS Configuration Block:
server {
listen 443 ssl http2;
server_name api.internal.coolvds.com;
# Standard Server SSL
ssl_certificate /etc/pki/server.crt;
ssl_certificate_key /etc/pki/server.key;
# mTLS Configuration
ssl_client_certificate /etc/pki/internal-ca.crt;
ssl_verify_client on;
# Performance tuning for handshake
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
proxy_pass http://backend_upstream;
}
}
Small checks matter. Verify your configuration with nginx -t before reloading. Also, ensure your system clock is synced using chronyd, as TLS relies heavily on accurate time.
3. The Network Layer: WireGuard Mesh
IPSec is bloated. OpenVPN is slow. For server-to-server communication across different zones (e.g., creating a secure bridge between your CoolVDS instance in Oslo and a backup node in Bergen), WireGuard is the standard.
WireGuard creates a cryptographically secure overlay network. We don't open database ports to the public interface. We bind the database to the WireGuard interface (wg0) only.
First, generate keys: wg genkey | tee privatekey | wg pubkey > publickey.
Then, configure the interface:
# /etc/wireguard/wg0.conf
[Interface]
Address = 10.100.0.1/24
SaveConfig = true
ListenPort = 51820
PrivateKey = [SERVER_PRIVATE_KEY]
# Peer (The Client or Secondary Server)
[Peer]
PublicKey = [PEER_PUBLIC_KEY]
AllowedIPs = 10.100.0.2/32
Endpoint = 192.0.2.45:51820
Bring it up with wg-quick up wg0. Now you have a secure tunnel with minimal latency overhead.
Why Infrastructure Choice Dictates Security posture
You can configure all the software firewalls you want, but if the underlying hypervisor is noisy or insecure, you are building a castle on sand. This is where