-
Notifications
You must be signed in to change notification settings - Fork 137
feat(object): add object sse_customer_key_wo #3619
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| ### Basic object creation | ||
|
|
||
| resource "scaleway_object_bucket" "some_bucket" { | ||
| name = "some-unique-name" | ||
| } | ||
|
|
||
| resource "scaleway_object" "some_file" { | ||
| bucket = scaleway_object_bucket.some_bucket.id | ||
| key = "object_path" | ||
|
|
||
| file = "myfile" | ||
| hash = filemd5("myfile") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ### Using Write-Only SSE Customer Key | ||
|
|
||
| resource "scaleway_object_bucket" "encrypted_bucket" { | ||
| name = "encrypted-bucket" | ||
| } | ||
|
|
||
| # Generate an ephemeral encryption key (not stored in the state) | ||
| ephemeral "random_password" "encryption_key" { | ||
| length = 32 | ||
| special = false | ||
| upper = true | ||
| lower = true | ||
| numeric = true | ||
| min_upper = 1 | ||
| min_lower = 1 | ||
| min_numeric = 1 | ||
| # Only hex characters for SSE-C keys | ||
| override_special = "" | ||
| } | ||
|
|
||
| resource "scaleway_object" "encrypted_file" { | ||
| bucket = scaleway_object_bucket.encrypted_bucket.id | ||
| key = "secret-file" | ||
| content = "This is a secret content" | ||
|
|
||
| # Use write-only encryption key | ||
| sse_customer_key_wo = ephemeral.random_password.encryption_key.result | ||
| sse_customer_key_wo_version = 1 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,7 @@ func DataSourceObject() *schema.Resource { | |
|
|
||
| datasource.FixDatasourceSchemaFlags(dsSchema, true, "bucket", "key") | ||
|
|
||
| datasource.AddOptionalFieldsToSchema(dsSchema, "region", "project_id") | ||
| datasource.AddOptionalFieldsToSchema(dsSchema, "region", "project_id", "sse_customer_key") | ||
|
|
||
| return &schema.Resource{ | ||
| ReadContext: DataSourceObjectRead, | ||
|
|
@@ -51,10 +51,31 @@ func DataSourceObjectRead(ctx context.Context, d *schema.ResourceData, m any) di | |
|
|
||
| tflog.Debug(ctx, fmt.Sprintf("SCW object read for bucket=%s key=%s", bucket, key)) | ||
|
|
||
| _, err = s3Client.HeadObject(ctx, &s3.HeadObjectInput{ | ||
| req := &s3.HeadObjectInput{ | ||
| Bucket: aws.String(bucket), | ||
| Key: aws.String(key), | ||
| }) | ||
| } | ||
|
|
||
| // Add encryption headers if present (similar to resourceObjectRead) | ||
| // Only the regular (non Write Only) sse_customer_key can be set. | ||
| // Data sources cannot read objects encrypted with write-only keys | ||
| // since the actual key is not available in the data source configuration. | ||
| // Data sources cannot have WriteOnly attributes. Making it available would | ||
| // set the key in the state. | ||
|
Comment on lines
+59
to
+64
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This limitation is why I am considering not merging this PR at all. Is this restriction (not being able to query the datasource specifically for sse_customer_key_wo encrypted objects) something we are OK with ? We might as well have a dedicated Ephemeral Resource at that point. |
||
| if encryptionKey, ok := d.GetOk("sse_customer_key"); ok { | ||
| encryptionKeyStr := encryptionKey.(string) | ||
|
|
||
| digestMD5, encryption, err := EncryptCustomerKey(encryptionKeyStr) | ||
| if err != nil { | ||
| return diag.FromErr(err) | ||
| } | ||
|
|
||
| req.SSECustomerAlgorithm = aws.String("AES256") | ||
| req.SSECustomerKeyMD5 = aws.String(digestMD5) | ||
| req.SSECustomerKey = encryption | ||
| } | ||
|
|
||
| _, err = s3Client.HeadObject(ctx, req) | ||
| if err != nil { | ||
| return diag.FromErr(fmt.Errorf("couldn't read object %s/%s: %w", bucket, key, err)) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,3 +74,144 @@ func TestAccDataSourceObject_Basic(t *testing.T) { | |
| }, | ||
| }) | ||
| } | ||
|
|
||
| func TestAccDataSourceObject_Encrypted(t *testing.T) { | ||
| tt := acctest.NewTestTools(t) | ||
| defer tt.Cleanup() | ||
|
|
||
| bucketName := sdkacctest.RandomWithPrefix("test-acc-scaleway-ds-obj-encrypted") | ||
| resource.ParallelTest(t, resource.TestCase{ | ||
| ProtoV6ProviderFactories: tt.ProviderFactories, | ||
| CheckDestroy: resource.ComposeTestCheckFunc( | ||
| objectchecks.IsObjectDestroyed(tt), | ||
| objectchecks.IsBucketDestroyed(tt), | ||
| ), | ||
| Steps: []resource.TestStep{ | ||
| { | ||
| Config: fmt.Sprintf(` | ||
| resource "scaleway_object_bucket" "base-01" { | ||
| name = "%s" | ||
| region= "%s" | ||
| tags = { | ||
| foo = "bar" | ||
| } | ||
| } | ||
|
|
||
| resource scaleway_object "file" { | ||
| bucket = scaleway_object_bucket.base-01.id | ||
| key = "myfile" | ||
| content = "Hello World" | ||
| sse_customer_key = "%s" | ||
| } | ||
|
|
||
| `, bucketName, objectTestsMainRegion, encryptionStr), | ||
| Check: resource.ComposeTestCheckFunc( | ||
| objectchecks.CheckBucketExists(tt, "scaleway_object_bucket.base-01", true), | ||
| objectchecks.IsObjectExists(tt, "scaleway_object.file"), | ||
| ), | ||
| }, | ||
| { | ||
| Config: fmt.Sprintf(` | ||
| resource "scaleway_object_bucket" "base-01" { | ||
| name = "%s" | ||
| region= "%s" | ||
| tags = { | ||
| foo = "bar" | ||
| } | ||
| } | ||
|
|
||
| resource scaleway_object "file" { | ||
| bucket = scaleway_object_bucket.base-01.id | ||
| key = "myfile" | ||
| content = "Hello World" | ||
| sse_customer_key = "%s" | ||
| } | ||
|
|
||
| data scaleway_object "by-key" { | ||
| key = "myfile" | ||
| bucket = scaleway_object_bucket.base-01.id | ||
| sse_customer_key = "%s" | ||
| } | ||
| `, bucketName, objectTestsMainRegion, encryptionStr, encryptionStr), | ||
| Check: resource.ComposeTestCheckFunc( | ||
| objectchecks.CheckBucketExists(tt, "scaleway_object_bucket.base-01", true), | ||
| resource.TestCheckResourceAttr("data.scaleway_object.by-key", "key", "myfile"), | ||
| resource.TestCheckResourceAttrSet("data.scaleway_object.by-key", "id"), | ||
| ), | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| func TestAccDataSourceObject_EncryptedWO(t *testing.T) { | ||
| tt := acctest.NewTestTools(t) | ||
| defer tt.Cleanup() | ||
|
|
||
| bucketName := sdkacctest.RandomWithPrefix("test-acc-scaleway-ds-obj-encryptedwo") | ||
| resource.ParallelTest(t, resource.TestCase{ | ||
| ProtoV6ProviderFactories: tt.ProviderFactories, | ||
| CheckDestroy: resource.ComposeTestCheckFunc( | ||
| objectchecks.IsObjectDestroyed(tt), | ||
| objectchecks.IsBucketDestroyed(tt), | ||
| ), | ||
| Steps: []resource.TestStep{ | ||
| { | ||
| Config: fmt.Sprintf(` | ||
| resource "scaleway_object_bucket" "base-01" { | ||
| name = "%s" | ||
| region= "%s" | ||
| tags = { | ||
| foo = "bar" | ||
| } | ||
| } | ||
|
|
||
| resource scaleway_object "file" { | ||
| bucket = scaleway_object_bucket.base-01.id | ||
| key = "myfile" | ||
| content = "Hello World" | ||
| sse_customer_key_wo = "%s" | ||
| sse_customer_key_wo_version = 1 | ||
| } | ||
|
|
||
| `, bucketName, objectTestsMainRegion, encryptionStr), | ||
| Check: resource.ComposeTestCheckFunc( | ||
| objectchecks.CheckBucketExists(tt, "scaleway_object_bucket.base-01", true), | ||
| objectchecks.IsObjectExists(tt, "scaleway_object.file"), | ||
| ), | ||
| }, | ||
| // The only way to get an encrypted object is to provide the sse_customer_key. For a sse_customer_key_wo, | ||
| // datasources cannot have Write Only attributes, so we have to pass it as a regular sse_customer_key. | ||
| // This is not ideal, as the key is then set in the state, making the Write Only useless... | ||
| // Querying objects encrypted with a sse_customer_key_wo is discouraged. | ||
|
Comment on lines
+182
to
+185
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This limitation is why I am considering not merging this PR at all. Is this restriction (not being able to query the datasource specifically for sse_customer_key_wo encrypted objects) something we are OK with ? We might as well have a dedicated Ephemeral Resource at that point. |
||
| { | ||
| Config: fmt.Sprintf(` | ||
| resource "scaleway_object_bucket" "base-01" { | ||
| name = "%s" | ||
| region= "%s" | ||
| tags = { | ||
| foo = "bar" | ||
| } | ||
| } | ||
|
|
||
| resource scaleway_object "file" { | ||
| bucket = scaleway_object_bucket.base-01.id | ||
| key = "myfile" | ||
| content = "Hello World" | ||
| sse_customer_key_wo = "%s" | ||
| sse_customer_key_wo_version = 1 | ||
| } | ||
|
|
||
| data scaleway_object "by-key" { | ||
| key = "myfile" | ||
| bucket = scaleway_object_bucket.base-01.id | ||
| sse_customer_key = "%s" | ||
| } | ||
| `, bucketName, objectTestsMainRegion, encryptionStr, encryptionStr), | ||
| Check: resource.ComposeTestCheckFunc( | ||
| objectchecks.CheckBucketExists(tt, "scaleway_object_bucket.base-01", true), | ||
| objectchecks.IsObjectExists(tt, "scaleway_object.file"), | ||
| ), | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| The `scaleway_object` resource allows you to create and manage objects for [Scaleway Object storage](https://www.scaleway.com/en/docs/object-storage/). | ||
|
|
||
| Refer to the [dedicated documentation](https://www.scaleway.com/en/docs/object-storage/how-to/upload-files-into-a-bucket/) for more information on Object Storage objects. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Currently we could not get an sse_customer_key encrypted datasource (the key is required to build the proper s3 HeadObject call headers)