OpenIKED on Ubuntu 24.04 on Azure User Guide
Overview
This image runs OpenIKED, the OpenBSD project's free implementation of the Internet Key Exchange version 2 (IKEv2) protocol. IKEv2 is the half of an IPsec VPN that does the hard part: it authenticates the two peers to each other, negotiates the cipher suite, and installs the security associations that the kernel then uses to encrypt traffic. OpenIKED drives the Linux kernel IPsec stack directly, so once a tunnel is up the data path runs in the kernel rather than through a userspace process.
Your gateway identity is unique to your VM. The IKEv2 host keypair is what proves this gateway is who it says it is. A shared keypair would let anybody holding the same image impersonate your VPN gateway, so no key material of any kind ships inside the cloudimg image. A fresh RSA 4096 host keypair, and a fresh per VM secret, are generated on the first boot of every deployed VM by openiked-firstboot.service. The daemon is prevented from starting at all until that has happened, so a VM can never run with a missing or borrowed identity.
The image is secure by default. The shipped /etc/iked.conf declares no policy and no pre-shared key. A VPN gateway that shipped with a policy would be accepting connections from somebody before you had said who, and one that shipped with a pre-shared key would be shipping a published credential. So the gateway accepts and initiates nothing at all until you declare your own peer. IP forwarding is also off by default, because a VPN appliance should not silently be a router.
You can prove it works before you trust it. The image ships openiked-ctl selftest, which performs a genuine IKEv2 negotiation between two isolated endpoints on the VM using this VM's own host key, and checks the result against the kernel's own IPsec state: that a keyed security association was installed, that both daemons reached the established state, that the peer's public key was validated and its signature verified, that the negotiated cipher is the modern one, and that real traffic was actually encrypted. It also ships a negative control that proves a peer presenting the wrong key is refused.
What is included:
- OpenIKED 7.3 (Ubuntu 24.04 noble archive package
openiked) running as theopenikedsystem service - A per VM RSA 4096 IKEv2 host keypair generated on first boot, private key mode
0600 root:root - A secure by default
/etc/iked.confwith no policy, no pre-shared key, and commented ready to copy examples using modern proposals only openiked-ctl, a management tool for status, key fingerprint, peer import, forwarding, config reload and the self testopeniked-selftest.sh, which proves a real IKEv2 negotiation and its negative control- A root only credentials file at
/root/openiked-credentials.txtrecording the host key fingerprint and a per VM secret
Key facts:
| Item | Value |
|---|---|
| Platform | Ubuntu 24.04 LTS (Azure Gen2) |
| Default administrator | azureuser |
| Service | openiked.service |
| Configuration | /etc/iked.conf |
| Private host key | /etc/iked/private/local.key (mode 0600, owner root:root) |
| Public host key | /etc/iked/local.pub |
| Credentials file | /root/openiked-credentials.txt (mode 0600) |
| Protocol ports | UDP 500 (IKE), UDP 4500 (IKE over NAT traversal) |
| Recommended VM size | Standard_B2s |
Prerequisites
- An active Microsoft Azure subscription.
- Permission to create virtual machines, network security groups and public IP addresses.
- An SSH key pair for the
azureuseradministrator account. - A remote IPsec peer you control, reachable over the internet or over an Azure VNet.
- The Azure CLI, if you prefer to deploy from the command line.
Step 1: Deploy from the Azure Marketplace
- Sign in to the Azure Portal and search the Marketplace for OpenIKED on Ubuntu 24.04 LTS by cloudimg.
- Select Create.
- Choose your subscription, resource group and region.
- Set the virtual machine name and select size Standard_B2s or larger.
- Set the administrator username to
azureuserand upload your SSH public key. - Under Inbound port rules, allow SSH (22) from your own address only.
- Review and create the VM.
Step 2: Deploy from the Azure CLI
az group create --name openiked-rg --location eastus
az vm create \
--resource-group openiked-rg \
--name openiked-vm \
--image cloudimg:openiked-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Allow SSH from your own address only, then allow the IKE ports from your VPN peer only. Never open UDP 500 or 4500 to the whole internet.
# SSH, from your address only
az network nsg rule create --resource-group openiked-rg \
--nsg-name openiked-vmNSG --name allow-ssh \
--priority 1000 --access Allow --protocol Tcp \
--destination-port-ranges 22 --source-address-prefixes "<your-public-ip>/32"
# IKEv2 and NAT traversal, from your VPN peer only
az network nsg rule create --resource-group openiked-rg \
--nsg-name openiked-vmNSG --name allow-ikev2 \
--priority 1010 --access Allow --protocol Udp \
--destination-port-ranges 500 4500 --source-address-prefixes "<peer-public-ip>/32"
Step 3: Connect as the Administrator over SSH
ssh azureuser@<vm-public-ip>
If you need the public address:
az vm show --resource-group openiked-rg --name openiked-vm \
--show-details --query publicIps --output tsv
Step 4: Confirm the Daemon and the Secure Default
sudo openiked-ctl status
The daemon is active and enabled, the per VM key is present with mode 600 root:root, and the policy count is zero, which is the secure default: the gateway accepts nothing until you declare a peer.
sudo ss -ulnp | grep -E ':(500|4500)'

Step 5: Your Gateway Identity is Unique to This VM
The host keypair below was generated on the first boot of this VM. It is not in the cloudimg image and no other deployment holds it.
sudo openiked-ctl fingerprint
sudo ls -l /etc/iked/private/local.key /etc/iked/local.pub
sudo stat -c '%a %U:%G' /etc/iked/private
The private key is mode 0600 owned by root, inside a directory that is mode 0700. Give a peer the public key only, never the private key:
sudo openiked-ctl pubkey

Step 6: Prove a Real IKEv2 Negotiation
A daemon that is running and a UDP port that is open prove nothing about a VPN. The self test performs an actual IKEv2 exchange between two isolated endpoints on this VM, authenticating with this VM's own host key, and then checks the kernel's IPsec state.
sudo openiked-ctl selftest
Every line is a distinct assertion: a keyed security association was installed in both directions rather than the kernel's empty placeholder, both daemons reached the established state, the peer's public key was validated and its signature verified, the identities are the expected ones, the negotiated transform is AES 256 with HMAC SHA2 512 and ECP 256 forward secrecy, and the kernel actually encrypted traffic.

Step 7: The Negative Control
A test that only ever passes is not a test. The negative control repeats the exchange with the responder holding the wrong private key, and passes only if no tunnel is established.
sudo openiked-ctl selftest --negative
sudo grep -E 'ikesa|childsa' /etc/iked.conf | grep '^#' | head -4
sudo sysctl -n net.ipv4.ip_forward
IP forwarding reports 0. The appliance terminates tunnels but does not route between networks until you enable it in Step 9.

Step 8: Build a Site to Site Tunnel
Public key authentication is the recommended method. Exchange public keys with your peer, import theirs, add a matching policy, then reload.
On this VM, print the public key and send it to your peer:
sudo openiked-ctl pubkey
Copy your peer's public key onto this VM, then trust it against the peer's address:
sudo openiked-ctl import-peer <peer-public-ip> /home/azureuser/peer-local.pub
Add the policy to /etc/iked.conf. The commented Example 1 in that file is ready to copy: replace the two network prefixes, this VM's private address and the peer's public address.
ikev2 "site-to-site" active esp \
from 10.10.0.0/16 to 10.20.0.0/16 \
local <this-vm-private-ip> peer <peer-public-ip> \
ikesa enc aes-256-gcm prf hmac-sha2-256 group ecp256 \
childsa enc aes-256 auth hmac-sha2-512 group ecp256
Validate and reload. The reload refuses to restart the daemon if the file does not parse, so a typo cannot take your gateway down:
sudo openiked-ctl reload
Watch the tunnel come up:
sudo openiked-ctl sa
A note on the cipher choice. The child security association uses aes-256 with hmac-sha2-512, not AES GCM and not SHA2 256. This is deliberate and it matters. OpenIKED 7.3 accepts childsa enc aes-256-gcm in the configuration file and reports the configuration as valid, but silently drops the proposal, so the tunnel never establishes. It likewise accepts auth hmac-sha2-256, and the peers authenticate successfully, but the Linux kernel interface then refuses to load the security association and the tunnel fails at the last step. The proposals shipped in /etc/iked.conf are the ones verified to work end to end on this image.
Step 9: What Azure Still Requires
An IPsec gateway is not usable straight out of the box, and this guide will not pretend otherwise. Three things are yours to configure.
1. Network security group. Allow inbound UDP 500 and UDP 4500 from your peer's address only, as shown in Step 2. Without this the IKE exchange never reaches the VM.
2. IP forwarding, in two places. To route traffic between your peer's network and an Azure subnet, rather than only terminating a tunnel at this host, enable forwarding in the guest:
sudo openiked-ctl forwarding on
and on the Azure network interface itself, which is a separate setting Azure enforces independently of the guest:
az network nic update --name <nic-name> --resource-group openiked-rg --ip-forwarding true
3. A user defined route. Azure does not learn your remote prefixes from IKEv2. Create a route table whose next hop is this VM's private address for the remote network, and associate it with the subnets that should reach the far side:
az network route-table create --resource-group openiked-rg --name openiked-rt
az network route-table route create --resource-group openiked-rg \
--route-table-name openiked-rt --name to-remote-site \
--address-prefix 10.20.0.0/16 \
--next-hop-type VirtualAppliance --next-hop-ip-address <this-vm-private-ip>
Step 10: Managing the Service
sudo systemctl status openiked
sudo systemctl restart openiked
sudo journalctl -u openiked -n 50 --no-pager
| Command | Purpose |
|---|---|
openiked-ctl status |
Daemon and per VM key health, exits non zero when unhealthy |
openiked-ctl fingerprint |
SHA 256 fingerprint of this VM's public key |
openiked-ctl pubkey |
Print the public key to send a peer |
openiked-ctl psk |
Print this VM's per VM secret, for pre-shared key policies |
openiked-ctl sa |
Live IKE security associations and kernel IPsec state |
openiked-ctl import-peer <ip> <file> |
Trust a peer's public key |
openiked-ctl forwarding on\|off\|status |
Guest IP forwarding |
openiked-ctl reload |
Validate then reload the configuration |
openiked-ctl selftest [--negative] |
Prove a real IKEv2 negotiation |
Step 11: Hardening Notes
- Never copy
/etc/iked/private/local.keyoff this VM. It is this gateway's identity. Share only the public key. - Prefer public key authentication over pre-shared keys. If you must use a pre-shared key, use the per VM secret from
openiked-ctl pskand never a shared or memorable string. - Keep the NSG narrow. UDP 500 and 4500 should be open to your peer's address only.
- Keep proposals modern. Do not add 3DES, DES, MD5, SHA1, or the modp768, modp1024 and modp1536 groups to a policy.
- Leave forwarding off unless you route. If this VM only terminates tunnels, forwarding should stay disabled.
- Security updates. OpenIKED is installed from the Ubuntu archive as a normal apt package, so
unattended-upgradespatches it along with the rest of the system and it stays visible to vulnerability scanning.
Support
cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with the offer name, your VM size and region, and the output of sudo openiked-ctl status and sudo openiked-ctl selftest.