From e0ee635ac13bf4997859a238845c7fa315554c5e Mon Sep 17 00:00:00 2001 From: Rulin Xing Date: Mon, 28 Apr 2025 18:53:18 -0700 Subject: [PATCH] Updated spec and added the DPO for SigV4 Auth --- .../AuthenticationParametersDpo.java | 17 ++- .../core/connection/AuthenticationType.java | 1 + .../BearerAuthenticationParametersDpo.java | 2 +- .../OAuthClientCredentialsParametersDpo.java | 4 +- .../SigV4AuthenticationParametersDpo.java | 116 ++++++++++++++++++ .../service/admin/PolarisAdminService.java | 5 + spec/polaris-management-service.yml | 32 ++++- 7 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 polaris-core/src/main/java/org/apache/polaris/core/connection/SigV4AuthenticationParametersDpo.java diff --git a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java index bf07c4b79a..7b566262f8 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationParametersDpo.java @@ -21,10 +21,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import jakarta.annotation.Nonnull; import java.util.Map; import org.apache.polaris.core.admin.model.AuthenticationParameters; import org.apache.polaris.core.admin.model.BearerAuthenticationParameters; import org.apache.polaris.core.admin.model.OAuthClientCredentialsParameters; +import org.apache.polaris.core.admin.model.SigV4AuthenticationParameters; import org.apache.polaris.core.secrets.UserSecretReference; /** @@ -38,6 +40,7 @@ @JsonSubTypes({ @JsonSubTypes.Type(value = OAuthClientCredentialsParametersDpo.class, name = "1"), @JsonSubTypes.Type(value = BearerAuthenticationParametersDpo.class, name = "2"), + @JsonSubTypes.Type(value = SigV4AuthenticationParametersDpo.class, name = "3"), }) public abstract class AuthenticationParametersDpo implements IcebergCatalogPropertiesProvider { @@ -56,7 +59,7 @@ public int getAuthenticationTypeCode() { return authenticationTypeCode; } - public abstract AuthenticationParameters asAuthenticationParametersModel(); + public abstract @Nonnull AuthenticationParameters asAuthenticationParametersModel(); public static AuthenticationParametersDpo fromAuthenticationParametersModelWithSecrets( AuthenticationParameters authenticationParameters, @@ -80,6 +83,18 @@ public static AuthenticationParametersDpo fromAuthenticationParametersModelWithS new BearerAuthenticationParametersDpo( secretReferences.get(INLINE_BEARER_TOKEN_REFERENCE_KEY)); break; + case SIGV4: + // SigV4 authentication is not secret-based + SigV4AuthenticationParameters sigV4AuthenticationParametersModel = + (SigV4AuthenticationParameters) authenticationParameters; + config = + new SigV4AuthenticationParametersDpo( + sigV4AuthenticationParametersModel.getRoleArn(), + sigV4AuthenticationParametersModel.getExternalId(), + sigV4AuthenticationParametersModel.getSigningRegion(), + sigV4AuthenticationParametersModel.getSigningName(), + sigV4AuthenticationParametersModel.getUserArn()); + break; default: throw new IllegalStateException( "Unsupported authentication type: " + authenticationParameters.getAuthenticationType()); diff --git a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java index 71ad0b72d3..e3353349f5 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/connection/AuthenticationType.java @@ -33,6 +33,7 @@ public enum AuthenticationType { NULL_TYPE(0), OAUTH(1), BEARER(2), + SIGV4(3), ; private static final AuthenticationType[] REVERSE_MAPPING_ARRAY; diff --git a/polaris-core/src/main/java/org/apache/polaris/core/connection/BearerAuthenticationParametersDpo.java b/polaris-core/src/main/java/org/apache/polaris/core/connection/BearerAuthenticationParametersDpo.java index bf80c7c4cb..49e6953752 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/connection/BearerAuthenticationParametersDpo.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/connection/BearerAuthenticationParametersDpo.java @@ -56,7 +56,7 @@ public BearerAuthenticationParametersDpo( } @Override - public AuthenticationParameters asAuthenticationParametersModel() { + public @Nonnull AuthenticationParameters asAuthenticationParametersModel() { return BearerAuthenticationParameters.builder() .setAuthenticationType(AuthenticationParameters.AuthenticationTypeEnum.BEARER) .build(); diff --git a/polaris-core/src/main/java/org/apache/polaris/core/connection/OAuthClientCredentialsParametersDpo.java b/polaris-core/src/main/java/org/apache/polaris/core/connection/OAuthClientCredentialsParametersDpo.java index 9a955de4fd..1b89de23bd 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/connection/OAuthClientCredentialsParametersDpo.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/connection/OAuthClientCredentialsParametersDpo.java @@ -86,7 +86,7 @@ public OAuthClientCredentialsParametersDpo( return clientSecretReference; } - public @Nonnull List getScopes() { + public @Nullable List getScopes() { return scopes; } @@ -115,7 +115,7 @@ public OAuthClientCredentialsParametersDpo( } @Override - public AuthenticationParameters asAuthenticationParametersModel() { + public @Nonnull AuthenticationParameters asAuthenticationParametersModel() { return OAuthClientCredentialsParameters.builder() .setAuthenticationType(AuthenticationParameters.AuthenticationTypeEnum.OAUTH) .setTokenUri(getTokenUri()) diff --git a/polaris-core/src/main/java/org/apache/polaris/core/connection/SigV4AuthenticationParametersDpo.java b/polaris-core/src/main/java/org/apache/polaris/core/connection/SigV4AuthenticationParametersDpo.java new file mode 100644 index 0000000000..ed29954162 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/connection/SigV4AuthenticationParametersDpo.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.polaris.core.connection; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableMap; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.Map; +import org.apache.iceberg.aws.AwsProperties; +import org.apache.iceberg.rest.auth.AuthProperties; +import org.apache.polaris.core.admin.model.AuthenticationParameters; +import org.apache.polaris.core.admin.model.SigV4AuthenticationParameters; +import org.apache.polaris.core.secrets.UserSecretsManager; + +/** + * The internal persistence-object counterpart to SigV4AuthenticationParameters defined in the API + * model. + */ +public class SigV4AuthenticationParametersDpo extends AuthenticationParametersDpo { + + @JsonProperty(value = "roleArn") + private final String roleArn; + + @JsonProperty(value = "externalId") + private final String externalId; + + @JsonProperty(value = "signingRegion") + private final String signingRegion; + + @JsonProperty(value = "signingName") + private final String signingName; + + @JsonProperty(value = "userArn") + private final String userArn; + + public SigV4AuthenticationParametersDpo( + @JsonProperty(value = "roleArn", required = true) String roleArn, + @JsonProperty(value = "externalId", required = false) String externalId, + @JsonProperty(value = "signingRegion", required = false) String signingRegion, + @JsonProperty(value = "signingName", required = false) String signingName, + @JsonProperty(value = "userArn", required = false) String userArn) { + super(AuthenticationType.SIGV4.getCode()); + this.roleArn = roleArn; + this.externalId = externalId; + this.signingRegion = signingRegion; + this.signingName = signingName; + this.userArn = userArn; + } + + public @Nonnull String getRoleArn() { + return roleArn; + } + + public @Nullable String getExternalId() { + return externalId; + } + + public @Nullable String getSigningRegion() { + return signingRegion; + } + + public @Nullable String getSigningName() { + return signingName; + } + + public @Nullable String getUserArn() { + return userArn; + } + + @Nonnull + @Override + public Map asIcebergCatalogProperties(UserSecretsManager secretsManager) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(AuthProperties.AUTH_TYPE, AuthProperties.AUTH_TYPE_SIGV4); + if (getSigningRegion() != null) { + builder.put(AwsProperties.REST_SIGNER_REGION, getSigningRegion()); + } + if (getSigningName() != null) { + builder.put(AwsProperties.REST_SIGNING_NAME, getSigningName()); + } + // TODO: Add a connection credential provider to get the tmp aws credentials for SigV4 auth + builder.put(AwsProperties.REST_ACCESS_KEY_ID, "access_key_id"); + builder.put(AwsProperties.REST_SECRET_ACCESS_KEY, "secret_access_key"); + builder.put(AwsProperties.REST_SESSION_TOKEN, "session_token"); + return builder.build(); + } + + @Override + public @Nonnull AuthenticationParameters asAuthenticationParametersModel() { + return SigV4AuthenticationParameters.builder() + .setAuthenticationType(AuthenticationParameters.AuthenticationTypeEnum.SIGV4) + .setRoleArn(this.roleArn) + .setExternalId(this.externalId) + .setSigningRegion(this.signingRegion) + .setSigningName(this.signingName) + .setUserArn(this.userArn) + .build(); + } +} diff --git a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java index 9b40f4228f..40b4576237 100644 --- a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java +++ b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java @@ -627,6 +627,11 @@ private Map extractSecretReferences( AuthenticationParametersDpo.INLINE_BEARER_TOKEN_REFERENCE_KEY, secretReference); break; } + case SIGV4: + { + // SigV4 authentication is not secret-based + break; + } default: throw new IllegalStateException( "Unsupported authentication type: " diff --git a/spec/polaris-management-service.yml b/spec/polaris-management-service.yml index 318f17a6c6..1255f9ce29 100644 --- a/spec/polaris-management-service.yml +++ b/spec/polaris-management-service.yml @@ -889,13 +889,14 @@ components: AuthenticationParameters: type: object - description: Authentication-specific information for a REST connection + description: Authentication-specific information for a connection properties: authenticationType: type: string enum: - OAUTH - BEARER + - SIGV4 description: The type of authentication to use when connecting to the remote rest service required: - authenticationType @@ -904,6 +905,7 @@ components: mapping: OAUTH: "#/components/schemas/OAuthClientCredentialsParameters" BEARER: "#/components/schemas/BearerAuthenticationParameters" + SIGV4: "#/components/schemas/SigV4AuthenticationParameters" OAuthClientCredentialsParameters: type: object @@ -938,6 +940,34 @@ components: format: password description: Bearer token (input-only) + SigV4AuthenticationParameters: + type: object + description: AWS Signature Version 4 authentication + allOf: + - $ref: '#/components/schemas/AuthenticationParameters' + properties: + roleArn: + type: string + description: The aws IAM role arn assume when signing requests + example: "arn:aws:iam::123456789001:role/role-that-has-remote-catalog-access" + externalId: + type: string + description: An optional external id used to establish a trust relationship with AWS in the trust policy + signingRegion: + type: string + description: Region to be used by the SigV4 protocol for signing requests + example: "us-west-2" + signingName: + type: string + description: The service name to be used by the SigV4 protocol for signing requests, the default signing name is "execute-api" is if not provided + example: "glue" + userArn: + type: string + description: The aws user arn used to assume the aws role, this represents the polaris service itself + example: "arn:aws:iam::123456789001:user/polaris-service-user" + required: + - roleArn + StorageConfigInfo: type: object description: A storage configuration used by catalogs