Skip to content

Commit 1200b76

Browse files
committed
Settings: Migrate ec2 discovery sensitive settings to elasticsearch keystore
This change adds secure settings for access/secret keys and proxy username/password to ec2 discovery. It adds the new settings with the prefix `discovery.ec2`, copies other relevant ec2 client settings to the same prefix, and deprecates all other settings (`cloud.aws.*` and `cloud.aws.ec2.*`). Note that this is simpler than the client configs in repository-s3 because discovery is only initialized once for the entire node, so there is no reason to complicate the configuration with the ability to have multiple sets of client settings. relates elastic#22475
1 parent 38009ef commit 1200b76

File tree

5 files changed

+216
-55
lines changed

5 files changed

+216
-55
lines changed

plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2Service.java

+68-29
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import com.amazonaws.ClientConfiguration;
2323
import com.amazonaws.Protocol;
2424
import com.amazonaws.services.ec2.AmazonEC2;
25+
import org.elasticsearch.common.settings.SecureSetting;
26+
import org.elasticsearch.common.settings.SecureString;
2527
import org.elasticsearch.common.settings.Setting;
2628
import org.elasticsearch.common.settings.Setting.Property;
2729
import org.elasticsearch.common.settings.Settings;
@@ -42,50 +44,52 @@ interface AwsEc2Service {
4244
/**
4345
* cloud.aws.access_key: AWS Access key. Shared with repository-s3 plugin
4446
*/
45-
Setting<String> KEY_SETTING =
46-
Setting.simpleString("cloud.aws.access_key", Property.NodeScope, Property.Filtered, Property.Shared);
47+
Setting<SecureString> KEY_SETTING = new Setting<>("cloud.aws.access_key", "", SecureString::new,
48+
Property.NodeScope, Property.Filtered, Property.Shared, Property.Deprecated);
4749
/**
4850
* cloud.aws.secret_key: AWS Secret key. Shared with repository-s3 plugin
4951
*/
50-
Setting<String> SECRET_SETTING =
51-
Setting.simpleString("cloud.aws.secret_key", Property.NodeScope, Property.Filtered, Property.Shared);
52+
Setting<SecureString> SECRET_SETTING = new Setting<>("cloud.aws.secret_key", "", SecureString::new,
53+
Property.NodeScope, Property.Filtered, Property.Shared, Property.Deprecated);
5254
/**
5355
* cloud.aws.protocol: Protocol for AWS API: http or https. Defaults to https. Shared with repository-s3 plugin
5456
*/
5557
Setting<Protocol> PROTOCOL_SETTING = new Setting<>("cloud.aws.protocol", "https", s -> Protocol.valueOf(s.toUpperCase(Locale.ROOT)),
56-
Property.NodeScope, Property.Shared);
58+
Property.NodeScope, Property.Shared, Property.Deprecated);
5759
/**
5860
* cloud.aws.proxy.host: In case of proxy, define its hostname/IP. Shared with repository-s3 plugin
5961
*/
60-
Setting<String> PROXY_HOST_SETTING = Setting.simpleString("cloud.aws.proxy.host", Property.NodeScope, Property.Shared);
62+
Setting<String> PROXY_HOST_SETTING = Setting.simpleString("cloud.aws.proxy.host",
63+
Property.NodeScope, Property.Shared, Property.Deprecated);
6164
/**
6265
* cloud.aws.proxy.port: In case of proxy, define its port. Defaults to 80. Shared with repository-s3 plugin
6366
*/
64-
Setting<Integer> PROXY_PORT_SETTING = Setting.intSetting("cloud.aws.proxy.port", 80, 0, 1<<16, Property.NodeScope,
65-
Property.Shared);
67+
Setting<Integer> PROXY_PORT_SETTING = Setting.intSetting("cloud.aws.proxy.port", 80, 0, 1<<16,
68+
Property.NodeScope, Property.Shared, Property.Deprecated);
6669
/**
6770
* cloud.aws.proxy.username: In case of proxy with auth, define the username. Shared with repository-s3 plugin
6871
*/
69-
Setting<String> PROXY_USERNAME_SETTING = Setting.simpleString("cloud.aws.proxy.username", Property.NodeScope, Property.Shared);
72+
Setting<SecureString> PROXY_USERNAME_SETTING = new Setting<>("cloud.aws.proxy.username", "", SecureString::new,
73+
Property.NodeScope, Property.Filtered, Property.Shared, Property.Deprecated);
7074
/**
7175
* cloud.aws.proxy.password: In case of proxy with auth, define the password. Shared with repository-s3 plugin
7276
*/
73-
Setting<String> PROXY_PASSWORD_SETTING =
74-
Setting.simpleString("cloud.aws.proxy.password", Property.NodeScope, Property.Filtered, Property.Shared);
77+
Setting<SecureString> PROXY_PASSWORD_SETTING = new Setting<>("cloud.aws.proxy.password", "", SecureString::new,
78+
Property.NodeScope, Property.Filtered, Property.Shared, Property.Deprecated);
7579
/**
7680
* cloud.aws.signer: If you are using an old AWS API version, you can define a Signer. Shared with repository-s3 plugin
7781
*/
78-
Setting<String> SIGNER_SETTING = Setting.simpleString("cloud.aws.signer", Property.NodeScope, Property.Shared);
82+
Setting<String> SIGNER_SETTING = Setting.simpleString("cloud.aws.signer", Property.NodeScope, Property.Shared, Property.Deprecated);
7983
/**
8084
* cloud.aws.region: Region. Shared with repository-s3 plugin
8185
*/
8286
Setting<String> REGION_SETTING =
83-
new Setting<>("cloud.aws.region", "", s -> s.toLowerCase(Locale.ROOT), Property.NodeScope, Property.Shared);
87+
new Setting<>("cloud.aws.region", "", s -> s.toLowerCase(Locale.ROOT), Property.NodeScope, Property.Shared, Property.Deprecated);
8488
/**
8589
* cloud.aws.read_timeout: Socket read timeout. Shared with repository-s3 plugin
8690
*/
8791
Setting<TimeValue> READ_TIMEOUT = Setting.timeSetting("cloud.aws.read_timeout",
88-
TimeValue.timeValueMillis(ClientConfiguration.DEFAULT_SOCKET_TIMEOUT), Property.NodeScope, Property.Shared);
92+
TimeValue.timeValueMillis(ClientConfiguration.DEFAULT_SOCKET_TIMEOUT), Property.NodeScope, Property.Shared, Property.Deprecated);
8993

9094
/**
9195
* Defines specific ec2 settings starting with cloud.aws.ec2.
@@ -95,69 +99,70 @@ interface CLOUD_EC2 {
9599
* cloud.aws.ec2.access_key: AWS Access key specific for EC2 API calls. Defaults to cloud.aws.access_key.
96100
* @see AwsEc2Service#KEY_SETTING
97101
*/
98-
Setting<String> KEY_SETTING = new Setting<>("cloud.aws.ec2.access_key", AwsEc2Service.KEY_SETTING, Function.identity(),
99-
Property.NodeScope, Property.Filtered);
102+
Setting<SecureString> KEY_SETTING = new Setting<>("cloud.aws.ec2.access_key", AwsEc2Service.KEY_SETTING,
103+
SecureString::new, Property.NodeScope, Property.Filtered, Property.Deprecated);
104+
100105
/**
101106
* cloud.aws.ec2.secret_key: AWS Secret key specific for EC2 API calls. Defaults to cloud.aws.secret_key.
102107
* @see AwsEc2Service#SECRET_SETTING
103108
*/
104-
Setting<String> SECRET_SETTING = new Setting<>("cloud.aws.ec2.secret_key", AwsEc2Service.SECRET_SETTING, Function.identity(),
105-
Property.NodeScope, Property.Filtered);
109+
Setting<SecureString> SECRET_SETTING = new Setting<>("cloud.aws.ec2.secret_key", AwsEc2Service.SECRET_SETTING,
110+
SecureString::new, Property.NodeScope, Property.Filtered, Property.Deprecated);
106111
/**
107112
* cloud.aws.ec2.protocol: Protocol for AWS API specific for EC2 API calls: http or https. Defaults to cloud.aws.protocol.
108113
* @see AwsEc2Service#PROTOCOL_SETTING
109114
*/
110115
Setting<Protocol> PROTOCOL_SETTING = new Setting<>("cloud.aws.ec2.protocol", AwsEc2Service.PROTOCOL_SETTING,
111-
s -> Protocol.valueOf(s.toUpperCase(Locale.ROOT)), Property.NodeScope);
116+
s -> Protocol.valueOf(s.toUpperCase(Locale.ROOT)), Property.NodeScope, Property.Deprecated);
112117
/**
113118
* cloud.aws.ec2.proxy.host: In case of proxy, define its hostname/IP specific for EC2 API calls. Defaults to cloud.aws.proxy.host.
114119
* @see AwsEc2Service#PROXY_HOST_SETTING
115120
*/
116121
Setting<String> PROXY_HOST_SETTING = new Setting<>("cloud.aws.ec2.proxy.host", AwsEc2Service.PROXY_HOST_SETTING,
117-
Function.identity(), Property.NodeScope);
122+
Function.identity(), Property.NodeScope, Property.Deprecated);
118123
/**
119124
* cloud.aws.ec2.proxy.port: In case of proxy, define its port specific for EC2 API calls. Defaults to cloud.aws.proxy.port.
120125
* @see AwsEc2Service#PROXY_PORT_SETTING
121126
*/
122127
Setting<Integer> PROXY_PORT_SETTING = new Setting<>("cloud.aws.ec2.proxy.port", AwsEc2Service.PROXY_PORT_SETTING,
123-
s -> Setting.parseInt(s, 0, 1<<16, "cloud.aws.ec2.proxy.port"), Property.NodeScope);
128+
s -> Setting.parseInt(s, 0, 1<<16, "cloud.aws.ec2.proxy.port"), Property.NodeScope, Property.Deprecated);
124129
/**
125130
* cloud.aws.ec2.proxy.username: In case of proxy with auth, define the username specific for EC2 API calls.
126131
* Defaults to cloud.aws.proxy.username.
127132
* @see AwsEc2Service#PROXY_USERNAME_SETTING
128133
*/
129-
Setting<String> PROXY_USERNAME_SETTING = new Setting<>("cloud.aws.ec2.proxy.username", AwsEc2Service.PROXY_USERNAME_SETTING,
130-
Function.identity(), Property.NodeScope);
134+
Setting<SecureString> PROXY_USERNAME_SETTING = new Setting<>("cloud.aws.ec2.proxy.username", AwsEc2Service.PROXY_USERNAME_SETTING,
135+
SecureString::new, Property.NodeScope, Property.Filtered, Property.Deprecated);
131136
/**
132137
* cloud.aws.ec2.proxy.password: In case of proxy with auth, define the password specific for EC2 API calls.
133138
* Defaults to cloud.aws.proxy.password.
134139
* @see AwsEc2Service#PROXY_PASSWORD_SETTING
135140
*/
136-
Setting<String> PROXY_PASSWORD_SETTING = new Setting<>("cloud.aws.ec2.proxy.password", AwsEc2Service.PROXY_PASSWORD_SETTING,
137-
Function.identity(), Property.NodeScope, Property.Filtered);
141+
Setting<SecureString> PROXY_PASSWORD_SETTING = new Setting<>("cloud.aws.ec2.proxy.password", AwsEc2Service.PROXY_PASSWORD_SETTING,
142+
SecureString::new, Property.NodeScope, Property.Filtered, Property.Deprecated);
138143
/**
139144
* cloud.aws.ec2.signer: If you are using an old AWS API version, you can define a Signer. Specific for EC2 API calls.
140145
* Defaults to cloud.aws.signer.
141146
* @see AwsEc2Service#SIGNER_SETTING
142147
*/
143148
Setting<String> SIGNER_SETTING = new Setting<>("cloud.aws.ec2.signer", AwsEc2Service.SIGNER_SETTING, Function.identity(),
144-
Property.NodeScope);
149+
Property.NodeScope, Property.Deprecated);
145150
/**
146151
* cloud.aws.ec2.region: Region specific for EC2 API calls. Defaults to cloud.aws.region.
147152
* @see AwsEc2Service#REGION_SETTING
148153
*/
149154
Setting<String> REGION_SETTING = new Setting<>("cloud.aws.ec2.region", AwsEc2Service.REGION_SETTING,
150-
s -> s.toLowerCase(Locale.ROOT), Property.NodeScope);
155+
s -> s.toLowerCase(Locale.ROOT), Property.NodeScope, Property.Deprecated);
151156
/**
152157
* cloud.aws.ec2.endpoint: Endpoint. If not set, endpoint will be guessed based on region setting.
153158
*/
154-
Setting<String> ENDPOINT_SETTING = Setting.simpleString("cloud.aws.ec2.endpoint", Property.NodeScope);
159+
Setting<String> ENDPOINT_SETTING = Setting.simpleString("cloud.aws.ec2.endpoint", Property.NodeScope, Property.Deprecated);
155160
/**
156161
* cloud.aws.ec2.read_timeout: Socket read timeout. Defaults to cloud.aws.read_timeout
157162
* @see AwsEc2Service#READ_TIMEOUT
158163
*/
159164
Setting<TimeValue> READ_TIMEOUT =
160-
Setting.timeSetting("cloud.aws.ec2.read_timeout", AwsEc2Service.READ_TIMEOUT, Property.NodeScope);
165+
Setting.timeSetting("cloud.aws.ec2.read_timeout", AwsEc2Service.READ_TIMEOUT, Property.NodeScope, Property.Deprecated);
161166
}
162167

163168
/**
@@ -172,6 +177,40 @@ class HostType {
172177
public static final String TAG_PREFIX = "tag:";
173178
}
174179

180+
/** The access key (ie login id) for connecting to ec2. */
181+
Setting<SecureString> ACCESS_KEY_SETTING = SecureSetting.secureString("discovery.ec2.access_key", CLOUD_EC2.KEY_SETTING, false);
182+
183+
/** The secret key (ie password) for connecting to ec2. */
184+
Setting<SecureString> SECRET_KEY_SETTING = SecureSetting.secureString("discovery.ec2.secret_key", CLOUD_EC2.SECRET_SETTING, false);
185+
186+
/** An override for the ec2 endpoint to connect to. */
187+
Setting<String> ENDPOINT_SETTING = new Setting<>("discovery.ec2.endpoint", CLOUD_EC2.ENDPOINT_SETTING,
188+
s -> s.toLowerCase(Locale.ROOT), Setting.Property.NodeScope);
189+
190+
/** The protocol to use to connect to to ec2. */
191+
Setting<Protocol> PROTOCOL_SETTING = new Setting<>("discovery.ec2.protocol", CLOUD_EC2.PROTOCOL_SETTING,
192+
s -> Protocol.valueOf(s.toUpperCase(Locale.ROOT)), Setting.Property.NodeScope);
193+
194+
/** The host name of a proxy to connect to ec2 through. */
195+
Setting<String> PROXY_HOST_SETTING = new Setting<>("discovery.ec2.proxy.host", CLOUD_EC2.PROXY_HOST_SETTING,
196+
Function.identity(), Setting.Property.NodeScope);
197+
198+
/** The port of a proxy to connect to ec2 through. */
199+
Setting<Integer> PROXY_PORT_SETTING = Setting.intSetting("discovery.ec2.proxy.port", CLOUD_EC2.PROXY_PORT_SETTING,
200+
0, Setting.Property.NodeScope);
201+
202+
/** The username of a proxy to connect to s3 through. */
203+
Setting<SecureString> PROXY_USERNAME_SETTING = SecureSetting.secureString("discovery.ec2.proxy.username",
204+
CLOUD_EC2.PROXY_USERNAME_SETTING, false);
205+
206+
/** The password of a proxy to connect to s3 through. */
207+
Setting<SecureString> PROXY_PASSWORD_SETTING = SecureSetting.secureString("discovery.ec2.proxy.password",
208+
CLOUD_EC2.PROXY_PASSWORD_SETTING, false);
209+
210+
/** The socket timeout for connecting to s3. */
211+
Setting<TimeValue> READ_TIMEOUT_SETTING = Setting.timeSetting("discovery.ec2.read_timeout",
212+
CLOUD_EC2.READ_TIMEOUT, Setting.Property.NodeScope);
213+
175214
/**
176215
* discovery.ec2.host_type: The type of host type to use to communicate with other instances.
177216
* Can be one of private_ip, public_ip, private_dns, public_dns or tag:XXXX where

plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImpl.java

+27-24
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.elasticsearch.common.Randomness;
3939
import org.elasticsearch.common.Strings;
4040
import org.elasticsearch.common.component.AbstractComponent;
41+
import org.elasticsearch.common.settings.SecureString;
4142
import org.elasticsearch.common.settings.Settings;
4243

4344
class AwsEc2ServiceImpl extends AbstractComponent implements AwsEc2Service, Closeable {
@@ -68,14 +69,15 @@ public synchronized AmazonEC2 client() {
6869
protected static AWSCredentialsProvider buildCredentials(Logger logger, Settings settings) {
6970
AWSCredentialsProvider credentials;
7071

71-
String key = CLOUD_EC2.KEY_SETTING.get(settings);
72-
String secret = CLOUD_EC2.SECRET_SETTING.get(settings);
73-
if (key.isEmpty() && secret.isEmpty()) {
74-
logger.debug("Using either environment variables, system properties or instance profile credentials");
75-
credentials = new DefaultAWSCredentialsProviderChain();
76-
} else {
77-
logger.debug("Using basic key/secret credentials");
78-
credentials = new StaticCredentialsProvider(new BasicAWSCredentials(key, secret));
72+
try (SecureString key = DISCOVERY_EC2.ACCESS_KEY_SETTING.get(settings);
73+
SecureString secret = DISCOVERY_EC2.SECRET_KEY_SETTING.get(settings)) {
74+
if (key.length() == 0 && secret.length() == 0) {
75+
logger.debug("Using either environment variables, system properties or instance profile credentials");
76+
credentials = new DefaultAWSCredentialsProviderChain();
77+
} else {
78+
logger.debug("Using basic key/secret credentials");
79+
credentials = new StaticCredentialsProvider(new BasicAWSCredentials(key.toString(), secret.toString()));
80+
}
7981
}
8082

8183
return credentials;
@@ -86,19 +88,20 @@ protected static ClientConfiguration buildConfiguration(Logger logger, Settings
8688
// the response metadata cache is only there for diagnostics purposes,
8789
// but can force objects from every response to the old generation.
8890
clientConfiguration.setResponseMetadataCacheSize(0);
89-
clientConfiguration.setProtocol(CLOUD_EC2.PROTOCOL_SETTING.get(settings));
90-
91-
if (PROXY_HOST_SETTING.exists(settings) || CLOUD_EC2.PROXY_HOST_SETTING.exists(settings)) {
92-
String proxyHost = CLOUD_EC2.PROXY_HOST_SETTING.get(settings);
93-
Integer proxyPort = CLOUD_EC2.PROXY_PORT_SETTING.get(settings);
94-
String proxyUsername = CLOUD_EC2.PROXY_USERNAME_SETTING.get(settings);
95-
String proxyPassword = CLOUD_EC2.PROXY_PASSWORD_SETTING.get(settings);
96-
97-
clientConfiguration
98-
.withProxyHost(proxyHost)
99-
.withProxyPort(proxyPort)
100-
.withProxyUsername(proxyUsername)
101-
.withProxyPassword(proxyPassword);
91+
clientConfiguration.setProtocol(DISCOVERY_EC2.PROTOCOL_SETTING.get(settings));
92+
93+
if (PROXY_HOST_SETTING.exists(settings) || DISCOVERY_EC2.PROXY_HOST_SETTING.exists(settings)) {
94+
String proxyHost = DISCOVERY_EC2.PROXY_HOST_SETTING.get(settings);
95+
Integer proxyPort = DISCOVERY_EC2.PROXY_PORT_SETTING.get(settings);
96+
try (SecureString proxyUsername = DISCOVERY_EC2.PROXY_USERNAME_SETTING.get(settings);
97+
SecureString proxyPassword = DISCOVERY_EC2.PROXY_PASSWORD_SETTING.get(settings)) {
98+
99+
clientConfiguration
100+
.withProxyHost(proxyHost)
101+
.withProxyPort(proxyPort)
102+
.withProxyUsername(proxyUsername.toString())
103+
.withProxyPassword(proxyPassword.toString());
104+
}
102105
}
103106

104107
// #155: we might have 3rd party users using older EC2 API version
@@ -125,15 +128,15 @@ public long delayBeforeNextRetry(AmazonWebServiceRequest originalRequest,
125128
10,
126129
false);
127130
clientConfiguration.setRetryPolicy(retryPolicy);
128-
clientConfiguration.setSocketTimeout((int) CLOUD_EC2.READ_TIMEOUT.get(settings).millis());
131+
clientConfiguration.setSocketTimeout((int) DISCOVERY_EC2.READ_TIMEOUT_SETTING.get(settings).millis());
129132

130133
return clientConfiguration;
131134
}
132135

133136
protected static String findEndpoint(Logger logger, Settings settings) {
134137
String endpoint = null;
135-
if (CLOUD_EC2.ENDPOINT_SETTING.exists(settings)) {
136-
endpoint = CLOUD_EC2.ENDPOINT_SETTING.get(settings);
138+
if (DISCOVERY_EC2.ENDPOINT_SETTING.exists(settings) || CLOUD_EC2.ENDPOINT_SETTING.exists(settings)) {
139+
endpoint = DISCOVERY_EC2.ENDPOINT_SETTING.get(settings);
137140
logger.debug("using explicit ec2 endpoint [{}]", endpoint);
138141
} else if (REGION_SETTING.exists(settings) || CLOUD_EC2.REGION_SETTING.exists(settings)) {
139142
final String region = CLOUD_EC2.REGION_SETTING.get(settings);

0 commit comments

Comments
 (0)