Skip to content

Commit

Permalink
Added support for sse_customer_key, sse_customer_key_md5, and `ss…
Browse files Browse the repository at this point in the history
…e_customer_algorithm` optional key quals in the `aws_s3_object` table to list objects encrypted with SSE-C Closes #2381 (#2409)
  • Loading branch information
ParthaI authored Feb 28, 2025
1 parent 08a09ba commit fdda4f9
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
60 changes: 60 additions & 0 deletions aws/table_aws_s3_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ func tableAwsS3Object(_ context.Context) *plugin.Table {
KeyColumns: []*plugin.KeyColumn{
{Name: "bucket_name", Require: plugin.Required, CacheMatch: query_cache.CacheMatchExact},
{Name: "prefix", Require: plugin.Optional, CacheMatch: query_cache.CacheMatchExact},

// If you encrypt an object by using server-side encryption with customer-provided
// encryption keys (SSE-C) when you store the object in Amazon S3, then when you
// GET the object, you must use the following query parameter:
{Name: "sse_customer_algorithm", Require: plugin.Optional},
{Name: "sse_customer_key", Require: plugin.Optional, CacheMatch: query_cache.CacheMatchExact},
{Name: "sse_customer_key_md5", Require: plugin.Optional},
},
},

HydrateConfig: []plugin.HydrateConfig{
{
Func: getBucketRegionForObjects,
Expand Down Expand Up @@ -287,6 +295,13 @@ func tableAwsS3Object(_ context.Context) *plugin.Table {
Transform: transform.FromField("SSECustomerAlgorithm"),
Hydrate: headS3Object,
},
{
Name: "sse_customer_key",
Description: "Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the x-amz-server-side-encryption-customer-algorithm header.",
Type: proto.ColumnType_STRING,
Transform: transform.FromQual("sse_customer_key"),
Hydrate: headS3Object,
},
{
Name: "sse_customer_key_md5",
Description: "If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.",
Expand Down Expand Up @@ -469,6 +484,9 @@ func listS3Objects(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateDa

func getS3Object(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
bucketName := d.EqualsQuals["bucket_name"].GetStringValue()
sseCusAlgorithm := d.EqualsQuals["sse_customer_algorithm"].GetStringValue()
sseCusKeyMd5 := d.EqualsQuals["sse_customer_key_md5"].GetStringValue()
sseCusKey := d.EqualsQuals["sse_customer_key"].GetStringValue()
bucketRegion := ""

// Bucket location will be nil if getBucketLocationForObjects returned an error but
Expand Down Expand Up @@ -497,6 +515,18 @@ func getS3Object(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData
Key: key,
}

// If you encrypt an object by using server-side encryption with customer-provided
// encryption keys (SSE-C) when you store the object in Amazon S3.
if sseCusAlgorithm != "" {
params.SSECustomerAlgorithm = &sseCusAlgorithm
}
if sseCusKey != "" {
params.SSECustomerKey = &sseCusKey
}
if sseCusKeyMd5 != "" {
params.SSECustomerKeyMD5 = &sseCusKeyMd5
}

object, err := svc.GetObject(ctx, params)
if err != nil {
// if the key is unavailable in the provided bucket
Expand All @@ -512,6 +542,9 @@ func getS3Object(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData

func headS3Object(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
bucketName := d.EqualsQuals["bucket_name"].GetStringValue()
sseCusAlgorithm := d.EqualsQuals["sse_customer_algorithm"].GetStringValue()
sseCusKeyMd5 := d.EqualsQuals["sse_customer_key_md5"].GetStringValue()
sseCusKey := d.EqualsQuals["sse_customer_key"].GetStringValue()
bucketRegion := ""

// Bucket location will be nil if getBucketLocationForObjects returned an error but
Expand Down Expand Up @@ -540,6 +573,18 @@ func headS3Object(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateDat
Key: key,
}

// If you encrypt an object by using server-side encryption with customer-provided
// encryption keys (SSE-C) when you store the object in Amazon S3.
if sseCusAlgorithm != "" {
params.SSECustomerAlgorithm = &sseCusAlgorithm
}
if sseCusKey != "" {
params.SSECustomerKey = &sseCusKey
}
if sseCusKeyMd5 != "" {
params.SSECustomerKeyMD5 = &sseCusKeyMd5
}

object, err := svc.HeadObject(ctx, params)
if err != nil {
// if the key is unavailable in the provided bucket
Expand All @@ -555,6 +600,9 @@ func headS3Object(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateDat

func getS3ObjectAttributes(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
bucketName := d.EqualsQuals["bucket_name"].GetStringValue()
sseCusAlgorithm := d.EqualsQuals["sse_customer_algorithm"].GetStringValue()
sseCusKeyMd5 := d.EqualsQuals["sse_customer_key_md5"].GetStringValue()
sseCusKey := d.EqualsQuals["sse_customer_key"].GetStringValue()
bucketRegion := ""

// Bucket location will be nil if getBucketLocationForObjects returned an error but
Expand Down Expand Up @@ -584,6 +632,18 @@ func getS3ObjectAttributes(ctx context.Context, d *plugin.QueryData, h *plugin.H
ObjectAttributes: []types.ObjectAttributes{types.ObjectAttributesChecksum, types.ObjectAttributesObjectParts},
}

// If you encrypt an object by using server-side encryption with customer-provided
// encryption keys (SSE-C) when you store the object in Amazon S3.
if sseCusAlgorithm != "" {
params.SSECustomerAlgorithm = &sseCusAlgorithm
}
if sseCusKey != "" {
params.SSECustomerKey = &sseCusKey
}
if sseCusKeyMd5 != "" {
params.SSECustomerKeyMD5 = &sseCusKeyMd5
}

objectAttributes, err := svc.GetObjectAttributes(ctx, params)
if err != nil {
plugin.Logger(ctx).Error("aws_s3_object.GetObjectAttributes", "api_error", err)
Expand Down
39 changes: 39 additions & 0 deletions docs/tables/aws_s3_object.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ The `aws_s3_object` table in Steampipe provides you with information about objec
- It's recommended that you specify the `prefix` column when querying buckets with a large number of objects to reduce the query time.
- The `body` column returns the raw bytes of the object data as a string. If the bytes entirely consist of valid UTF8 runes, e.g., `.txt files`, an UTF8 data will be set as column value and you will be able to query the object body ([refer example below](#get-data-details-of-a-particular-object-in-a-bucket)). However, for the invalid UTF8 runes, e.g., `.png files`, the bas64 encoding of the bytes will be set as column value and you will not be able to query the object body for those objects.
- Using this table adds to the cost of your monthly bill from AWS. Optimizations have been put in place to minimize the impact as much as possible. You should refer to AWS S3 Pricing to understand the cost implications.
- If you encrypt an object by using server-side encryption with customer-provided encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object, you must use the following query parameter:
- `sse_customer_algorithm`
- `sse_customer_key_md5`
- `sse_customer_key`

## Examples

Expand Down Expand Up @@ -452,4 +456,39 @@ from
where
bucket_name = 'steampipe-test'
and prefix = 'test1/log_text.txt';
```

### Retrieve object details encrypted with customer-provided encryption keys (SSE-C)
This query retrieves details of objects stored in an S3 bucket that are encrypted using Server-Side Encryption with Customer-Provided Keys (SSE-C). SSE-C allows you to provide your own encryption keys when storing objects in S3, ensuring that AWS does not manage the encryption keys.

```sql+postgres
select
key,
bucket_name,
content_language,
content_length,
content_type
from
aws_s3_object
where
bucket_name = 'tes-encryption-31'
and sse_customer_algorithm = 'AES256'
and sse_customer_key = '/J03dxHHdcPTDNi97Aq7mYxBjnxOX0kV6UzSHVOh8es='
and sse_customer_key_md5 = 'gaWCs7+kcAeTCCLlbVdTXA==';
```

```sql+sqlite
select
key,
bucket_name,
content_language,
content_length,
content_type
from
aws_s3_object
where
bucket_name = 'tes-encryption-31'
and sse_customer_algorithm = 'AES256'
and sse_customer_key = '/J03dxHHdcPTDNi97Aq7mYxBjnxOX0kV6UzSHVOh8es='
and sse_customer_key_md5 = 'gaWCs7+kcAeTCCLlbVdTXA==';
```

0 comments on commit fdda4f9

Please sign in to comment.