Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/134893.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 134893
summary: Add trust configuration for cross cluster api keys
area: Security
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public boolean isSystemDefault() {
return configs.stream().allMatch(SslTrustConfig::isSystemDefault);
}

@Override
public boolean hasExplicitConfig() {
return configs.stream().allMatch(SslTrustConfig::hasExplicitConfig);
}

@Override
public X509ExtendedTrustManager createTrustManager() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,8 @@ public int hashCode() {
return Objects.hash(certificateAuthorities);
}

@Override
public boolean hasExplicitConfig() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ public interface SslTrustConfig {
*/
Collection<? extends StoredCertificate> getConfiguredCertificates();

/**
* @return {@code true} if this trust config is based on any explicit trust settings
*/
default boolean hasExplicitConfig() {
return false;
}

/**
* @return {@code true} if this trust config is based on the system default truststore
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,9 @@ public String toString() {
sb.append('}');
return sb.toString();
}

@Override
public boolean hasExplicitConfig() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ public X509ExtendedTrustManager createTrustManager() {
return TRUST_MANAGER;
}

@Override
public boolean hasExplicitConfig() {
return true;
}

@Override
public String toString() {
return "trust everything";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,9 @@ private static CertificateTrustRestrictions readTrustGroup(Path path) throws IOE
final List<String> trustNodeNames = settings.getAsList(RESTRICTIONS_KEY_SUBJECT_NAME);
return new CertificateTrustRestrictions(trustNodeNames);
}

@Override
public boolean hasExplicitConfig() {
return delegate.hasExplicitConfig();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,53 @@

import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.ssl.DiagnosticTrustManager;
import org.elasticsearch.common.ssl.PemKeyConfig;
import org.elasticsearch.test.SecurityIntegTestCase;

import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySignerSettings.SIGNING_CERT_PATH;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySignerSettings.SIGNING_KEYSTORE_ALIAS;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySignerSettings.SIGNING_KEYSTORE_PATH;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySignerSettings.SIGNING_KEYSTORE_SECURE_PASSWORD;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySignerSettings.SIGNING_KEYSTORE_TYPE;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySignerSettings.SIGNING_KEY_PATH;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.DIAGNOSE_TRUST_EXCEPTIONS;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_CERTIFICATE_AUTHORITIES;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_CERT_PATH;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_KEYSTORE_ALIAS;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_KEYSTORE_PATH;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_KEYSTORE_SECURE_PASSWORD;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_KEYSTORE_TYPE;
import static org.elasticsearch.xpack.security.transport.CrossClusterApiKeySigningSettings.SIGNING_KEY_PATH;
import static org.hamcrest.Matchers.equalToIgnoringCase;

public class CrossClusterApiKeySignerIntegTests extends SecurityIntegTestCase {
public class CrossClusterApiKeySignatureManagerIntegTests extends SecurityIntegTestCase {

private static final String DYNAMIC_TEST_CLUSTER_ALIAS = "dynamic_test_cluster";
private static final String STATIC_TEST_CLUSTER_ALIAS = "static_test_cluster";

public void testSignWithPemKeyConfig() {
final CrossClusterApiKeySigner signer = getCrossClusterApiKeySignerInstance();
final CrossClusterApiKeySignatureManager manager = getCrossClusterApiKeySignatureManagerInstance();
final String[] testHeaders = randomArray(5, String[]::new, () -> randomAlphanumericOfLength(randomInt(20)));

X509CertificateSignature signature = signer.sign(STATIC_TEST_CLUSTER_ALIAS, testHeaders);
signature.certificate().getPublicKey();

X509CertificateSignature signature = manager.signerForClusterAlias(STATIC_TEST_CLUSTER_ALIAS).sign(testHeaders);
var keyConfig = new PemKeyConfig(
"signing_rsa.crt",
"signing_rsa.key",
new char[0],
getDataPath("/org/elasticsearch/xpack/security/signature/signing_rsa.crt").getParent()
);

var verifier = manager.verifier();

assertThat(signature.algorithm(), equalToIgnoringCase(keyConfig.getKeys().getFirst().v2().getSigAlgName()));
assertEquals(signature.certificate(), keyConfig.getKeys().getFirst().v2());
assertEquals(signature.certificates()[0], keyConfig.getKeys().getFirst().v2());
assertTrue(verifier.verify(signature, testHeaders));
}

public void testSignUnknownClusterAlias() {
final CrossClusterApiKeySigner signer = getCrossClusterApiKeySignerInstance();
final CrossClusterApiKeySignatureManager manager = getCrossClusterApiKeySignatureManagerInstance();
final String[] testHeaders = randomArray(5, String[]::new, () -> randomAlphanumericOfLength(randomInt(20)));

X509CertificateSignature signature = signer.sign("unknowncluster", testHeaders);
X509CertificateSignature signature = manager.signerForClusterAlias("unknowncluster").sign(testHeaders);
assertNull(signature);
}

public void testSeveralKeyStoreAliases() {
final CrossClusterApiKeySigner signer = getCrossClusterApiKeySignerInstance();

final CrossClusterApiKeySignatureManager manager = getCrossClusterApiKeySignatureManagerInstance();
try {
// Create a new config without an alias. Since there are several aliases in the keystore, no signature should be generated
updateClusterSettings(
Expand All @@ -69,7 +71,8 @@ public void testSeveralKeyStoreAliases() {
);

{
X509CertificateSignature signature = signer.sign(DYNAMIC_TEST_CLUSTER_ALIAS, "test", "test");
var signer = manager.signerForClusterAlias(DYNAMIC_TEST_CLUSTER_ALIAS);
X509CertificateSignature signature = signer.sign("test", "test");
assertNull(signature);
}

Expand All @@ -79,7 +82,8 @@ public void testSeveralKeyStoreAliases() {
.put(SIGNING_KEYSTORE_ALIAS.getConcreteSettingForNamespace(DYNAMIC_TEST_CLUSTER_ALIAS).getKey(), "wholelottakey")
);
{
X509CertificateSignature signature = signer.sign(DYNAMIC_TEST_CLUSTER_ALIAS, "test", "test");
var signer = manager.signerForClusterAlias(DYNAMIC_TEST_CLUSTER_ALIAS);
X509CertificateSignature signature = signer.sign("test", "test");
assertNotNull(signature);
}

Expand All @@ -89,7 +93,8 @@ public void testSeveralKeyStoreAliases() {
.put(SIGNING_KEYSTORE_ALIAS.getConcreteSettingForNamespace(DYNAMIC_TEST_CLUSTER_ALIAS).getKey(), "idonotexist")
);
{
X509CertificateSignature signature = signer.sign(DYNAMIC_TEST_CLUSTER_ALIAS, "test", "test");
var signer = manager.signerForClusterAlias(DYNAMIC_TEST_CLUSTER_ALIAS);
X509CertificateSignature signature = signer.sign("test", "test");
assertNotNull(signature);
}
} finally {
Expand All @@ -103,10 +108,28 @@ public void testSeveralKeyStoreAliases() {
}
}

public void testVerifyDiagnosticTrustManagerDisabled() {
final CrossClusterApiKeySignatureManager manager = getCrossClusterApiKeySignatureManagerInstance();

try {
updateClusterSettings(Settings.builder().put(DIAGNOSE_TRUST_EXCEPTIONS.getKey(), false));
assertFalse(manager.getTrustManager() instanceof DiagnosticTrustManager);
} finally {
updateClusterSettings(Settings.builder().putNull(DIAGNOSE_TRUST_EXCEPTIONS.getKey()));
}
}

public void testVerifyDiagnosticTrustManagerEnabledDefault() {
final CrossClusterApiKeySignatureManager manager = getCrossClusterApiKeySignatureManagerInstance();

assertTrue(manager.getTrustManager() instanceof DiagnosticTrustManager);
}

@Override
protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) {
var builder = Settings.builder();
MockSecureSettings secureSettings = (MockSecureSettings) builder.put(super.nodeSettings(nodeOrdinal, otherSettings))
.put(SIGNING_CERTIFICATE_AUTHORITIES.getKey(), getDataPath("/org" + "/elasticsearch/xpack/security/signature/root.crt"))
.put(
SIGNING_CERT_PATH.getConcreteSettingForNamespace(STATIC_TEST_CLUSTER_ALIAS).getKey(),
getDataPath("/org/elasticsearch/xpack/security/signature/signing_rsa.crt")
Expand All @@ -123,8 +146,8 @@ protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) {
return builder.build();
}

private static CrossClusterApiKeySigner getCrossClusterApiKeySignerInstance() {
return CrossClusterTestHelper.getCrossClusterApiKeySigner(internalCluster());
private static CrossClusterApiKeySignatureManager getCrossClusterApiKeySignatureManagerInstance() {
return CrossClusterTestHelper.getCrossClusterApiKeySignatureManager(internalCluster());
}

}
Loading