vishal210893 opened a new issue, #13596:
URL: https://github.com/apache/iceberg/issues/13596

   ### Apache Iceberg version
   
   1.9.1
   
   ### Query engine
   
   Other
   
   ### Please describe the bug šŸž
   
   ## Background
   
   I’m trying to use Apache Iceberg’s `GlueCatalog` against an S3-backed 
warehouse with **temporary credentials** (Access Key, Secret Key, **Session 
Token**).
   
   * AWS CLI (`aws s3 ls …`) works fine with the exact same env-vars.
   
   * With Iceberg + GlueCatalog, I repeatedly get:
   
     ```
     S3Exception: The request signature we calculated does not match the 
signature you provided...
     ```
   
     or
   
     ```
     AccessDeniedException: 403 Forbidden
     ```
   
   * I’ve tried:
   
     * Switching `s3://` → `s3a://` and Hadoop/S3A configs
     * Using Iceberg’s `rest.*` override properties
     * Writing a full `StaticAwsClientFactory` that implements **all** 
`AwsClientFactory` methods and injecting it via `client.factory`
     * Forcing `io-impl = org.apache.iceberg.aws.s3.S3FileIO`
     * Verifying in debug logs that my factory **is** called
     * Inspecting the AWS-SDK HTTP wire logs for the `x-amz-security-token` 
header
     * Ensuring my system clock is in sync
   
   Nothing stops Iceberg from signing requests incorrectly or losing the 
session token header—every S3 call is ultimately rejected as 403 or 
signature-mismatch.
   
   ---
   
   ## Environment
   
   * **Iceberg**: 1.9.1
   * **iceberg-aws**: 1.9.1
   * **iceberg-parquet**: 1.9.1
   * **AWS SDK v2 modules**:
   
     * `software.amazon.awssdk:glue`
     * `software.amazon.awssdk:sts`
     * `software.amazon.awssdk:s3`
   * **Java**: 11
   * **OS**: macOS / Linux (client in IST time zone)
   * **Credentials**: temporary STS credentials with session token
   
   ---
   
   ## Reproduction Steps
   
   1. **pom.xml dependencies** (as in my project):
   
      ```xml
      <!-- Iceberg Core -->
      <dependency>
        <groupId>org.apache.iceberg</groupId>
        <artifactId>iceberg-core</artifactId>
        <version>1.9.1</version>
      </dependency>
   
      <!-- Iceberg AWS/Glue support -->
      <dependency>
        <groupId>org.apache.iceberg</groupId>
        <artifactId>iceberg-aws</artifactId>
        <version>1.9.1</version>
      </dependency>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>glue</artifactId>
      </dependency>
   
      <!-- Iceberg Parquet -->
      <dependency>
        <groupId>org.apache.iceberg</groupId>
        <artifactId>iceberg-parquet</artifactId>
        <version>1.9.1</version>
      </dependency>
   
      <!-- AWS SDK v2 for STS and S3 -->
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>sts</artifactId>
      </dependency>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
      </dependency>
      ```
   
   2. **GlueCatalogController.java**
      I configure both system properties and catalog props, then call 
`catalog.loadTable(...)`:
   
      ```java
      public class GlueCatalogController {
        public ResponseEntity<Object> getFilteredData() {
          try {
            // 1) System props (AWS SDK picks these up)
            System.setProperty("aws.accessKeyId",     "<ACCESS_KEY_ID>");
            System.setProperty("aws.secretAccessKey", "<SECRET_ACCESS_KEY>");
            System.setProperty("aws.sessionToken",    "<SESSION_TOKEN>");
            System.setProperty("aws.region",          "us-east-1");
   
            // 2) Iceberg catalog properties
            Map<String, String> props = new HashMap<>();
            props.put("warehouse", "s3://my-iceberg-bucket/warehouse");
            props.put("io-impl",   "org.apache.iceberg.aws.s3.S3FileIO");
            props.put("catalog-impl","org.apache.iceberg.aws.glue.GlueCatalog");
            props.put("glue.id",   "<AWS_ACCOUNT_ID>");
            props.put("glue.endpoint","https://glue.us-east-1.amazonaws.com";);
   
            // 3) Attempt to wire in my factory
            props.put("client.factory",
              "com.fdl.controller.StaticAwsClientFactory");
   
            GlueCatalog catalog = new GlueCatalog();
            catalog.initialize("glue", props);
   
            Table table = catalog.loadTable(TableIdentifier.of(
              "my_db","my_table"
            ));
            log.info("Schema: {}", table.schema().asStruct());
            return ResponseEntity.ok().build();
          } catch (Exception e) {
            log.error("Failed to load Iceberg table", e);
            throw e;
          }
        }
      }
      ```
   
   3. **StaticAwsClientFactory.java**
      Full implementation of **all** calls:
   
      ```java
      public class StaticAwsClientFactory implements AwsClientFactory {
        private String accessKeyId, secretAccessKey, sessionToken, region;
   
        // Iceberg will call this
        @Override
        public void initialize(Map<String, String> props) {
          // These exact keys must match AwsClientProperties constants:
          accessKeyId     = 
props.get(AwsClientProperties.CLIENT_FACTORY_ACCESS_KEY_ID);
          secretAccessKey = 
props.get(AwsClientProperties.CLIENT_FACTORY_SECRET_ACCESS_KEY);
          sessionToken    = 
props.get(AwsClientProperties.CLIENT_FACTORY_SESSION_TOKEN);
          region          = 
props.get(AwsClientProperties.CLIENT_FACTORY_REGION);
   
          System.out.println("Factory init – token: " +
            (sessionToken == null ? "null" : sessionToken.substring(0,10) + 
"…"));
        }
   
        private StaticCredentialsProvider creds() {
          AwsSessionCredentials creds = AwsSessionCredentials.create(
            accessKeyId, secretAccessKey, sessionToken);
          return StaticCredentialsProvider.create(creds);
        }
   
        @Override
        public S3Client s3() {
          System.out.println("Building S3Client with token: " +
            (sessionToken == null ? "null" : sessionToken.substring(0,10) + 
"…"));
          return S3Client.builder()
              .credentialsProvider(creds())
              .region(Region.of(region))
              .build();
        }
   
        @Override
        public GlueClient glue() {
          return GlueClient.builder()
              .credentialsProvider(creds())
              .region(Region.of(region))
              .build();
        }
   
        @Override
        public KmsClient kms() {
          return KmsClient.builder()
              .credentialsProvider(creds())
              .region(Region.of(region))
              .build();
        }
   
        @Override
        public DynamoDbClient dynamo() {
          return DynamoDbClient.builder()
              .credentialsProvider(creds())
              .region(Region.of(region))
              .build();
        }
      }
      ```
   
   4. **What actually happens**
   
      * Debug logs confirm `StaticAwsClientFactory.initialize()` and `.s3()` 
**do** run.
      * Yet **every** S3 request still returns 403 or signature-mismatch.
      * I’ve enabled AWS SDK wire logs and **never** see an 
`x-amz-security-token` header, so the session token never makes it to S3.
   
   ---
   
   ## Expected Behavior
   
   1. `GlueCatalog` should use my `StaticAwsClientFactory` for **all** AWS 
calls (Glue, S3, KMS, DynamoDB).
   2. Every S3 request should be signed with the provided session token (i.e. 
`x-amz-security-token` must appear in the signed headers).
   3. `catalog.loadTable(...)` should succeed and return the Iceberg table 
metadata.
   
   ---
   
   ## Actual Behavior
   
   * Iceberg/Hadoop/S3A or Iceberg’s default FileIO is **silently ignoring** 
the session token.
   * S3 rejects the request with 403 or signature mismatch.
   * No combination of `rest.*` props or 
`EnvironmentVariableCredentialsProvider` or client-factory wiring seems to fix 
it.
   
   ---
   
   ## Workarounds Tried
   
   * Switching **only** to `s3a://` + Hadoop/S3A configs (`fs.s3a.*`)
   * Using Iceberg’s **`rest.access-key-id`**, **`rest.secret-access-key`**, 
**`rest.session-token`**, **`rest.signer.region`**, **`rest.signing.name`** 
properties
   * Writing a **custom AwsClientFactory** (full code above)
   * Forcing `io-impl = org.apache.iceberg.aws.s3.S3FileIO`
   * Remapping `s3://` → S3A via `fs.s3.impl = 
org.apache.hadoop.fs.s3a.S3AFileSystem`
   * Ensuring the exact property keys:
   
     * `client.factory` = fully-qualified factory class
     * `catalog-impl`, `warehouse`, `glue.id`, `glue.endpoint`, `io-impl`
   * Syncing system clock (no skew)
   * Verifying AWS CLI works with the same creds
   
   ---
   
   ## Questions / Next Steps
   
   1. **Is this a bug** in `GlueCatalog` or in Iceberg’s AWS client-factory 
wiring that drops the session token?
   2. **Which configuration** or code change am I still missing to get 
`x-amz-security-token` included?
   3. Should Iceberg’s docs be updated to show exactly how to supply 
**temporary credentials** to a GlueCatalog?
   
   Any guidance or a fix would be greatly appreciated—I’m completely stuck. 
Thank you!
   
   
   ### Willingness to contribute
   
   - [ ] I can contribute a fix for this bug independently
   - [ ] I would be willing to contribute a fix for this bug with guidance from 
the Iceberg community
   - [x] I cannot contribute a fix for this bug at this time


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to