Skip to content

Commit c7ffbfc

Browse files
Add Region and Signer Algorithm Overrides to S3 Repos
Closes elastic#51861
1 parent da5b35b commit c7ffbfc

File tree

4 files changed

+71
-9
lines changed

4 files changed

+71
-9
lines changed

docs/plugins/repository-s3.asciidoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,22 @@ pattern then you should set this setting to `true` when upgrading.
184184
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Builder.html#disableChunkedEncoding--[AWS
185185
Java SDK documentation] for details. Defaults to `false`.
186186

187+
`region`::
188+
189+
Allows specifying the signing region to use. Specificing this setting manually should not be necessary for most use cases. Generally,
190+
the SDK will correctly guess the singing region to use. It should be considered an expert level setting to support S3-compatible APIs
191+
that require https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html[v4 signatures] and use a region other than the
192+
default `us-east-1`. Defaults to empty string which means that the SDK will try to automatically determine the correct signing region.
193+
194+
`signer_override`::
195+
196+
Allows specifying the name of the signature algorithm to use for signing requests by the S3 client. Specifying this setting should not
197+
be necessary for most use cases. It should be considered an expert level setting to support S3-compatible APIs that do not support the
198+
signing algorithm that the SDK automatically determines for them.
199+
See the
200+
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html#setSignerOverride-java.lang.String-[AWS
201+
Java SDK documentation] for details. Defaults to empty string which means that no signing algorithm override will be used.
202+
187203
[float]
188204
[[repository-s3-compatible-services]]
189205
===== S3-compatible services

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.Map;
3636
import java.util.Objects;
3737
import java.util.Set;
38+
import java.util.function.Function;
3839

3940
/**
4041
* A container for settings used to create an S3 client.
@@ -103,6 +104,14 @@ final class S3ClientSettings {
103104
static final Setting.AffixSetting<Boolean> DISABLE_CHUNKED_ENCODING = Setting.affixKeySetting(PREFIX, "disable_chunked_encoding",
104105
key -> Setting.boolSetting(key, false, Property.NodeScope));
105106

107+
/** An override for the s3 region to use for signing requests. */
108+
static final Setting.AffixSetting<String> REGION = Setting.affixKeySetting(PREFIX, "region",
109+
key -> new Setting<>(key, "", Function.identity(), Property.NodeScope));
110+
111+
/** An override for the signer to use. */
112+
static final Setting.AffixSetting<String> SIGNER_OVERRIDE = Setting.affixKeySetting(PREFIX, "signer_override",
113+
key -> new Setting<>(key, "", Function.identity(), Property.NodeScope));
114+
106115
/** Credentials to authenticate with s3. */
107116
final S3BasicCredentials credentials;
108117

@@ -141,10 +150,16 @@ final class S3ClientSettings {
141150
/** Whether chunked encoding should be disabled or not. */
142151
final boolean disableChunkedEncoding;
143152

153+
/** Region to use for signing requests or empty string to use default. */
154+
final String region;
155+
156+
/** Signer override to use or empty string to use default. */
157+
final String signerOverride;
158+
144159
private S3ClientSettings(S3BasicCredentials credentials, String endpoint, Protocol protocol,
145160
String proxyHost, int proxyPort, String proxyUsername, String proxyPassword,
146161
int readTimeoutMillis, int maxRetries, boolean throttleRetries,
147-
boolean pathStyleAccess, boolean disableChunkedEncoding) {
162+
boolean pathStyleAccess, boolean disableChunkedEncoding, String region, String signerOverride) {
148163
this.credentials = credentials;
149164
this.endpoint = endpoint;
150165
this.protocol = protocol;
@@ -157,6 +172,8 @@ private S3ClientSettings(S3BasicCredentials credentials, String endpoint, Protoc
157172
this.throttleRetries = throttleRetries;
158173
this.pathStyleAccess = pathStyleAccess;
159174
this.disableChunkedEncoding = disableChunkedEncoding;
175+
this.region = region;
176+
this.signerOverride = signerOverride;
160177
}
161178

162179
/**
@@ -182,10 +199,13 @@ S3ClientSettings refine(RepositoryMetaData metadata) {
182199
final boolean usePathStyleAccess = getRepoSettingOrDefault(USE_PATH_STYLE_ACCESS, normalizedSettings, pathStyleAccess);
183200
final boolean newDisableChunkedEncoding = getRepoSettingOrDefault(
184201
DISABLE_CHUNKED_ENCODING, normalizedSettings, disableChunkedEncoding);
202+
final String newRegion = getRepoSettingOrDefault(REGION, normalizedSettings, region);
203+
final String newSignerOverride = getRepoSettingOrDefault(SIGNER_OVERRIDE, normalizedSettings, signerOverride);
185204
if (Objects.equals(endpoint, newEndpoint) && protocol == newProtocol && Objects.equals(proxyHost, newProxyHost)
186205
&& proxyPort == newProxyPort && newReadTimeoutMillis == readTimeoutMillis && maxRetries == newMaxRetries
187206
&& newThrottleRetries == throttleRetries
188-
&& newDisableChunkedEncoding == disableChunkedEncoding) {
207+
&& newDisableChunkedEncoding == disableChunkedEncoding
208+
&& Objects.equals(region, newRegion) && Objects.equals(signerOverride, newSignerOverride)) {
189209
return this;
190210
}
191211
return new S3ClientSettings(
@@ -200,7 +220,9 @@ S3ClientSettings refine(RepositoryMetaData metadata) {
200220
newMaxRetries,
201221
newThrottleRetries,
202222
usePathStyleAccess,
203-
newDisableChunkedEncoding
223+
newDisableChunkedEncoding,
224+
newRegion,
225+
newSignerOverride
204226
);
205227
}
206228

@@ -266,7 +288,9 @@ static S3ClientSettings getClientSettings(final Settings settings, final String
266288
getConfigValue(settings, clientName, MAX_RETRIES_SETTING),
267289
getConfigValue(settings, clientName, USE_THROTTLE_RETRIES_SETTING),
268290
getConfigValue(settings, clientName, USE_PATH_STYLE_ACCESS),
269-
getConfigValue(settings, clientName, DISABLE_CHUNKED_ENCODING)
291+
getConfigValue(settings, clientName, DISABLE_CHUNKED_ENCODING),
292+
getConfigValue(settings, clientName, REGION),
293+
getConfigValue(settings, clientName, SIGNER_OVERRIDE)
270294
);
271295
}
272296
}
@@ -290,13 +314,15 @@ public boolean equals(final Object o) {
290314
Objects.equals(proxyHost, that.proxyHost) &&
291315
Objects.equals(proxyUsername, that.proxyUsername) &&
292316
Objects.equals(proxyPassword, that.proxyPassword) &&
293-
Objects.equals(disableChunkedEncoding, that.disableChunkedEncoding);
317+
Objects.equals(disableChunkedEncoding, that.disableChunkedEncoding) &&
318+
Objects.equals(region, that.region) &&
319+
Objects.equals(signerOverride, that.signerOverride);
294320
}
295321

296322
@Override
297323
public int hashCode() {
298324
return Objects.hash(credentials, endpoint, protocol, proxyHost, proxyPort, proxyUsername, proxyPassword,
299-
readTimeoutMillis, maxRetries, throttleRetries, disableChunkedEncoding);
325+
readTimeoutMillis, maxRetries, throttleRetries, disableChunkedEncoding, region, signerOverride);
300326
}
301327

302328
private static <T> T getConfigValue(Settings settings, String clientName,

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ AmazonS3 buildClient(final S3ClientSettings clientSettings) {
142142
builder.withClientConfiguration(buildConfiguration(clientSettings));
143143

144144
final String endpoint = Strings.hasLength(clientSettings.endpoint) ? clientSettings.endpoint : Constants.S3_HOSTNAME;
145-
logger.debug("using endpoint [{}]", endpoint);
145+
final String region = Strings.hasLength(clientSettings.region) ? clientSettings.region : null;
146+
logger.debug("using endpoint [{}] and region [{}]", endpoint, region);
146147

147148
// If the endpoint configuration isn't set on the builder then the default behaviour is to try
148149
// and work out what region we are in and use an appropriate endpoint - see AwsClientBuilder#setRegion.
@@ -152,7 +153,7 @@ AmazonS3 buildClient(final S3ClientSettings clientSettings) {
152153
//
153154
// We do this because directly constructing the client is deprecated (was already deprecated in 1.1.223 too)
154155
// so this change removes that usage of a deprecated API.
155-
builder.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, null));
156+
builder.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region));
156157
if (clientSettings.pathStyleAccess) {
157158
builder.enablePathStyleAccess();
158159
}
@@ -178,6 +179,10 @@ static ClientConfiguration buildConfiguration(S3ClientSettings clientSettings) {
178179
clientConfiguration.setProxyPassword(clientSettings.proxyPassword);
179180
}
180181

182+
if (Strings.hasLength(clientSettings.signerOverride)) {
183+
clientConfiguration.setSignerOverride(clientSettings.signerOverride);
184+
}
185+
181186
clientConfiguration.setMaxErrorRetry(clientSettings.maxRetries);
182187
clientConfiguration.setUseThrottleRetries(clientSettings.throttleRetries);
183188
clientConfiguration.setSocketTimeout(clientSettings.readTimeoutMillis);
@@ -232,5 +237,4 @@ public void refresh() {
232237
public void close() {
233238
releaseCachedClients();
234239
}
235-
236240
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,20 @@ public void testUseChunkedEncodingCanBeSet() {
158158
assertThat(settings.get("default").disableChunkedEncoding, is(false));
159159
assertThat(settings.get("other").disableChunkedEncoding, is(true));
160160
}
161+
162+
public void testRegionCanBeSet() {
163+
final String region = randomAlphaOfLength(5);
164+
final Map<String, S3ClientSettings> settings = S3ClientSettings.load(
165+
Settings.builder().put("s3.client.other.region", region).build());
166+
assertThat(settings.get("default").region, is(""));
167+
assertThat(settings.get("other").region, is(region));
168+
}
169+
170+
public void testSignerOverrideCanBeSet() {
171+
final String signerOverride = randomAlphaOfLength(5);
172+
final Map<String, S3ClientSettings> settings = S3ClientSettings.load(
173+
Settings.builder().put("s3.client.other.signer_override", signerOverride).build());
174+
assertThat(settings.get("default").region, is(""));
175+
assertThat(settings.get("other").signerOverride, is(signerOverride));
176+
}
161177
}

0 commit comments

Comments
 (0)