Query TigerLake S3 Tables with AWS Glue and Athena
Expose Iceberg tables written by TigerLake to the AWS Glue Data Catalog and query them with Amazon Athena, with no ETL or data duplication.
After Tiger Cloud Iceberg connector syncs your Tiger Cloud service data to Iceberg tables in Amazon S3 Tables, this guide shows you how to make those tables discoverable through the AWS Glue Data Catalog and query them with Amazon Athena.
This integration does not change the Iceberg connector's write path and does not use the Iceberg connector generic REST catalog configuration. The Iceberg connector continues to write directly to the Amazon S3 Tables Iceberg REST endpoint using AWS SigV4. AWS Glue federation makes those existing S3 Tables resources discoverable to Athena.
AWS documents each service separately. This guide provides the Iceberg connector-specific resource mapping and the minimum sequence needed to expose a namespace and tables created by the Iceberg connector through the federated catalog.
AWS documentation:
- Integrating Amazon S3 Tables with AWS analytics services
- Enabling S3 Tables integration with the Data Catalog
- Querying S3 Tables with Athena
Responsibilities
Section titled “Responsibilities”The S3 table bucket owner performs the steps in this guide in the AWS account and Region that contain the table bucket. Enabling Glue federation is an account-and-Region-level operation, not an Iceberg connector operation.
The setup involves two separate AWS principals:
- The Glue federation access role reads the S3 table bucket. It needs S3 Tables read permissions.
- The user or role submitting Athena queries needs Athena API access, access to the Athena results location,
lakeformation:GetDataAccess, and Lake Formation grants on the catalog resources.
Do not assume that granting permissions to one principal grants them to the other.
Prerequisites for this integration guide
To follow these steps, you'll need:
- Tiger Cloud Iceberg connector set up and active in your Tiger Cloud service, writing to an AWS S3 Tables destination.
- AWS CLI v2 authenticated to the table bucket's AWS account.
- Permission to inspect the S3 table bucket and Glue Data Catalog.
- A Lake Formation data lake administrator for granting query access.
- A regular S3 bucket for Athena query results, unless the Athena workgroup is configured to use Athena-managed results.
Set reusable values:
export AWS_REGION='<region>'export AWS_ACCOUNT_ID='<account-id>'export TABLE_BUCKET='<table-bucket-name>'export TABLE_BUCKET_ARN="arn:aws:s3tables:${AWS_REGION}:${AWS_ACCOUNT_ID}:bucket/${TABLE_BUCKET}"export GLUE_CATALOG="s3tablescatalog/${TABLE_BUCKET}"export GLUE_CATALOG_ID="${AWS_ACCOUNT_ID}:${GLUE_CATALOG}"export TIGERLAKE_NAMESPACE='timescaledb'- Verify that the Iceberg connector created the S3 Tables resources
List namespaces:
Terminal window aws s3tables list-namespaces \--region "$AWS_REGION" \--table-bucket-arn "$TABLE_BUCKET_ARN"The Iceberg connector normally creates the
timescaledbnamespace. List its tables:Terminal window aws s3tables list-tables \--region "$AWS_REGION" \--table-bucket-arn "$TABLE_BUCKET_ARN" \--namespace "$TIGERLAKE_NAMESPACE"Do not continue until the expected tables created by the Iceberg connector appear here. Glue and Athena cannot expose a table that the Iceberg connector has not yet created.
- Enable or verify Glue federation
S3 Tables integration creates a parent Glue catalog named
s3tablescatalog. Each S3 table bucket in the account and Region is automatically mounted as a child catalog.Check whether the parent catalog already exists:
Terminal window aws glue get-catalog \--region "$AWS_REGION" \--catalog-id s3tablescatalogIf it exists, do not create another catalog. Verify the child catalog:
Terminal window aws glue get-catalog \--region "$AWS_REGION" \--catalog-id "$GLUE_CATALOG_ID"If
s3tablescatalogdoes not exist, enable integration from the Amazon S3 console underTable buckets, or create it with the AWS CLI. The principal performing this operation needs at leastglue:CreateCatalogandglue:PassConnection.Create
catalog.json, replacing the placeholders:{"Name": "s3tablescatalog","CatalogInput": {"Description": "Federated catalog for Amazon S3 Tables","FederatedCatalog": {"Identifier": "arn:aws:s3tables:<region>:<account-id>:bucket/*","ConnectionName": "aws:s3tables"},"CreateDatabaseDefaultPermissions": [],"CreateTableDefaultPermissions": [],"AllowFullTableExternalDataAccess": "True"}}Then create the catalog once:
Terminal window aws glue create-catalog \--region "$AWS_REGION" \--cli-input-json file://catalog.jsonEmpty default permissions are intentional in a least-privilege configuration; query access is granted explicitly through Lake Formation later in this guide.
- Grant the Glue federation role access to S3 Tables
Calling
glue get-catalogon the child catalog causes Glue to access the federated S3 Tables source. If it fails with an error such as:not authorized to perform: s3tables:GetTableBucketadd an identity-based policy like the following to the role named in the error:
{"Version": "2012-10-17","Statement": [{"Sid": "ReadTigerLakeS3Tables","Effect": "Allow","Action": ["s3tables:GetTableBucket","s3tables:GetNamespace","s3tables:ListNamespaces","s3tables:GetTable","s3tables:ListTables","s3tables:GetTableMetadataLocation","s3tables:GetTableData"],"Resource": ["arn:aws:s3tables:<region>:<account-id>:bucket/<table-bucket>","arn:aws:s3tables:<region>:<account-id>:bucket/<table-bucket>/table/*"]}]}Manage this policy through the system that owns the role, such as CloudFormation or Terraform, rather than creating unmanaged configuration drift.
Verify that Glue can see the namespace and tables:
Terminal window aws glue get-database \--region "$AWS_REGION" \--catalog-id "$GLUE_CATALOG_ID" \--name "$TIGERLAKE_NAMESPACE"aws glue get-tables \--region "$AWS_REGION" \--catalog-id "$GLUE_CATALOG_ID" \--database-name "$TIGERLAKE_NAMESPACE" \--query 'TableList[].Name'Glue federation is live metadata federation; no Glue crawler is required.
- Prepare the Athena query principal
Choose the IAM role that will run Athena queries and a regular S3 bucket that will hold query results:
Terminal window export ATHENA_ROLE_NAME='<athena-query-role>'export ATHENA_WORKGROUP='primary'export ATHENA_RESULTS_BUCKET='<athena-results-bucket>'Create
athena-query-policy.json, replacing the placeholders with the same Region, account, workgroup, and results bucket used above:{"Version": "2012-10-17","Statement": [{"Sid": "RunAthenaQueries","Effect": "Allow","Action": ["athena:GetWorkGroup","athena:StartQueryExecution","athena:GetQueryExecution","athena:GetQueryResults","athena:StopQueryExecution"],"Resource": "arn:aws:athena:<region>:<account-id>:workgroup/<workgroup>"},{"Sid": "GetLakeFormationDataAccess","Effect": "Allow","Action": "lakeformation:GetDataAccess","Resource": "*"},{"Sid": "ListAthenaResultsBucket","Effect": "Allow","Action": ["s3:GetBucketLocation", "s3:ListBucket"],"Resource": "arn:aws:s3:::<athena-results-bucket>"},{"Sid": "ReadWriteAthenaResults","Effect": "Allow","Action": ["s3:GetObject", "s3:PutObject"],"Resource": "arn:aws:s3:::<athena-results-bucket>/*"}]}Attach it to an IAM role:
Terminal window aws iam put-role-policy \--role-name "$ATHENA_ROLE_NAME" \--policy-name TigerLakeAthenaQueryAccess \--policy-document file://athena-query-policy.jsonThe caller must have permission to update that role. If the query principal is managed by IAM Identity Center, add the JSON policy to its permission set and provision the permission set to the AWS account. Do not modify the generated
AWSReservedSSO_*role directly.Athena query results
Section titled “Athena query results”Athena SQL must have a result location. Configure one on the workgroup, enable Athena-managed results, or provide a regular S3 location with each query. A customer-managed results bucket uses the S3 permissions included in
athena-query-policy.json. Use an encrypted results bucket with an expiration lifecycle rule. Do not use the S3 table bucket as the Athena results location. - Grant Lake Formation access
Resolve the IAM role ARN used by the Athena caller. For an IAM Identity Center permission set, it commonly resembles:
arn:aws:iam::<account-id>:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_<permission-set>_<suffix>Set it explicitly:
Terminal window export ATHENA_PRINCIPAL_ARN='<query-user-or-role-arn>'Grant visibility on the Iceberg connector namespace:
Terminal window aws lakeformation grant-permissions \--region "$AWS_REGION" \--principal DataLakePrincipalIdentifier="$ATHENA_PRINCIPAL_ARN" \--resource \"{\"Database\":{\"CatalogId\":\"${GLUE_CATALOG_ID}\",\"Name\":\"${TIGERLAKE_NAMESPACE}\"}}" \--permissions DESCRIBEGrant read-only access to every current and future table in that namespace:
Terminal window aws lakeformation grant-permissions \--region "$AWS_REGION" \--principal DataLakePrincipalIdentifier="$ATHENA_PRINCIPAL_ARN" \--resource \"{\"Table\":{\"CatalogId\":\"${GLUE_CATALOG_ID}\",\"DatabaseName\":\"${TIGERLAKE_NAMESPACE}\",\"TableWildcard\":{}}}" \--permissions SELECT DESCRIBEFor stricter isolation, replace
TableWildcardwith a named table resource and grant each table separately.Verify a table grant:
Terminal window aws lakeformation list-permissions \--region "$AWS_REGION" \--principal DataLakePrincipalIdentifier="$ATHENA_PRINCIPAL_ARN" \--resource \"{\"Table\":{\"CatalogId\":\"${GLUE_CATALOG_ID}\",\"DatabaseName\":\"${TIGERLAKE_NAMESPACE}\",\"Name\":\"<table-name>\"}}"The result should include
DESCRIBEon the table andSELECTon its columns. - Query with the Athena console
Open Athena in the same Region as the S3 table bucket and choose:
Data source: AwsDataCatalogCatalog: s3tablescatalog/<table-bucket>Database: timescaledbRun:
SHOW TABLES;Then query a table created by the Iceberg connector:
SELECT *FROM <table-name>LIMIT 10; - Query from the CLI
Set the remaining values:
Terminal window export ATHENA_WORKGROUP='primary'export ATHENA_RESULTS="s3://${ATHENA_RESULTS_BUCKET}/tigerlake/"export TIGERLAKE_TABLE='<table-name>'Submit a count query:
Terminal window QUERY_ID=$(aws athena start-query-execution \--region "$AWS_REGION" \--work-group "$ATHENA_WORKGROUP" \--query-execution-context \"{\"Catalog\":\"${GLUE_CATALOG}\",\"Database\":\"${TIGERLAKE_NAMESPACE}\"}" \--result-configuration "OutputLocation=${ATHENA_RESULTS}" \--query-string "SELECT count(*) AS row_count FROM ${TIGERLAKE_TABLE}" \--query 'QueryExecutionId' \--output text)echo "Query ID: $QUERY_ID"Check the query without using
exit, which would close an interactive shell:Terminal window aws athena get-query-execution \--region "$AWS_REGION" \--query-execution-id "$QUERY_ID" \--query 'QueryExecution.Status' \--output jsonWhen its state is
SUCCEEDED, print tab-separated results directly to the terminal:Terminal window aws athena get-query-results \--region "$AWS_REGION" \--query-execution-id "$QUERY_ID" \--query 'ResultSet.Rows[*].Data[*].VarCharValue' \--output textA failed query cannot be resumed after permissions are fixed. Submit a new query to obtain a new query execution ID.
Validate ongoing replication
Section titled “Validate ongoing replication”Run a count query, insert additional rows into the source TimescaleDB table, wait for the Iceberg connector to commit a new Iceberg snapshot, and run the count query again. An increased count confirms the complete path:
TimescaleDB -> Iceberg connector -> S3 Tables -> Glue -> Lake Formation -> AthenaAthena reads the current Iceberg snapshot; Glue does not copy the table data.
Troubleshooting
Section titled “Troubleshooting”s3tables:GetTableBucket is denied
Section titled “s3tables:GetTableBucket is denied”The Glue federation role lacks access to the table bucket. Add the S3 Tables read policy from step 3 to the role named in the error.
athena:StartQueryExecution or athena:GetWorkGroup is denied
Section titled “athena:StartQueryExecution or athena:GetWorkGroup is denied”The query caller lacks Athena API access. Grant access to the selected workgroup. Verify the active CLI identity with:
aws sts get-caller-identityaws configure listPrincipal does not have any privilege on specified resource
Section titled “Principal does not have any privilege on specified resource”This is a Lake Formation authorization failure. Confirm all three items:
- The query principal has IAM permission for
lakeformation:GetDataAccess. - It has
DESCRIBEon the Iceberg connector database. - It has
SELECTandDESCRIBEon the queried table.
The Athena query has no output location
Section titled “The Athena query has no output location”Configure a result location on the Athena workgroup or pass --result-configuration OutputLocation=s3://... when starting the query.
Glue or Athena does not show a table that exists in S3 Tables
Section titled “Glue or Athena does not show a table that exists in S3 Tables”AWS analytics integration requires lowercase table and column names. Quoted PostgreSQL identifiers containing uppercase characters can produce tables that S3 Tables accepts but Glue/Athena cannot expose. Test with lowercase identifiers and review the source table schema.
A permission change did not repair an existing query
Section titled “A permission change did not repair an existing query”Athena query executions are immutable. Submit a new query after changing IAM or Lake Formation permissions.
Production recommendations
Section titled “Production recommendations”- Use a read-only IAM role or IAM Identity Center permission set for Athena consumers.
- Grant
SELECTandDESCRIBE; avoid Athena write or DDL permissions on tables managed by the Iceberg connector. - Use a dedicated Athena workgroup with an enforced, encrypted result location, scan limits, CloudWatch metrics, and cost allocation tags.
- Apply an expiration lifecycle policy to customer-managed Athena result files.
- Manage IAM and Lake Formation grants through infrastructure as code.
- Scope S3 Tables permissions to the customer's table bucket and tables.