Skip to content

Commit 179c6a7

Browse files
committed
ikev2 vpn backed by vault pkiengine
1 parent e107f9a commit 179c6a7

37 files changed

Lines changed: 1458 additions & 49 deletions

api/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666
<artifactId>cloud-framework-direct-download</artifactId>
6767
<version>${project.version}</version>
6868
</dependency>
69+
<dependency>
70+
<groupId>com.bettercloud</groupId>
71+
<artifactId>vault-java-driver</artifactId>
72+
</dependency>
6973
</dependencies>
7074
<build>
7175
<plugins>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.exception;
18+
19+
/**
20+
* @since 4.12.0.0
21+
*/
22+
public class RemoteAccessVpnException extends ManagementServerException {
23+
private static final long serialVersionUID = -5851224796385227880L;
24+
25+
public RemoteAccessVpnException(String message) {
26+
super(message);
27+
}
28+
}

api/src/main/java/com/cloud/network/RemoteAccessVpn.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ enum State {
3232

3333
String getIpsecPresharedKey();
3434

35+
String getCaCertificate();
36+
3537
String getLocalIp();
3638

3739
Long getNetworkId();
@@ -42,4 +44,6 @@ enum State {
4244

4345
@Override
4446
boolean isDisplay();
47+
48+
String getVpnType();
4549
}

api/src/main/java/com/cloud/network/vpn/RemoteAccessVpnService.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,23 @@
2222
import org.apache.cloudstack.api.command.user.vpn.ListVpnUsersCmd;
2323

2424
import com.cloud.exception.NetworkRuleConflictException;
25+
import com.cloud.exception.RemoteAccessVpnException;
2526
import com.cloud.exception.ResourceUnavailableException;
2627
import com.cloud.network.RemoteAccessVpn;
2728
import com.cloud.network.VpnUser;
2829
import com.cloud.user.Account;
2930
import com.cloud.utils.Pair;
3031

3132
public interface RemoteAccessVpnService {
32-
static final String RemoteAccessVpnClientIpRangeCK = "remote.access.vpn.client.iprange";
33+
enum Type {
34+
L2TP, IKEV2
35+
}
3336

34-
RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange, boolean openFirewall, Boolean forDisplay) throws NetworkRuleConflictException;
37+
String RemoteAccessVpnTypeConfigKey = "remote.access.vpn.type";
38+
String RemoteAccessVpnClientIpRangeCK = "remote.access.vpn.client.iprange";
39+
40+
RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange, boolean openFirewall, Boolean forDisplay)
41+
throws NetworkRuleConflictException, RemoteAccessVpnException;
3542

3643
boolean destroyRemoteAccessVpnForIp(long ipId, Account caller, boolean forceCleanup) throws ResourceUnavailableException;
3744

api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateRemoteAccessVpnCmd.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.cloud.event.EventTypes;
3434
import com.cloud.exception.InvalidParameterValueException;
3535
import com.cloud.exception.NetworkRuleConflictException;
36+
import com.cloud.exception.RemoteAccessVpnException;
3637
import com.cloud.exception.ResourceUnavailableException;
3738
import com.cloud.network.IpAddress;
3839
import com.cloud.network.RemoteAccessVpn;
@@ -156,6 +157,10 @@ public void create() {
156157
s_logger.info("Network rule conflict: " + e.getMessage());
157158
s_logger.trace("Network Rule Conflict: ", e);
158159
throw new ServerApiException(ApiErrorCode.NETWORK_RULE_CONFLICT_ERROR, e.getMessage());
160+
} catch (RemoteAccessVpnException e) {
161+
s_logger.info("Create vpn internal error: " + e.getMessage());
162+
s_logger.trace("Create vpn internal error: ", e);
163+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
159164
}
160165
}
161166

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//Licensed to the Apache Software Foundation (ASF) under one
2+
//or more contributor license agreements. See the NOTICE file
3+
//distributed with this work for additional information
4+
//regarding copyright ownership. The ASF licenses this file
5+
//to you under the Apache License, Version 2.0 (the
6+
//"License"); you may not use this file except in compliance
7+
//with the License. You may obtain a copy of the License at
8+
//
9+
//http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
//Unless required by applicable law or agreed to in writing,
12+
//software distributed under the License is distributed on an
13+
//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
//KIND, either express or implied. See the License for the
15+
//specific language governing permissions and limitations
16+
//under the License.
17+
package org.apache.cloudstack.api.command.user.vpn;
18+
19+
import javax.inject.Inject;
20+
21+
import org.apache.cloudstack.acl.RoleType;
22+
import org.apache.cloudstack.api.APICommand;
23+
import org.apache.cloudstack.api.ApiConstants;
24+
import org.apache.cloudstack.api.BaseCmd;
25+
import org.apache.cloudstack.api.Parameter;
26+
import org.apache.cloudstack.api.response.CertificateResponse;
27+
import org.apache.cloudstack.pki.PkiDetail;
28+
import org.apache.cloudstack.pki.PkiManager;
29+
30+
import com.cloud.domain.Domain;
31+
import com.cloud.exception.RemoteAccessVpnException;
32+
import com.cloud.user.Account;
33+
import com.cloud.user.DomainService;
34+
import com.cloud.utils.exception.CloudRuntimeException;
35+
36+
/**
37+
* @author Khosrow Moossavi
38+
* @since 4.12.0.0
39+
*/
40+
@APICommand(
41+
name = ListRemoteAccessVpnCaCertificatesCmd.APINAME,
42+
description = "Lists the CA public certificate(s) as support by the configured/provided CA plugin",
43+
responseObject = CertificateResponse.class,
44+
requestHasSensitiveInfo = false,
45+
responseHasSensitiveInfo = false,
46+
since = "4.12.0.0",
47+
authorized = {
48+
RoleType.Admin,
49+
RoleType.ResourceAdmin,
50+
RoleType.DomainAdmin,
51+
RoleType.User
52+
}
53+
)
54+
public class ListRemoteAccessVpnCaCertificatesCmd extends BaseCmd {
55+
public static final String APINAME = "listVpnCaCertificate";
56+
57+
@Inject private DomainService domainService;
58+
@Inject private PkiManager pkiManager;
59+
60+
/////////////////////////////////////////////////////
61+
//////////////// API parameters /////////////////////
62+
/////////////////////////////////////////////////////
63+
64+
@Parameter(name = ApiConstants.DOMAIN, type = CommandType.STRING, description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
65+
private String domain;
66+
67+
/////////////////////////////////////////////////////
68+
/////////////////// Accessors ///////////////////////
69+
/////////////////////////////////////////////////////
70+
71+
public String getDomain() {
72+
return domain;
73+
}
74+
75+
/////////////////////////////////////////////////////
76+
/////////////// API Implementation///////////////////
77+
/////////////////////////////////////////////////////
78+
79+
@Override
80+
public void execute() {
81+
final PkiDetail certificate;
82+
83+
try {
84+
Domain domain = domainService.getDomain(getDomain());
85+
certificate = pkiManager.getCertificate(domain);
86+
} catch (final RemoteAccessVpnException e) {
87+
throw new CloudRuntimeException("Failed to get CA certificates for given domain");
88+
}
89+
90+
final CertificateResponse certificateResponse = new CertificateResponse("cacertificates");
91+
certificateResponse.setCertificate(certificate.getIssuingCa());
92+
certificateResponse.setResponseName(getCommandName());
93+
setResponseObject(certificateResponse);
94+
}
95+
96+
@Override
97+
public String getCommandName() {
98+
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
99+
}
100+
101+
@Override
102+
public long getEntityOwnerId() {
103+
return Account.ACCOUNT_TYPE_NORMAL;
104+
}
105+
}

api/src/main/java/org/apache/cloudstack/api/response/RemoteAccessVpnResponse.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ public class RemoteAccessVpnResponse extends BaseResponse implements ControlledE
7777
@Param(description = "is vpn for display to the regular user", since = "4.4", authorized = {RoleType.Admin})
7878
private Boolean forDisplay;
7979

80+
@SerializedName(ApiConstants.TYPE)
81+
@Param(description = "the type of remote access vpn implementation")
82+
private String type;
83+
84+
@SerializedName(ApiConstants.CERTIFICATE)
85+
@Param(description = "the client certificate")
86+
private String certificate;
87+
8088
public void setPublicIp(String publicIp) {
8189
this.publicIp = publicIp;
8290
}
@@ -129,4 +137,12 @@ public void setId(String id) {
129137
public void setForDisplay(Boolean forDisplay) {
130138
this.forDisplay = forDisplay;
131139
}
140+
141+
public void setType(String type) {
142+
this.type = type;
143+
}
144+
145+
public void setCertificate(String certificate) {
146+
this.certificate = certificate;
147+
}
132148
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.pki;
18+
19+
/**
20+
* @author Khosrow Moossavi
21+
* @since 4.12.0.0
22+
*/
23+
public class PkiDetail {
24+
private String certificate;
25+
private String issuingCa;
26+
private String privateKey;
27+
private String privateKeyType;
28+
private String serialNumber;
29+
30+
public PkiDetail certificate(final String certificate) {
31+
this.certificate = certificate;
32+
return this;
33+
}
34+
35+
public PkiDetail issuingCa(final String issuingCa) {
36+
this.issuingCa = issuingCa;
37+
return this;
38+
}
39+
40+
public PkiDetail privateKey(final String privateKey) {
41+
this.privateKey = privateKey;
42+
return this;
43+
}
44+
45+
public PkiDetail privateKeyType(final String privateKeyType) {
46+
this.privateKeyType = privateKeyType;
47+
return this;
48+
}
49+
50+
public PkiDetail serialNumber(final String serialNumber) {
51+
this.serialNumber = serialNumber;
52+
return this;
53+
}
54+
55+
public String getCertificate() {
56+
return certificate;
57+
}
58+
59+
public String getIssuingCa() {
60+
return issuingCa;
61+
}
62+
63+
public String getPrivateKey() {
64+
return privateKey;
65+
}
66+
67+
public String getPrivateKeyType() {
68+
return privateKeyType;
69+
}
70+
71+
public String getSerialNumber() {
72+
return serialNumber;
73+
}
74+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.pki;
18+
19+
import com.cloud.domain.Domain;
20+
import com.cloud.exception.RemoteAccessVpnException;
21+
import com.cloud.utils.net.Ip;
22+
23+
/**
24+
* @author Khosrow Moossavi
25+
* @since 4.12.0.0
26+
*/
27+
public interface PkiManager {
28+
String CREDENTIAL_ISSUING_CA = "credential.issuing.ca";
29+
String CREDENTIAL_SERIAL_NUMBER = "credential.serial.number";
30+
String CREDENTIAL_CERTIFICATE = "credential.certificate";
31+
String CREDENTIAL_PRIVATE_KEY = "credential.private.key";
32+
33+
/**
34+
* Issue a Certificate for specific IP and specific Domain act as the CA
35+
*
36+
* @param domain object to extract name and id to be used to issuing CA
37+
* @param publicIp to be included in the certificate
38+
*
39+
* @return detail about just signed PKI, including issuing CA, certificate, private key and serial number
40+
*
41+
* @throws RemoteAccessVpnException
42+
*/
43+
PkiDetail issueCertificate(Domain domain, Ip publicIp) throws RemoteAccessVpnException;
44+
45+
/**
46+
* Get a Certificate for specific Domain act as the CA
47+
*
48+
* @param domain object to extract its id to be find the issuing CA
49+
*
50+
* @return details about signed PKI, including issuing CA, certificate and serial number
51+
*
52+
* @throws RemoteAccessVpnException
53+
*/
54+
PkiDetail getCertificate(Domain domain) throws RemoteAccessVpnException;
55+
}

0 commit comments

Comments
 (0)