(aws-s3): support S3 Metadata (metadataConfiguration / metadataTableConfiguration) on the Bucket L2
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
### Describe the feature
Add L2 support for S3 Metadata to `s3.Bucket` by exposing the `MetadataConfiguration` (V2) and `MetadataTableConfiguration` (V1) properties of `AWS::S3::Bucket`.
Both properties exist on the L1 `CfnBucket` today, but neither is reachable from the L2 `Bucket` construct:
| CloudFormation property | L1 `CfnBucket` | L2 `Bucket` |
| --- | --- | --- |
| `MetadataConfiguration` (V2) | Yes | **Missing** |
| `MetadataTableConfiguration` (V1) | Yes | **Missing** |
The full L1 surface that has no L2 equivalent:
```
MetadataConfiguration (V2)
|- JournalTableConfiguration [required]
| |- RecordExpiration [required] Expiration, Days
| |- EncryptionConfiguration SseAlgorithm, KmsKeyArn
| |- TableArn / TableName
|- InventoryTableConfiguration
| |- ConfigurationState [required]
| |- EncryptionConfiguration
| |- TableArn / TableName
|- AnnotationTableConfiguration
| |- ConfigurationState [required]
| |- EncryptionConfiguration
| |- Role
| |- TableArn / TableName
|- Destination
|- TableBucketType [required]
|- TableBucketArn / TableNamespace
MetadataTableConfiguration (V1)
|- S3TablesDestination [required]
|- TableBucketArn [required]
|- TableName [required]
|- TableArn / TableNamespace
```
Related AWS launches this covers:
- [Accelerating data discovery with S3 Metadata](https://docs.aws.amazon.com/AmazonS3/latest/userguide/metadata-tables-overview.html) (journal and inventory tables)
- [Amazon S3 adds annotations to provide AI agents and analytics tools with context for data discovery](https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-s3-annotations-business-context/) (Jun 16, 2026)
### Use Case
S3 Metadata keeps a queryable journal of object-level changes and an inventory of the current state of a bucket, stored as Apache Iceberg tables. Annotations extend that with custom business context that AI agents and analytics tools can discover without a separate metadata system.
Enabling any of this on a bucket defined with the `Bucket` L2 currently requires dropping to the escape hatch:
```ts
const bucket = new s3.Bucket(this, 'Bucket');
const cfnBucket = bucket.node.defaultChild as s3.CfnBucket;
cfnBucket.metadataConfiguration = {
journalTableConfiguration: {
recordExpiration: { expiration: 'ENABLED', days: 10 },
encryptionConfiguration: { sseAlgorithm: 'aws:kms', kmsKeyArn: key.keyArn },
},
inventoryTableConfiguration: {
configurationState: 'ENABLED',
encryptionConfiguration: { sseAlgorithm: 'aws:kms', kmsKeyArn: key.keyArn },
},
};
```
That loses everything the L2 normally provides: no typed enums for `Expiration` / `ConfigurationState` / `SseAlgorithm` / `TableBucketType`, no `Duration` for the record expiration period, no `kms.IKey` or `iam.IRole` references (raw ARN strings instead), and no synth-time validation of the required-field combinations.
### Proposed Solution
Add a `metadataConfiguration` prop to `BucketProps`, modelled on how `inventories` is already handled in `bucket.ts`, with strong CDK types for each leaf:
```ts
new s3.Bucket(this, 'Bucket', {
metadataConfiguration: {
journalTable: {
recordExpiration: {
expiration: s3.MetadataRecordExpiration.ENABLED,
duration: Duration.days(10),
},
encryption: s3.MetadataTableEncryption.kms(key),
},
inventoryTable: {
configurationState: s3.MetadataConfigurationState.ENABLED,
encryption: s3.MetadataTableEncryption.kms(key),
},
annotationTable: {
configurationState: s3.MetadataConfigurationState.ENABLED,
role,
},
},
});
```
Design points to settle during implementation:
- **V1 vs V2.** V1 (`MetadataTableConfiguration`, customer-managed table bucket) and V2 (`MetadataConfiguration`, AWS managed table bucket) are mutually exclusive on a bucket. These should be separate props with a validation that rejects setting both, rather than a union type (unions are not jsii-compatible).
- **Typed leaves.** `expiration` / `configurationState` / `tableBucketType` become enums; `sseAlgorithm` + `kmsKeyArn` become an enum-like class taking a `kms.IKey`; `days` becomes a `Duration`; `role` becomes an `iam.IRole`.
- **Read-only fields.** `TableArn` and `TableName` appear in the L1 props but are service-populated for V2 configurations. Whether to expose them as settable props needs confirmation against the service behavior before they are added.
- **KMS key policy.** The CloudFormation reference example grants `kms:Decrypt` and `kms:GenerateDataKey` to the `metadata.s3.amazonaws.com` and `maintenance.s3tables.amazonaws.com` service principals. Whether the L2 should wire this grant automatically, or leave it to the user, should be decided explicitly (and verified with an integration test).
- **Backwards compatibility.** All new props are optional and additive, so no feature flag is required.
Deliverables: the prop plus supporting types, unit tests covering each table configuration and the V1/V2 exclusivity validation, an integration test with a deployed snapshot, and a README section.
### Other Information
Reference CloudFormation template from the [MetadataConfiguration docs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-metadataconfiguration.html):
```yaml
TestMetadataBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: amzn-s3-demo-bucket
MetadataConfiguration:
JournalTableConfiguration:
RecordExpiration:
Expiration: ENABLED
Days: 10
EncryptionConfiguration:
SseAlgorithm: aws:kms
KmsKeyArn: !GetAtt S3MetadataKMSKey.Arn
InventoryTableConfiguration:
ConfigurationState: ENABLED
EncryptionConfiguration:
SseAlgorithm: aws:kms
KmsKeyArn: !GetAtt S3MetadataKMSKey.Arn
```
I could not find an existing issue or pull request covering either property.
### Acknowledgements
- [X] I may be able to implement this feature request
- [ ] This feature might incur a breaking change
### AWS CDK Library version (aws-cdk-lib)
2.263.0
### AWS CDK CLI version
2.1134.0
### Environment details (OS name and version, etc.)
macOS (Darwin 25.5.0)
Contributor guide
Research direction
Start with bucket.ts and the existing inventories handling, then compare the L2 design with the CfnBucket metadataConfiguration and metadataTableConfiguration properties. Resolve the V1/V2 API, typed references, validation, and KMS policy decisions before adding the requested unit, integration, and README coverage. Done means both metadata variants are exposed with exclusivity validation and documented tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100