Skip to content

S3 Inventory delivery fails with 'internal error' when the destination bucket's default encryption uses a bare KMS alias instead of a fully qualified ARN.

10 minute read
Content level: Intermediate
0

S3 Inventory reports never deliver and the console shows only a generic "internal error." That message is a catch-all. This article documents one specific, easily-missed cause, where every permission you'd check looks correct. However, the destination bucket's SSE-KMS default encryption references the KMS key by a bare alias / key ID instead of a fully qualified key ARN.

Symptom

S3 Inventory reports never arrive. This most often shows up on a newly configured inventory, or after the destination bucket's default encryption was set or changed to reference the key by a bare alias: the scheduled delivery fails, and so does every one after it. (It is not a case of a working inventory suddenly stopping.) On the source bucket's Management → Inventory configurations view, the most recent run shows a failure and the console surfaces a generic "internal error" with no cause and no actionable detail. Nothing looked wrong at setup: the inventory configuration was accepted without error when you created it, and the destination bucket, its policy, and the KMS key all appear correctly configured.

Why this is hard to diagnose

This error gives no direction, and every obvious suspect reads as properly configured. All of the following were verified correct before the actual cause was found:

  • ✅ Destination bucket policy grants s3:PutObject/s3:PutObject* to the s3.amazonaws.com service principal.
  • ✅ KMS key policy grants kms:GenerateDataKey* (and kms:Encrypt) to s3.amazonaws.com.
  • ✅ Object Ownership / ACLs on the destination support the delivery model.
  • ✅ Network-perimeter / VPCE deny policies correctly exempt AWS service principals.

Because all of these pass, the symptom actively steers you toward the wrong layer. In this case, the problem isn't permission. It's the KMS key resolution.

This is different from the documented Access Denied error, "Access denied Inventory export for 2021-02-19 failed because S3 doesn't have access to the destination bucket or KMS key. Ask the owner of the destination bucket or KMS key to grant the necessary access and then try again." That error explicitly names permissions as the cause, so you know where to look, while the "internal error" in this article gives you nothing to go on.

One cause: a bare KMS alias in the destination's default encryption

The destination bucket's SSE-KMS default encryption referenced the KMS key by a form that carries no account context, i.e. a bare alias (alias/my-inventory-key, with no account or region), or equivalently a bare key ID (the key UUID alone, e.g. 1234abcd-12ab-34cd-56ef-1234567890ab) - rather than a fully qualified key ARN (arn:aws:kms:<region>:<dest-acct-id>:alias/my-inventory-key or arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>).

S3 Inventory delivery is an AWS service operation. AWS requires a fully qualified KMS key ARN for cross-account and service operations, because a reference with no account context (bare alias or bare key ID) resolves in the requester's account by default and cannot be resolved to a specific key in the delivery context. When S3 attempts GenerateDataKey to encrypt the report, the reference is unresolvable and the operation fails (surfaced in the console as the generic "internal error").

Two facts from the AWS documentation combine to make this both real and silent:

  • From the S3 API reference (ServerSideEncryptionByDefault, the KMSMasterKeyID field): "If you are using encryption with cross-account or Amazon Web Services service operations, you must use a fully qualified KMS key ARN."
  • From the PutBucketEncryption API reference: "Amazon S3 doesn't validate the KMS key ID provided in PutBucketEncryption requests."

So S3 accepts the bare-alias default-encryption configuration at config time without any error, and the misconfiguration only manifests later, at the delivery attempt.

How you end up in this state

A bare alias can be set on a bucket's default encryption via the AWS CLI (aws s3api put-bucket-encryption) or via infrastructure-as-code (CloudFormation/CDK/Terraform). In all of these paths, S3 accepts the bare alias / key ID without validation. There is no config-time error to warn you, regardless of how the value is applied. Which is exactly why this is easy to introduce and hard to catch.

Note: this concerns the destination bucket's default encryption (KMSMasterKeyID set via put-bucket-encryption), which accepts a bare alias without validation. Do not confuse it with the inventory configuration's own Encryption.SSEKMS.KeyId field, which is a different setting that does validate at config time. Setting that field to a bare key ID or a bare alias is rejected immediately:

An error occurred (InvalidKmskeyId) when calling the PutBucketInventoryConfiguration operation: Invalid kms key id ARN.

Both the bare key ID and the bare alias (alias/<name>) were tested and produce this same error. Note the mismatch worth being aware of: the SSEKMS API data type documents this field only as "the ID of the ... KMS ... symmetric encryption customer managed key" (Type: String, no format constraint), yet the runtime requires a fully qualified ARN. The error message is the authoritative signal here and the field being labeled "the ID" is exactly why passing a bare ID is a natural mistake.

Reproduced: the exact behavior, isolated to key-reference form

All four rows below were reproduced in a sandbox; the only variable changed between them is the form of the KMS key reference in the destination bucket's default encryption, with bucket policy, key policy, and all permissions held identical and correct throughout.

#KMSMasterKeyID formExampleInventory delivery result
1Bare aliasalias/my-inventory-key❌ Fails - "internal error"
2Bare key ID1234abcd-12ab-34cd-56ef-1234567890ab❌ Fails - "internal error"
3Alias ARNarn:aws:kms:<region>:<dest-acct-id>:alias/my-inventory-key✅ Delivered
4Key ARNarn:aws:kms:<region>:<dest-acct-id>:key/<key-id>✅ Delivered

What this proves: the bare alias / ID existed in the destination/bucket-owner account and still failed, while both forms that pin an account (alias ARN and key ARN) succeeded. So the resolution does not happen in the bucket-owner account (expected and documented). The reference must carry account context for the service delivery path to resolve the key.

The fix

Set the destination bucket's default-encryption KMSMasterKeyID to the fully qualified key ARN:

arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>

No permission changes are required. The bucket policy and key policy that were already in place are correct. Only the key reference form changes.

AWS CLI:

aws s3api put-bucket-encryption --bucket amzn-s3-demo-inventory-destination --server-side-encryption-configuration '{ "Rules": [{ "ApplyServerSideEncryptionByDefault": { "SSEAlgorithm": "aws:kms", "KMSMasterKeyID": "arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>" }, "BucketKeyEnabled": true }] }'

Console: on the destination bucket, Properties → Default encryption → Edit, choose Enter AWS KMS key ARN, and paste the full ...:key/<key-id> ARN (not the bare alias).

An alias can still be used, but it must be referenced as a fully qualified alias ARN:

arn:aws:kms:<region>:<dest-acct-id>:alias/<alias-id>

Alternative fix: specify the key ARN in the inventory configuration itself

Instead of correcting the destination bucket's default encryption, you can leave it as-is and have the inventory configuration specify its own encryption key. The S3 User Guide describes these as two alternative modes: "When you configure server-side encryption for your inventory report, you can use the bucket settings for default encryption or you can specify an encryption key." When the inventory configuration sets Encryption.SSEKMS.KeyId, that key is used to encrypt the delivered report instead of the destination bucket's default encryption. So the broken bare reference on the bucket default is never consulted.

Two constraints carry over:

  • The KeyId must be a fully qualified ARN. The inventory configuration validates this field at config time and rejects a bare key ID or bare alias with InvalidKmskeyId: Invalid kms key id ARN. (see the Note above).
  • The KMS key policy must already grant s3.amazonaws.com the kms:GenerateDataKey* / kms:Encrypt permissions for the referenced key.

AWS CLI:

aws s3api put-bucket-inventory-configuration --bucket <source-bucket> --id <inventory-id> --inventory-configuration '{ "Destination": { "S3BucketDestination": { "Bucket": "arn:aws:s3:::amzn-s3-demo-inventory-destination", "Format": "CSV", "Encryption": { "SSEKMS": { "KeyId": "arn:aws:kms:<region>:<dest-acct-id>:key/<key-id>" } } } }, "IsEnabled": true, "Id": "<inventory-id>", "IncludedObjectVersions": "Current", "Schedule": { "Frequency": "Daily" } }'

Which fix to choose:

  • Fix the bucket default encryption (recommended): corrects the misconfiguration for every consumer of that bucket's default encryption (this inventory, any other inventory configurations, any other AWS service delivery that relies on the default, and cross-account writers).
  • Specify the key in the inventory configuration (targeted): fixes only this inventory report's delivery. The destination bucket's default encryption is still misconfigured and will still fail for anything else that relies on it. This is the right lever when you don't control the destination bucket's default encryption (for example, a cross-account destination owned by another team) but you do control your inventory configuration.

Verify the fix

1. Confirm the stored value is actually a fully qualified key ARN (or alias ARN):

aws s3api get-bucket-encryption --bucket amzn-s3-demo-inventory-destination

KMSMasterKeyID should read arn:aws:kms:<region>:<dest-acct-id>:key/<key-id> or arn:aws:kms:<region>:<dest-acct-id>:alias/<alias-id>.

For checking if the inventory configuration specifies the KMS key:

aws s3api get-bucket-inventory-configuration --bucket amzn-s3-demo-inventory-source --id example

2. Wait for the next scheduled inventory run, then confirm the report object lands in the destination and the configuration's last run shows success.

Confirming the key reference

How the stored key reference displays depends on its form:

On the console -

  • A bare alias displays as the alias (alias/my-inventory-key). This is your diagnostic tell: a bucket throwing inventory "internal error" whose default-encryption key shows as a bare alias is the smoking gun.
  • A bare key ID (1234abcd-...) displays as only the key ID. Another tell that points to the misconfiguration.
  • A full alias ARN is resolved and displayed as the underlying key ARN (...:key/...). This is a correct configuration.

With CLI- This will show the KMS key form as well, either the full ARNs (arn:aws:kms:<region>:<dest-acct-id>:key/<key-id> or arn:aws:kms:<region>:<dest-acct-id>:alias/<alias-id>) or just the base ID or alias ( alias/name or 1234abcd-12ab-34cd-56ef-1234567890ab)

Related: a sibling failure with a different fix

S3 Server Access Logging has a closely related failure mode, delivery to a destination bucket with SSE-KMS default encryption, but the opposite resolution: server access log delivery requires SSE-S3 and does not support a customer-managed KMS key at all, so the fix there is to switch the destination to SSE-S3. See the AWS Knowledge Center article "Why didn't my Amazon S3 server access logs get delivered to my bucket?". For S3 Inventory, by contrast, the destination can use a customer-managed KMS key, it just has to be referenced by a fully qualified key ARN.

References

AWS
SUPPORT ENGINEER

published 14 days ago79 views