-
Notifications
You must be signed in to change notification settings - Fork 25
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
Support s3 Server Side Encryption #372
Conversation
Shouldn't we have internally a list of allowed parms for |
api/v1beta1/verticadb_webhook.go
Outdated
// communal.s3ServerSideEncryption cannot change after creation | ||
if v.Spec.Communal.S3ServerSideEncryption != oldObj.Spec.Communal.S3ServerSideEncryption { | ||
err := field.Invalid(field.NewPath("spec").Child("communal").Child("s3ServerSideEncryption"), | ||
v.Spec.Communal.S3ServerSideEncryption, | ||
"communal.s3ServerSideEncryption cannot change after creation") | ||
allErrs = append(allErrs, err) | ||
} |
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.
Can we move this to a separate function (checkImmutableS3ServerSideEncryption
)? I have been doing this for new additions to this function to avoid making it so big.
api/v1beta1/verticadb_webhook.go
Outdated
@@ -307,6 +338,38 @@ func (v *VerticaDB) validateCommunalPath(allErrs field.ErrorList) field.ErrorLis | |||
return append(allErrs, err) | |||
} | |||
|
|||
func (v *VerticaDB) validateS3ServerSideEncryption(allErrs field.ErrorList) field.ErrorList { | |||
if !v.IsS3() || v.IsSseS3() || v.Spec.Communal.S3ServerSideEncryption == "" { |
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.
What is the v.IsSseS3()
check needed for?
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 is to return if SSE-S3, but we do not really need it here.
api/v1beta1/verticadb_types.go
Outdated
// Available values are: SSE-S3, SSE-KMS and SSE-C. | ||
// - SSE-S3: the S3 service manages encryption keys. | ||
// - SSE-KMS: encryption keys are managed by the Key Management Service (KMS). | ||
// KMS key identifier must be supplied through communal.additionalConfig map. | ||
// - SSE-C: the client manages encryption keys and provides them to S3 for each operation. | ||
// The client key must be supplied through communal.s3SseCustomerKeySecret. |
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 suggest we include mention of default value and how to disable encryption.
// Available values are: SSE-S3, SSE-KMS and SSE-C. | |
// - SSE-S3: the S3 service manages encryption keys. | |
// - SSE-KMS: encryption keys are managed by the Key Management Service (KMS). | |
// KMS key identifier must be supplied through communal.additionalConfig map. | |
// - SSE-C: the client manages encryption keys and provides them to S3 for each operation. | |
// The client key must be supplied through communal.s3SseCustomerKeySecret. | |
// Available values are: SSE-S3, SSE-KMS, SSE-C and empty string (""). | |
// - SSE-S3: the S3 service manages encryption keys. | |
// - SSE-KMS: encryption keys are managed by the Key Management Service (KMS). | |
// KMS key identifier must be supplied through communal.additionalConfig map. | |
// - SSE-C: the client manages encryption keys and provides them to S3 for each operation. | |
// The client key must be supplied through communal.s3SseCustomerKeySecret. | |
// - Empty string (""): No encryption. This is the default value. |
pkg/builder/builder.go
Outdated
@@ -875,6 +875,21 @@ func BuildAzureSASCommunalCredSecret(vdb *vapi.VerticaDB, blobEndpoint, sas stri | |||
return secret | |||
} | |||
|
|||
// BuildS3SseCustomerKeySecret builds a secret that is setup for S3 SSE-C server-side encryption |
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 think this is for test purposes only. Can we add a comment to that affect?
// BuildS3SseCustomerKeySecret builds a secret that is setup for S3 SSE-C server-side encryption | |
// BuildS3SseCustomerKeySecret is a test helper that builds a secret that is setup for | |
// S3 SSE-C server-side encryption |
for _, row := range strings.Split(content, "\n") { | ||
if row != "" { | ||
s := strings.Split(row, " = ") | ||
parmNames[strings.ToLower(s[0])] = s[1] |
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.
Why do we need to lowercase the parm name? Is this for easy comparison? I think the config parms are case sensitive. So I'm not sure if that is necessary.
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.
For example awsauth
and AWSauth
are the same. The to lowercase is to avoid this case. I think we should also check additionalConfig keys for this kind of duplication:
additionalConfig:
awsauth: "ffff:fff"
AWSAuth: "aaaa:aaaa"
We should make sure only is passed into auth_conf
. If both are passed, the 1st one in the file will be applied.
EDIT: the last one in the file will be applied.
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.
Okay, please add a comment to explain why this is done.
pkg/controllers/vdb/init_db.go
Outdated
// getAdditionalConfigParmsContent constructs a string containing additional server config parameters | ||
func (g *GenericDatabaseInitializer) getAdditionalConfigParmsContent(content string) string { | ||
parmNames := genCommunalParmsMap(content) | ||
acpContent := "" |
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.
Lets using a string builder rather than rebuilding a string for each parm that we add.
@@ -358,6 +384,19 @@ func (g *GenericDatabaseInitializer) getAzureAuthParmsContent(ctx context.Contex | |||
return dedent.Dedent(content), ctrl.Result{}, nil | |||
} | |||
|
|||
// getAdditionalConfigParmsContent constructs a string containing additional server config parameters | |||
func (g *GenericDatabaseInitializer) getAdditionalConfigParmsContent(content string) 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.
What is the behaviour in the server if we put in a config value that the server doesn't recognize. Is there an error in the server? A message in the vertica.log? Or is it silently ignored? We should document what happens here.
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 get an error Invalid configuration parameter *****
.
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.
What happens to the server then?
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.
The configuration is aborted and process exits.
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.
How does someone debug this? I assume the create db is retried again and again. Each time most of the log files in the pod are removed before attempting create again.
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.
Yes create db is retried again and again and you can see that error in the operator logs.
pkg/controllers/vdb/init_db.go
Outdated
clientKey, ok := secret.Data[cloud.S3SseCustomerKeyName] | ||
if !ok { | ||
g.VRec.Eventf(g.Vdb, corev1.EventTypeWarning, events.S3SseCustomerWrongKey, | ||
"The sseCustomerKey secret '%s' does not have a key named '%s'", g.Vdb.Spec.Communal.S3SseCustomerKeySecret, cloud.S3SseCustomerKeyName) |
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.
"The sseCustomerKey secret '%s' does not have a key named '%s'", g.Vdb.Spec.Communal.S3SseCustomerKeySecret, cloud.S3SseCustomerKeyName) | |
"The s3SseCustomerKey secret '%s' does not have a key named '%s'", g.Vdb.Spec.Communal.S3SseCustomerKeySecret, cloud.S3SseCustomerKeyName) |
pkg/controllers/vdb/init_db.go
Outdated
acpContent := "" | ||
for k, v := range g.Vdb.Spec.Communal.AdditionalConfig { | ||
_, ok := parmNames[strings.ToLower(k)] | ||
if !ok { |
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 should log a warning if we don't include a parameter that was specified.
I don't want to do any kind of filtering. One of the benefits of not filtering is if a new vertica server version comes out that exposes a new parm, you don't need a new operator version to try it out. So, really the operator can't ever know the config parms that are supported. |
@@ -307,6 +338,38 @@ func (v *VerticaDB) validateCommunalPath(allErrs field.ErrorList) field.ErrorLis | |||
return append(allErrs, err) | |||
} | |||
|
|||
func (v *VerticaDB) validateS3ServerSideEncryption(allErrs field.ErrorList) field.ErrorList { |
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.
A few other things to validate:
- should we validate if someone sets the
communal.s3SseCustomerKeySecret
without settingcommunal.s3ServerSideEncryption
? - if
communal.s3ServerSideEncryption
is set but the communal path isn't s3?
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.
My idea is that if communal.s3ServerSideEncryption
is not set, server-side encryption is considered disabled and other parameters are just ignored. The is a check for that in init_db.go
. Same if communal path is not s3, all sse are just ignored. I understand a need of validation for the later.
It would be difficult to add an e2e test. I was not able to get it to work on minio. I was getting an |
Makes sense. Thanks for taking a look. |
api/v1beta1/verticadb_types.go
Outdated
// To avoid duplicate values, if a parameter is already set through another CR field, | ||
// (like S3ServerSideEncryption through communal.s3ServerSideEncryption), the corresponding | ||
// key/value pair is skipped. | ||
// These are set only during initial bootstrap. After the database has been initialized, | ||
// changing the options in the CR will have no affect in the server. |
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.
Suggestion call out what happens if you use a parameter that isn't supported by your server version:
// To avoid duplicate values, if a parameter is already set through another CR field, | |
// (like S3ServerSideEncryption through communal.s3ServerSideEncryption), the corresponding | |
// key/value pair is skipped. | |
// These are set only during initial bootstrap. After the database has been initialized, | |
// changing the options in the CR will have no affect in the server. | |
// To avoid duplicate values, if a parameter is already set through another CR field, | |
// (like S3ServerSideEncryption through communal.s3ServerSideEncryption), the corresponding | |
// key/value pair is skipped. If a config value is set that isn't supported by the server version | |
// you are running, the server will fail to start. These are set only during initial bootstrap. After | |
// the database has been initialized, changing the options in the CR will have no affect in the server. |
pkg/controllers/vdb/init_db.go
Outdated
g.VRec.Eventf(g.Vdb, corev1.EventTypeWarning, events.AdditionalConfigParmIgnored, | ||
"The additional config parameter '%s' has been ignored because it has already been set in previous steps", k) |
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.
A log message is probably sufficient. An event might be a bit alarming.
pkg/controllers/vdb/init_db.go
Outdated
const DefaultSseSupportedVersion = "v12.0.1" | ||
// The '%s' are placeholders for the version extracted from a vdb | ||
// and the minimum version you must be on to setup server side encryption. | ||
eventMsg := "The engine (%s) doesn't have the required change for server-side encryption. " + |
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 message is very similar to the one in hasCompatibleVersionForKerberos
. Could we put that in the generic function and may just pass in the portion that's different (i.e. "server-side encryption")?
pkg/controllers/vdb/init_db.go
Outdated
@@ -395,8 +395,7 @@ func (g *GenericDatabaseInitializer) getAdditionalConfigParmsContent(content str | |||
// we skip to the next parm. | |||
_, ok := parmNames[strings.ToLower(k)] | |||
if ok { | |||
g.VRec.Eventf(g.Vdb, corev1.EventTypeWarning, events.AdditionalConfigParmIgnored, |
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 if you were ready for a re-review, but we should remove this event you added.
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.
Looks good. Thanks for applying the revisions.
Thanks for the comments! They were very helpful and made me understand some aspects of the code. |
This adds the ability to use s3 server side encryption, provided the vertica server that you run supports it (>= 12.0.1).
There are 3 types of s3 server side encryption. Here are samples to set for each one:
An additional change in here allows you to set any config parameter in the CR and pass it through to the server. This will allow you try out new server versions without waiting for the operator to expose them in the CRD. For example: