Skip to content

Commit ec1fe3b

Browse files
authored
feature(gateway): add VPNaaS support (#306)
1 parent 014c955 commit ec1fe3b

13 files changed

+1897
-8
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.idea
2+
.vscode
23
/go.work
34
/go.work.sum
45
temp/

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ See updating [Changelog example here](https://keepachangelog.com/en/1.0.0/)
55

66
## [Unreleased]
77

8+
### Added
9+
- **Experimental**, Gateway: support for VPN feature. Note that VPN feature is currently in beta, you can learn more about it on the [product page](https://upcloud.com/resources/docs/networking#nat-and-vpn-gateways)
10+
811
## [8.2.0]
912

1013
### Added

upcloud/gateway.go

+134-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,23 @@ import "time"
55
// GatewayConfiguredStatus represents a desired status of the service
66
type GatewayConfiguredStatus string
77

8-
// GatewayConfiguredStatus represents a current actual status of the service
8+
// GatewayConfiguredStatus represents current, actual status of the service
99
type GatewayOperationalState string
1010

1111
// GatewayFeature represents a feature of the service
1212
type GatewayFeature string
1313

14+
// GatewayTunnelOperationalState represents current, actual status of the tunnel
15+
type GatewayTunnelOperationalState string
16+
17+
type (
18+
GatewayConnectionType string
19+
GatewayRouteType string
20+
GatewayIPSecAuthType string
21+
GatewayIPSecAlgorithm string
22+
GatewayIPSecIntegrityAlgorithm string
23+
)
24+
1425
const (
1526
GatewayConfiguredStatusStarted GatewayConfiguredStatus = "started"
1627
GatewayConfiguredStatusStopped GatewayConfiguredStatus = "stopped"
@@ -30,14 +41,55 @@ const (
3041
GatewayOperationalStateDeleteLinkNetwork GatewayOperationalState = "delete-link-network"
3142
GatewayOperationalStateDeleteService GatewayOperationalState = "delete-service"
3243

33-
// GatewayFeatureNAT is the network address translation (NAT) feature of the network gateway
44+
GatewayTunnelOperationalStateUninitialized GatewayTunnelOperationalState = "uninitialized"
45+
GatewayTunnelOperationalStateCreated GatewayTunnelOperationalState = "created"
46+
GatewayTunnelOperationalStateConnecting GatewayTunnelOperationalState = "connecting"
47+
GatewayTunnelOperationalStateEstabilished GatewayTunnelOperationalState = "established"
48+
GatewayTunnelOperationalStateRekeying GatewayTunnelOperationalState = "rekeying"
49+
GatewayTunnelOperationalStateRekeyed GatewayTunnelOperationalState = "rekeyed"
50+
GatewayTunnelOperationalStateDeleting GatewayTunnelOperationalState = "deleting"
51+
GatewayTunnelOperationalStateDestroying GatewayTunnelOperationalState = "destroying"
52+
GatewayTunnelOperationalStateUnknown GatewayTunnelOperationalState = "unknown"
53+
54+
// GatewayFeatureNAT is a Network Address Translation (NAT) service that offers a way for cloud servers in SDN private networks to connect to the Internet through the public IP assigned to the network gateway service
3455
GatewayFeatureNAT GatewayFeature = "nat"
56+
57+
// GatewayFeatureVPN is a Virtual Private Network (VPN) service used to establish an encrypted network connection when using public networks
58+
// Please note that VPN feature is currently in beta. You can learn more about it on its [product page]
59+
// Also note that VPN is available only in some of the gateway plans. To check which plans support VPN, you can use the GetGatewayPlans method.
60+
//
61+
// [product page]: https://upcloud.com/resources/docs/networking#nat-and-vpn-gateways
62+
GatewayFeatureVPN GatewayFeature = "vpn"
63+
64+
GatewayConnectionTypeIPSec GatewayConnectionType = "ipsec"
65+
66+
GatewayRouteTypeStatic GatewayRouteType = "static"
67+
68+
GatewayTunnelIPSecAuthTypePSK GatewayIPSecAuthType = "psk"
69+
70+
GatewayIPSecAlgorithm_aes128gcm16 GatewayIPSecAlgorithm = "aes128gcm16"
71+
GatewayIPSecAlgorithm_aes128gcm128 GatewayIPSecAlgorithm = "aes128gcm128"
72+
GatewayIPSecAlgorithm_aes192gcm16 GatewayIPSecAlgorithm = "aes192gcm16"
73+
GatewayIPSecAlgorithm_aes192gcm128 GatewayIPSecAlgorithm = "aes192gcm128"
74+
GatewayIPSecAlgorithm_aes256gcm16 GatewayIPSecAlgorithm = "aes256gcm16"
75+
GatewayIPSecAlgorithm_aes256gcm128 GatewayIPSecAlgorithm = "aes256gcm128"
76+
GatewayIPSecAlgorithm_aes128 GatewayIPSecAlgorithm = "aes128"
77+
GatewayIPSecAlgorithm_aes192 GatewayIPSecAlgorithm = "aes192"
78+
GatewayIPSecAlgorithm_aes256 GatewayIPSecAlgorithm = "aes256"
79+
80+
GatewayIPSecIntegrityAlgorithm_aes128gmac GatewayIPSecIntegrityAlgorithm = "aes128gmac"
81+
GatewayIPSecIntegrityAlgorithm_aes256gmac GatewayIPSecIntegrityAlgorithm = "aes256gmac"
82+
GatewayIPSecIntegrityAlgorithm_sha1 GatewayIPSecIntegrityAlgorithm = "sha1"
83+
GatewayIPSecIntegrityAlgorithm_sha256 GatewayIPSecIntegrityAlgorithm = "sha256"
84+
GatewayIPSecIntegrityAlgorithm_sha384 GatewayIPSecIntegrityAlgorithm = "sha384"
85+
GatewayIPSecIntegrityAlgorithm_sha512 GatewayIPSecIntegrityAlgorithm = "sha512"
3586
)
3687

3788
type Gateway struct {
3889
UUID string `json:"uuid,omitempty"`
3990
Name string `json:"name,omitempty"`
4091
Zone string `json:"zone,omitempty"`
92+
Plan string `json:"plan,omitempty"`
4193
Labels []Label `json:"labels,omitempty"`
4294
ConfiguredStatus GatewayConfiguredStatus `json:"configured_status,omitempty"`
4395
OperationalState GatewayOperationalState `json:"operational_state,omitempty"`
@@ -46,6 +98,7 @@ type Gateway struct {
4698
CreatedAt time.Time `json:"created_at,omitempty"`
4799
UpdatedAt time.Time `json:"updated_at,omitempty"`
48100
Addresses []GatewayAddress `json:"addresses,omitempty"`
101+
Connections []GatewayConnection `json:"connections,omitempty"`
49102
}
50103

51104
type GatewayAddress struct {
@@ -57,3 +110,82 @@ type GatewayRouter struct {
57110
CreatedAt time.Time `json:"created_at,omitempty"`
58111
UUID string `json:"uuid,omitempty"`
59112
}
113+
114+
type GatewayConnection struct {
115+
Name string `json:"name,omitempty"`
116+
Type GatewayConnectionType `json:"type,omitempty"`
117+
LocalRoutes []GatewayRoute `json:"local_routes,omitempty"`
118+
RemoteRoutes []GatewayRoute `json:"remote_routes,omitempty"`
119+
Tunnels []GatewayTunnel `json:"tunnels,omitempty"`
120+
CreatedAt time.Time `json:"created_at,omitempty"`
121+
UpdatedAt time.Time `json:"updated_at,omitempty"`
122+
}
123+
124+
type GatewayRoute struct {
125+
Name string `json:"name,omitempty"`
126+
StaticNetwork string `json:"static_network,omitempty"`
127+
Type GatewayRouteType `json:"type,omitempty"`
128+
}
129+
130+
type GatewayTunnel struct {
131+
Name string `json:"name,omitempty"`
132+
LocalAddress GatewayTunnelLocalAddress `json:"local_address,omitempty"`
133+
RemoteAddress GatewayTunnelRemoteAddress `json:"remote_address,omitempty"`
134+
IPSec GatewayTunnelIPSec `json:"ipsec,omitempty"`
135+
OperationalState GatewayTunnelOperationalState `json:"operational_state,omitempty"`
136+
CreatedAt time.Time `json:"created_at,omitempty"`
137+
UpdatedAt time.Time `json:"updated_at,omitempty"`
138+
}
139+
140+
type GatewayTunnelLocalAddress struct {
141+
// Name of the UpCloud gateway address; should correspond to the name of one of the gateway address structs
142+
Name string `json:"name,omitempty"`
143+
}
144+
145+
type GatewayTunnelRemoteAddress struct {
146+
// Address is a remote peer address VPN will connect to; must be global non-private unicast IP address.
147+
Address string `json:"address,omitempty"`
148+
}
149+
150+
type GatewayTunnelIPSec struct {
151+
// Tunnel IPSec authentication object
152+
Authentication GatewayTunnelIPSecAuth `json:"authentication,omitempty"`
153+
// IKE SA rekey time in seconds
154+
RekeyTime int `json:"rekey_time,omitempty"`
155+
// IKE child SA rekey time in seconds
156+
ChildRekeyTime int `json:"child_rekey_time,omitempty"`
157+
// Delay before sending Dead Peer Detection packets if no traffic is detected, in seconds
158+
DPDDelay int `json:"dpd_delay,omitempty"`
159+
// Timeout period for DPD reply before considering the peer to be dead, in seconds
160+
DPDTimeout int `json:"dpd_timeout,omitempty"`
161+
// Maximum IKE SA lifetime in seconds
162+
IKELifetime int `json:"ike_lifetime,omitempty"`
163+
// List of Phase 1: Proposal algorithms
164+
Phase1Algorithms []GatewayIPSecAlgorithm `json:"phase1_algorithms,omitempty"`
165+
// List of Phase 1 integrity algorithms
166+
Phase1IntegrityAlgorithms []GatewayIPSecIntegrityAlgorithm `json:"phase1_integrity_algorithms,omitempty"`
167+
// List of Phase 1 Diffie-Hellman group numbers
168+
Phase1DHGroupNumbers []int `json:"phase1_dh_group_numbers,omitempty"`
169+
// List of Phase 2: Security Association algorithms
170+
Phase2Algorithms []GatewayIPSecAlgorithm `json:"phase2_algorithms,omitempty"`
171+
// List of Phase 2 integrity algorithms
172+
Phase2IntegrityAlgorithms []GatewayIPSecIntegrityAlgorithm `json:"phase2_integrity_algorithms,omitempty"`
173+
// List of Phase 2 Diffie-Hellman group numbers
174+
Phase2DHGroupNumbers []int `json:"phase2_dh_group_numbers,omitempty"`
175+
}
176+
177+
type GatewayTunnelIPSecAuth struct {
178+
Authentication GatewayIPSecAuthType `json:"authentication,omitempty"`
179+
// PSK is a user-provided pre-shared key.
180+
// Note that this field is only meant to be used when providing API with your pre-shared key; it will always be empty in API responses
181+
PSK string `json:"psk,omitempty"`
182+
}
183+
184+
type GatewayPlan struct {
185+
Name string `json:"name,omitempty"`
186+
PerGatewayBandwidthMbps int `json:"per_gateway_bandwidth_mbps,omitempty"`
187+
PerGatewayMaxConnections int `json:"per_gateway_max_connections,omitempty"`
188+
ServerNumber int `json:"server_number,omitempty"`
189+
SupportedFeatures []GatewayFeature `json:"supported_features,omitempty"`
190+
VPNTunnelAmount int `json:"vpn_tunnel_amount,omitempty"`
191+
}

upcloud/gateway_test.go

+163-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package upcloud
22

33
import (
44
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/require"
58
)
69

710
func TestGateway(t *testing.T) {
@@ -18,7 +21,8 @@ func TestGateway(t *testing.T) {
1821
"configured_status": "started",
1922
"created_at": "2022-12-01T09:04:08.529138Z",
2023
"features": [
21-
"nat"
24+
"nat",
25+
"vpn"
2226
],
2327
"name": "example-gateway",
2428
"operational_state": "running",
@@ -36,10 +40,66 @@ func TestGateway(t *testing.T) {
3640
],
3741
"updated_at": "2022-12-01T19:04:08.529138Z",
3842
"uuid": "10c153e0-12e4-4dea-8748-4f34850ff76d",
39-
"zone": "fi-hel1"
43+
"zone": "fi-hel1",
44+
"plan": "advanced",
45+
"connections": [
46+
{
47+
"name": "example-connection",
48+
"type": "ipsec",
49+
"local_routes": [
50+
{
51+
"name": "upcloud-example-route",
52+
"type": "static",
53+
"static_network": "10.0.0.0/24"
54+
}
55+
],
56+
"remote_routes": [
57+
{
58+
"name": "remote-example-route",
59+
"type": "static",
60+
"static_network": "10.0.1.0/24"
61+
}
62+
],
63+
"tunnels": [
64+
{
65+
"name": "example-tunnel-1",
66+
"local_address": {
67+
"name": "public-ip-1"
68+
},
69+
"remote_address": {
70+
"address": "100.10.0.111"
71+
},
72+
"ipsec": {
73+
"authentication": {
74+
"authentication": "psk"
75+
},
76+
"child_rekey_time": 1440,
77+
"dpd_delay": 30,
78+
"dpd_timeout": 120,
79+
"ike_lifetime": 86400,
80+
"phase1_algorithms": ["aes128gcm128", "aes256gcm128"],
81+
"phase1_dh_group_numbers": [14, 16, 18, 19, 20, 21],
82+
"phase1_integrity_algorithms": ["aes128gmac", "aes256gmac", "sha256", "sha384", "sha512"],
83+
"phase2_algorithms": ["aes128gcm128", "aes256gcm128"],
84+
"phase2_dh_group_numbers": [14, 16, 18, 19, 20, 21],
85+
"phase2_integrity_algorithms": ["aes128gmac", "aes256gmac", "sha256", "sha384", "sha512"],
86+
"rekey_time": 14400
87+
},
88+
"operational_state": "established",
89+
"created_at": "2022-12-01T09:04:08.529138Z",
90+
"updated_at": "2022-12-01T09:04:08.529138Z"
91+
}
92+
],
93+
"created_at": "2022-12-01T09:04:08.529138Z",
94+
"updated_at": "2022-12-01T09:04:08.529138Z"
95+
}
96+
]
4097
}
4198
`
4299

100+
timestamp, err := time.Parse(time.RFC3339, "2022-12-01T09:04:08.529138Z")
101+
require.NoError(t, err)
102+
43103
gateway := &Gateway{
44104
Addresses: []GatewayAddress{{
45105
Address: "192.0.2.96",
@@ -49,6 +109,7 @@ func TestGateway(t *testing.T) {
49109
CreatedAt: timeParse("2022-12-01T09:04:08.529138Z"),
50110
Features: []GatewayFeature{
51111
GatewayFeatureNAT,
112+
GatewayFeatureVPN,
52113
},
53114
Name: "example-gateway",
54115
OperationalState: "running",
@@ -64,7 +125,107 @@ func TestGateway(t *testing.T) {
64125
UpdatedAt: timeParse("2022-12-01T19:04:08.529138Z"),
65126
UUID: "10c153e0-12e4-4dea-8748-4f34850ff76d",
66127
Zone: "fi-hel1",
128+
Plan: "advanced",
129+
Connections: []GatewayConnection{
130+
{
131+
Name: "example-connection",
132+
Type: GatewayConnectionTypeIPSec,
133+
LocalRoutes: []GatewayRoute{
134+
{
135+
Name: "upcloud-example-route",
136+
Type: GatewayRouteTypeStatic,
137+
StaticNetwork: "10.0.0.0/24",
138+
},
139+
},
140+
RemoteRoutes: []GatewayRoute{
141+
{
142+
Name: "remote-example-route",
143+
Type: GatewayRouteTypeStatic,
144+
StaticNetwork: "10.0.1.0/24",
145+
},
146+
},
147+
Tunnels: []GatewayTunnel{
148+
{
149+
Name: "example-tunnel-1",
150+
LocalAddress: GatewayTunnelLocalAddress{
151+
Name: "public-ip-1",
152+
},
153+
RemoteAddress: GatewayTunnelRemoteAddress{
154+
Address: "100.10.0.111",
155+
},
156+
IPSec: GatewayTunnelIPSec{
157+
Authentication: GatewayTunnelIPSecAuth{
158+
Authentication: GatewayTunnelIPSecAuthTypePSK,
159+
},
160+
ChildRekeyTime: 1440,
161+
DPDDelay: 30,
162+
DPDTimeout: 120,
163+
IKELifetime: 86400,
164+
Phase1Algorithms: []GatewayIPSecAlgorithm{
165+
GatewayIPSecAlgorithm_aes128gcm128,
166+
GatewayIPSecAlgorithm_aes256gcm128,
167+
},
168+
Phase1DHGroupNumbers: []int{14, 16, 18, 19, 20, 21},
169+
Phase1IntegrityAlgorithms: []GatewayIPSecIntegrityAlgorithm{
170+
GatewayIPSecIntegrityAlgorithm_aes128gmac,
171+
GatewayIPSecIntegrityAlgorithm_aes256gmac,
172+
GatewayIPSecIntegrityAlgorithm_sha256,
173+
GatewayIPSecIntegrityAlgorithm_sha384,
174+
GatewayIPSecIntegrityAlgorithm_sha512,
175+
},
176+
Phase2Algorithms: []GatewayIPSecAlgorithm{
177+
GatewayIPSecAlgorithm_aes128gcm128,
178+
GatewayIPSecAlgorithm_aes256gcm128,
179+
},
180+
Phase2DHGroupNumbers: []int{14, 16, 18, 19, 20, 21},
181+
Phase2IntegrityAlgorithms: []GatewayIPSecIntegrityAlgorithm{
182+
GatewayIPSecIntegrityAlgorithm_aes128gmac,
183+
GatewayIPSecIntegrityAlgorithm_aes256gmac,
184+
GatewayIPSecIntegrityAlgorithm_sha256,
185+
GatewayIPSecIntegrityAlgorithm_sha384,
186+
GatewayIPSecIntegrityAlgorithm_sha512,
187+
},
188+
RekeyTime: 14400,
189+
},
190+
OperationalState: GatewayTunnelOperationalStateEstabilished,
191+
CreatedAt: timestamp,
192+
UpdatedAt: timestamp,
193+
},
194+
},
195+
CreatedAt: timestamp,
196+
UpdatedAt: timestamp,
197+
},
198+
},
67199
}
68200

69201
testJSON(t, &Gateway{}, gateway, jsonStr)
70202
}
203+
204+
func TestGatewayPlan(t *testing.T) {
205+
t.Parallel()
206+
207+
jsonStr := `
208+
{
209+
"name": "advanced",
210+
"per_gateway_bandwidth_mbps": 10000,
211+
"per_gateway_max_connections": 100000,
212+
"server_number": 2,
213+
"supported_features": [
214+
"nat",
215+
"vpn"
216+
],
217+
"vpn_tunnel_amount": 10
218+
}
219+
`
220+
221+
plan := &GatewayPlan{
222+
Name: "advanced",
223+
PerGatewayBandwidthMbps: 10000,
224+
PerGatewayMaxConnections: 100000,
225+
ServerNumber: 2,
226+
SupportedFeatures: []GatewayFeature{GatewayFeatureNAT, GatewayFeatureVPN},
227+
VPNTunnelAmount: 10,
228+
}
229+
230+
testJSON(t, &GatewayPlan{}, plan, jsonStr)
231+
}

0 commit comments

Comments
 (0)