Skip to content

Commit 00c4af6

Browse files
committed
Refactor CredentialsController, add RemoteConnection plugin
This PR moves to a more dynamic approach to resolving remote credentials, where the whole Request object can be used to determine the endpoint it should be proxied to, the remote credentials to use and STS mechanism. RemoteS3ConnectionProvider returns remote credentials, optional STS role and optional RemoteS3Facade configs (used to provide and endpoint but also change the path-style if needed). It takes as arguments the ParsedRequest, Identity and SigningMetadata. The request flow with this change goes: Client request to aws-proxy -> CredentialsProvider to get emulated secret key and Identity -> SecurityFacade -> S3RequestRewriter -> RemoteS3ConnectionProvider to get remote credentials, role and remote configs -> (Optional) Assume Remote Role -> Sing request to remote -> Send request to remote
1 parent 2b5f030 commit 00c4af6

File tree

64 files changed

+749
-521
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+749
-521
lines changed

trino-aws-proxy-glue/src/main/java/io/trino/aws/proxy/glue/rest/TrinoGlueResource.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public TrinoGlueResource(ObjectMapper objectMapper, GlueRequestHandler requestHa
5959
@Produces(MediaType.APPLICATION_JSON)
6060
public Response gluePost(@Context Request request, @Context SigningMetadata signingMetadata, @Context RequestLoggingSession requestLoggingSession)
6161
{
62-
requestLoggingSession.logProperty("request.glue.emulated.key", signingMetadata.credentials().emulated().secretKey());
62+
requestLoggingSession.logProperty("request.glue.emulated.key", signingMetadata.credential().secretKey());
6363

6464
String target = request.requestHeaders().unmodifiedHeaders().getFirst("x-amz-target")
6565
.orElseThrow(() -> InvalidInputException.builder().statusCode(BAD_REQUEST.getStatusCode()).build());

trino-aws-proxy-glue/src/test/java/io/trino/aws/proxy/glue/TestGlueBase.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
package io.trino.aws.proxy.glue;
1515

16-
import io.trino.aws.proxy.spi.credentials.Credentials;
16+
import io.trino.aws.proxy.spi.credentials.IdentityCredential;
1717
import jakarta.annotation.PreDestroy;
1818
import jakarta.ws.rs.core.UriBuilder;
1919
import org.junit.jupiter.api.Test;
@@ -64,7 +64,7 @@ public abstract class TestGlueBase<T extends TestingGlueContext>
6464
protected final GlueClient glueClient;
6565
protected final T context;
6666

67-
protected TestGlueBase(TrinoGlueConfig config, Credentials testingCredentials, T context)
67+
protected TestGlueBase(TrinoGlueConfig config, IdentityCredential testingCredentials, T context)
6868
{
6969
this.context = requireNonNull(context, "context is null");
7070

trino-aws-proxy-glue/src/test/java/io/trino/aws/proxy/glue/TestGlueInS3Proxy.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import io.trino.aws.proxy.server.testing.TestingUtil.ForTesting;
2020
import io.trino.aws.proxy.server.testing.harness.BuilderFilter;
2121
import io.trino.aws.proxy.server.testing.harness.TrinoAwsProxyTest;
22-
import io.trino.aws.proxy.spi.credentials.Credentials;
22+
import io.trino.aws.proxy.spi.credentials.IdentityCredential;
2323

2424
import java.net.URI;
2525

@@ -51,7 +51,7 @@ public record Context(URI baseUrl)
5151
}
5252

5353
@Inject
54-
public TestGlueInS3Proxy(TestingHttpServer httpServer, TrinoGlueConfig config, @ForTesting Credentials testingCredentials)
54+
public TestGlueInS3Proxy(TestingHttpServer httpServer, TrinoGlueConfig config, @ForTesting IdentityCredential testingCredentials)
5555
{
5656
super(config, testingCredentials, new Context(httpServer.getBaseUrl()));
5757
}

trino-aws-proxy-glue/src/test/java/io/trino/aws/proxy/glue/TestingCredentialsProvider.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@
1414
package io.trino.aws.proxy.glue;
1515

1616
import io.trino.aws.proxy.spi.credentials.Credential;
17-
import io.trino.aws.proxy.spi.credentials.Credentials;
1817
import io.trino.aws.proxy.spi.credentials.CredentialsProvider;
18+
import io.trino.aws.proxy.spi.credentials.IdentityCredential;
1919

2020
import java.util.Optional;
2121
import java.util.UUID;
2222

2323
public class TestingCredentialsProvider
2424
implements CredentialsProvider
2525
{
26-
public static final Credentials CREDENTIALS = Credentials.build(new Credential(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
26+
public static final IdentityCredential CREDENTIALS = new IdentityCredential(new Credential(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
2727

2828
@Override
29-
public Optional<Credentials> credentials(String emulatedAccessKey, Optional<String> session)
29+
public Optional<IdentityCredential> credentials(String emulatedAccessKey, Optional<String> session)
3030
{
3131
return Optional.of(CREDENTIALS);
3232
}

trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/Credentials.java

-61
This file was deleted.

trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/CredentialsProvider.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import java.util.Optional;
1717

18+
// TODO: Add back file-based provider
1819
public interface CredentialsProvider
1920
{
2021
CredentialsProvider NOOP = (_, _) -> Optional.empty();
@@ -24,5 +25,5 @@ public interface CredentialsProvider
2425
* Your implementation should have a centralized credentials mechanism, likely
2526
* some type of database along with a way of registering credentials, etc.
2627
*/
27-
Optional<Credentials> credentials(String emulatedAccessKey, Optional<String> session);
28+
Optional<IdentityCredential> credentials(String emulatedAccessKey, Optional<String> session);
2829
}

trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/credentials/EmulatedAssumedRole.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public record EmulatedAssumedRole(Credential emulatedCredential, String arn, Str
2121
{
2222
public EmulatedAssumedRole
2323
{
24-
requireNonNull(emulatedCredential, "emulatedCredential is null");
24+
requireNonNull(emulatedCredential, "credential is null");
2525
requireNonNull(arn, "arn is null");
2626
requireNonNull(roleId, "roleId is null");
2727
requireNonNull(expiration, "expiration is null");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.aws.proxy.spi.credentials;
15+
16+
import java.util.Optional;
17+
18+
import static java.util.Objects.requireNonNull;
19+
20+
public record IdentityCredential(Credential emulated, Optional<Identity> identity)
21+
{
22+
public IdentityCredential
23+
{
24+
requireNonNull(emulated, "emulated is null");
25+
requireNonNull(identity, "identity is null");
26+
}
27+
28+
public IdentityCredential(Credential emulatedCredential, Identity identity)
29+
{
30+
this(emulatedCredential, Optional.of(identity));
31+
}
32+
33+
public IdentityCredential(Credential emulatedCredential)
34+
{
35+
this(emulatedCredential, Optional.empty());
36+
}
37+
38+
public static IdentityCredential of(Credential emulatedCredential)
39+
{
40+
return new IdentityCredential(emulatedCredential, Optional.empty());
41+
}
42+
}

trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/plugin/TrinoAwsProxyServerBinding.java

+7
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
import io.trino.aws.proxy.spi.plugin.config.CredentialsProviderConfig;
2626
import io.trino.aws.proxy.spi.plugin.config.PluginIdentifierConfig;
2727
import io.trino.aws.proxy.spi.plugin.config.RemoteS3Config;
28+
import io.trino.aws.proxy.spi.plugin.config.RemoteS3ConnectionProviderConfig;
2829
import io.trino.aws.proxy.spi.plugin.config.S3RequestRewriterConfig;
2930
import io.trino.aws.proxy.spi.plugin.config.S3SecurityFacadeProviderConfig;
31+
import io.trino.aws.proxy.spi.remote.RemoteS3ConnectionProvider;
3032
import io.trino.aws.proxy.spi.remote.RemoteS3Facade;
3133
import io.trino.aws.proxy.spi.rest.S3RequestRewriter;
3234
import io.trino.aws.proxy.spi.security.S3SecurityFacadeProvider;
@@ -49,6 +51,11 @@ static Module assumedRoleProviderModule(String identifier, Class<? extends Assum
4951
return optionalPluginModule(AssumedRoleProviderConfig.class, identifier, AssumedRoleProvider.class, implementationClass, module);
5052
}
5153

54+
static Module remoteS3ConnectionProviderModule(String identifier, Class<? extends RemoteS3ConnectionProvider> implementationClass, Module module)
55+
{
56+
return optionalPluginModule(RemoteS3ConnectionProviderConfig.class, identifier, RemoteS3ConnectionProvider.class, implementationClass, module);
57+
}
58+
5259
static Module s3SecurityFacadeProviderModule(String identifier, Class<? extends S3SecurityFacadeProvider> implementationClass, Module module)
5360
{
5461
return optionalPluginModule(S3SecurityFacadeProviderConfig.class, identifier, S3SecurityFacadeProvider.class, implementationClass, module);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.aws.proxy.spi.plugin.config;
15+
16+
import io.airlift.configuration.Config;
17+
import jakarta.validation.constraints.NotNull;
18+
19+
import java.util.Optional;
20+
21+
public class RemoteS3ConnectionProviderConfig
22+
implements PluginIdentifierConfig
23+
{
24+
private Optional<String> identifier = Optional.empty();
25+
26+
@NotNull
27+
@Override
28+
public Optional<String> getPluginIdentifier()
29+
{
30+
return identifier;
31+
}
32+
33+
@Config("remote-s3-connection-provider.type")
34+
public void setPluginIdentifier(String identifier)
35+
{
36+
this.identifier = Optional.ofNullable(identifier);
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.aws.proxy.spi.remote;
15+
16+
import com.google.common.collect.ImmutableMap;
17+
import io.trino.aws.proxy.spi.credentials.Credential;
18+
19+
import java.util.Map;
20+
import java.util.Optional;
21+
22+
import static java.util.Objects.requireNonNull;
23+
24+
public record RemoteS3Connection(
25+
Credential remoteCredential,
26+
Optional<RemoteSessionRole> remoteSessionRole,
27+
Optional<Map<String, String>> remoteS3FacadeConfiguration)
28+
{
29+
public RemoteS3Connection
30+
{
31+
requireNonNull(remoteCredential, "remoteCredential is null");
32+
requireNonNull(remoteSessionRole, "remoteSessionRole is null");
33+
remoteS3FacadeConfiguration = requireNonNull(remoteS3FacadeConfiguration, "remoteS3FacadeConfiguration is null").map(ImmutableMap::copyOf);
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.aws.proxy.spi.remote;
15+
16+
import io.trino.aws.proxy.spi.credentials.Identity;
17+
import io.trino.aws.proxy.spi.rest.ParsedS3Request;
18+
import io.trino.aws.proxy.spi.signing.SigningMetadata;
19+
20+
import java.util.Optional;
21+
22+
// TODO: This should have a config implementation (hard-coding a single set of Remote Credentials) and an HTTP implementation
23+
public interface RemoteS3ConnectionProvider
24+
{
25+
RemoteS3ConnectionProvider NOOP = (_, _, _) -> Optional.empty();
26+
27+
Optional<RemoteS3Connection> remoteConnection(SigningMetadata signingMetadata, Optional<Identity> identity, ParsedS3Request request);
28+
}

trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/remote/RemoteSessionRole.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
*/
1414
package io.trino.aws.proxy.spi.remote;
1515

16+
import java.net.URI;
1617
import java.util.Optional;
1718

1819
import static java.util.Objects.requireNonNull;
1920

20-
public record RemoteSessionRole(String region, String roleArn, Optional<String> externalId)
21+
public record RemoteSessionRole(String region, String roleArn, Optional<String> externalId, Optional<URI> stsEndpoint)
2122
{
2223
public RemoteSessionRole
2324
{

trino-aws-proxy-spi/src/main/java/io/trino/aws/proxy/spi/rest/S3RequestRewriter.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,25 @@
1313
*/
1414
package io.trino.aws.proxy.spi.rest;
1515

16-
import io.trino.aws.proxy.spi.credentials.Credentials;
16+
import io.trino.aws.proxy.spi.credentials.Identity;
17+
import io.trino.aws.proxy.spi.signing.SigningMetadata;
1718

1819
import java.util.Optional;
1920

2021
import static java.util.Objects.requireNonNull;
2122

2223
public interface S3RequestRewriter
2324
{
24-
S3RequestRewriter NOOP = (_, _) -> Optional.empty();
25+
S3RequestRewriter NOOP = (_, _, _) -> Optional.empty();
2526

2627
record S3RewriteResult(String finalRequestBucket, String finalRequestKey)
2728
{
28-
public S3RewriteResult {
29+
public S3RewriteResult
30+
{
2931
requireNonNull(finalRequestBucket, "finalRequestBucket is null");
3032
requireNonNull(finalRequestKey, "finalRequestKey is null");
3133
}
3234
}
3335

34-
Optional<S3RewriteResult> rewrite(Credentials credentials, ParsedS3Request request);
36+
Optional<S3RewriteResult> rewrite(Optional<Identity> identity, SigningMetadata signingMetadata, ParsedS3Request request);
3537
}

0 commit comments

Comments
 (0)