Skip to content

Commit 1f1d2eb

Browse files
authored
Merge branch 'apache:main' into feature/xen-full-clone
2 parents d2cc61b + 850b443 commit 1f1d2eb

29 files changed

Lines changed: 2375 additions & 183 deletions

File tree

.asf.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ github:
5151

5252
collaborators:
5353
- ingox
54-
- gpordeus
54+
- gp-santos
5555
- erikbocks
5656
- Imvedansh
5757
- Damans227

.github/workflows/merge-conflict-checker.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@
1717

1818
name: "PR Merge Conflict Check"
1919
on:
20-
push:
21-
pull_request:
22-
types: [opened, synchronize, reopened]
20+
schedule:
21+
- cron: '*/10 * * * *'
22+
workflow_dispatch:
2323

24-
permissions: # added using https://github.com/step-security/secure-workflows
25-
contents: read
24+
permissions: {}
2625

2726
concurrency:
28-
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
29-
cancel-in-progress: true
27+
group: "gh-aw-${{ github.workflow }}"
3028

3129
jobs:
3230
triage:

api/src/main/java/org/apache/cloudstack/api/command/admin/ca/ProvisionCertificateCmd.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ public class ProvisionCertificateCmd extends BaseAsyncCmd {
6363
description = "Name of the CA service provider, otherwise the default configured provider plugin will be used")
6464
private String provider;
6565

66+
@Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN,
67+
description = "When true, uses SSH to re-provision the agent's certificate, bypassing the NIO agent connection. " +
68+
"Use this when agents are disconnected due to a CA change. Supported for KVM hosts and SystemVMs. Default is false",
69+
since = "4.23.0")
70+
private Boolean forced;
71+
6672
/////////////////////////////////////////////////////
6773
/////////////////// Accessors ///////////////////////
6874
/////////////////////////////////////////////////////
@@ -79,6 +85,10 @@ public String getProvider() {
7985
return provider;
8086
}
8187

88+
public boolean isForced() {
89+
return forced != null && forced;
90+
}
91+
8292
/////////////////////////////////////////////////////
8393
/////////////// API Implementation///////////////////
8494
/////////////////////////////////////////////////////
@@ -90,7 +100,7 @@ public void execute() {
90100
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId());
91101
}
92102

93-
boolean result = caManager.provisionCertificate(host, getReconnect(), getProvider());
103+
boolean result = caManager.provisionCertificate(host, getReconnect(), getProvider(), isForced());
94104
SuccessResponse response = new SuccessResponse(getCommandName());
95105
response.setSuccess(result);
96106
setResponseObject(response);

api/src/main/java/org/apache/cloudstack/api/command/admin/user/GetUserCmd.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.apache.cloudstack.api.BaseCmd;
2323
import org.apache.cloudstack.api.Parameter;
2424
import org.apache.cloudstack.api.response.UserResponse;
25-
25+
import org.apache.cloudstack.api.ApiArgValidator;
2626
import com.cloud.exception.InvalidParameterValueException;
2727
import com.cloud.user.UserAccount;
2828

@@ -35,7 +35,7 @@ public class GetUserCmd extends BaseCmd {
3535
//////////////// API parameters /////////////////////
3636
/////////////////////////////////////////////////////
3737

38-
@Parameter(name = ApiConstants.USER_API_KEY, type = CommandType.STRING, required = true, description = "API key of the user")
38+
@Parameter(name = ApiConstants.USER_API_KEY, type = CommandType.STRING, required = true, description = "API key of the user", validations = {ApiArgValidator.NotNullOrEmpty})
3939
private String apiKey;
4040

4141
/////////////////////////////////////////////////////

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.List;
2424
import java.util.Map;
2525

26+
import com.trilead.ssh2.Connection;
27+
2628
import org.apache.cloudstack.framework.ca.CAProvider;
2729
import org.apache.cloudstack.framework.ca.CAService;
2830
import org.apache.cloudstack.framework.ca.Certificate;
@@ -39,7 +41,10 @@ public interface CAManager extends CAService, Configurable, PluggableService {
3941
ConfigKey<String> CAProviderPlugin = new ConfigKey<>("Advanced", String.class,
4042
"ca.framework.provider.plugin",
4143
"root",
42-
"The CA provider plugin that is used for secure CloudStack management server-agent communication for encryption and authentication. Restart management server(s) when changed.", true);
44+
"The CA provider plugin used for CloudStack internal certificate management (MS-agent encryption and authentication). " +
45+
"The default 'root' provider auto-generates a CA on first startup, but also supports user-provided custom CA material " +
46+
"via the ca.plugin.root.private.key, ca.plugin.root.public.key, and ca.plugin.root.ca.certificate settings. " +
47+
"Restart management server(s) when changed.", false);
4348

4449
ConfigKey<Integer> CertKeySize = new ConfigKey<>("Advanced", Integer.class,
4550
"ca.framework.cert.keysize",
@@ -85,6 +90,12 @@ public interface CAManager extends CAService, Configurable, PluggableService {
8590
"The actual implementation will depend on the configured CA provider.",
8691
false);
8792

93+
ConfigKey<Boolean> CaInjectDefaultTruststore = new ConfigKey<>("Advanced", Boolean.class,
94+
"ca.framework.inject.default.truststore", "true",
95+
"When true, injects the CA provider's certificate into the JVM default truststore on management server startup. " +
96+
"This allows outgoing HTTPS connections from the management server to trust servers with certificates signed by the configured CA. " +
97+
"Restart management server(s) when changed.", false);
98+
8899
/**
89100
* Returns a list of available CA provider plugins
90101
* @return returns list of CAProvider
@@ -130,12 +141,26 @@ public interface CAManager extends CAService, Configurable, PluggableService {
130141
boolean revokeCertificate(final BigInteger certSerial, final String certCn, final String provider);
131142

132143
/**
133-
* Provisions certificate for given active and connected agent host
144+
* Provisions certificate for given agent host.
145+
* When forced=true, uses SSH to re-provision bypassing the NIO agent connection (for disconnected agents).
134146
* @param host
147+
* @param reconnect
135148
* @param provider
149+
* @param forced when true, provisions via SSH instead of NIO; supports KVM hosts and SystemVMs
136150
* @return returns success/failure as boolean
137151
*/
138-
boolean provisionCertificate(final Host host, final Boolean reconnect, final String provider);
152+
boolean provisionCertificate(final Host host, final Boolean reconnect, final String provider, final boolean forced);
153+
154+
/**
155+
* Provisions certificate for a KVM host using an existing SSH connection.
156+
* Runs keystore-setup to generate a CSR, issues a certificate, then runs keystore-cert-import.
157+
* Used during host discovery and for forced re-provisioning when the NIO agent is unreachable.
158+
* @param sshConnection active SSH connection to the KVM host
159+
* @param agentIp IP address of the KVM host agent
160+
* @param agentHostname hostname of the KVM host agent
161+
* @param caProvider optional CA provider plugin name (null uses default)
162+
*/
163+
void provisionCertificateViaSsh(Connection sshConnection, String agentIp, String agentHostname, String caProvider);
139164

140165
/**
141166
* Setups up a new keystore and generates CSR for a host

plugins/ca/root-ca/src/main/java/org/apache/cloudstack/ca/provider/RootCACustomTrustManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,17 @@ public final class RootCACustomTrustManager implements X509TrustManager {
4040
private boolean authStrictness = true;
4141
private boolean allowExpiredCertificate = true;
4242
private CrlDao crlDao;
43-
private X509Certificate caCertificate;
43+
private List<X509Certificate> caCertificates;
4444
private Map<String, X509Certificate> activeCertMap;
4545

46-
public RootCACustomTrustManager(final String clientAddress, final boolean authStrictness, final boolean allowExpiredCertificate, final Map<String, X509Certificate> activeCertMap, final X509Certificate caCertificate, final CrlDao crlDao) {
46+
public RootCACustomTrustManager(final String clientAddress, final boolean authStrictness, final boolean allowExpiredCertificate, final Map<String, X509Certificate> activeCertMap, final List<X509Certificate> caCertificates, final CrlDao crlDao) {
4747
if (StringUtils.isNotEmpty(clientAddress)) {
4848
this.clientAddress = clientAddress.replace("/", "").split(":")[0];
4949
}
5050
this.authStrictness = authStrictness;
5151
this.allowExpiredCertificate = allowExpiredCertificate;
5252
this.activeCertMap = activeCertMap;
53-
this.caCertificate = caCertificate;
53+
this.caCertificates = caCertificates;
5454
this.crlDao = crlDao;
5555
}
5656

@@ -151,6 +151,6 @@ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) thr
151151

152152
@Override
153153
public X509Certificate[] getAcceptedIssuers() {
154-
return new X509Certificate[]{caCertificate};
154+
return caCertificates.toArray(new X509Certificate[0]);
155155
}
156156
}

0 commit comments

Comments
 (0)