IPsec tunnels
IPsec tunnels are available on Frontdoor V2 to customers who have IPsec shares enabled. The endpoints below live under
the /frontdoor/v2 base path. Contact your account manager to request access.
This guide explains how to manage IPsec tunnels — the VPN ingress points that IPsec shares are published on. For the concepts, see IPsec shares.
Why this matters
- An IPsec tunnel provisions a managed VPN endpoint that peers with a remote site's IPsec device.
- Provisioning is asynchronous. A tunnel transitions
NEW → DEPLOYED(orERROR); plan for eventual consistency and poll after create. - Once deployed, the tunnel exposes a generated VPN configuration you hand to the remote site to bring the tunnel up.
Assumptions
- The examples assume you have a valid bearer token. If you need help obtaining a token, see Authentication for NetFoundry REST APIs.
- Base URL for all API calls is https://gateway.production.netfoundry.io/frontdoor.
- Expected headers for all API calls:
Authorization: Bearer YOUR_ACCESS_TOKENAccept: application/hal+json or application/json
All IPsec tunnel paths are under the /frontdoor/v2/{frontdoorId} base.
Operations
List tunnels
Request example:
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://gateway.production.netfoundry.io/frontdoor/v2/$FRONTDOOR_ID/ipsec-tunnels?page=0&size=20"
Response example:
{
"content": [
{
"id": "tnl-1",
"name": "customer-a-dc1",
"frontdoorId": "3d6d2b6e-6c7a-4a7f-8c3d-9a9d2e1f0b1c",
"locationId": "us-east-1",
"status": "DEPLOYED",
"peerPublicIp": "203.0.113.1",
"peerCidr": "172.31.0.0/16"
},
{
"id": "tnl-2",
"name": "customer-b-dc1",
"frontdoorId": "3d6d2b6e-6c7a-4a7f-8c3d-9a9d2e1f0b1c",
"locationId": "us-east-1",
"status": "NEW",
"peerPublicIp": "198.51.100.7",
"peerCidr": "10.50.0.0/16"
}
],
"pageable": {"pageNumber": 0, "pageSize": 20},
"totalElements": 2,
"totalPages": 1
}
You can filter by any property, for example ?status=DEPLOYED, ?name=customer-a-dc1, or ?peerPublicIp=203.0.113.1,
and sort with ?sort=name,asc.
Get a tunnel
Request example:
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://gateway.production.netfoundry.io/frontdoor/v2/$FRONTDOOR_ID/ipsec-tunnels/$TUNNEL_ID"
Response example:
{
"id": "tnl-1",
"name": "customer-a-dc1",
"frontdoorId": "3d6d2b6e-6c7a-4a7f-8c3d-9a9d2e1f0b1c",
"locationId": "us-east-1",
"status": "DEPLOYED",
"peerPublicIp": "203.0.113.1",
"peerCidr": "172.31.0.0/16",
"nlbPrivateIp": "10.1.5.10",
"nlbDnsName": "nlb-xxxx.elb.us-east-1.amazonaws.com",
"vpnConnectionId": "vpn-0ded9b82a6bb8357b"
}
Create a tunnel
Provisioning happens asynchronously. The call returns 202 Accepted; poll the GET endpoint until status is
DEPLOYED. One tunnel is allowed per Frontdoor and location pair.
Request example:
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "customer-a-dc1",
"peerPublicIp": "203.0.113.1",
"peerCidr": "172.31.0.0/16"
}' \
"https://gateway.production.netfoundry.io/frontdoor/v2/$FRONTDOOR_ID/ipsec-tunnels"
Request fields:
name(required): A recognizable name for the tunnel.peerPublicIp(required): The public IPv4 address of the remote site's IPsec device.peerCidr(required): The CIDR block behind the peer (for example,172.31.0.0/16).locationId(optional): The location/site to deploy the tunnel to.nlbPrivateIp(optional): A pinned private IP for the load balancer. If omitted, a free address is chosen.
The call returns 202 Accepted with the created tunnel. Fields like nlbDnsName and vpnConnectionId stay empty
until the tunnel reaches DEPLOYED:
{
"id": "tnl-1",
"name": "customer-a-dc1",
"frontdoorId": "3d6d2b6e-6c7a-4a7f-8c3d-9a9d2e1f0b1c",
"locationId": "us-east-1",
"status": "NEW",
"peerPublicIp": "203.0.113.1",
"peerCidr": "172.31.0.0/16"
}
Get the VPN tunnel configuration
Returns the VPN connection details, including tunnel endpoints, status, and the negotiated IKE/ESP parameters. The
tunnel must be DEPLOYED.
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://gateway.production.netfoundry.io/frontdoor/v2/$FRONTDOOR_ID/ipsec-tunnels/$TUNNEL_ID/tunnel-config"
Response example. The endpoint returns a single tunnel:
{
"state": "available",
"tunnels": [
{
"outsideIpAddress": "203.0.113.10",
"status": "UP",
"statusMessage": "IPSEC IS UP",
"insideCidr": "169.254.21.0/30",
"ikeVersions": ["ikev2"],
"phase1EncryptionAlgorithms": ["AES256"],
"phase1IntegrityAlgorithms": ["SHA2-256"],
"phase1DHGroupNumbers": [14, 20],
"phase1LifetimeSeconds": 28800,
"phase2EncryptionAlgorithms": ["AES256"],
"phase2IntegrityAlgorithms": ["SHA2-256"],
"phase2DHGroupNumbers": [14, 20],
"phase2LifetimeSeconds": 3600,
"rekeyMarginTimeSeconds": 540,
"rekeyFuzzPercentage": 100,
"dpdTimeoutSeconds": 30,
"dpdTimeoutAction": "clear"
}
]
}
Get a sample VPN configuration
Returns a generated, vendor-style sample configuration (text/plain) for the remote site. This is the only place the
pre-shared key is exposed, so treat the output as sensitive and deliver it over a secure channel.
curl -s \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/plain" \
"https://gateway.production.netfoundry.io/frontdoor/v2/$FRONTDOOR_ID/ipsec-tunnels/$TUNNEL_ID/sample-config"
Delete a tunnel
Teardown happens asynchronously (status transitions DELETING → DELETED). All IPsec shares targeting the tunnel must
be deleted first, or the request returns 400.
curl -s -X DELETE \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
"https://gateway.production.netfoundry.io/frontdoor/v2/$FRONTDOOR_ID/ipsec-tunnels/$TUNNEL_ID"
The call returns 202 Accepted with the tunnel at status DELETING:
{
"id": "tnl-1",
"name": "customer-a-dc1",
"frontdoorId": "3d6d2b6e-6c7a-4a7f-8c3d-9a9d2e1f0b1c",
"locationId": "us-east-1",
"status": "DELETING",
"peerPublicIp": "203.0.113.1",
"peerCidr": "172.31.0.0/16"
}
Technical notes
Metrics
Tunnel time-series metrics are available with a selectable window (30m, 1h default, 1d, 7d):
GET /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels/{id}/metrics?window=1h
Paths
- GET /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels[?page=0&size=20]
- GET /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels/{id}
- POST /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels
- DELETE /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels/{id}
- GET /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels/{id}/tunnel-config
- GET /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels/{id}/sample-config
- GET /frontdoor/v2/\{frontdoorId\}/ipsec-tunnels/{id}/metrics[?window=1h]
Common errors
400 Bad Request (client error)
{
"error": "invalid_request",
"message": "Value for <property> must be of <type>"
}
Possible reasons include:
- Clock skew: If tokens seem instantly expired, check system time synchronization on the machine making requests.
- Token format:
Authorizationheader must be exactlyAuthorization: Bearer <token>with a space after Bearer orAuthorization: Basic <username:token>with a space after Basic and a color separator.
401 Unauthorized (missing/expired token)
{
"error": "unauthorized",
"message": "Bearer token is missing or invalid"
}
Possible reasons include:
- Clock skew: If tokens seem instantly expired, check system time synchronization on the machine making requests.
- Token format:
Authorizationheader must be exactlyAuthorization: Bearer <token>with a space after Bearer orAuthorization: Basic <username:token>with a space after Basic and a color separator.
403 Forbidden (not_authorized)
{
"error": "not_found",
"message": "Frontdoor 3d6d2b6e-6c7a-4a7f-8c3d-9a9d2e1f0b1c not found"
}
Possible reasons include:
- Invalid token: The token is not valid.
- The token does not grant access to the requested resource.
- Clock skew: If tokens seem instantly expired, check system time synchronization on the machine making requests.
- Token format:
Authorizationheader must be exactlyAuthorization: Bearer <token>with a space after Bearer orAuthorization: Basic <username:token>with a space after Basic and a color separator.