Skip to content

Commit

Permalink
S3 access grants plugin auto-configuration (awspring#1247)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatejNedic authored Oct 4, 2024
1 parent 27eaa94 commit bbd8aca
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 0 deletions.
15 changes: 15 additions & 0 deletions docs/src/main/asciidoc/s3.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,21 @@ public class SimpleResourceLoadingBean {
Resolving resources throughout all buckets can be very time consuming depending on the number of buckets a user owns.
====

=== Using S3 Access grants

Sometimes there is a need to make access control to S3 bucket contents fine grained.
Since IAM polices and S3 Policies only support 10kbs size, S3 Access Grant is solving this by allowing fine grained access control over content in bucket.

To use S3 Access Grants out of the box with `S3Client` and `S3Template` introduce following plugin:

[source,xml]
----
<dependency>
<groupId>software.amazon.s3.accessgrants</groupId>
<artifactId>aws-s3-accessgrants-java-plugin</artifactId>
</dependency>
----

=== Using S3Template

Spring Cloud AWS provides a higher abstraction on the top of `S3Client` providing methods for the most common use cases when working with S3.
Expand Down
5 changes: 5 additions & 0 deletions spring-cloud-aws-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
<artifactId>amazon-dax-client</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>software.amazon.s3.accessgrants</groupId>
<artifactId>aws-s3-accessgrants-java-plugin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.util.ClassUtils;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
import software.amazon.awssdk.s3accessgrants.plugin.S3AccessGrantsPlugin;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
Expand Down Expand Up @@ -78,6 +80,11 @@ S3ClientBuilder s3ClientBuilder(AwsClientBuilderConfigurer awsClientBuilderConfi
connectionDetails.getIfAvailable(), configurer.getIfAvailable(), s3ClientCustomizers.orderedStream(),
awsSyncClientCustomizers.orderedStream());

if (ClassUtils.isPresent("software.amazon.awssdk.s3accessgrants.plugin.S3AccessGrantsPlugin", null)) {
S3AccessGrantsPlugin s3AccessGrantsPlugin = S3AccessGrantsPlugin.builder()
.enableFallback(properties.getPlugin().getEnableFallback()).build();
builder.addPlugin(s3AccessGrantsPlugin);
}
Optional.ofNullable(this.properties.getCrossRegionEnabled()).ifPresent(builder::crossRegionAccessEnabled);

builder.serviceConfiguration(this.properties.toS3Configuration());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.awspring.cloud.autoconfigure.s3.properties;

public class S3PluginProperties {

/**
* If set to false if Access Grants does not find/return permissions, S3Client won't try to determine if policies
* grant access If set to true fallback policies S3/IAM will be evaluated.
*/
private boolean enableFallback;

public boolean getEnableFallback() {
return enableFallback;
}

public void setEnableFallback(boolean enableFallback) {
this.enableFallback = enableFallback;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ public class S3Properties extends AwsClientProperties {
@NestedConfigurationProperty
private S3CrtClientProperties crt;

@NestedConfigurationProperty
private S3PluginProperties plugin = new S3PluginProperties();

@Nullable
public Boolean getAccelerateModeEnabled() {
return this.accelerateModeEnabled;
Expand Down Expand Up @@ -175,4 +178,12 @@ public S3Configuration toS3Configuration() {
propertyMapper.from(this::getUseArnRegionEnabled).whenNonNull().to(config::useArnRegionEnabled);
return config.build();
}

public S3PluginProperties getPlugin() {
return plugin;
}

public void setPlugin(S3PluginProperties plugin) {
this.plugin = plugin;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import software.amazon.awssdk.core.client.config.SdkClientOption;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.identity.spi.IdentityProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.utils.AttributeMap;

Expand Down Expand Up @@ -82,6 +83,10 @@ public Boolean getDualstackEnabled() {
return clientConfigurationAttributes.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED);
}

public IdentityProvider getIdentityProviders() {
return clientConfigurationAttributes.get(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER);
}

public DefaultsMode getDefaultsMode() {
return clientConfigurationAttributes.get(AwsClientOption.DEFAULTS_MODE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.s3accessgrants.plugin.S3AccessGrantsIdentityProvider;
import software.amazon.awssdk.s3accessgrants.plugin.S3AccessGrantsPlugin;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
Expand All @@ -69,6 +71,30 @@ class S3AutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(AwsAutoConfiguration.class, RegionProviderAutoConfiguration.class,
CredentialsProviderAutoConfiguration.class, S3AutoConfiguration.class));

private final ApplicationContextRunner contextRunnerWithoutGrant = new ApplicationContextRunner()
.withPropertyValues("spring.cloud.aws.region.static:eu-west-1")
.withConfiguration(AutoConfigurations.of(AwsAutoConfiguration.class, RegionProviderAutoConfiguration.class,
CredentialsProviderAutoConfiguration.class, S3AutoConfiguration.class))
.withClassLoader(new FilteredClassLoader(S3AccessGrantsPlugin.class));

@Test
void setsS3AccessGrantIdentityProvider() {
contextRunner.run(context -> {
S3ClientBuilder builder = context.getBean(S3ClientBuilder.class);
ConfiguredAwsClient client = new ConfiguredAwsClient(builder.build());
assertThat(client.getIdentityProviders()).isInstanceOf(S3AccessGrantsIdentityProvider.class);
});
}

@Test
void doesNotSetS3AccessGrantIdentityProvider() {
contextRunnerWithoutGrant.run(context -> {
S3ClientBuilder builder = context.getBean(S3ClientBuilder.class);
ConfiguredAwsClient client = new ConfiguredAwsClient(builder.build());
assertThat(client.getIdentityProviders()).isNotInstanceOf(S3AccessGrantsIdentityProvider.class);
});
}

@Test
void createsS3ClientBean() {
this.contextRunner.run(context -> {
Expand Down Expand Up @@ -149,6 +175,7 @@ void withCustomGlobalEndpointAndS3Endpoint() {
"spring.cloud.aws.s3.endpoint:http://localhost:9999").run(context -> {
S3ClientBuilder builder = context.getBean(S3ClientBuilder.class);
ConfiguredAwsClient client = new ConfiguredAwsClient(builder.build());
assertThat(client.getIdentityProviders()).isInstanceOf(S3AccessGrantsIdentityProvider.class);
assertThat(client.getEndpoint()).isEqualTo(URI.create("http://localhost:9999"));
assertThat(client.isEndpointOverridden()).isTrue();
});
Expand Down
7 changes: 7 additions & 0 deletions spring-cloud-aws-dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<bytebuddy.version>1.14.9</bytebuddy.version>
<spring-modulith.version>1.2.3</spring-modulith.version>
<wiremock-standalone.version>3.3.1</wiremock-standalone.version>
<amazon.s3.accessgrants>2.2.0</amazon.s3.accessgrants>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -68,6 +69,12 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>software.amazon.s3.accessgrants</groupId>
<artifactId>aws-s3-accessgrants-java-plugin</artifactId>
<version>${amazon.s3.accessgrants}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
Expand Down

0 comments on commit bbd8aca

Please sign in to comment.