Skip to content

Adds support to S3 server side encryption using AWS KMS #3651

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

Merged
merged 16 commits into from
Jan 28, 2021

Conversation

lucasvmiguel
Copy link
Contributor

@lucasvmiguel lucasvmiguel commented Jan 6, 2021

What this PR does: Adds support to S3 server side encryption using KMS.

Which issue(s) this PR fixes:
Fixes #3437

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]
  • Manually tests to verify if S3 SSE is working
    • Data stored without SSE
    • Data stored with deprecated SSE (s3.sse-encryption=true)
    • Data stored with S3 SSE (sse-config.type=SSE-S3)
    • Data store with S3 KMS (sse-config.type=SSE-KMS)

TIP: Just to help future folks that want to use this feature (because I lost sometime to understand how I'd fetch the data back from the S3 bucket). You basically have to create the following IAM policy and attach to an IAM role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt",
                "s3:GetObject"
            ],
            "Resource": [
                "<AWS KMS KEY ARN>",
                "<AWS S3 BUCKET ARN>/*"
            ]
        }
    ]
}

@lucasvmiguel lucasvmiguel changed the title (WIP) Adds support to S3 server side encryption using KMS. # Adds support to S3 server side encryption using AWS KMS Jan 7, 2021
@lucasvmiguel lucasvmiguel changed the title Adds support to S3 server side encryption using AWS KMS (WIP) Adds support to S3 server side encryption using AWS KMS Jan 7, 2021
Copy link
Contributor

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! I haven't review it properly. Just leaving a comment about a little thing I've noticed and then will do a proper review.

@lucasvmiguel lucasvmiguel force-pushed the issue-3437 branch 2 times, most recently from 1df3429 to 7e6f625 Compare January 7, 2021 16:28
@lucasvmiguel
Copy link
Contributor Author

lucasvmiguel commented Jan 11, 2021

Manual tests performed

bucket name params result
cortex-test-sse none stored without SSE
cortex-test-sse-2 s3.sse-encryption=true stored encrypted data with SSE-S3
cortex-test-sse-3 s3.sse-config.type=SSE-S3 stored encrypted data with SSE-S3
cortex-test-sse-4 s3.sse-config.type=SSE-KMS and s3.sse-config.kms-key-id=SOME_KEY stored encrypted data with SSE-KMS

@lucasvmiguel lucasvmiguel changed the title (WIP) Adds support to S3 server side encryption using AWS KMS Adds support to S3 server side encryption using AWS KMS Jan 11, 2021
Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
Copy link
Contributor

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job @lucasvmiguel and sorry for the extremely delay in the review! Overall LGTM, just left few comments to polish it a bit before merging. Thanks!

@@ -100,7 +108,10 @@ func (cfg *S3Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
f.StringVar(&cfg.AccessKeyID, prefix+"s3.access-key-id", "", "AWS Access Key ID")
f.StringVar(&cfg.SecretAccessKey, prefix+"s3.secret-access-key", "", "AWS Secret Access Key")
f.BoolVar(&cfg.Insecure, prefix+"s3.insecure", false, "Disable https on s3 connection.")
f.BoolVar(&cfg.SSEEncryption, prefix+"s3.sse-encryption", false, "Enable AES256 AWS Server Side Encryption")
f.BoolVar(&cfg.SSEEncryption, prefix+"s3.sse-encryption", false, "Enable AWS Server Side Encryption [Deprecated: Use sse-config instead. if s3.sse-encryption is enabled, it assumes sse-config SSE-S3 type]")
f.StringVar(&cfg.SSEConfig.Type, prefix+"s3.sse-config.type", "", "Enable AWS Server Side Encryption. Only SSE-S3 and SSE-KMS are supported")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're used to define RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) on the receiver config. I would suggest you to do the same on SSEConfig, passing prefix+"s3.sse." as prefix to SSEConfig.RegisterFlagsWithPrefix().

@@ -100,7 +108,10 @@ func (cfg *S3Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
f.StringVar(&cfg.AccessKeyID, prefix+"s3.access-key-id", "", "AWS Access Key ID")
f.StringVar(&cfg.SecretAccessKey, prefix+"s3.secret-access-key", "", "AWS Secret Access Key")
f.BoolVar(&cfg.Insecure, prefix+"s3.insecure", false, "Disable https on s3 connection.")
f.BoolVar(&cfg.SSEEncryption, prefix+"s3.sse-encryption", false, "Enable AES256 AWS Server Side Encryption")
f.BoolVar(&cfg.SSEEncryption, prefix+"s3.sse-encryption", false, "Enable AWS Server Side Encryption [Deprecated: Use sse-config instead. if s3.sse-encryption is enabled, it assumes sse-config SSE-S3 type]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add also a // TODO Remove in Cortex 1.9.0 (because we guarantee deprecated config to be removed at least after 2 minor releases).

)

// SSEEncryptionConfig configures server side encryption (SSE)
type SSEEncryptionConfig struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this when we already have SSEConfig?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSEConfig is the struct responsible to receive the config from the CLI or a config file. After SSEConfig is filled with the values provided by the user, a SSEEncryptionConfig struct will be created to be worked inside the application. In the end, SSEEncryptionConfig will have different values than SSEConfig.

Comment on lines +24 to +25
KMSKeyID *string
KMSEncryptionContext *string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a big fan of pointers in config structs. You can achieve the same assuming empty string means not configured (which should be fine in this context).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AWS lib uses string pointers several times in there. Removing string pointers from sse_config.go (SSEEncryptionConfig) means that I will have to treat that on the file s3_storage_client.go, which has more logic that should have.

@@ -72,6 +72,7 @@ type S3Config struct {
SSEEncryption bool `yaml:"sse_encryption"`
HTTPConfig HTTPConfig `yaml:"http_config"`
SignatureVersion string `yaml:"signature_version"`
SSEConfig SSEConfig `yaml:"sse_config"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In recent times we stopped appending _config to sub-config structs cause it's a bit redundant. I would remove it from here too.

Suggested change
SSEConfig SSEConfig `yaml:"sse_config"`
SSEConfig SSEConfig `yaml:"sse"`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to not use _config, we won't be compatible with Thanos config.

I don't mind to remove _config, I just thought that we wanted the config interface exactly the same as Thanos. (to not "break" any future migration)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not 1:1 compatible with Thanos even in the blocks storage. It's perfectly fine. We just wanna let configure the same things, so that when we'll add KMS support to blocks storage too we can keep the same config struct.

CHANGELOG.md Outdated
@@ -2,6 +2,11 @@

## master / unreleased


* [FEATURE] Adds support to S3 server side encryption using KMS. The following config fields have been added. #3651
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're used to group CHANGELOG entries together by type. Please move this entry below, under the group of [FEATURE].

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
@lucasvmiguel lucasvmiguel requested a review from pracucci January 19, 2021 16:23
CHANGELOG.md Outdated
@@ -24,13 +24,17 @@
* `-cluster.peer-timeout` in favor of `-alertmanager.cluster.peer-timeout`
* [CHANGE] Blocks storage: the default value of `-blocks-storage.bucket-store.sync-interval` has been changed from `5m` to `15m`. #3724
* [FEATURE] Querier: Queries can be federated across multiple tenants. The tenants IDs involved need to be specified separated by a `|` character in the `X-Scope-OrgID` request header. This is an experimental feature, which can be enabled by setting `-tenant-federation.enabled=true` on all Cortex services. #3250
* [ENHANCEMENT] Allow specifying JAEGER_ENDPOINT instead of sampling server or local agent port. #3682
* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `<prefix>.s3.sse-encryption`, you should use the following config fields that have been added. #3651
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've just released 1.7.0-rc.0. Could you rebase master and move the CHANGELOG entry under the master / unreleased section, please?

CHANGELOG.md Outdated
* [FEATURE] Alertmanager: introduced the experimental option `-alertmanager.sharding-enabled` to shard tenants across multiple Alertmanager instances. This feature is still under heavy development and its usage is discouraged. The following new metrics are exported by the Alertmanager: #3664
* `cortex_alertmanager_ring_check_errors_total`
* `cortex_alertmanager_sync_configs_total`
* `cortex_alertmanager_sync_configs_failed_total`
* `cortex_alertmanager_tenants_discovered`
* `cortex_alertmanager_tenants_owned`
* [ENHANCEMENT] Allow specifying JAEGER_ENDPOINT instead of sampling server or local agent port. #3682
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've just released 1.7.0-rc.0. Could you rebase master and move the CHANGELOG entry under the master / unreleased section, please?

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
@lucasvmiguel lucasvmiguel requested a review from pracucci January 25, 2021 14:00
Copy link
Contributor

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow up! We're very close! I left last comments.

Please mention that S3 server-side encryption is experimental in docs/configuration/v1-guarantees.md (there's a list of experimental features). This will allow us to introduce config breaking changes in the near future if we find out any issue (or improvement).

CHANGELOG.md Outdated
@@ -2,6 +2,10 @@

## master / unreleased

* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `<prefix>.s3.sse-encryption`, you should use the following config fields that have been added. #3651
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `<prefix>.s3.sse-encryption`, you should use the following config fields that have been added. #3651
* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `-<prefix>.s3.sse-encryption`, you should use the following CLI flags that have been added. #3651

CHANGELOG.md Outdated
@@ -2,6 +2,10 @@

## master / unreleased

* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `<prefix>.s3.sse-encryption`, you should use the following config fields that have been added. #3651
- `<prefix>.s3.sse.type`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `<prefix>.s3.sse.type`
- `-<prefix>.s3.sse.type`

CHANGELOG.md Outdated
@@ -2,6 +2,10 @@

## master / unreleased

* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `<prefix>.s3.sse-encryption`, you should use the following config fields that have been added. #3651
- `<prefix>.s3.sse.type`
- `<prefix>.s3.sse.kms-key-id`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `<prefix>.s3.sse.kms-key-id`
- `-<prefix>.s3.sse.kms-key-id`

CHANGELOG.md Outdated
* [FEATURE] Adds support to S3 server side encryption using KMS. Deprecated `<prefix>.s3.sse-encryption`, you should use the following config fields that have been added. #3651
- `<prefix>.s3.sse.type`
- `<prefix>.s3.sse.kms-key-id`
- `<prefix>.s3.sse.kms-encryption-context`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `<prefix>.s3.sse.kms-encryption-context`
- `-<prefix>.s3.sse.kms-encryption-context`

type SSEConfig struct {
Type string `yaml:"type"`
KMSKeyID string `yaml:"kms_key_id"`
KMSEncryptionContext chunk.Tags `yaml:"kms_encryption_context"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should use chunk.Tags here. I would simplify it just taking in input the context json as a string. Moreover, I would clarify in the CLI flag description that it expects a JSON as a string.

},
},
{
name: "Test invalid SEE type",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "Test invalid SEE type",
name: "Test invalid SSE type",

},
},
{
name: "Test SSE encryption with SSEKMS type with context",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is duplicated from above.

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
@lucasvmiguel lucasvmiguel requested a review from pracucci January 27, 2021 10:43
Copy link
Contributor

@pracucci pracucci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow up! I have a last question about context parsing.

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
Copy link
Contributor

@pstibrany pstibrany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you! Please take a look at final comments before merging.

}

// NewSSEParsedConfig creates a struct to configure server side encryption (SSE)
func NewSSEParsedConfig(sseType string, kmsKeyID string, kmsEncryptionContext string) (*SSEParsedConfig, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Perhaps this should have been a method on SSEConfig or take it as a parameter?

func TestNewSSEParsedConfig(t *testing.T) {
kmsKeyID := "test"
kmsEncryptionContext := `{"a": "bc", "b": "cd"}`
parsedKMSEncryptionContext := "eyJhIjoiYmMiLCJiIjoiY2QifQ=="
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
parsedKMSEncryptionContext := "eyJhIjoiYmMiLCJiIjoiY2QifQ=="
parsedKMSEncryptionContext = base64.StdEncoding.EncodeToString([]byte(`{"a":"bc","b":"cd"}`)) // compact form of kmsEncryptionContext

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>
@pstibrany pstibrany merged commit f639b18 into cortexproject:master Jan 28, 2021
simonswine pushed a commit to grafana/e2e that referenced this pull request Jan 13, 2022
…t/cortex#3651)

* Adds support to S3 server side encryption using AWS KMS

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* refatored based on PR review

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* small refactor

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* rebased master

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* rebased master correctly

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* added new line

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* refactored

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* reordered changelog

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* refactored NewSSEParsedConfig

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

* removed unused struct

Signed-off-by: Lucas Miguel <lucasvieira.dev@gmail.com>

Co-authored-by: Lucas Vieira <lucas.vieira@ASSUMESEEQUITE.workdayinternal.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support multiple AWS S3 SSE (Server side encryption)
3 participants