Skip to content

Commit 05265c7

Browse files
shwstpprrohityadavcloud
authored andcommitted
framework/cluster: improve cluster service, integration API server
- mTLS implementation for cluster service communication - Listen only on the specified cluster node IP address instead of all interfaces - Validate incoming cluster service requests are from peer management servers based on the server's certificate dns name which can be through global config - ca.framework.cert.management.custom.san - Hardening of KVM command wrapper script exeicution - Improve API server integration port check - cloudstack-management.default: don't have JMX configuration if not needed. JMX is used for instrumentation; users who need to use it should enable it explicitly Co-authored-by: Abhishek Kumar <[email protected]> Co-authored-by: Wei Zhou <[email protected]> Co-authored-by: Rohit Yadav <[email protected]> Signed-off-by: Abhishek Kumar <[email protected]>
1 parent 14a42b7 commit 05265c7

File tree

37 files changed

+1391
-291
lines changed

37 files changed

+1391
-291
lines changed

api/src/main/java/org/apache/cloudstack/ca/CAManager.java

+8
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ public interface CAManager extends CAService, Configurable, PluggableService {
7777
"15",
7878
"The number of days before expiry of a client certificate, the validations are checked. Admins are alerted when auto-renewal is not allowed, otherwise auto-renewal is attempted.", true, ConfigKey.Scope.Cluster);
7979

80+
81+
ConfigKey<String> CertManagementCustomSubjectAlternativeName = new ConfigKey<>("Advanced", String.class,
82+
"ca.framework.cert.management.custom.san",
83+
"cloudstack.internal",
84+
"The custom Subject Alternative Name that will be added to the management server certificate. " +
85+
"The actual implementation will depend on the configured CA provider.",
86+
false);
87+
8088
/**
8189
* Returns a list of available CA provider plugins
8290
* @return returns list of CAProvider

core/src/main/java/com/cloud/resource/CommandWrapper.java

+26-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919

2020
package com.cloud.resource;
2121

22+
import org.apache.log4j.Logger;
23+
2224
import com.cloud.agent.api.Answer;
2325
import com.cloud.agent.api.Command;
24-
import org.apache.log4j.Logger;
26+
import com.cloud.utils.exception.CloudRuntimeException;
27+
import com.cloud.utils.script.Script;
2528

2629
public abstract class CommandWrapper<T extends Command, A extends Answer, R extends ServerResource> {
2730
protected Logger logger = Logger.getLogger(getClass());
@@ -32,4 +35,26 @@ public abstract class CommandWrapper<T extends Command, A extends Answer, R exte
3235
* @return A and the Answer from the command.
3336
*/
3437
public abstract A execute(T command, R serverResource);
38+
39+
protected String sanitizeBashCommandArgument(String input) {
40+
StringBuilder sanitized = new StringBuilder();
41+
for (char c : input.toCharArray()) {
42+
if ("\\\"'`$|&;()<>*?![]{}~".indexOf(c) != -1) {
43+
sanitized.append('\\');
44+
}
45+
sanitized.append(c);
46+
}
47+
return sanitized.toString();
48+
}
49+
50+
public void removeDpdkPort(String portToRemove) {
51+
logger.debug("Removing DPDK port: " + portToRemove);
52+
int port;
53+
try {
54+
port = Integer.valueOf(portToRemove);
55+
} catch (NumberFormatException nfe) {
56+
throw new CloudRuntimeException(String.format("Invalid DPDK port specified: '%s'", portToRemove));
57+
}
58+
Script.executeCommand("ovs-vsctl", "del-port", String.valueOf(port));
59+
}
3560
}

framework/ca/src/main/java/org/apache/cloudstack/framework/ca/CAProvider.java

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.security.GeneralSecurityException;
2323
import java.security.KeyStore;
2424
import java.security.KeyStoreException;
25+
import java.security.cert.CertificateParsingException;
2526
import java.security.cert.X509Certificate;
2627
import java.util.List;
2728
import java.util.Map;
@@ -45,6 +46,7 @@ public interface CAProvider {
4546

4647
/**
4748
* Issues certificate with provided options
49+
*
4850
* @param domainNames
4951
* @param ipAddresses
5052
* @param validityDays
@@ -104,4 +106,6 @@ public interface CAProvider {
104106
* @return returns description
105107
*/
106108
String getDescription();
109+
110+
boolean isManagementCertificate(java.security.cert.Certificate certificate) throws CertificateParsingException;
107111
}

framework/ca/src/main/java/org/apache/cloudstack/framework/ca/CAService.java

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.security.GeneralSecurityException;
2222
import java.security.KeyStore;
2323
import java.security.KeyStoreException;
24+
import java.security.cert.CertificateParsingException;
2425

2526
import javax.net.ssl.SSLContext;
2627
import javax.net.ssl.SSLEngine;
@@ -47,4 +48,6 @@ public interface CAService {
4748
* @return returns char[] passphrase
4849
*/
4950
char[] getKeyStorePassphrase();
51+
52+
boolean isManagementCertificate(java.security.cert.Certificate certificate) throws CertificateParsingException;
5053
}

framework/cluster/src/main/java/com/cloud/cluster/ClusterManager.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
// under the License.
1717
package com.cloud.cluster;
1818

19-
import org.apache.cloudstack.management.ManagementServerHost;
2019
import org.apache.cloudstack.framework.config.ConfigKey;
20+
import org.apache.cloudstack.management.ManagementServerHost;
2121

2222
import com.cloud.utils.component.Manager;
2323

@@ -77,6 +77,8 @@ public interface ClusterManager extends Manager {
7777
*/
7878
String getSelfPeerName();
7979

80+
String getSelfNodeIP();
81+
8082
long getManagementNodeId();
8183

8284
/**

framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,17 @@
4040
import javax.inject.Inject;
4141
import javax.naming.ConfigurationException;
4242

43-
import com.cloud.cluster.dao.ManagementServerStatusDao;
44-
import org.apache.cloudstack.management.ManagementServerHost;
4543
import org.apache.cloudstack.framework.config.ConfigDepot;
4644
import org.apache.cloudstack.framework.config.ConfigKey;
4745
import org.apache.cloudstack.framework.config.Configurable;
4846
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
47+
import org.apache.cloudstack.management.ManagementServerHost;
4948
import org.apache.cloudstack.utils.identity.ManagementServerNode;
5049
import org.apache.log4j.Logger;
5150

5251
import com.cloud.cluster.dao.ManagementServerHostDao;
5352
import com.cloud.cluster.dao.ManagementServerHostPeerDao;
53+
import com.cloud.cluster.dao.ManagementServerStatusDao;
5454
import com.cloud.utils.DateUtil;
5555
import com.cloud.utils.Profiler;
5656
import com.cloud.utils.component.ComponentLifecycle;
@@ -130,7 +130,7 @@ public ClusterManagerImpl() {
130130
// recursive remote calls between nodes
131131
//
132132
_executor = Executors.newCachedThreadPool(new NamedThreadFactory("Cluster-Worker"));
133-
setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK);
133+
setRunLevel(ComponentLifecycle.RUN_LEVEL_COMPONENT);
134134
}
135135

136136
private void registerRequestPdu(final ClusterServiceRequestPdu pdu) {
@@ -475,6 +475,7 @@ public String getSelfPeerName() {
475475
return Long.toString(_msId);
476476
}
477477

478+
@Override
478479
public String getSelfNodeIP() {
479480
return _clusterNodeIP;
480481
}

framework/cluster/src/main/java/com/cloud/cluster/ClusterServiceAdapter.java

-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,5 @@ public interface ClusterServiceAdapter extends Adapter {
2828

2929
public ClusterService getPeerService(String strPeer) throws RemoteException;
3030

31-
public String getServiceEndpointName(String strPeer);
32-
3331
public int getServicePort();
3432
}

framework/cluster/src/main/java/com/cloud/cluster/ClusterServiceServletAdapter.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
import javax.inject.Inject;
2424
import javax.naming.ConfigurationException;
2525

26-
import org.apache.log4j.Logger;
26+
import org.apache.cloudstack.ca.CAManager;
2727
import org.apache.cloudstack.framework.config.ConfigDepot;
28+
import org.apache.log4j.Logger;
2829

2930
import com.cloud.cluster.dao.ManagementServerHostDao;
3031
import com.cloud.utils.NumbersUtil;
@@ -44,14 +45,16 @@ public class ClusterServiceServletAdapter extends AdapterBase implements Cluster
4445
@Inject
4546
private ManagementServerHostDao _mshostDao;
4647
@Inject
48+
private CAManager caService;
49+
@Inject
4750
protected ConfigDepot _configDepot;
4851

4952
private ClusterServiceServletContainer _servletContainer;
5053

5154
private int _clusterServicePort = DEFAULT_SERVICE_PORT;
5255

5356
public ClusterServiceServletAdapter() {
54-
setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK);
57+
setRunLevel(ComponentLifecycle.RUN_LEVEL_COMPONENT);
5558
}
5659

5760
@Override
@@ -66,12 +69,10 @@ public ClusterService getPeerService(String strPeer) throws RemoteException {
6669
String serviceUrl = getServiceEndpointName(strPeer);
6770
if (serviceUrl == null)
6871
return null;
69-
70-
return new ClusterServiceServletImpl(serviceUrl);
72+
return new ClusterServiceServletImpl(serviceUrl, caService);
7173
}
7274

73-
@Override
74-
public String getServiceEndpointName(String strPeer) {
75+
protected String getServiceEndpointName(String strPeer) {
7576
try {
7677
init();
7778
} catch (ConfigurationException e) {
@@ -95,7 +96,7 @@ public int getServicePort() {
9596

9697
private String composeEndpointName(String nodeIP, int port) {
9798
StringBuffer sb = new StringBuffer();
98-
sb.append("http://").append(nodeIP).append(":").append(port).append("/clusterservice");
99+
sb.append("https://").append(nodeIP).append(":").append(port).append("/clusterservice");
99100
return sb.toString();
100101
}
101102

@@ -108,7 +109,8 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
108109
@Override
109110
public boolean start() {
110111
_servletContainer = new ClusterServiceServletContainer();
111-
_servletContainer.start(new ClusterServiceServletHttpHandler(_manager), _clusterServicePort);
112+
_servletContainer.start(new ClusterServiceServletHttpHandler(_manager), _manager.getSelfNodeIP(),
113+
_clusterServicePort, caService);
112114
return true;
113115
}
114116

0 commit comments

Comments
 (0)