Skip to content

Commit 2bcfe1a

Browse files
authored
Remove insecure settings (#46147)
This commit removes the oxymoron of insecure secure settings from the code base. In particular, we remove the ability to set the access_key and secret_key for S3 repositories inside the repository definition (in the cluster state). Instead, these settings now must be in the keystore. Thus, it also removes some leniency where these settings could be placed in the elasticsearch.yml, would not be rejected there, but would not be consumed for any purpose.
1 parent 12b76b8 commit 2bcfe1a

File tree

7 files changed

+13
-222
lines changed

7 files changed

+13
-222
lines changed

plugins/repository-s3/build.gradle

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,8 @@ bundlePlugin {
6565
}
6666
}
6767

68-
task testRepositoryCreds(type: Test) {
69-
include '**/RepositoryCredentialsTests.class'
70-
systemProperty 'es.allow_insecure_settings', 'true'
71-
}
72-
check.dependsOn(testRepositoryCreds)
73-
7468
test {
75-
// these are tested explicitly in separate test tasks
76-
exclude '**/RepositoryCredentialsTests.class'
69+
// this is tested explicitly in separate test tasks
7770
exclude '**/S3RepositoryThirdPartyTests.class'
7871
}
7972

plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3ClientSettings.java

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -182,20 +182,14 @@ S3ClientSettings refine(RepositoryMetaData metadata) {
182182
final boolean usePathStyleAccess = getRepoSettingOrDefault(USE_PATH_STYLE_ACCESS, normalizedSettings, pathStyleAccess);
183183
final boolean newDisableChunkedEncoding = getRepoSettingOrDefault(
184184
DISABLE_CHUNKED_ENCODING, normalizedSettings, disableChunkedEncoding);
185-
final S3BasicCredentials newCredentials;
186-
if (checkDeprecatedCredentials(repoSettings)) {
187-
newCredentials = loadDeprecatedCredentials(repoSettings);
188-
} else {
189-
newCredentials = credentials;
190-
}
191185
if (Objects.equals(endpoint, newEndpoint) && protocol == newProtocol && Objects.equals(proxyHost, newProxyHost)
192186
&& proxyPort == newProxyPort && newReadTimeoutMillis == readTimeoutMillis && maxRetries == newMaxRetries
193-
&& newThrottleRetries == throttleRetries && Objects.equals(credentials, newCredentials)
187+
&& newThrottleRetries == throttleRetries
194188
&& newDisableChunkedEncoding == disableChunkedEncoding) {
195189
return this;
196190
}
197191
return new S3ClientSettings(
198-
newCredentials,
192+
credentials,
199193
newEndpoint,
200194
newProtocol,
201195
newProxyHost,
@@ -229,29 +223,6 @@ static Map<String, S3ClientSettings> load(Settings settings) {
229223
return Collections.unmodifiableMap(clients);
230224
}
231225

232-
static boolean checkDeprecatedCredentials(Settings repositorySettings) {
233-
if (S3Repository.ACCESS_KEY_SETTING.exists(repositorySettings)) {
234-
if (S3Repository.SECRET_KEY_SETTING.exists(repositorySettings) == false) {
235-
throw new IllegalArgumentException("Repository setting [" + S3Repository.ACCESS_KEY_SETTING.getKey()
236-
+ " must be accompanied by setting [" + S3Repository.SECRET_KEY_SETTING.getKey() + "]");
237-
}
238-
return true;
239-
} else if (S3Repository.SECRET_KEY_SETTING.exists(repositorySettings)) {
240-
throw new IllegalArgumentException("Repository setting [" + S3Repository.SECRET_KEY_SETTING.getKey()
241-
+ " must be accompanied by setting [" + S3Repository.ACCESS_KEY_SETTING.getKey() + "]");
242-
}
243-
return false;
244-
}
245-
246-
// backcompat for reading keys out of repository settings (clusterState)
247-
private static S3BasicCredentials loadDeprecatedCredentials(Settings repositorySettings) {
248-
assert checkDeprecatedCredentials(repositorySettings);
249-
try (SecureString key = S3Repository.ACCESS_KEY_SETTING.get(repositorySettings);
250-
SecureString secret = S3Repository.SECRET_KEY_SETTING.get(repositorySettings)) {
251-
return new S3BasicCredentials(key.toString(), secret.toString());
252-
}
253-
}
254-
255226
private static S3BasicCredentials loadCredentials(Settings settings, String clientName) {
256227
try (SecureString accessKey = getConfigValue(settings, clientName, ACCESS_KEY_SETTING);
257228
SecureString secretKey = getConfigValue(settings, clientName, SECRET_KEY_SETTING);

plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3Repository.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525
import org.elasticsearch.common.Strings;
2626
import org.elasticsearch.common.blobstore.BlobPath;
2727
import org.elasticsearch.common.blobstore.BlobStore;
28-
import org.elasticsearch.common.logging.DeprecationLogger;
29-
import org.elasticsearch.common.settings.SecureSetting;
30-
import org.elasticsearch.common.settings.SecureString;
3128
import org.elasticsearch.common.settings.Setting;
3229
import org.elasticsearch.common.unit.ByteSizeUnit;
3330
import org.elasticsearch.common.unit.ByteSizeValue;
@@ -54,16 +51,9 @@
5451
*/
5552
class S3Repository extends BlobStoreRepository {
5653
private static final Logger logger = LogManager.getLogger(S3Repository.class);
57-
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
5854

5955
static final String TYPE = "s3";
6056

61-
/** The access key to authenticate with s3. This setting is insecure because cluster settings are stored in cluster state */
62-
static final Setting<SecureString> ACCESS_KEY_SETTING = SecureSetting.insecureString("access_key");
63-
64-
/** The secret key to authenticate with s3. This setting is insecure because cluster settings are stored in cluster state */
65-
static final Setting<SecureString> SECRET_KEY_SETTING = SecureSetting.insecureString("secret_key");
66-
6757
/**
6858
* Default is to use 100MB (S3 defaults) for heaps above 2GB and 5% of
6959
* the available memory for smaller heaps.
@@ -186,12 +176,6 @@ class S3Repository extends BlobStoreRepository {
186176
this.storageClass = STORAGE_CLASS_SETTING.get(metadata.settings());
187177
this.cannedACL = CANNED_ACL_SETTING.get(metadata.settings());
188178

189-
if (S3ClientSettings.checkDeprecatedCredentials(metadata.settings())) {
190-
// provided repository settings
191-
deprecationLogger.deprecated("Using s3 access/secret key from repository settings. Instead "
192-
+ "store these in named clients and the elasticsearch keystore for secure settings.");
193-
}
194-
195179
logger.debug(
196180
"using bucket [{}], chunk_size [{}], server_side_encryption [{}], buffer_size [{}], cannedACL [{}], storageClass [{}]",
197181
bucket,

plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3RepositoryPlugin.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,7 @@ public List<Setting<?>> getSettings() {
105105
S3ClientSettings.READ_TIMEOUT_SETTING,
106106
S3ClientSettings.MAX_RETRIES_SETTING,
107107
S3ClientSettings.USE_THROTTLE_RETRIES_SETTING,
108-
S3ClientSettings.USE_PATH_STYLE_ACCESS,
109-
S3Repository.ACCESS_KEY_SETTING,
110-
S3Repository.SECRET_KEY_SETTING);
108+
S3ClientSettings.USE_PATH_STYLE_ACCESS);
111109
}
112110

113111
@Override

plugins/repository-s3/src/main/plugin-metadata/plugin-security.policy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
grant {
21+
2122
// needed because of problems in ClientConfiguration
2223
// TODO: get these fixed in aws sdk
2324
permission java.lang.RuntimePermission "accessDeclaredMembers";
@@ -38,6 +39,5 @@ grant {
3839
// s3 client opens socket connections for to access repository
3940
permission java.net.SocketPermission "*", "connect";
4041

41-
// only for tests : org.elasticsearch.repositories.s3.S3RepositoryPlugin
42-
permission java.util.PropertyPermission "es.allow_insecure_settings", "read,write";
42+
4343
};

plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/RepositoryCredentialsTests.java

Lines changed: 5 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -24,53 +24,28 @@
2424
import com.amazonaws.services.s3.AmazonS3;
2525
import org.apache.logging.log4j.LogManager;
2626
import org.apache.logging.log4j.Logger;
27-
import org.elasticsearch.client.node.NodeClient;
2827
import org.elasticsearch.cluster.metadata.RepositoryMetaData;
29-
import org.elasticsearch.common.SuppressForbidden;
3028
import org.elasticsearch.common.settings.MockSecureSettings;
3129
import org.elasticsearch.common.settings.Settings;
32-
import org.elasticsearch.common.settings.SettingsFilter;
3330
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
3431
import org.elasticsearch.plugins.Plugin;
3532
import org.elasticsearch.plugins.PluginsService;
3633
import org.elasticsearch.repositories.RepositoriesService;
37-
import org.elasticsearch.rest.AbstractRestChannel;
38-
import org.elasticsearch.rest.RestController;
39-
import org.elasticsearch.rest.RestRequest;
40-
import org.elasticsearch.rest.RestResponse;
41-
import org.elasticsearch.rest.action.admin.cluster.RestGetRepositoriesAction;
4234
import org.elasticsearch.test.ESSingleNodeTestCase;
43-
import org.elasticsearch.test.rest.FakeRestRequest;
4435
import org.elasticsearch.threadpool.ThreadPool;
4536

46-
import java.security.AccessController;
47-
import java.security.PrivilegedAction;
4837
import java.util.Collection;
4938
import java.util.List;
50-
import java.util.concurrent.CountDownLatch;
51-
import java.util.concurrent.atomic.AtomicReference;
5239

5340
import static org.elasticsearch.repositories.s3.S3ClientSettings.ACCESS_KEY_SETTING;
5441
import static org.elasticsearch.repositories.s3.S3ClientSettings.SECRET_KEY_SETTING;
5542
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
56-
import static org.hamcrest.Matchers.containsString;
5743
import static org.hamcrest.Matchers.instanceOf;
5844
import static org.hamcrest.Matchers.is;
59-
import static org.hamcrest.Matchers.not;
6045
import static org.hamcrest.Matchers.notNullValue;
61-
import static org.mockito.Mockito.mock;
6246

63-
@SuppressForbidden(reason = "test requires to set a System property to allow insecure settings when running in IDE")
6447
public class RepositoryCredentialsTests extends ESSingleNodeTestCase {
6548

66-
static {
67-
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
68-
// required for client settings overwriting when running in IDE
69-
System.setProperty("es.allow_insecure_settings", "true");
70-
return null;
71-
});
72-
}
73-
7449
@Override
7550
protected Collection<Class<? extends Plugin>> getPlugins() {
7651
return List.of(ProxyS3RepositoryPlugin.class);
@@ -95,52 +70,11 @@ protected Settings nodeSettings() {
9570
.build();
9671
}
9772

98-
public void testRepositoryCredentialsOverrideSecureCredentials() {
99-
final String repositoryName = "repo-creds-override";
100-
final Settings.Builder repositorySettings = Settings.builder()
101-
// repository settings for credentials override node secure settings
102-
.put(S3Repository.ACCESS_KEY_SETTING.getKey(), "insecure_aws_key")
103-
.put(S3Repository.SECRET_KEY_SETTING.getKey(), "insecure_aws_secret");
104-
105-
final String clientName = randomFrom("default", "other", null);
106-
if (clientName != null) {
107-
repositorySettings.put(S3Repository.CLIENT_NAME.getKey(), clientName);
108-
}
109-
createRepository(repositoryName, repositorySettings.build());
110-
111-
final RepositoriesService repositories = getInstanceFromNode(RepositoriesService.class);
112-
assertThat(repositories.repository(repositoryName), notNullValue());
113-
assertThat(repositories.repository(repositoryName), instanceOf(S3Repository.class));
114-
115-
final S3Repository repository = (S3Repository) repositories.repository(repositoryName);
116-
final AmazonS3 client = repository.createBlobStore().clientReference().client();
117-
assertThat(client, instanceOf(ProxyS3RepositoryPlugin.ClientAndCredentials.class));
118-
119-
final AWSCredentials credentials = ((ProxyS3RepositoryPlugin.ClientAndCredentials) client).credentials.getCredentials();
120-
assertThat(credentials.getAWSAccessKeyId(), is("insecure_aws_key"));
121-
assertThat(credentials.getAWSSecretKey(), is("insecure_aws_secret"));
122-
123-
assertWarnings(
124-
"[secret_key] setting was deprecated in Elasticsearch and will be removed in a future release!"
125-
+ " See the breaking changes documentation for the next major version.",
126-
"Using s3 access/secret key from repository settings. Instead store these in named clients and"
127-
+ " the elasticsearch keystore for secure settings.",
128-
"[access_key] setting was deprecated in Elasticsearch and will be removed in a future release!"
129-
+ " See the breaking changes documentation for the next major version.");
130-
}
131-
13273
public void testReinitSecureCredentials() {
13374
final String clientName = randomFrom("default", "other");
13475

13576
final Settings.Builder repositorySettings = Settings.builder();
136-
final boolean hasInsecureSettings = randomBoolean();
137-
if (hasInsecureSettings) {
138-
// repository settings for credentials override node secure settings
139-
repositorySettings.put(S3Repository.ACCESS_KEY_SETTING.getKey(), "insecure_aws_key");
140-
repositorySettings.put(S3Repository.SECRET_KEY_SETTING.getKey(), "insecure_aws_secret");
141-
} else {
142-
repositorySettings.put(S3Repository.CLIENT_NAME.getKey(), clientName);
143-
}
77+
repositorySettings.put(S3Repository.CLIENT_NAME.getKey(), clientName);
14478

14579
final String repositoryName = "repo-reinit-creds";
14680
createRepository(repositoryName, repositorySettings.build());
@@ -155,10 +89,7 @@ public void testReinitSecureCredentials() {
15589
assertThat(client, instanceOf(ProxyS3RepositoryPlugin.ClientAndCredentials.class));
15690

15791
final AWSCredentials credentials = ((ProxyS3RepositoryPlugin.ClientAndCredentials) client).credentials.getCredentials();
158-
if (hasInsecureSettings) {
159-
assertThat(credentials.getAWSAccessKeyId(), is("insecure_aws_key"));
160-
assertThat(credentials.getAWSSecretKey(), is("insecure_aws_secret"));
161-
} else if ("other".equals(clientName)) {
92+
if ("other".equals(clientName)) {
16293
assertThat(credentials.getAWSAccessKeyId(), is("secure_other_key"));
16394
assertThat(credentials.getAWSSecretKey(), is("secure_other_secret"));
16495
} else {
@@ -177,10 +108,7 @@ public void testReinitSecureCredentials() {
177108
plugin.reload(newSettings);
178109

179110
// check the not-yet-closed client reference still has the same credentials
180-
if (hasInsecureSettings) {
181-
assertThat(credentials.getAWSAccessKeyId(), is("insecure_aws_key"));
182-
assertThat(credentials.getAWSSecretKey(), is("insecure_aws_secret"));
183-
} else if ("other".equals(clientName)) {
111+
if ("other".equals(clientName)) {
184112
assertThat(credentials.getAWSAccessKeyId(), is("secure_other_key"));
185113
assertThat(credentials.getAWSSecretKey(), is("secure_other_secret"));
186114
} else {
@@ -195,64 +123,11 @@ public void testReinitSecureCredentials() {
195123
assertThat(client, instanceOf(ProxyS3RepositoryPlugin.ClientAndCredentials.class));
196124

197125
final AWSCredentials newCredentials = ((ProxyS3RepositoryPlugin.ClientAndCredentials) client).credentials.getCredentials();
198-
if (hasInsecureSettings) {
199-
assertThat(newCredentials.getAWSAccessKeyId(), is("insecure_aws_key"));
200-
assertThat(newCredentials.getAWSSecretKey(), is("insecure_aws_secret"));
201-
} else {
202-
assertThat(newCredentials.getAWSAccessKeyId(), is("new_secret_aws_key"));
203-
assertThat(newCredentials.getAWSSecretKey(), is("new_secret_aws_secret"));
204-
}
205-
}
206-
207-
if (hasInsecureSettings) {
208-
assertWarnings(
209-
"[secret_key] setting was deprecated in Elasticsearch and will be removed in a future release!"
210-
+ " See the breaking changes documentation for the next major version.",
211-
"Using s3 access/secret key from repository settings. Instead store these in named clients and"
212-
+ " the elasticsearch keystore for secure settings.",
213-
"[access_key] setting was deprecated in Elasticsearch and will be removed in a future release!"
214-
+ " See the breaking changes documentation for the next major version.");
126+
assertThat(newCredentials.getAWSAccessKeyId(), is("new_secret_aws_key"));
127+
assertThat(newCredentials.getAWSSecretKey(), is("new_secret_aws_secret"));
215128
}
216129
}
217130

218-
public void testInsecureRepositoryCredentials() throws Exception {
219-
final String repositoryName = "repo-insecure-creds";
220-
createRepository(repositoryName, Settings.builder()
221-
.put(S3Repository.ACCESS_KEY_SETTING.getKey(), "insecure_aws_key")
222-
.put(S3Repository.SECRET_KEY_SETTING.getKey(), "insecure_aws_secret")
223-
.build());
224-
225-
final RestRequest fakeRestRequest = new FakeRestRequest();
226-
fakeRestRequest.params().put("repository", repositoryName);
227-
final RestGetRepositoriesAction action =
228-
new RestGetRepositoriesAction(mock(RestController.class), getInstanceFromNode(SettingsFilter.class));
229-
230-
final CountDownLatch latch = new CountDownLatch(1);
231-
final AtomicReference<AssertionError> error = new AtomicReference<>();
232-
action.handleRequest(fakeRestRequest, new AbstractRestChannel(fakeRestRequest, true) {
233-
@Override
234-
public void sendResponse(RestResponse response) {
235-
try {
236-
String responseAsString = response.content().utf8ToString();
237-
assertThat(responseAsString, containsString(repositoryName));
238-
assertThat(responseAsString, not(containsString("insecure_")));
239-
} catch (final AssertionError ex) {
240-
error.set(ex);
241-
}
242-
latch.countDown();
243-
}
244-
}, getInstanceFromNode(NodeClient.class));
245-
246-
latch.await();
247-
if (error.get() != null) {
248-
throw error.get();
249-
}
250-
251-
assertWarnings(
252-
"Using s3 access/secret key from repository settings. Instead store these in named clients and"
253-
+ " the elasticsearch keystore for secure settings.");
254-
}
255-
256131
private void createRepository(final String name, final Settings repositorySettings) {
257132
assertAcked(client().admin().cluster().preparePutRepository(name)
258133
.setType(S3Repository.TYPE)

0 commit comments

Comments
 (0)