26
26
import org .elasticsearch .common .Strings ;
27
27
import org .elasticsearch .common .bytes .BytesReference ;
28
28
import org .elasticsearch .common .collect .MapBuilder ;
29
+ import org .elasticsearch .common .settings .SecureSetting ;
30
+ import org .elasticsearch .common .settings .SecureString ;
29
31
import org .elasticsearch .common .settings .Setting ;
30
32
import org .elasticsearch .common .settings .Setting .Property ;
31
33
import org .elasticsearch .common .settings .Settings ;
52
54
import java .util .Map ;
53
55
import java .util .Objects ;
54
56
import java .util .Set ;
57
+ import java .util .concurrent .ConcurrentHashMap ;
55
58
import java .util .concurrent .atomic .AtomicBoolean ;
56
59
import java .util .function .Function ;
57
60
import java .util .function .Supplier ;
@@ -205,23 +208,20 @@ public void validate(final String username, final Map<Setting<?>, Object> settin
205
208
final String namespace =
206
209
HttpExporter .AUTH_USERNAME_SETTING .getNamespace (
207
210
HttpExporter .AUTH_USERNAME_SETTING .getConcreteSetting (key ));
208
- final String password =
209
- (String ) settings .get (AUTH_PASSWORD_SETTING .getConcreteSettingForNamespace (namespace ));
210
211
211
212
// password must be specified along with username for any auth
212
213
if (Strings .isNullOrEmpty (username ) == false ) {
213
- if (Strings .isNullOrEmpty (password )) {
214
- throw new SettingsException (
215
- "[" + AUTH_USERNAME_SETTING .getConcreteSettingForNamespace (namespace ).getKey () + "] is set " +
216
- "but [" + AUTH_PASSWORD_SETTING .getConcreteSettingForNamespace (namespace ).getKey () + "] is " +
217
- "missing" );
218
- }
219
214
final String type =
220
215
(String ) settings .get (Exporter .TYPE_SETTING .getConcreteSettingForNamespace (namespace ));
221
216
if ("http" .equals (type ) == false ) {
222
217
throw new SettingsException ("username for [" + key + "] is set but type is [" + type + "]" );
223
218
}
224
219
}
220
+
221
+ // it would be ideal to validate that just one of either AUTH_PASSWORD_SETTING or
222
+ // AUTH_SECURE_PASSWORD_SETTING were present here, but that is not currently possible with the settings
223
+ // validation framework.
224
+ // https://github.com/elastic/elasticsearch/issues/51332
225
225
}
226
226
227
227
@ Override
@@ -231,8 +231,8 @@ public Iterator<Setting<?>> settings() {
231
231
HttpExporter .AUTH_USERNAME_SETTING .getConcreteSetting (key ));
232
232
233
233
final List <Setting <?>> settings = Arrays .asList (
234
- Exporter .TYPE_SETTING .getConcreteSettingForNamespace (namespace ),
235
- HttpExporter . AUTH_PASSWORD_SETTING . getConcreteSettingForNamespace ( namespace ));
234
+ Exporter .TYPE_SETTING .getConcreteSettingForNamespace (namespace ));
235
+
236
236
return settings .iterator ();
237
237
}
238
238
@@ -284,8 +284,18 @@ public Iterator<Setting<?>> settings() {
284
284
},
285
285
Property .Dynamic ,
286
286
Property .NodeScope ,
287
- Property .Filtered ),
287
+ Property .Filtered ,
288
+ Property .Deprecated ),
288
289
TYPE_DEPENDENCY );
290
+ /**
291
+ * Secure password for basic auth.
292
+ */
293
+ public static final Setting .AffixSetting <SecureString > AUTH_SECURE_PASSWORD_SETTING =
294
+ Setting .affixKeySetting (
295
+ "xpack.monitoring.exporters." ,
296
+ "auth.secure_password" ,
297
+ key -> SecureSetting .secureString (key , null ),
298
+ TYPE_DEPENDENCY );
289
299
/**
290
300
* The SSL settings.
291
301
*
@@ -400,6 +410,7 @@ public Iterator<Setting<?>> settings() {
400
410
*/
401
411
private final AtomicBoolean clusterAlertsAllowed = new AtomicBoolean (false );
402
412
413
+ private static final ConcurrentHashMap <String , SecureString > SECURE_AUTH_PASSWORDS = new ConcurrentHashMap <>();
403
414
private final ThreadContext threadContext ;
404
415
private final DateFormatter dateTimeFormatter ;
405
416
@@ -697,6 +708,25 @@ private static void configureTimeouts(final RestClientBuilder builder, final Con
697
708
builder .setRequestConfigCallback (new TimeoutRequestConfigCallback (connectTimeout , socketTimeout ));
698
709
}
699
710
711
+
712
+ /**
713
+ * Caches secure settings for use when dynamically configuring HTTP exporters
714
+ * @param settings settings used for configuring HTTP exporter
715
+ * @return names of HTTP exporters whose secure settings changed, if any
716
+ */
717
+ public static List <String > loadSettings (Settings settings ) {
718
+ final List <String > changedExporters = new ArrayList <>();
719
+ for (final String namespace : AUTH_SECURE_PASSWORD_SETTING .getNamespaces (settings )) {
720
+ final Setting <SecureString > s = AUTH_SECURE_PASSWORD_SETTING .getConcreteSettingForNamespace (namespace );
721
+ final SecureString securePassword = s .get (settings );
722
+ final SecureString existingPassword = SECURE_AUTH_PASSWORDS .put (namespace , securePassword );
723
+ if (securePassword .equals (existingPassword ) == false ) {
724
+ changedExporters .add (namespace );
725
+ }
726
+ }
727
+ return changedExporters ;
728
+ }
729
+
700
730
/**
701
731
* Creates the optional {@link CredentialsProvider} with the username/password to use with <em>all</em> requests for user
702
732
* authentication.
@@ -708,7 +738,19 @@ private static void configureTimeouts(final RestClientBuilder builder, final Con
708
738
@ Nullable
709
739
private static CredentialsProvider createCredentialsProvider (final Config config ) {
710
740
final String username = AUTH_USERNAME_SETTING .getConcreteSettingForNamespace (config .name ()).get (config .settings ());
711
- final String password = AUTH_PASSWORD_SETTING .getConcreteSettingForNamespace (config .name ()).get (config .settings ());
741
+
742
+ final String deprecatedPassword = AUTH_PASSWORD_SETTING .getConcreteSettingForNamespace (config .name ()).get (config .settings ());
743
+ final SecureString securePassword = SECURE_AUTH_PASSWORDS .get (config .name ());
744
+ final String password ;
745
+ if (securePassword != null ) {
746
+ password = securePassword .toString ();
747
+ if (Strings .isNullOrEmpty (deprecatedPassword ) == false ) {
748
+ logger .warn ("exporter [{}] specified both auth.secure_password and auth.password. using auth.secure_password and " +
749
+ "ignoring auth.password" , config .name ());
750
+ }
751
+ } else {
752
+ password = deprecatedPassword ;
753
+ }
712
754
713
755
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider ();
714
756
credentialsProvider .setCredentials (AuthScope .ANY , new UsernamePasswordCredentials (username , password ));
@@ -873,9 +915,19 @@ public void doClose() {
873
915
}
874
916
}
875
917
876
- public static List <Setting .AffixSetting <?>> getSettings () {
918
+ public static List <Setting .AffixSetting <?>> getDynamicSettings () {
877
919
return Arrays .asList (HOST_SETTING , TEMPLATE_CREATE_LEGACY_VERSIONS_SETTING , AUTH_PASSWORD_SETTING , AUTH_USERNAME_SETTING ,
878
920
BULK_TIMEOUT_SETTING , CONNECTION_READ_TIMEOUT_SETTING , CONNECTION_TIMEOUT_SETTING , PIPELINE_CHECK_TIMEOUT_SETTING ,
879
921
PROXY_BASE_PATH_SETTING , SNIFF_ENABLED_SETTING , TEMPLATE_CHECK_TIMEOUT_SETTING , SSL_SETTING , HEADERS_SETTING );
880
922
}
923
+
924
+ public static List <Setting .AffixSetting <?>> getSecureSettings () {
925
+ return Collections .singletonList (AUTH_SECURE_PASSWORD_SETTING );
926
+ }
927
+
928
+ public static List <Setting .AffixSetting <?>> getSettings () {
929
+ List <Setting .AffixSetting <?>> allSettings = new ArrayList <>(getDynamicSettings ());
930
+ allSettings .addAll (getSecureSettings ());
931
+ return allSettings ;
932
+ }
881
933
}
0 commit comments