Support site-to-site VPN customer gateway with dynamic peer IP (authentication by ID)
- Dominant language
- Java
- Stars
- 3.1k
- Forks
- 1.4k
- Avg merge
- 6d 19h
- Merged PRs (30d)
- 32
Description
### The required feature described as a wish
Support site-to-site VPN customer gateway with dynamic peer IP (authentication by ID)
##### ISSUE TYPE
* Enhancement Request
##### COMPONENT NAME
~~~
Component:api
Component:UI
Component:systemvm (Virtual Router / strongSwan)
~~~
##### CLOUDSTACK VERSION
~~~
4.22.0.0
~~~
##### SUMMARY
Today a VPN Customer Gateway requires a fixed, resolvable peer IP/FQDN in the
`Gateway` field. This makes it impossible to terminate a site-to-site IPsec
tunnel against a remote endpoint that has a **dynamic public IP** (a very common
case: branch offices / remote sites behind a consumer or SME ISP link with no
static IP), where the remote peer must instead be identified by an **IKE
identity (ID)** rather than by its source IP.
The underlying engine (strongSwan on the VR) fully supports this scenario via
`right=%any` + `rightid=`. The limitation is purely in the CloudStack
orchestration layer, which models and identifies the peer by IP only.
It would be valuable to allow a Customer Gateway to be created **without a fixed
peer IP**, identifying the remote peer by an ID instead, so the VR acts as a pure
responder for a dynamic-IP peer.
##### CURRENT BEHAVIOUR
When the remote site has no static IP, there is no supported way to configure
the tunnel:
* The `Gateway` field validates the input as an IP/FQDN and rejects anything
that is not a single resolvable address. For example, entering `0.0.0.0/0`
returns:
~~~
The customer gateway ip/Domain 0.0.0.0/0 is invalid!
~~~
* If a Customer Gateway ends up with a null/`0.0.0.0` peer, the VR
(`CsSite2SiteVpn` in `systemvm/debian/opt/cloud/bin/configure.py`) generates a
broken configuration:
* the strongSwan connection is written with `right=0.0.0.0` and `auto=route`,
which makes charon try to *initiate/route* toward a null address
(`installing trap failed, remote address unknown` in `charon` log);
* the INPUT firewall rule for IKE/ESP is generated with `-s 0.0.0.0`
(the null host, which matches no real packet) instead of `-s 0.0.0.0/0`
(any), so the remote peer's IKE packets are silently dropped by the
`INPUT DROP` policy before reaching charon.
* There is no field on the Customer Gateway to declare a remote **ID**. When we manually open the INPUT firewall, the session establishes without identity verification.
Net result: a dynamic-IP, ID-authenticated remote peer cannot be configured
through the UI/API at all.
##### EXPECTED BEHAVIOUR
Allow a Customer Gateway to represent a **dynamic-IP peer**:
* Make the peer `Gateway` IP optional **when** a remote ID / peer identity is
provided (new field). The remote ID replaces the IP as the peer's
authentication identity (IKE ID types: IPv4/IPv6 address, FQDN, RFC822/email,
or DN).
* On the VR, when the peer is dynamic, `CsSite2SiteVpn` should generate:
* `right=%any`
* `rightid=`
* `auto=add` (responder only — the VR cannot initiate toward an unknown IP)
* the PSK indexed by the remote **ID** in `ipsec.*.secrets` (not by IP)
* an INPUT firewall rule opening UDP/500, UDP/4500 and ESP (proto 50) toward
the source-NAT IP, either with `-s 0.0.0.0/0` or restricted to an
operator-supplied source range (possibly a list)
* Reuse the existing **Passive** mode semantics (the VR already supports waiting
for the remote side to initiate, used today for VPC-to-VPC), since a dynamic
peer is inherently the initiator.
This has been validated manually on a 4.22 VR (strongSwan 5.9.8): with
`right=%any` / `rightid=` / PSK-by-ID and the INPUT rule opened, an IKEv2
tunnel from a dynamic-IP peer authenticating by ID establishes correctly and
passes traffic both ways (`ESTABLISHED` + `INSTALLED, TUNNEL`, bidirectional
`bytes_i` / `bytes_o`). The only blocker to native support is the orchestration
layer.
##### PROPOSED IMPLEMENTATION (for discussion)
* **API / DB / UI**: add an optional `remoteid` (peer identity) attribute to
Create/Update VPN Customer Gateway; make `gateway` optional when `remoteid`
is set; expose a clear "dynamic peer IP" indication in the UI.
* **VR (`CsSite2SiteVpn` in `configure.py`)**: branch on dynamic peer to emit
`right=%any`, `rightid`, `auto=add`, PSK-by-ID, and the open INPUT rule.
* **Tests**: extend `test/integration/smoke/test_vpc_vpn.py` with a
dynamic-peer / responder case.
##### SECURITY CONSIDERATIONS
Because a dynamic peer cannot be filtered by source IP, this mode opens
UDP/500 + UDP/4500 + ESP on the public interface. To keep this safe
and explicit:
* the feature should be **opt-in** (an explicit "dynamic peer" flag on the
Customer Gateway), never a silent fallback;
* `rightid` should be **mandatory** in this mode so the peer is constrained to a
known identity;
* IKEv2 should be used (no PSK-hash exposure, unlike IKEv1 aggressive mode);
* the UI should warn that the PSK becomes the primary authentication barrier and
must be long and random;
* optionally allow restricting the INPUT rule to an operator-supplied source
CIDR (e.g. the remote ISP's known range) instead of `0.0.0.0/0`. As operators oftens have multiple CIDR a list of CIDR would be better.
##### ENVIRONMENT (where observed)
~~~
CloudStack 4.22.0.0
System VM template: systemvm-kvm-4.22.0-x86_64
Virtual Router strongSwan: 5.9.8
Tunnel: IKEv2, PSK, remote peer behind NAT with dynamic public IP,
authenticating by RFC822-style ID
~~~
Contributor guide
Research direction
Start with the Customer Gateway Create/Update API, database and UI paths, then read CsSite2SiteVpn in systemvm/debian/opt/cloud/bin/configure.py to trace current peer and firewall generation. Review test/integration/smoke/test_vpc_vpn.py and the proposed dynamic-peer responder case. Done means an explicit dynamic-peer gateway accepts a remote ID and produces the described responder configuration, firewall behavior, and passing integration coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, python
- Domain
- infrastructure, networking, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100