-
Notifications
You must be signed in to change notification settings - Fork 265
CNTRLPLANE-3237: Carry referenced Secret data from API to plugin lifecycle for KMS #2212
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 |
|---|---|---|
|
|
@@ -42,6 +42,7 @@ const ( | |
| encryptionSecretMigrationInterval = time.Hour * 24 * 7 // one week | ||
| kmsEndpointFormat = "unix:///var/run/kmsplugin/kms-%d.sock" | ||
| defaultKMSTimeout = 10 * time.Second | ||
| openshiftConfigNS = "openshift-config" | ||
| ) | ||
|
|
||
| // keyController creates new keys if necessary. It | ||
|
|
@@ -117,6 +118,7 @@ func NewKeyController( | |
| apiServerInformer.Informer(), | ||
| operatorClient.Informer(), | ||
| kubeInformersForNamespaces.InformersFor("openshift-config-managed").Core().V1().Secrets().Informer(), | ||
| // TODO: add informer for openshift-config namespace to watch referenced Secrets for KMS plugin secret data changes | ||
| deployer, | ||
| ).ToController( | ||
| c.controllerInstanceName, | ||
|
|
@@ -223,7 +225,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact | |
|
|
||
| sort.Sort(sort.StringSlice(reasons)) | ||
| internalReason := strings.Join(reasons, ", ") | ||
| keySecret, err := c.generateKeySecret(newKeyID, currentMode, apiEncryptionConfiguration, internalReason, externalReason) | ||
| keySecret, err := c.generateKeySecret(ctx, newKeyID, currentMode, apiEncryptionConfiguration, internalReason, externalReason) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create key: %v", err) | ||
| } | ||
|
|
@@ -260,7 +262,7 @@ func (c *keyController) validateExistingSecret(ctx context.Context, keySecret *c | |
| return nil // we made this key earlier | ||
| } | ||
|
|
||
| func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode, apiServerEncryption configv1.APIServerEncryption, internalReason, externalReason string) (*corev1.Secret, error) { | ||
| func (c *keyController) generateKeySecret(ctx context.Context, keyID uint64, currentMode state.Mode, apiServerEncryption configv1.APIServerEncryption, internalReason, externalReason string) (*corev1.Secret, error) { | ||
| bs := crypto.ModeToNewKeyFunc[currentMode]() | ||
| ks := state.KeyState{ | ||
| Key: apiserverv1.Key{ | ||
|
|
@@ -281,6 +283,24 @@ func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode, | |
| }, | ||
| Plugin: apiServerEncryption.KMS, | ||
| } | ||
|
|
||
| if secretName, expectedKeys, err := referencedSecretName(apiServerEncryption.KMS); err != nil { | ||
| return nil, err | ||
| } else if len(secretName) > 0 { | ||
| refSecret, err := c.secretClient.Secrets(openshiftConfigNS).Get(ctx, secretName, metav1.GetOptions{}) | ||
|
p0lyn0mial marked this conversation as resolved.
|
||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to get secret %s in %s: %w", secretName, openshiftConfigNS, err) | ||
| } | ||
| for _, key := range expectedKeys { | ||
|
p0lyn0mial marked this conversation as resolved.
Member
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 lgtm, just asking for my knowledge: I believe I mentioned about validating the secret before, but you mentioned the encryption controllers should not have semantic knowledge about the secret (which also makes sense).
Contributor
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. I think we basically have two options: Option 1 would be to restrict fields to only well-known ones essentially what we have today. Copying arbitrary fields seems too permissive. What’s the point of copying fields we won’t need? The expected fields will have to be documented for users, just like we document them for, for example, identity providers.
Member
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. I agree about the reasons of working on selective set of data keys. I think it is better to logically store provider specific details (i.e. Vault) in kms/vault.go. So that they won't be spread across all over the code base. |
||
| v, ok := refSecret.Data[key] | ||
| if !ok { | ||
| return nil, fmt.Errorf("secret %s in %s is missing required key %q", secretName, openshiftConfigNS, key) | ||
| } | ||
| if err := ks.KMS.PluginSecretData.Set(secretName, key, v); err != nil { | ||
| return nil, err | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return secrets.FromKeyState(c.instanceName, ks) | ||
| } | ||
|
|
@@ -383,6 +403,25 @@ func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, extern | |
| return latestKeyID, "rotation-interval-has-passed", time.Since(latestKey.Migrated.Timestamp) > encryptionSecretMigrationInterval | ||
| } | ||
|
|
||
| // referencedSecretName returns the name of the secret referenced by the KMS plugin | ||
| // config and the specific data keys to carry from that secret. Only the listed keys | ||
| // are copied into the Key Secret; any other data in the referenced secret is ignored. | ||
| func referencedSecretName(plugin configv1.KMSPluginConfig) (string, []string, error) { | ||
| switch plugin.Type { | ||
| case configv1.VaultKMSProvider: | ||
| switch plugin.Vault.Authentication.Type { | ||
| case configv1.VaultAuthenticationTypeAppRole: | ||
| // The Vault AppRole secret must contain "role-id" and "secret-id" keys. | ||
| // These are the only keys carried into the encryption key secret. | ||
| return plugin.Vault.Authentication.AppRole.Secret.Name, []string{"role-id", "secret-id"}, nil | ||
| default: | ||
| return "", nil, fmt.Errorf("unsupported Vault authentication type %q", plugin.Vault.Authentication.Type) | ||
| } | ||
|
Contributor
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. should we return an error on unrecognized types ?
Member
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. We should return error. Updated. |
||
| default: | ||
| return "", nil, fmt.Errorf("unsupported KMS provider type %q", plugin.Type) | ||
| } | ||
| } | ||
|
|
||
| // TODO make this un-settable once set | ||
| // ex: we could require the tech preview no upgrade flag to be set before we will honor this field | ||
| type unsupportedEncryptionConfig struct { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.