-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add support for S3 SSE with KMS #29
Conversation
Can one of the admins verify this patch? |
f90b8ab
to
af0f548
Compare
ok to test |
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.
Thanks for the PR!
Body: body, | ||
Bucket: &bucket, | ||
Key: &key, | ||
SSEKMSKeyId: &op.KMSKeyID, |
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.
Do we also need this for the other actions?
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.
I find the docs unclear regarding GetObjectInput
with KMS. Deleting and listing objects is definitely possible without the key. I compared the code with the Docker registries implementation and usage of GetObject and it seems that s3.GetObject
does "the right thing" if it tries to get an encrypted object without explicitly specifying the key ID.
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.
Ok, we'll try it out and see how it works both with ""
for the key and with a real one.
docs/config-definition.md
Outdated
@@ -70,6 +70,7 @@ The configurable parameters are as follows: | |||
| `disableSSL` | bool | `false` | Set this to `true` if you are using Minio (or another local, S3-compatible storage service) and your deployment is not secured. | | |||
| `s3ForcePathStyle` | bool | `false` | Set this to `true` if you are using a local storage service like Minio. | | |||
| `s3Url` | string | Required field for non-AWS-hosted storage| *Example*: http://minio:9000<br><br>You can specify the AWS S3 URL here for explicitness, but Ark can already generate it from `region`, `availabilityZone`, and `bucket`. This field is primarily for local sotrage services like Minio.| | |||
| `kmsKeyID` | string | Empty | *Example*: "502b409c-4da1-419f-a16e-eif453b3i49f"<br><br>Specify an AWS KMS key id to enable encryption of the backups stored in S3. Only works with AWS S3 and may require explicitly granting key usage rights. | |
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.
Remove blank space in between .
and |
?
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.
Done
af0f548
to
97a89bf
Compare
docs/config-definition.md
Outdated
@@ -70,6 +70,7 @@ The configurable parameters are as follows: | |||
| `disableSSL` | bool | `false` | Set this to `true` if you are using Minio (or another local, S3-compatible storage service) and your deployment is not secured. | | |||
| `s3ForcePathStyle` | bool | `false` | Set this to `true` if you are using a local storage service like Minio. | | |||
| `s3Url` | string | Required field for non-AWS-hosted storage| *Example*: http://minio:9000<br><br>You can specify the AWS S3 URL here for explicitness, but Ark can already generate it from `region`, `availabilityZone`, and `bucket`. This field is primarily for local sotrage services like Minio.| | |||
| `kmsKeyID` | string | Empty | *Example*: "502b409c-4da1-419f-a16e-eif453b3i49f"<br><br>Specify an AWS KMS key id to enable encryption of the backups stored in S3. Only works with AWS S3 and may require explicitly granting key usage rights.| |
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.
nit: link "AWS KMS key" to http://docs.aws.amazon.com/kms/latest/developerguide/overview.html for convenience?
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.
other than this LGTM!
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.
Good idea 🙂
97a89bf
to
fdd3e88
Compare
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.
@madddi thanks for this!
It's not quite working yet, but I think I see why (commented inline above). This is the error I am getting:
I0811 15:59:22.620810 1 backup_controller.go:263] backup heptio-ark/test5 failed: InvalidArgument: Server Side Encryption with AWS KMS managed key requires HTTP header x-amz-server-side-encryption : aws:kms
status code: 400, request id: 2D8DF113E54DD682
Body: body, | ||
Bucket: &bucket, | ||
Key: &key, | ||
SSEKMSKeyId: &op.KMSKeyID, |
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.
This also needs ServerSideEncryption: "aws:kms"
if op.KMSKeyID != ""
.
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.
Given that we need to set ServerSideEncryption
based on the presence of kmsKeyID
, let's only set ServerSideEncryption
and SSEKMSKeyId
if necessary.
@@ -27,14 +27,16 @@ import ( | |||
var _ cloudprovider.ObjectStorageAdapter = &objectStorageAdapter{} | |||
|
|||
type objectStorageAdapter struct { | |||
s3 *s3.S3 | |||
s3 *s3.S3 | |||
KMSKeyID string |
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.
Very minor nit, but this should probably be package-local kmsKeyID
rather than KMSKeyID
.
7b6ec6e
to
9e66aa0
Compare
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.
Works great for me now. I had a couple of comments but I'm also +1 as-is.
$ aws s3api head-object --bucket moyer-dev-ark --key test/test.tar.gz
{
"AcceptRanges": "bytes",
"ContentType": "binary/octet-stream",
"LastModified": "Fri, 11 Aug 2017 20:37:49 GMT",
"ContentLength": 54752,
"ETag": "\"a8ec4baa50e668fc0cbe15fedc452873\"",
"ServerSideEncryption": "aws:kms",
"SSEKMSKeyId": "arn:aws:kms:us-east-2:835338462208:key/18a72e1f-6e67-4c2a-98d6-c81a4c0612b2",
"Metadata": {}
}
// if kmsKeyID is not empty, enable "aws:kms" encryption and amend the key ID | ||
if op.kmsKeyID != "" { | ||
sseType := "aws:kms" | ||
req.ServerSideEncryption = &sseType |
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.
Small nit if you're interested, aws-sdk-go
has a helper for this req.ServerSideEncryption = aws.String("aws:kms")
. I have no idea why the API is this way.
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.
Thanks, good to know. Assigning the string a variable just for the pointer was ugly.
@@ -98,6 +98,7 @@ type AWSConfig struct { | |||
DisableSSL bool `json:"disableSSL"` | |||
S3ForcePathStyle bool `json:"s3ForcePathStyle"` | |||
S3Url string `json:"s3Url"` | |||
KMSKeyID string `json:"kmsKeyId"` |
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.
I got tripped up on this being kmsKeyId
and not kmsKeyID
. It looks like we're inconsistent in other keys (s3Url
rather than s3URL
but disableSSL
, not disableSsl
). @ncdc thoughts?
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.
It's possible some of the discrepancies are from me manually generating some tags vs using vim-go's :GoAddTags
- can't say for sure. Consistency would be nice... But not something we need to change right now. Especially since it breaks backwards compat.
9e66aa0
to
8958057
Compare
docs/config-definition.md
Outdated
@@ -1,9 +1,9 @@ | |||
# Ark Config definition | |||
|
|||
* [Overview][10] |
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.
@abiogenesis-now I thought you said we didn't have to renumber everything?
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.
We don't >< I think the numbers might make it confusing (because people assume that it needs to be in order when it doesn't, @madddi could just append the new link to the end of the numbered list). Essentially the stuff at the bottom are K/V pairs (shorthands and their links), which are most useful when you are reusing the same link multiple times throughout a doc.
This is probably fine as is but let me know if you think we should add some sort of note about this to Contributing or something @ncdc
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.
I'd prefer to keep the changes to a minimum, and just append the new link. Would you mind doing that @madddi? Sorry for the confusion!
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.
I already knew I could just append the new link but thought it'd be nicer if the order of the links and the numbers would match. I'll change it, no problem.
} | ||
|
||
func (op *objectStorageAdapter) PutObject(bucket string, key string, body io.ReadSeeker) error { | ||
|
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.
Remove blank line
req := &s3.PutObjectInput{ | ||
Bucket: &bucket, | ||
Key: &key, | ||
Body: body, | ||
} | ||
|
||
// if kmsKeyID is not empty, enable "aws:kms" encryption and amend the key ID |
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.
I'm not sure "amend" is the correct word. Maybe just end the comment at "encryption"?
@@ -32,7 +32,7 @@ type storageAdapter struct { | |||
|
|||
var _ cloudprovider.StorageAdapter = &storageAdapter{} | |||
|
|||
func NewStorageAdapter(config *aws.Config, availabilityZone string) (cloudprovider.StorageAdapter, error) { | |||
func NewStorageAdapter(config *aws.Config, availabilityZone string, KMSKeyID string) (cloudprovider.StorageAdapter, error) { |
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.
s/KMSKeyID/kmsKeyID/
@@ -48,7 +48,8 @@ func NewStorageAdapter(config *aws.Config, availabilityZone string) (cloudprovid | |||
az: availabilityZone, | |||
}, | |||
objectStorage: &objectStorageAdapter{ | |||
s3: s3.New(sess), | |||
s3: s3.New(sess), | |||
kmsKeyID: KMSKeyID, |
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.
s/KMSKeyID/kmsKeyID/
8958057
to
34f4af1
Compare
Signed-off-by: Mathias Merscher <Mathias.Merscher@dg-i.net>
34f4af1
to
df320d7
Compare
@abiogenesis-now @mattmoyer any other comments? |
LGTM -- @ncdc do you think this encryption feature is worth mentioning in the last bullet point of |
@abiogenesis-now we can do it in a follow-up if needed |
Thanks again @madddi!!! |
use ubi8-minimal
Issue #24
If not specified in the configuration,
kmsKeyID
should be an empty string, which gets passed toPutObjectInput
. Because an empty string is essentially undefined and the AWS SDK checks if a key ID is given, I did not add checks on our side.