Skip to main content

IPsec tunnels

Frontdoor V2 feature

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 (or ERROR); 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

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: Authorization header must be exactly Authorization: Bearer <token> with a space after Bearer or Authorization: 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: Authorization header must be exactly Authorization: Bearer <token> with a space after Bearer or Authorization: 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: Authorization header must be exactly Authorization: Bearer <token> with a space after Bearer or Authorization: Basic <username:token> with a space after Basic and a color separator.