diff --git a/client/client.ovpn.template b/client/client.ovpn.template index f85caa1..da82f55 100644 --- a/client/client.ovpn.template +++ b/client/client.ovpn.template @@ -1,7 +1,7 @@ # AtlasHorizon VPN — client profile template. -# Per user: paste ca.crt, the user's cert/key, and ta.key (from the offline -# CA, see openvpn/pki/README.md) into the inline blocks below, save as -# .ovpn, import into OpenVPN Connect. +# ONE profile for everyone: paste ca.crt and ta.key (from the offline CA, +# see openvpn/pki/README.md) into the inline blocks below and distribute. +# No per-user certificates — identity is AD user/pass + Duo. # # Login: AD username; password field takes either # ADpassword -> Duo push @@ -33,12 +33,6 @@ verb 3 # ----- paste ca.crt ----- - -# ----- paste .crt ----- - - -# ----- paste .key ----- - # ----- paste ta.key ----- diff --git a/openvpn/pki/README.md b/openvpn/pki/README.md index 6c64df9..72b64b9 100644 --- a/openvpn/pki/README.md +++ b/openvpn/pki/README.md @@ -1,10 +1,14 @@ -# OpenVPN PKI — offline CA workflow +# OpenVPN PKI — offline CA workflow (server cert only) + +There are **no individual client certificates** in this design — users +authenticate with AD password + Duo. The PKI exists solely so clients can +verify they're talking to the real server (`remote-cert-tls server`), and +`ta.key` (tls-crypt) gates who can attempt a handshake at all. The CA private key **never touches the VPS**. Run easy-rsa on an offline -machine (or at minimum a machine that isn't this server), then copy only the -issued material here. +machine, then copy only the issued material here. -## One-time CA + server cert (on the offline machine) +## One-time setup (on the offline machine) ```bash git clone https://github.com/OpenVPN/easy-rsa.git && cd easy-rsa/easyrsa3 @@ -12,39 +16,34 @@ git clone https://github.com/OpenVPN/easy-rsa.git && cd easy-rsa/easyrsa3 ./easyrsa build-ca # sets the CA passphrase — keep offline ./easyrsa build-server-full racknerd-vpn nopass openvpn --genkey tls-crypt ta.key # shared tls-crypt key -./easyrsa gen-crl ``` ## Copy to the VPS (this directory) -| File on offline box | Name here | -|--------------------------------------|---------------| -| `pki/ca.crt` | `ca.crt` | -| `pki/issued/racknerd-vpn.crt` | `server.crt` | -| `pki/private/racknerd-vpn.key` | `server.key` | -| `ta.key` | `ta.key` | -| `pki/crl.pem` (optional, see server.conf) | `crl.pem` | +| File on offline box | Name here | +|--------------------------------|--------------| +| `pki/ca.crt` | `ca.crt` | +| `pki/issued/racknerd-vpn.crt` | `server.crt` | +| `pki/private/racknerd-vpn.key` | `server.key` | +| `ta.key` | `ta.key` | `chmod 600 server.key ta.key` after copying. -## Per-user client certs (offline) +## Client profile -```bash -./easyrsa build-client-full nick nopass -``` +Build ONE `.ovpn` from `client/client.ovpn.template`, pasting `ca.crt` and +`ta.key` into the inline blocks. The same profile goes to every user. -Build the client's `.ovpn` from `client/client.ovpn.template`, pasting -`ca.crt`, the client cert/key, and `ta.key` into the inline blocks. -CN should match the AD username — the server logs use it -(`username-as-common-name` keeps them consistent). +## Revoking access -## Revoking a client +No client certs means no CRL — access control lives where the identity +lives: -```bash -./easyrsa revoke nick && ./easyrsa gen-crl -``` - -Copy the fresh `crl.pem` here, uncomment `crl-verify` in `server.conf`, and -`docker compose restart openvpn`. +- **Disable the AD account** (or remove it from the VPN group if you use + `security_group_dn`) — kills new logins immediately. +- Remove/disable the user in **Duo** as backup. +- If a *profile* leaks (ta.key compromised): regenerate `ta.key`, replace + it here, restart openvpn, redistribute the profile — old profiles stop + working instantly. Everything in this directory except this README is gitignored. diff --git a/openvpn/server.conf b/openvpn/server.conf index 4a3cc93..e9a488d 100644 --- a/openvpn/server.conf +++ b/openvpn/server.conf @@ -1,6 +1,8 @@ # OpenVPN road-warrior endpoint — RackNerd hub -# Auth chain: client cert (offline CA) + user/pass -> PAM -> RADIUS +# Auth chain: AD user/pass -> PAM -> RADIUS # -> Duo Auth Proxy (127.0.0.1:1812) -> LDAPS to the DCs. +# No individual client certs: identity is LDAP + Duo only. tls-crypt +# (shared key in the profile) still gates who can attempt a handshake. port 1194 proto udp4 @@ -25,23 +27,21 @@ push "dhcp-option DOMAIN-SEARCH ad.oswaldtheotter.net" push "dhcp-option DOMAIN-SEARCH ad.trochalakis.net" push "block-outside-dns" -# PKI — issued from the offline CA, see pki/README.md +# PKI — server certificate only (offline CA, see pki/README.md); +# clients present no certificate. ca /etc/openvpn/pki/ca.crt cert /etc/openvpn/pki/server.crt key /etc/openvpn/pki/server.key dh none tls-crypt /etc/openvpn/pki/ta.key -# Enable once you publish a CRL from the offline CA (revoked laptops etc.): -;crl-verify /etc/openvpn/pki/crl.pem -remote-cert-tls client tls-version-min 1.2 data-ciphers AES-256-GCM:CHACHA20-POLY1305 auth SHA256 # User auth via Duo (password only = push; "password,123456" = passcode) plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn -verify-client-cert require +verify-client-cert none username-as-common-name hand-window 120 # allow time for the Duo push round-trip reneg-sec 0 # no mid-session TLS renegotiation (would re-prompt Duo)