Op
Networking Azure

OpenIKED on Ubuntu 24.04 on Azure User Guide

| Product: OpenIKED on Ubuntu 24.04 LTS on Azure

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 the openiked system 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.conf with 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 test
  • openiked-selftest.sh, which proves a real IKEv2 negotiation and its negative control
  • A root only credentials file at /root/openiked-credentials.txt recording 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

  1. An active Microsoft Azure subscription.
  2. Permission to create virtual machines, network security groups and public IP addresses.
  3. An SSH key pair for the azureuser administrator account.
  4. A remote IPsec peer you control, reachable over the internet or over an Azure VNet.
  5. The Azure CLI, if you prefer to deploy from the command line.

Step 1: Deploy from the Azure Marketplace

  1. Sign in to the Azure Portal and search the Marketplace for OpenIKED on Ubuntu 24.04 LTS by cloudimg.
  2. Select Create.
  3. Choose your subscription, resource group and region.
  4. Set the virtual machine name and select size Standard_B2s or larger.
  5. Set the administrator username to azureuser and upload your SSH public key.
  6. Under Inbound port rules, allow SSH (22) from your own address only.
  7. 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)'

The openiked service is active and enabled at boot, OpenIKED 7.3 from the Ubuntu 24.04 archive, listening on UDP 500 and UDP 4500, with the shipped configuration declaring zero active IKEv2 policies and zero pre-shared keys so the gateway accepts and initiates nothing until a peer is declared

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

The per VM IKEv2 host key generated on this VM's own first boot: openiked-ctl status reporting the daemon active, the private key present at mode 600 root root, the public key and its SHA 256 fingerprint, the private directory at mode 700, and the first boot service and sentinel that minted it, confirming no key material ships in the cloudimg image

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.

The built in self test performing a real IKEv2 negotiation: keyed ESP security associations installed in both namespaces rather than a larval placeholder, both daemons reaching the established VALID state, the peer public key validated and signature verified, the expected peer identities, an AES 256 with HMAC SHA2 512 and ECP 256 forward secrecy transform, and six packets actually encrypted by the kernel, ending in SELFTEST_OK

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.

The negative control: with the responder holding the wrong private key the initiator refuses to mark the security association valid and no IPsec tunnel is established, confirming the check discriminates, alongside the shipped modern proposals and IP forwarding reporting 0 because the appliance is not a router by default

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.key off 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 psk and 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-upgrades patches 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.