Skip to content

Inaccessible profile file (due to JVM security manager) blocks client creation #5754

Closed
@DaveCTurner

Description

@DaveCTurner

Describe the bug

Elasticsearch uses the JVM Security Manager to restrict the files to which it has access, and in particular will block access to files in $HOME/.aws by default. The v1 SDK (e.g. version 1.12.270) treats this as if the files do not exist, which is what we want, but the v2 SDK (e.g. version 2.28.13) apparently just fails if the Security Manager denies this access:

java.security.AccessControlException: access denied ("java.io.FilePermission" "/Users/davidturner/.aws/credentials" "read")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:488) ~[?:?]
	at java.security.AccessController.checkPermission(AccessController.java:1085) ~[?:?]
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:411) ~[?:?]
	at java.lang.SecurityManager.checkRead(SecurityManager.java:742) ~[?:?]
	at sun.nio.fs.UnixPath.checkRead(UnixPath.java:840) ~[?:?]
	at sun.nio.fs.UnixFileSystemProvider.readAttributesIfExists(UnixFileSystemProvider.java:183) ~[?:?]
	at java.nio.file.Files.isRegularFile(Files.java:2370) ~[?:?]
	at software.amazon.awssdk.profiles.ProfileFileLocation.lambda$resolveIfExists$2(ProfileFileLocation.java:90) ~[profiles-2.28.13.jar:?]
	at java.util.Optional.filter(Optional.java:218) ~[?:?]
	at software.amazon.awssdk.profiles.ProfileFileLocation.resolveIfExists(ProfileFileLocation.java:90) ~[profiles-2.28.13.jar:?]
	at software.amazon.awssdk.profiles.ProfileFileLocation.credentialsFileLocation(ProfileFileLocation.java:77) ~[profiles-2.28.13.jar:?]
	at software.amazon.awssdk.profiles.ProfileFile.addCredentialsFile(ProfileFile.java:151) ~[profiles-2.28.13.jar:?]
	at software.amazon.awssdk.utils.builder.SdkBuilder.applyMutation(SdkBuilder.java:61) ~[utils-2.28.13.jar:?]
	at software.amazon.awssdk.profiles.ProfileFile.defaultProfileFile(ProfileFile.java:99) ~[profiles-2.28.13.jar:?]
	at software.amazon.awssdk.core.retry.RetryMode$Resolver.fromProfileFile(RetryMode.java:183) ~[sdk-core-2.28.13.jar:?]
	at software.amazon.awssdk.core.retry.RetryMode$Resolver.lambda$resolve$0(RetryMode.java:171) ~[sdk-core-2.28.13.jar:?]
	at software.amazon.awssdk.utils.OptionalUtils.firstPresent(OptionalUtils.java:47) ~[utils-2.28.13.jar:?]
	at software.amazon.awssdk.core.retry.RetryMode$Resolver.resolve(RetryMode.java:171) ~[sdk-core-2.28.13.jar:?]
	at software.amazon.awssdk.core.retry.RetryMode.defaultRetryMode(RetryMode.java:119) ~[sdk-core-2.28.13.jar:?]
	at software.amazon.awssdk.awscore.retry.AwsRetryStrategy.defaultRetryStrategy(AwsRetryStrategy.java:45) ~[aws-core-2.28.13.jar:?]
	at software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder.lambda$setOverrides$3(AwsDefaultClientBuilder.java:213) ~[aws-core-2.28.13.jar:?]
	at java.util.Optional.ifPresent(Optional.java:178) ~[?:?]
	at software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder.setOverrides(AwsDefaultClientBuilder.java:212) ~[aws-core-2.28.13.jar:?]
	at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.syncClientConfiguration(SdkDefaultClientBuilder.java:199) ~[sdk-core-2.28.13.jar:?]
	at software.amazon.awssdk.services.ec2.DefaultEc2ClientBuilder.buildClient(DefaultEc2ClientBuilder.java:36) ~[ec2-2.28.13.jar:?]
	at software.amazon.awssdk.services.ec2.DefaultEc2ClientBuilder.buildClient(DefaultEc2ClientBuilder.java:25) ~[ec2-2.28.13.jar:?]
	at software.amazon.awssdk.core.client.builder.SdkDefaultClientBuilder.build(SdkDefaultClientBuilder.java:173) ~[sdk-core-2.28.13.jar:?]
	at java.security.AccessController.doPrivileged(AccessController.java:319) ~[?:?]
	at org.elasticsearch.discovery.ec2.SocketAccess.doPrivileged(SocketAccess.java:32) ~[main/:?]
	at org.elasticsearch.discovery.ec2.AwsEc2ServiceImpl.buildClient(AwsEc2ServiceImpl.java:90) ~[main/:?]
	at org.elasticsearch.discovery.ec2.AwsEc2ServiceImpl.buildClient(AwsEc2ServiceImpl.java:45) ~[main/:?]
	at org.elasticsearch.discovery.ec2.AwsEc2ServiceImpl.lambda$refreshAndClearCache$3(AwsEc2ServiceImpl.java:123) ~[main/:?]
	at org.elasticsearch.common.util.LazyInitializable.maybeCompute(LazyInitializable.java:93) ~[elasticsearch-9.0.0-SNAPSHOT.jar:9.0.0-SNAPSHOT]
	at org.elasticsearch.common.util.LazyInitializable.getOrCompute(LazyInitializable.java:71) ~[elasticsearch-9.0.0-SNAPSHOT.jar:9.0.0-SNAPSHOT]
	at org.elasticsearch.discovery.ec2.AwsEc2ServiceImpl.client(AwsEc2ServiceImpl.java:113) ~[main/:?]
	at org.elasticsearch.discovery.ec2.AwsEc2SeedHostsProvider.fetchDynamicNodes(AwsEc2SeedHostsProvider.java:101) ~[main/:?]
	at org.elasticsearch.discovery.ec2.AwsEc2SeedHostsProvider$TransportAddressesCache.refresh(AwsEc2SeedHostsProvider.java:224) ~[main/:?]
	at org.elasticsearch.discovery.ec2.AwsEc2SeedHostsProvider$TransportAddressesCache.refresh(AwsEc2SeedHostsProvider.java:216) ~[main/:?]
	at org.elasticsearch.common.util.SingleObjectCache.getOrRefresh(SingleObjectCache.java:43) ~[elasticsearch-9.0.0-SNAPSHOT.jar:9.0.0-SNAPSHOT]
	at org.elasticsearch.discovery.ec2.AwsEc2SeedHostsProvider.getSeedAddresses(AwsEc2SeedHostsProvider.java:93) ~[main/:?]
	at org.elasticsearch.discovery.ec2.Ec2DiscoveryTests.buildDynamicHosts(Ec2DiscoveryTests.java:156) ~[test/:?]
	at org.elasticsearch.discovery.ec2.Ec2DiscoveryTests.buildDynamicHosts(Ec2DiscoveryTests.java:85) ~[test/:?]
	at org.elasticsearch.discovery.ec2.Ec2DiscoveryTests.testDefaultSettings(Ec2DiscoveryTests.java:169) ~[test/:?]

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

We expect software.amazon.awssdk.profiles.ProfileFileLocation#resolveIfExists to catch a SecurityException and convert it into Optional.empty(). The API docs for java.nio.file.Files#isRegularFile and java.nio.file.Files#isReadable both explicitly mention the possibility of throwing a SecurityException rather than just returning false if the file is nonexistent or unreadable.

Current Behavior

Instead software.amazon.awssdk.profiles.ProfileFileLocation#resolveIfExists does not catch any exceptions and instead treats a SecurityException similar to any other failure.

Stack trace is shown above.

Reproduction Steps

Somewhat tricky because it involves running the JVM with the Security Manager installed. If the description above is unclear then please let me know and I'll put more effort in here.

Possible Solution

diff --git a/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileFileLocation.java b/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileFileLocation.java
index 5b97526dae7..d53e460234e 100644
--- a/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileFileLocation.java
+++ b/core/profiles/src/main/java/software/amazon/awssdk/profiles/ProfileFileLocation.java
@@ -87,6 +87,10 @@ public final class ProfileFileLocation {
     }

     private static Optional<Path> resolveIfExists(Path path) {
-        return Optional.ofNullable(path).filter(Files::isRegularFile).filter(Files::isReadable);
+        try {
+            return Optional.ofNullable(path).filter(Files::isRegularFile).filter(Files::isReadable);
+        } catch (SecurityException e) {
+            return Optional.empty();
+        }
     }
 }

Additional Information/Context

We are aware that the Security Manager is deprecated and will not be available in a future JDK version. We are working to replace it with an alternative implementation that will maintain the same protections, which we therefore expect to suffer the same problems.

AWS Java SDK version used

2.28.13

JDK version used

21+35-2513 (Oracle)

Operating System and version

Mac OS X 15.2 (aarch64)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions