Three laptops on one team, three different VPN menus, and a ticket that says the connection works everywhere except the Mac. The plan behind those clients can be identical even when the menus are not. What has to line up is narrower than most rollouts assume: one gateway identity, one credential type, one route set and one resolver policy. Write those four down before anyone exports a profile, and the platform work turns into a checklist instead of an investigation.

Start with the access contract, not the client file

The access contract is five lines a reviewer can check without opening a vendor console. It names the private prefixes that must be reachable, the internal names that must resolve, the resolver that answers them, the traffic allowed to stay on the local path, and the gateway certificate the client should expect to see. Everything else in the rollout is a translation of those lines into a file format.

An office example makes the shape concrete: application servers in 10.60.0.0/16, private names under corp.example, an internal resolver at 10.61.0.53, and ordinary browsing left on whatever path the device already uses. That last item is a policy decision rather than a client default, and several clients will send everything through the tunnel if nobody says otherwise. Record the contract with a date and an owner, because that record is what tells you later whether the tunnel changed or the policy did.

Pick one protocol and one authentication pair you can defend

IKEv2 with certificate-based gateway authentication and EAP for the user is the usual pick when all three platforms must work without extra software, since Windows, macOS and NetworkManager each ship an IKEv2 client. The trouble is that supporting IKEv2 describes a label, not a feature set. EAP methods, hardware-backed keys, certificate-to-account mapping and automatic reconnect are implemented per platform. A combination that works on two of the three is common enough that you should assume it until tested.

Test the pair on every target platform before the deployment guide is written, not after. A gateway offering both EAP-MSCHAPv2 and EAP-TLS gives you room to fall back, provided the fallback is documented as supported rather than discovered during an incident. Two supported paths are cheap insurance; an undocumented third path is a future ticket.

When no single pair covers all three clients, the honest options are to add a client, add a gateway profile, or narrow the supported platform list. Turning off certificate validation on the platform that complains loudest is not one of them. That change converts a compatibility gap into an interception risk, and no later step in the rollout repairs it.

Build one artifact per platform from the contract

Windows takes a VPNv2 profile, delivered by MDM or created locally with Add-VpnConnection plus its XML payload. The parts that bite are scope and trust. A device-scoped profile and a user-scoped profile install into different stores, so the certificate the client needs must sit in the store that matches the scope you chose. Getting that pairing wrong produces a profile that imports cleanly and then fails on the first connect.

macOS takes a configuration profile with the managed VPN payload, signed and pushed through MDM or installed by hand for a pilot. The identity and the CA chain travel as separate payloads, which is why a profile can install without complaint and still fail at connect time. Check the payload list, not just the install result.

Linux depends on the backend behind NetworkManager, and strongSwan plus the NetworkManager plugin are separate packages. Connection properties are plugin-specific rather than generic VPN keys, so a key copied from another plugin often saves without error and then fails on activation. Build the connection on a clean image to confirm the plugin is present where it will actually run.

The three artifacts differ in format, but each one encodes the same five contract lines. That is the test for whether an artifact is finished: every line is represented somewhere, and nothing extra was invented along the way.

PlatformArtifactCheck before handoff
WindowsVPNv2 profile or Add-VpnConnectionScope matches certificate store
macOSManaged VPN payload plus certificate payloadBoth payloads present in one profile
LinuxNetworkManager connection with strongSwan backendPlugin package installed on the image

Verify routes, resolver and reconnect on a clean account

Connected is not the acceptance test. On Windows, Get-VpnConnection shows the profile and route print shows whether the private prefix landed on the tunnel interface. On macOS, scutil --nc list confirms the active service while scutil --dns shows the resolver order the system will really use.

On Linux, nmcli connection show --active proves the connection is up and resolvectl status shows DNS per link. A resolver present in the connection file but missing from the per-link output means split DNS is not being applied. That is the difference between names resolving and names resolving through the tunnel, and it changes which support team owns the next step. Compare the per-link output before and after the connection comes up, not only after.

Run the whole check as a fresh account with no cached credentials and no administrator-installed certificate. Then repeat it after a suspend and resume, and once more after forcing a credential re-entry. Those two transitions surface most of the reconnect failures that a first connection never shows.

Version the package and keep a rollback path

Tag each platform package with the contract revision it implements, and note the client and gateway versions you accepted it against. When behaviour changes after a client update, the tag points at a contract to re-test instead of a file to guess at.

Keep the previous package for each platform retrievable, and write its removal command next to it. Uninstalling a VPN profile is not the mirror image of installing one on Windows, macOS or Linux, and the differences show up at the worst possible time. Rehearse the removal once on a spare device so the archive becomes a plan rather than a hope.

Zvinyorwa zvakafanana