Support use of IRSA for repository-s3 plugin credentials (#3475)
* Support use of IRSA for repository-s3 plugin credentials Signed-off-by: Andriy Redko <andriy.redko@aiven.io> * Address code review comments Signed-off-by: Andriy Redko <andriy.redko@aiven.io> * Address code review comments Signed-off-by: Andriy Redko <andriy.redko@aiven.io>
This commit is contained in:
parent
2bfe8b31af
commit
596d32a5fa
|
@ -51,6 +51,7 @@ versions << [
|
||||||
dependencies {
|
dependencies {
|
||||||
api "com.amazonaws:aws-java-sdk-s3:${versions.aws}"
|
api "com.amazonaws:aws-java-sdk-s3:${versions.aws}"
|
||||||
api "com.amazonaws:aws-java-sdk-core:${versions.aws}"
|
api "com.amazonaws:aws-java-sdk-core:${versions.aws}"
|
||||||
|
api "com.amazonaws:aws-java-sdk-sts:${versions.aws}"
|
||||||
api "com.amazonaws:jmespath-java:${versions.aws}"
|
api "com.amazonaws:jmespath-java:${versions.aws}"
|
||||||
api "org.apache.httpcomponents:httpclient:${versions.httpclient}"
|
api "org.apache.httpcomponents:httpclient:${versions.httpclient}"
|
||||||
api "org.apache.httpcomponents:httpcore:${versions.httpcore}"
|
api "org.apache.httpcomponents:httpcore:${versions.httpcore}"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
724bd22c0ff41c496469e18f9bea12bdfb2f7540
|
|
@ -32,17 +32,39 @@
|
||||||
|
|
||||||
package org.opensearch.repositories.s3;
|
package org.opensearch.repositories.s3;
|
||||||
|
|
||||||
|
import com.amazonaws.auth.AWSCredentialsProvider;
|
||||||
import com.amazonaws.services.s3.AmazonS3;
|
import com.amazonaws.services.s3.AmazonS3;
|
||||||
import com.amazonaws.services.s3.AmazonS3Client;
|
import com.amazonaws.services.s3.AmazonS3Client;
|
||||||
|
|
||||||
|
import org.opensearch.common.Nullable;
|
||||||
import org.opensearch.common.concurrent.RefCountedReleasable;
|
import org.opensearch.common.concurrent.RefCountedReleasable;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the shutdown of the wrapped {@link AmazonS3Client} using reference
|
* Handles the shutdown of the wrapped {@link AmazonS3Client} using reference
|
||||||
* counting.
|
* counting.
|
||||||
*/
|
*/
|
||||||
public class AmazonS3Reference extends RefCountedReleasable<AmazonS3> {
|
public class AmazonS3Reference extends RefCountedReleasable<AmazonS3> {
|
||||||
|
|
||||||
AmazonS3Reference(AmazonS3 client) {
|
AmazonS3Reference(AmazonS3 client) {
|
||||||
super("AWS_S3_CLIENT", client, client::shutdown);
|
this(client, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
AmazonS3Reference(AmazonS3WithCredentials client) {
|
||||||
|
this(client.client(), client.credentials());
|
||||||
|
}
|
||||||
|
|
||||||
|
AmazonS3Reference(AmazonS3 client, @Nullable AWSCredentialsProvider credentials) {
|
||||||
|
super("AWS_S3_CLIENT", client, () -> {
|
||||||
|
client.shutdown();
|
||||||
|
if (credentials instanceof Closeable) {
|
||||||
|
try {
|
||||||
|
((Closeable) credentials).close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
/* Do nothing here */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* The OpenSearch Contributors require contributions made to
|
||||||
|
* this file be licensed under the Apache-2.0 license or a
|
||||||
|
* compatible open source license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.opensearch.repositories.s3;
|
||||||
|
|
||||||
|
import com.amazonaws.auth.AWSCredentialsProvider;
|
||||||
|
import com.amazonaws.services.s3.AmazonS3;
|
||||||
|
|
||||||
|
import org.opensearch.common.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The holder of the AmazonS3 and AWSCredentialsProvider
|
||||||
|
*/
|
||||||
|
final class AmazonS3WithCredentials {
|
||||||
|
private final AmazonS3 client;
|
||||||
|
private final AWSCredentialsProvider credentials;
|
||||||
|
|
||||||
|
private AmazonS3WithCredentials(final AmazonS3 client, @Nullable final AWSCredentialsProvider credentials) {
|
||||||
|
this.client = client;
|
||||||
|
this.credentials = credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
AmazonS3 client() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
AWSCredentialsProvider credentials() {
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AmazonS3WithCredentials create(final AmazonS3 client, @Nullable final AWSCredentialsProvider credentials) {
|
||||||
|
return new AmazonS3WithCredentials(client, credentials);
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,6 +67,29 @@ final class S3ClientSettings {
|
||||||
/** Placeholder client name for normalizing client settings in the repository settings. */
|
/** Placeholder client name for normalizing client settings in the repository settings. */
|
||||||
private static final String PLACEHOLDER_CLIENT = "placeholder";
|
private static final String PLACEHOLDER_CLIENT = "placeholder";
|
||||||
|
|
||||||
|
// Properties to support using IAM Roles for Service Accounts (IRSA)
|
||||||
|
|
||||||
|
/** The identity token file for connecting to s3. */
|
||||||
|
static final Setting.AffixSetting<String> IDENTITY_TOKEN_FILE_SETTING = Setting.affixKeySetting(
|
||||||
|
PREFIX,
|
||||||
|
"identity_token_file",
|
||||||
|
key -> SecureSetting.simpleString(key, Property.NodeScope)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** The role ARN (Amazon Resource Name) for connecting to s3. */
|
||||||
|
static final Setting.AffixSetting<SecureString> ROLE_ARN_SETTING = Setting.affixKeySetting(
|
||||||
|
PREFIX,
|
||||||
|
"role_arn",
|
||||||
|
key -> SecureSetting.secureString(key, null)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** The role session name for connecting to s3. */
|
||||||
|
static final Setting.AffixSetting<SecureString> ROLE_SESSION_NAME_SETTING = Setting.affixKeySetting(
|
||||||
|
PREFIX,
|
||||||
|
"role_session_name",
|
||||||
|
key -> SecureSetting.secureString(key, null)
|
||||||
|
);
|
||||||
|
|
||||||
/** The access key (ie login id) for connecting to s3. */
|
/** The access key (ie login id) for connecting to s3. */
|
||||||
static final Setting.AffixSetting<SecureString> ACCESS_KEY_SETTING = Setting.affixKeySetting(
|
static final Setting.AffixSetting<SecureString> ACCESS_KEY_SETTING = Setting.affixKeySetting(
|
||||||
PREFIX,
|
PREFIX,
|
||||||
|
@ -189,6 +212,9 @@ final class S3ClientSettings {
|
||||||
/** Credentials to authenticate with s3. */
|
/** Credentials to authenticate with s3. */
|
||||||
final S3BasicCredentials credentials;
|
final S3BasicCredentials credentials;
|
||||||
|
|
||||||
|
/** Credentials to authenticate with s3 using IAM Roles for Service Accounts (IRSA). */
|
||||||
|
final IrsaCredentials irsaCredentials;
|
||||||
|
|
||||||
/** The s3 endpoint the client should talk to, or empty string to use the default. */
|
/** The s3 endpoint the client should talk to, or empty string to use the default. */
|
||||||
final String endpoint;
|
final String endpoint;
|
||||||
|
|
||||||
|
@ -221,6 +247,7 @@ final class S3ClientSettings {
|
||||||
|
|
||||||
private S3ClientSettings(
|
private S3ClientSettings(
|
||||||
S3BasicCredentials credentials,
|
S3BasicCredentials credentials,
|
||||||
|
IrsaCredentials irsaCredentials,
|
||||||
String endpoint,
|
String endpoint,
|
||||||
Protocol protocol,
|
Protocol protocol,
|
||||||
int readTimeoutMillis,
|
int readTimeoutMillis,
|
||||||
|
@ -233,6 +260,7 @@ final class S3ClientSettings {
|
||||||
ProxySettings proxySettings
|
ProxySettings proxySettings
|
||||||
) {
|
) {
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
|
this.irsaCredentials = irsaCredentials;
|
||||||
this.endpoint = endpoint;
|
this.endpoint = endpoint;
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
this.readTimeoutMillis = readTimeoutMillis;
|
this.readTimeoutMillis = readTimeoutMillis;
|
||||||
|
@ -301,6 +329,7 @@ final class S3ClientSettings {
|
||||||
validateInetAddressFor(newProxyHost);
|
validateInetAddressFor(newProxyHost);
|
||||||
return new S3ClientSettings(
|
return new S3ClientSettings(
|
||||||
newCredentials,
|
newCredentials,
|
||||||
|
irsaCredentials,
|
||||||
newEndpoint,
|
newEndpoint,
|
||||||
newProtocol,
|
newProtocol,
|
||||||
newReadTimeoutMillis,
|
newReadTimeoutMillis,
|
||||||
|
@ -396,12 +425,27 @@ final class S3ClientSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IrsaCredentials loadIrsaCredentials(Settings settings, String clientName) {
|
||||||
|
String identityTokenFile = getConfigValue(settings, clientName, IDENTITY_TOKEN_FILE_SETTING);
|
||||||
|
try (
|
||||||
|
SecureString roleArn = getConfigValue(settings, clientName, ROLE_ARN_SETTING);
|
||||||
|
SecureString roleSessionName = getConfigValue(settings, clientName, ROLE_SESSION_NAME_SETTING)
|
||||||
|
) {
|
||||||
|
if (identityTokenFile.length() != 0 || roleArn.length() != 0 || roleSessionName.length() != 0) {
|
||||||
|
return new IrsaCredentials(identityTokenFile.toString(), roleArn.toString(), roleSessionName.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pkg private for tests
|
// pkg private for tests
|
||||||
/** Parse settings for a single client. */
|
/** Parse settings for a single client. */
|
||||||
static S3ClientSettings getClientSettings(final Settings settings, final String clientName) {
|
static S3ClientSettings getClientSettings(final Settings settings, final String clientName) {
|
||||||
final Protocol awsProtocol = getConfigValue(settings, clientName, PROTOCOL_SETTING);
|
final Protocol awsProtocol = getConfigValue(settings, clientName, PROTOCOL_SETTING);
|
||||||
return new S3ClientSettings(
|
return new S3ClientSettings(
|
||||||
S3ClientSettings.loadCredentials(settings, clientName),
|
S3ClientSettings.loadCredentials(settings, clientName),
|
||||||
|
S3ClientSettings.loadIrsaCredentials(settings, clientName),
|
||||||
getConfigValue(settings, clientName, ENDPOINT_SETTING),
|
getConfigValue(settings, clientName, ENDPOINT_SETTING),
|
||||||
awsProtocol,
|
awsProtocol,
|
||||||
Math.toIntExact(getConfigValue(settings, clientName, READ_TIMEOUT_SETTING).millis()),
|
Math.toIntExact(getConfigValue(settings, clientName, READ_TIMEOUT_SETTING).millis()),
|
||||||
|
@ -482,7 +526,8 @@ final class S3ClientSettings {
|
||||||
&& proxySettings.equals(that.proxySettings)
|
&& proxySettings.equals(that.proxySettings)
|
||||||
&& Objects.equals(disableChunkedEncoding, that.disableChunkedEncoding)
|
&& Objects.equals(disableChunkedEncoding, that.disableChunkedEncoding)
|
||||||
&& Objects.equals(region, that.region)
|
&& Objects.equals(region, that.region)
|
||||||
&& Objects.equals(signerOverride, that.signerOverride);
|
&& Objects.equals(signerOverride, that.signerOverride)
|
||||||
|
&& Objects.equals(irsaCredentials, that.irsaCredentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -512,4 +557,51 @@ final class S3ClientSettings {
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to store IAM Roles for Service Accounts (IRSA) credentials
|
||||||
|
* See please: https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
|
||||||
|
*/
|
||||||
|
static class IrsaCredentials {
|
||||||
|
private final String identityTokenFile;
|
||||||
|
private final String roleArn;
|
||||||
|
private final String roleSessionName;
|
||||||
|
|
||||||
|
IrsaCredentials(String identityTokenFile, String roleArn, String roleSessionName) {
|
||||||
|
this.identityTokenFile = Strings.isNullOrEmpty(identityTokenFile) ? null : identityTokenFile;
|
||||||
|
this.roleArn = Strings.isNullOrEmpty(roleArn) ? null : roleArn;
|
||||||
|
this.roleSessionName = Strings.isNullOrEmpty(roleSessionName) ? "s3-sdk-java-" + System.currentTimeMillis() : roleSessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdentityTokenFile() {
|
||||||
|
return identityTokenFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleArn() {
|
||||||
|
return roleArn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoleSessionName() {
|
||||||
|
return roleSessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final IrsaCredentials that = (IrsaCredentials) o;
|
||||||
|
return Objects.equals(identityTokenFile, that.identityTokenFile)
|
||||||
|
&& Objects.equals(roleArn, that.roleArn)
|
||||||
|
&& Objects.equals(roleSessionName, that.roleSessionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(identityTokenFile, roleArn, roleSessionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,10 @@ public class S3RepositoryPlugin extends Plugin implements RepositoryPlugin, Relo
|
||||||
S3Repository.ACCESS_KEY_SETTING,
|
S3Repository.ACCESS_KEY_SETTING,
|
||||||
S3Repository.SECRET_KEY_SETTING,
|
S3Repository.SECRET_KEY_SETTING,
|
||||||
S3ClientSettings.SIGNER_OVERRIDE,
|
S3ClientSettings.SIGNER_OVERRIDE,
|
||||||
S3ClientSettings.REGION
|
S3ClientSettings.REGION,
|
||||||
|
S3ClientSettings.ROLE_ARN_SETTING,
|
||||||
|
S3ClientSettings.IDENTITY_TOKEN_FILE_SETTING,
|
||||||
|
S3ClientSettings.ROLE_SESSION_NAME_SETTING
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,11 @@ package org.opensearch.repositories.s3;
|
||||||
import com.amazonaws.ClientConfiguration;
|
import com.amazonaws.ClientConfiguration;
|
||||||
import com.amazonaws.auth.AWSCredentials;
|
import com.amazonaws.auth.AWSCredentials;
|
||||||
import com.amazonaws.auth.AWSCredentialsProvider;
|
import com.amazonaws.auth.AWSCredentialsProvider;
|
||||||
|
import com.amazonaws.auth.AWSSessionCredentialsProvider;
|
||||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||||
import com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper;
|
import com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper;
|
||||||
|
import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
|
||||||
|
import com.amazonaws.auth.STSAssumeRoleWithWebIdentitySessionCredentialsProvider;
|
||||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
import com.amazonaws.client.builder.AwsClientBuilder;
|
||||||
import com.amazonaws.http.IdleConnectionReaper;
|
import com.amazonaws.http.IdleConnectionReaper;
|
||||||
import com.amazonaws.http.SystemPropertyTlsKeyManagersProvider;
|
import com.amazonaws.http.SystemPropertyTlsKeyManagersProvider;
|
||||||
|
@ -45,6 +48,8 @@ import com.amazonaws.internal.SdkSSLContext;
|
||||||
import com.amazonaws.services.s3.AmazonS3;
|
import com.amazonaws.services.s3.AmazonS3;
|
||||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||||
import com.amazonaws.services.s3.internal.Constants;
|
import com.amazonaws.services.s3.internal.Constants;
|
||||||
|
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
|
||||||
|
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
|
||||||
|
|
||||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
|
@ -52,9 +57,11 @@ import org.apache.http.protocol.HttpContext;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.opensearch.cluster.metadata.RepositoryMetadata;
|
import org.opensearch.cluster.metadata.RepositoryMetadata;
|
||||||
|
import org.opensearch.common.Nullable;
|
||||||
import org.opensearch.common.Strings;
|
import org.opensearch.common.Strings;
|
||||||
import org.opensearch.common.collect.MapBuilder;
|
import org.opensearch.common.collect.MapBuilder;
|
||||||
import org.opensearch.common.settings.Settings;
|
import org.opensearch.common.settings.Settings;
|
||||||
|
import org.opensearch.repositories.s3.S3ClientSettings.IrsaCredentials;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
@ -67,6 +74,9 @@ import java.net.Socket;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.amazonaws.SDKGlobalConfiguration.AWS_ROLE_ARN_ENV_VAR;
|
||||||
|
import static com.amazonaws.SDKGlobalConfiguration.AWS_ROLE_SESSION_NAME_ENV_VAR;
|
||||||
|
import static com.amazonaws.SDKGlobalConfiguration.AWS_WEB_IDENTITY_ENV_VAR;
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
|
|
||||||
class S3Service implements Closeable {
|
class S3Service implements Closeable {
|
||||||
|
@ -163,9 +173,11 @@ class S3Service implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxy for testing
|
// proxy for testing
|
||||||
AmazonS3 buildClient(final S3ClientSettings clientSettings) {
|
AmazonS3WithCredentials buildClient(final S3ClientSettings clientSettings) {
|
||||||
final AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
|
final AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
|
||||||
builder.withCredentials(buildCredentials(logger, clientSettings));
|
|
||||||
|
final AWSCredentialsProvider credentials = buildCredentials(logger, clientSettings);
|
||||||
|
builder.withCredentials(credentials);
|
||||||
builder.withClientConfiguration(buildConfiguration(clientSettings));
|
builder.withClientConfiguration(buildConfiguration(clientSettings));
|
||||||
|
|
||||||
String endpoint = Strings.hasLength(clientSettings.endpoint) ? clientSettings.endpoint : Constants.S3_HOSTNAME;
|
String endpoint = Strings.hasLength(clientSettings.endpoint) ? clientSettings.endpoint : Constants.S3_HOSTNAME;
|
||||||
|
@ -192,7 +204,8 @@ class S3Service implements Closeable {
|
||||||
if (clientSettings.disableChunkedEncoding) {
|
if (clientSettings.disableChunkedEncoding) {
|
||||||
builder.disableChunkedEncoding();
|
builder.disableChunkedEncoding();
|
||||||
}
|
}
|
||||||
return SocketAccess.doPrivileged(builder::build);
|
final AmazonS3 client = SocketAccess.doPrivileged(builder::build);
|
||||||
|
return AmazonS3WithCredentials.create(client, credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pkg private for tests
|
// pkg private for tests
|
||||||
|
@ -258,24 +271,83 @@ class S3Service implements Closeable {
|
||||||
|
|
||||||
// pkg private for tests
|
// pkg private for tests
|
||||||
static AWSCredentialsProvider buildCredentials(Logger logger, S3ClientSettings clientSettings) {
|
static AWSCredentialsProvider buildCredentials(Logger logger, S3ClientSettings clientSettings) {
|
||||||
final S3BasicCredentials credentials = clientSettings.credentials;
|
final S3BasicCredentials basicCredentials = clientSettings.credentials;
|
||||||
if (credentials == null) {
|
final IrsaCredentials irsaCredentials = buildFromEnviroment(clientSettings.irsaCredentials);
|
||||||
|
|
||||||
|
// If IAM Roles for Service Accounts (IRSA) credentials are configured, start with them first
|
||||||
|
if (irsaCredentials != null) {
|
||||||
|
logger.debug("Using IRSA credentials");
|
||||||
|
|
||||||
|
AWSSecurityTokenService securityTokenService = null;
|
||||||
|
final String region = Strings.hasLength(clientSettings.region) ? clientSettings.region : null;
|
||||||
|
if (region != null || basicCredentials != null) {
|
||||||
|
securityTokenService = SocketAccess.doPrivileged(
|
||||||
|
() -> AWSSecurityTokenServiceClientBuilder.standard()
|
||||||
|
.withCredentials((basicCredentials != null) ? new AWSStaticCredentialsProvider(basicCredentials) : null)
|
||||||
|
.withRegion(region)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irsaCredentials.getIdentityTokenFile() == null) {
|
||||||
|
return new PrivilegedSTSAssumeRoleSessionCredentialsProvider<>(
|
||||||
|
securityTokenService,
|
||||||
|
new STSAssumeRoleSessionCredentialsProvider.Builder(irsaCredentials.getRoleArn(), irsaCredentials.getRoleSessionName())
|
||||||
|
.withStsClient(securityTokenService)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new PrivilegedSTSAssumeRoleSessionCredentialsProvider<>(
|
||||||
|
securityTokenService,
|
||||||
|
new STSAssumeRoleWithWebIdentitySessionCredentialsProvider.Builder(
|
||||||
|
irsaCredentials.getRoleArn(),
|
||||||
|
irsaCredentials.getRoleSessionName(),
|
||||||
|
irsaCredentials.getIdentityTokenFile()
|
||||||
|
).withStsClient(securityTokenService).build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (basicCredentials != null) {
|
||||||
|
logger.debug("Using basic key/secret credentials");
|
||||||
|
return new AWSStaticCredentialsProvider(basicCredentials);
|
||||||
|
} else {
|
||||||
logger.debug("Using instance profile credentials");
|
logger.debug("Using instance profile credentials");
|
||||||
return new PrivilegedInstanceProfileCredentialsProvider();
|
return new PrivilegedInstanceProfileCredentialsProvider();
|
||||||
} else {
|
|
||||||
logger.debug("Using basic key/secret credentials");
|
|
||||||
return new AWSStaticCredentialsProvider(credentials);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IrsaCredentials buildFromEnviroment(IrsaCredentials defaults) {
|
||||||
|
if (defaults == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String webIdentityTokenFile = defaults.getIdentityTokenFile();
|
||||||
|
if (webIdentityTokenFile == null) {
|
||||||
|
webIdentityTokenFile = System.getenv(AWS_WEB_IDENTITY_ENV_VAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
String roleArn = defaults.getRoleArn();
|
||||||
|
if (roleArn == null) {
|
||||||
|
roleArn = System.getenv(AWS_ROLE_ARN_ENV_VAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
String roleSessionName = defaults.getRoleSessionName();
|
||||||
|
if (roleSessionName == null) {
|
||||||
|
roleSessionName = System.getenv(AWS_ROLE_SESSION_NAME_ENV_VAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IrsaCredentials(webIdentityTokenFile, roleArn, roleSessionName);
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized void releaseCachedClients() {
|
private synchronized void releaseCachedClients() {
|
||||||
// the clients will shutdown when they will not be used anymore
|
// the clients will shutdown when they will not be used anymore
|
||||||
for (final AmazonS3Reference clientReference : clientsCache.values()) {
|
for (final AmazonS3Reference clientReference : clientsCache.values()) {
|
||||||
clientReference.decRef();
|
clientReference.decRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear previously cached clients, they will be build lazily
|
// clear previously cached clients, they will be build lazily
|
||||||
clientsCache = emptyMap();
|
clientsCache = emptyMap();
|
||||||
derivedClientSettings = emptyMap();
|
derivedClientSettings = emptyMap();
|
||||||
|
|
||||||
// shutdown IdleConnectionReaper background thread
|
// shutdown IdleConnectionReaper background thread
|
||||||
// it will be restarted on new client usage
|
// it will be restarted on new client usage
|
||||||
IdleConnectionReaper.shutdown();
|
IdleConnectionReaper.shutdown();
|
||||||
|
@ -300,6 +372,43 @@ class S3Service implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class PrivilegedSTSAssumeRoleSessionCredentialsProvider<P extends AWSSessionCredentialsProvider & Closeable>
|
||||||
|
implements
|
||||||
|
AWSCredentialsProvider,
|
||||||
|
Closeable {
|
||||||
|
private final P credentials;
|
||||||
|
private final AWSSecurityTokenService securityTokenService;
|
||||||
|
|
||||||
|
private PrivilegedSTSAssumeRoleSessionCredentialsProvider(
|
||||||
|
@Nullable final AWSSecurityTokenService securityTokenService,
|
||||||
|
final P credentials
|
||||||
|
) {
|
||||||
|
this.securityTokenService = securityTokenService;
|
||||||
|
this.credentials = credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AWSCredentials getCredentials() {
|
||||||
|
return SocketAccess.doPrivileged(credentials::getCredentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refresh() {
|
||||||
|
SocketAccess.doPrivilegedVoid(credentials::refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
SocketAccess.doPrivilegedIOException(() -> {
|
||||||
|
credentials.close();
|
||||||
|
if (securityTokenService != null) {
|
||||||
|
securityTokenService.shutdown();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
releaseCachedClients();
|
releaseCachedClients();
|
||||||
|
|
|
@ -36,11 +36,16 @@ import com.amazonaws.ClientConfiguration;
|
||||||
import com.amazonaws.Protocol;
|
import com.amazonaws.Protocol;
|
||||||
import com.amazonaws.auth.AWSCredentialsProvider;
|
import com.amazonaws.auth.AWSCredentialsProvider;
|
||||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||||
|
import com.amazonaws.http.IdleConnectionReaper;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.opensearch.common.settings.MockSecureSettings;
|
import org.opensearch.common.settings.MockSecureSettings;
|
||||||
import org.opensearch.common.settings.Settings;
|
import org.opensearch.common.settings.Settings;
|
||||||
import org.opensearch.test.OpenSearchTestCase;
|
import org.opensearch.test.OpenSearchTestCase;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -51,6 +56,11 @@ import static org.opensearch.repositories.s3.S3ClientSettings.PROTOCOL_SETTING;
|
||||||
import static org.opensearch.repositories.s3.S3ClientSettings.PROXY_TYPE_SETTING;
|
import static org.opensearch.repositories.s3.S3ClientSettings.PROXY_TYPE_SETTING;
|
||||||
|
|
||||||
public class AwsS3ServiceImplTests extends OpenSearchTestCase {
|
public class AwsS3ServiceImplTests extends OpenSearchTestCase {
|
||||||
|
@AfterClass
|
||||||
|
public static void shutdownIdleConnectionReaper() {
|
||||||
|
// created by default STS client
|
||||||
|
IdleConnectionReaper.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
public void testAWSCredentialsDefaultToInstanceProviders() {
|
public void testAWSCredentialsDefaultToInstanceProviders() {
|
||||||
final String inexistentClientName = randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
|
final String inexistentClientName = randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
|
||||||
|
@ -86,6 +96,101 @@ public class AwsS3ServiceImplTests extends OpenSearchTestCase {
|
||||||
assertThat(defaultCredentialsProvider, instanceOf(S3Service.PrivilegedInstanceProfileCredentialsProvider.class));
|
assertThat(defaultCredentialsProvider, instanceOf(S3Service.PrivilegedInstanceProfileCredentialsProvider.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCredentialsAndIrsaWithIdentityTokenFileCredentialsFromKeystore() throws IOException {
|
||||||
|
final Map<String, String> plainSettings = new HashMap<>();
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
final String clientNamePrefix = "some_client_name_";
|
||||||
|
final int clientsCount = randomIntBetween(0, 4);
|
||||||
|
for (int i = 0; i < clientsCount; i++) {
|
||||||
|
final String clientName = clientNamePrefix + i;
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".role_arn", clientName + "_role_arn");
|
||||||
|
|
||||||
|
// Use static AWS credentials for tests
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".access_key", clientName + "_aws_access_key");
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".secret_key", clientName + "_aws_secret_key");
|
||||||
|
|
||||||
|
// Use explicit region setting
|
||||||
|
plainSettings.put("s3.client." + clientName + ".region", "us-east1");
|
||||||
|
plainSettings.put("s3.client." + clientName + ".identity_token_file", clientName + "_identity_token_file");
|
||||||
|
}
|
||||||
|
final Settings settings = Settings.builder().loadFromMap(plainSettings).setSecureSettings(secureSettings).build();
|
||||||
|
final Map<String, S3ClientSettings> allClientsSettings = S3ClientSettings.load(settings);
|
||||||
|
// no less, no more
|
||||||
|
assertThat(allClientsSettings.size(), is(clientsCount + 1)); // including default
|
||||||
|
for (int i = 0; i < clientsCount; i++) {
|
||||||
|
final String clientName = clientNamePrefix + i;
|
||||||
|
final S3ClientSettings someClientSettings = allClientsSettings.get(clientName);
|
||||||
|
final AWSCredentialsProvider credentialsProvider = S3Service.buildCredentials(logger, someClientSettings);
|
||||||
|
assertThat(credentialsProvider, instanceOf(S3Service.PrivilegedSTSAssumeRoleSessionCredentialsProvider.class));
|
||||||
|
((Closeable) credentialsProvider).close();
|
||||||
|
}
|
||||||
|
// test default exists and is an Instance provider
|
||||||
|
final S3ClientSettings defaultClientSettings = allClientsSettings.get("default");
|
||||||
|
final AWSCredentialsProvider defaultCredentialsProvider = S3Service.buildCredentials(logger, defaultClientSettings);
|
||||||
|
assertThat(defaultCredentialsProvider, instanceOf(S3Service.PrivilegedInstanceProfileCredentialsProvider.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCredentialsAndIrsaCredentialsFromKeystore() throws IOException {
|
||||||
|
final Map<String, String> plainSettings = new HashMap<>();
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
final String clientNamePrefix = "some_client_name_";
|
||||||
|
final int clientsCount = randomIntBetween(0, 4);
|
||||||
|
for (int i = 0; i < clientsCount; i++) {
|
||||||
|
final String clientName = clientNamePrefix + i;
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".role_arn", clientName + "_role_arn");
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".role_session_name", clientName + "_role_session_name");
|
||||||
|
|
||||||
|
// Use static AWS credentials for tests
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".access_key", clientName + "_aws_access_key");
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".secret_key", clientName + "_aws_secret_key");
|
||||||
|
|
||||||
|
// Use explicit region setting
|
||||||
|
plainSettings.put("s3.client." + clientName + ".region", "us-east1");
|
||||||
|
}
|
||||||
|
final Settings settings = Settings.builder().loadFromMap(plainSettings).setSecureSettings(secureSettings).build();
|
||||||
|
final Map<String, S3ClientSettings> allClientsSettings = S3ClientSettings.load(settings);
|
||||||
|
// no less, no more
|
||||||
|
assertThat(allClientsSettings.size(), is(clientsCount + 1)); // including default
|
||||||
|
for (int i = 0; i < clientsCount; i++) {
|
||||||
|
final String clientName = clientNamePrefix + i;
|
||||||
|
final S3ClientSettings someClientSettings = allClientsSettings.get(clientName);
|
||||||
|
final AWSCredentialsProvider credentialsProvider = S3Service.buildCredentials(logger, someClientSettings);
|
||||||
|
assertThat(credentialsProvider, instanceOf(S3Service.PrivilegedSTSAssumeRoleSessionCredentialsProvider.class));
|
||||||
|
((Closeable) credentialsProvider).close();
|
||||||
|
}
|
||||||
|
// test default exists and is an Instance provider
|
||||||
|
final S3ClientSettings defaultClientSettings = allClientsSettings.get("default");
|
||||||
|
final AWSCredentialsProvider defaultCredentialsProvider = S3Service.buildCredentials(logger, defaultClientSettings);
|
||||||
|
assertThat(defaultCredentialsProvider, instanceOf(S3Service.PrivilegedInstanceProfileCredentialsProvider.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIrsaCredentialsFromKeystore() throws IOException {
|
||||||
|
final Map<String, String> plainSettings = new HashMap<>();
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
final String clientNamePrefix = "some_client_name_";
|
||||||
|
final int clientsCount = randomIntBetween(0, 4);
|
||||||
|
for (int i = 0; i < clientsCount; i++) {
|
||||||
|
final String clientName = clientNamePrefix + i;
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".role_arn", clientName + "_role_arn");
|
||||||
|
secureSettings.setString("s3.client." + clientName + ".role_session_name", clientName + "_role_session_name");
|
||||||
|
}
|
||||||
|
final Settings settings = Settings.builder().loadFromMap(plainSettings).setSecureSettings(secureSettings).build();
|
||||||
|
final Map<String, S3ClientSettings> allClientsSettings = S3ClientSettings.load(settings);
|
||||||
|
// no less, no more
|
||||||
|
assertThat(allClientsSettings.size(), is(clientsCount + 1)); // including default
|
||||||
|
for (int i = 0; i < clientsCount; i++) {
|
||||||
|
final String clientName = clientNamePrefix + i;
|
||||||
|
final S3ClientSettings someClientSettings = allClientsSettings.get(clientName);
|
||||||
|
final AWSCredentialsProvider credentialsProvider = S3Service.buildCredentials(logger, someClientSettings);
|
||||||
|
assertThat(credentialsProvider, instanceOf(S3Service.PrivilegedSTSAssumeRoleSessionCredentialsProvider.class));
|
||||||
|
((Closeable) credentialsProvider).close();
|
||||||
|
}
|
||||||
|
// test default exists and is an Instance provider
|
||||||
|
final S3ClientSettings defaultClientSettings = allClientsSettings.get("default");
|
||||||
|
final AWSCredentialsProvider defaultCredentialsProvider = S3Service.buildCredentials(logger, defaultClientSettings);
|
||||||
|
assertThat(defaultCredentialsProvider, instanceOf(S3Service.PrivilegedInstanceProfileCredentialsProvider.class));
|
||||||
|
}
|
||||||
|
|
||||||
public void testSetDefaultCredential() {
|
public void testSetDefaultCredential() {
|
||||||
final MockSecureSettings secureSettings = new MockSecureSettings();
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
final String awsAccessKey = randomAlphaOfLength(8);
|
final String awsAccessKey = randomAlphaOfLength(8);
|
||||||
|
|
|
@ -317,9 +317,10 @@ public class RepositoryCredentialsTests extends OpenSearchSingleNodeTestCase {
|
||||||
private static final Logger logger = LogManager.getLogger(ProxyS3Service.class);
|
private static final Logger logger = LogManager.getLogger(ProxyS3Service.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
AmazonS3 buildClient(final S3ClientSettings clientSettings) {
|
AmazonS3WithCredentials buildClient(final S3ClientSettings clientSettings) {
|
||||||
final AmazonS3 client = super.buildClient(clientSettings);
|
final AmazonS3WithCredentials client = super.buildClient(clientSettings);
|
||||||
return new ClientAndCredentials(client, buildCredentials(logger, clientSettings));
|
final AWSCredentialsProvider credentials = buildCredentials(logger, clientSettings);
|
||||||
|
return AmazonS3WithCredentials.create(new ClientAndCredentials(client.client(), credentials), credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ import java.net.InetSocketAddress;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.startsWith;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.emptyString;
|
import static org.hamcrest.Matchers.emptyString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
@ -118,6 +119,52 @@ public class S3ClientSettingsTests extends OpenSearchTestCase {
|
||||||
assertThat(e.getMessage(), is("Missing access key and secret key for s3 client [default]"));
|
assertThat(e.getMessage(), is("Missing access key and secret key for s3 client [default]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testIrsaCredentialsTypeWithIdentityTokenFile() {
|
||||||
|
final Map<String, S3ClientSettings> settings = S3ClientSettings.load(
|
||||||
|
Settings.builder().put("s3.client.default.identity_token_file", "file").build()
|
||||||
|
);
|
||||||
|
final S3ClientSettings defaultSettings = settings.get("default");
|
||||||
|
final S3ClientSettings.IrsaCredentials credentials = defaultSettings.irsaCredentials;
|
||||||
|
assertThat(credentials.getIdentityTokenFile(), is("file"));
|
||||||
|
assertThat(credentials.getRoleArn(), is(nullValue()));
|
||||||
|
assertThat(credentials.getRoleSessionName(), startsWith("s3-sdk-java-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIrsaCredentialsTypeRoleArn() {
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
secureSettings.setString("s3.client.default.role_arn", "role");
|
||||||
|
final Map<String, S3ClientSettings> settings = S3ClientSettings.load(Settings.builder().setSecureSettings(secureSettings).build());
|
||||||
|
final S3ClientSettings defaultSettings = settings.get("default");
|
||||||
|
final S3ClientSettings.IrsaCredentials credentials = defaultSettings.irsaCredentials;
|
||||||
|
assertThat(credentials.getRoleArn(), is("role"));
|
||||||
|
assertThat(credentials.getRoleSessionName(), startsWith("s3-sdk-java-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIrsaCredentialsTypeWithRoleArnAndRoleSessionName() {
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
secureSettings.setString("s3.client.default.role_arn", "role");
|
||||||
|
secureSettings.setString("s3.client.default.role_session_name", "session");
|
||||||
|
final Map<String, S3ClientSettings> settings = S3ClientSettings.load(Settings.builder().setSecureSettings(secureSettings).build());
|
||||||
|
final S3ClientSettings defaultSettings = settings.get("default");
|
||||||
|
final S3ClientSettings.IrsaCredentials credentials = defaultSettings.irsaCredentials;
|
||||||
|
assertThat(credentials.getRoleArn(), is("role"));
|
||||||
|
assertThat(credentials.getRoleSessionName(), is("session"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIrsaCredentialsTypeWithRoleArnAndRoleSessionNameAndIdentityTokeFile() {
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
secureSettings.setString("s3.client.default.role_arn", "role");
|
||||||
|
secureSettings.setString("s3.client.default.role_session_name", "session");
|
||||||
|
final Map<String, S3ClientSettings> settings = S3ClientSettings.load(
|
||||||
|
Settings.builder().setSecureSettings(secureSettings).put("s3.client.default.identity_token_file", "file").build()
|
||||||
|
);
|
||||||
|
final S3ClientSettings defaultSettings = settings.get("default");
|
||||||
|
final S3ClientSettings.IrsaCredentials credentials = defaultSettings.irsaCredentials;
|
||||||
|
assertThat(credentials.getIdentityTokenFile(), is("file"));
|
||||||
|
assertThat(credentials.getRoleArn(), is("role"));
|
||||||
|
assertThat(credentials.getRoleSessionName(), is("session"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testCredentialsTypeWithAccessKeyAndSecretKey() {
|
public void testCredentialsTypeWithAccessKeyAndSecretKey() {
|
||||||
final MockSecureSettings secureSettings = new MockSecureSettings();
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
secureSettings.setString("s3.client.default.access_key", "access_key");
|
secureSettings.setString("s3.client.default.access_key", "access_key");
|
||||||
|
@ -199,7 +246,7 @@ public class S3ClientSettingsTests extends OpenSearchTestCase {
|
||||||
assertThat(settings.get("default").region, is(""));
|
assertThat(settings.get("default").region, is(""));
|
||||||
assertThat(settings.get("other").region, is(region));
|
assertThat(settings.get("other").region, is(region));
|
||||||
try (S3Service s3Service = new S3Service()) {
|
try (S3Service s3Service = new S3Service()) {
|
||||||
AmazonS3Client other = (AmazonS3Client) s3Service.buildClient(settings.get("other"));
|
AmazonS3Client other = (AmazonS3Client) s3Service.buildClient(settings.get("other")).client();
|
||||||
assertThat(other.getSignerRegionOverride(), is(region));
|
assertThat(other.getSignerRegionOverride(), is(region));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,12 @@
|
||||||
package org.opensearch.repositories.s3;
|
package org.opensearch.repositories.s3;
|
||||||
|
|
||||||
import org.opensearch.cluster.metadata.RepositoryMetadata;
|
import org.opensearch.cluster.metadata.RepositoryMetadata;
|
||||||
|
import org.opensearch.common.settings.MockSecureSettings;
|
||||||
import org.opensearch.common.settings.Settings;
|
import org.opensearch.common.settings.Settings;
|
||||||
import org.opensearch.test.OpenSearchTestCase;
|
import org.opensearch.test.OpenSearchTestCase;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class S3ServiceTests extends OpenSearchTestCase {
|
public class S3ServiceTests extends OpenSearchTestCase {
|
||||||
|
|
||||||
public void testCachedClientsAreReleased() {
|
public void testCachedClientsAreReleased() {
|
||||||
|
@ -56,4 +58,29 @@ public class S3ServiceTests extends OpenSearchTestCase {
|
||||||
final S3ClientSettings clientSettingsReloaded = s3Service.settings(metadata1);
|
final S3ClientSettings clientSettingsReloaded = s3Service.settings(metadata1);
|
||||||
assertNotSame(clientSettings, clientSettingsReloaded);
|
assertNotSame(clientSettings, clientSettingsReloaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCachedClientsWithCredentialsAreReleased() {
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
secureSettings.setString("s3.client.default.role_arn", "role");
|
||||||
|
final Map<String, S3ClientSettings> defaults = S3ClientSettings.load(
|
||||||
|
Settings.builder().setSecureSettings(secureSettings).put("s3.client.default.identity_token_file", "file").build()
|
||||||
|
);
|
||||||
|
final S3Service s3Service = new S3Service();
|
||||||
|
s3Service.refreshAndClearCache(defaults);
|
||||||
|
final Settings settings = Settings.builder().put("endpoint", "http://first").put("region", "us-east-2").build();
|
||||||
|
final RepositoryMetadata metadata1 = new RepositoryMetadata("first", "s3", settings);
|
||||||
|
final RepositoryMetadata metadata2 = new RepositoryMetadata("second", "s3", settings);
|
||||||
|
final S3ClientSettings clientSettings = s3Service.settings(metadata2);
|
||||||
|
final S3ClientSettings otherClientSettings = s3Service.settings(metadata2);
|
||||||
|
assertSame(clientSettings, otherClientSettings);
|
||||||
|
final AmazonS3Reference reference = s3Service.client(metadata1);
|
||||||
|
reference.close();
|
||||||
|
s3Service.close();
|
||||||
|
final AmazonS3Reference referenceReloaded = s3Service.client(metadata1);
|
||||||
|
assertNotSame(referenceReloaded, reference);
|
||||||
|
referenceReloaded.close();
|
||||||
|
s3Service.close();
|
||||||
|
final S3ClientSettings clientSettingsReloaded = s3Service.settings(metadata1);
|
||||||
|
assertNotSame(clientSettings, clientSettingsReloaded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue