3232import java .util .Collection ;
3333import java .util .Map ;
3434import java .util .Objects ;
35+ import java .util .Optional ;
3536import java .util .Set ;
3637import java .util .concurrent .ConcurrentHashMap ;
3738import java .util .stream .Collectors ;
38- import java .util .stream .Stream ;
3939
4040import javax .net .ssl .X509KeyManager ;
4141
4545public class CrossClusterApiKeySigner {
4646 private final Logger logger = LogManager .getLogger (getClass ());
4747 private final Environment environment ;
48+ private static final Map <String , String > SIGNATURE_ALGORITHM_BY_TYPE = Map .of ("RSA" , "SHA256withRSA" , "EC" , "SHA256withECDSA" );
4849
4950 private final Map <String , SigningConfig > signingConfigByClusterAlias = new ConcurrentHashMap <>();
5051
@@ -69,6 +70,8 @@ public void loadSigningConfig(String clusterAlias, @Nullable Settings settings,
6970 updateSecureSettings
7071 );
7172
73+ logger .trace ("Loading signing config for [{}] with settings [{}]" , clusterAlias , effectiveSettings );
74+
7275 SigningConfig signingConfig = new SigningConfig (null , null , effectiveSettings );
7376 if (effectiveSettings .getByPrefix (SETTINGS_PART_SIGNING ).isEmpty () == false ) {
7477 try {
@@ -80,16 +83,20 @@ public void loadSigningConfig(String clusterAlias, @Nullable Settings settings,
8083 );
8184 if (keyConfig .hasKeyMaterial ()) {
8285 String alias = effectiveSettings .get (SETTINGS_PART_SIGNING + "." + KEYSTORE_ALIAS_SUFFIX );
83- var keyPair = Strings .isNullOrEmpty (alias )
84- ? buildKeyPairForCluster (keyConfig )
85- : buildKeyPairForCluster (keyConfig , alias );
86+ var keyPair = Strings .isNullOrEmpty (alias ) ? buildKeyPair (keyConfig ) : buildKeyPair (keyConfig , alias );
8687 if (keyPair != null ) {
88+ logger .trace ("Key pair [{}] found for [{}]" , keyPair , clusterAlias );
8789 signingConfig = new SigningConfig (keyPair , keyConfig .getDependentFiles (), effectiveSettings );
8890 }
91+ } else {
92+ logger .error (Strings .format ("No signing credentials found in signing config for cluster [%s]" , clusterAlias ));
8993 }
9094 } catch (Exception e ) {
95+ // Since this can be called by the settings applier we don't want to surface an error here
9196 logger .error (Strings .format ("Failed to load signing config for cluster [%s]" , clusterAlias ), e );
9297 }
98+ } else {
99+ logger .trace ("No signing settings found for [{}]" , clusterAlias );
93100 }
94101 return signingConfig ;
95102 });
@@ -98,6 +105,7 @@ public void loadSigningConfig(String clusterAlias, @Nullable Settings settings,
98105 public X509CertificateSignature sign (String clusterAlias , String ... headers ) {
99106 SigningConfig signingConfig = signingConfigByClusterAlias .get (clusterAlias );
100107 if (signingConfig == null || signingConfig .keyPair () == null ) {
108+ logger .trace ("No signing config found for [{}] returning empty signature" , clusterAlias );
101109 return null ;
102110 }
103111 var keyPair = signingConfig .keyPair ();
@@ -110,7 +118,10 @@ public X509CertificateSignature sign(String clusterAlias, String... headers) {
110118 final byte [] sigBytes = signature .sign ();
111119 return new X509CertificateSignature (keyPair .certificate , algorithm , new BytesArray (sigBytes ));
112120 } catch (GeneralSecurityException e ) {
113- throw new ElasticsearchSecurityException ("Failed to sign cross cluster headers" , e );
121+ throw new ElasticsearchSecurityException (
122+ Strings .format ("Failed to sign cross cluster headers for cluster [%s]" , clusterAlias ),
123+ e
124+ );
114125 }
115126 }
116127
@@ -153,13 +164,14 @@ void reloadSigningConfigs(Set<String> clusterAliases) {
153164 clusterAliases .forEach (alias -> loadSigningConfig (alias , null , true ));
154165 }
155166
156- private X509KeyPair buildKeyPairForCluster (SslKeyConfig keyConfig ) {
167+ private X509KeyPair buildKeyPair (SslKeyConfig keyConfig ) {
157168 final X509KeyManager keyManager = keyConfig .createKeyManager ();
158169 if (keyManager == null ) {
159170 return null ;
160171 }
161172
162- final Set <String > aliases = Stream .of ("RSA" , "EC" )
173+ final Set <String > aliases = SIGNATURE_ALGORITHM_BY_TYPE .keySet ()
174+ .stream ()
163175 .map (keyType -> keyManager .getServerAliases (keyType , null ))
164176 .filter (Objects ::nonNull )
165177 .flatMap (Arrays ::stream )
@@ -182,12 +194,24 @@ private X509KeyPair buildKeyPairForCluster(SslKeyConfig keyConfig) {
182194 };
183195 }
184196
185- private X509KeyPair buildKeyPairForCluster (SslKeyConfig keyConfig , String alias ) {
197+ private X509KeyPair buildKeyPair (SslKeyConfig keyConfig , String alias ) {
186198 final X509KeyManager keyManager = keyConfig .createKeyManager ();
187199 if (keyManager == null ) {
188200 return null ;
189201 }
190202
203+ final String keyType = keyManager .getPrivateKey (alias ).getAlgorithm ();
204+ if (SIGNATURE_ALGORITHM_BY_TYPE .containsKey (keyType ) == false ) {
205+ throw new IllegalStateException (
206+ Strings .format (
207+ "The key associated with alias [%s] uses unsupported key algorithm type [%s], only %s is supported" ,
208+ alias ,
209+ keyType ,
210+ SIGNATURE_ALGORITHM_BY_TYPE .keySet ()
211+ )
212+ );
213+ }
214+
191215 final X509Certificate [] chain = keyManager .getCertificateChain (alias );
192216 logger .trace ("KeyConfig [{}] has entry for alias: [{}] [{}]" , keyConfig , alias , chain != null );
193217
@@ -208,16 +232,20 @@ private static String calculateFingerprint(X509Certificate certificate) {
208232
209233 private record X509KeyPair (X509Certificate certificate , PrivateKey privateKey , String signatureAlgorithm , String fingerprint ) {
210234 X509KeyPair (X509Certificate certificate , PrivateKey privateKey ) {
211- this (certificate , privateKey , switch (privateKey .getAlgorithm ()) {
212- case "RSA" -> "SHA256withRSA" ;
213- case "EC" -> "SHA256withECDSA" ;
214- default -> throw new IllegalArgumentException (
215- "Unsupported Key Type [" + privateKey .getAlgorithm () + "] for [" + privateKey + "]"
216- );
217- }, calculateFingerprint (certificate ));
235+ this (
236+ certificate ,
237+ privateKey ,
238+ Optional .ofNullable (SIGNATURE_ALGORITHM_BY_TYPE .get (privateKey .getAlgorithm ()))
239+ .orElseThrow (
240+ () -> new IllegalArgumentException (
241+ "Unsupported Key Type [" + privateKey .getAlgorithm () + "] for [" + privateKey + "]"
242+ )
243+ ),
244+ calculateFingerprint (certificate )
245+ );
218246 }
219247 }
220248
221- private record SigningConfig (@ Nullable X509KeyPair keyPair , Collection <Path > dependentFiles , @ Nullable Settings settings ) {}
249+ private record SigningConfig (@ Nullable X509KeyPair keyPair , @ Nullable Collection <Path > dependentFiles , @ Nullable Settings settings ) {}
222250
223251}
0 commit comments