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 KMS plugin registry #49742
Add KMS plugin registry #49742
Conversation
1a51e8f
to
bfe736c
Compare
// +optional | ||
CacheSize int `json:"cachesize,omitempty"` | ||
// configfile is the path to the configuration file for the named KMS provider. | ||
ConfigFile string `json:"configfile"` |
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 like to see this structure follow the admission plugin configuration structure and allow either a path or a rawextension directly 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.
I'd like to see this structure follow the admission plugin configuration structure and allow either a path or a rawextension directly here.
This is ok as a followup
if err != nil { | ||
return nil, true, err | ||
} | ||
if !PluginEnabledFn(name, config1) { |
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 am not entirely sure whether this part is relevant to this process, and I think it can be removed without introducing any immediate issues. Have copied this from admissions plugins code.
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 am not entirely sure whether this part is relevant to this process, and I think it can be removed without introducing any immediate issues. Have copied this from admissions plugins code.
You should probably leave it for zero config options.
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.
You should probably leave it for zero config options.
Does that mean I should delete this? I'm sorry, I didn't understand zero config options
Update: So I'll leave this code here.
I'd like to see this moved to be a peer of AdmissionConfiguration and gain proper validation functions. There is code duplication that should be resolved, but as a building block, I think this keeps our types closer to where they need to be. The actual handling of the |
Name string `json:"name"` | ||
// cacheSize is the maximum number of secrets which are cached in memory. The default value is 1000. | ||
// +optional | ||
CacheSize int `json:"cachesize,omitempty"` |
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.
shouldn't cachesize be part of the config?
nm, misread where this struct was
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 not specific to the plugin's configuration. It is a property of the envelope transformer. It will also be used by cloudprovidedkms based plugins (example #48574, see configuration in description)
@@ -38,6 +39,7 @@ const ( | |||
aesCBCTransformerPrefixV1 = "k8s:enc:aescbc:v1:" | |||
aesGCMTransformerPrefixV1 = "k8s:enc:aesgcm:v1:" | |||
secretboxTransformerPrefixV1 = "k8s:enc:secretbox:v1:" | |||
envelopeTransformerPrefixV1 = "k8s:enc:envelope:v1:" |
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.
seems like this should match the config field name, both envelope
or both kms
I think this moves us in the right direction in spite of the debt. Fix the prefix and I can get behind this one. |
3613e7b
to
df65bee
Compare
Fixed the prefix, and added unit tests. Accidentally closed the PR. @lavalamp @cheftako Can you PTAL at this? The idea is to mirror the admission plugins code |
/release-note-none |
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.
Minor tweaks
} | ||
defer f.Close() | ||
envelopeService, pluginFound, err := KMSPluginRegistry.getPlugin(provider.KMS.Name, f) | ||
if pluginFound == false { |
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.
Please reorder found vs err handling. Assuming that there is an actual error, reporting that should take precedence. Especially as the failure to find a plugin provider could be the result of the error.
|
||
// All registered KMS options. | ||
type KMSPlugins struct { | ||
lock sync.Mutex |
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 would expect that registration is a rare event but that getting a plugin might not be. If so then this might benefit from a RWLock.
if found { | ||
glog.Fatalf("KMS plugin %q was registered twice", name) | ||
} | ||
if ps.registry == nil { |
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 works but it feels wrong to me to access a map just prior to initializing. May be less work on later devs if you put the nil check first.
// known but failed to initialize. The config parameter specifies the io.Reader | ||
// handler of the configuration file for the cloud provider, or nil for no configuration. | ||
func (ps *KMSPlugins) getPlugin(name string, config io.Reader) (envelope.Service, bool, error) { | ||
ps.lock.Lock() |
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.
Not sure it is a good idea to hold the lock for this entire method. As it stands there are multiple pieces of code for which you are holding the lock that you do not control and could even be RPC calls. Assuming that the lock is only securing access to the registry object, I would suggest you should create a smaller get method which just access registry with its lock and then call that from here.
df65bee
to
adea7c3
Compare
@cheftako Addressed those issues, thanks! I also added support for cloudprovidedkms configuration with tests. It looks almost the same as the KMS one. Another quick pass would be greatly appreciated, since the cloudprovidedkms was something you had recommended. Example code after this PR in kube-apiserver:
No dependency to cloudproviders introduced, no changes in function signature, other apiservers don't break. If you want to see how #48574 looks after this PR, here's a version based on this PR: https://github.com/sakshamsharma/kubernetes/tree/gkms-with-plugin (commit of note: see latest commit) Example of how to register vault:
@deads2k @liggitt if this is still acceptable for you, can we merge this in? The other PR can then get in too (basically the changes on the above mentioned branch on my fork) because the controversial part is covered in this one. |
adea7c3
to
38266b7
Compare
38266b7
to
e73d9d6
Compare
e73d9d6
to
ead42cc
Compare
I'll merge this bit this it is directly related to the API machinery and gives a good (if slightly debt-y) plugin mechanism. The other implementation pull seems to have slipped past sig-auth until a couple days ago. There probably ought to be more time to comment there. /lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: deads2k, sakshamsharma Associated issue: 48574 The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
if found == true { | ||
return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") | ||
} | ||
f, err := os.Open(provider.KMS.ConfigFile) |
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 feels wrong that we are trying to open/read the file here. It would seem better to just pass this location down to the factory and let it do the read. Especially as in something like a hybrid case this could be a key into a config server or be a file+coordinate into a larger config file. We should need to know or care about such things. However if we insist on opening+reading the file then we end up having to care about these things.
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 admissions factory used this format, which is why I stuck with this. We can change this in a follow-up.
Once this PR is merged, I'll open a new one to change this and remove the reflect mentioned in your 2nd comment, along with some other cleanup.
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 feels wrong that we are trying to open/read the file here. It would seem better to just pass this location down to the factory and let it do the read. Especially as in something like a
To make this API congruent to the admission config, there will be a choice of separate file or embedded content depending the sensitivity (which we don't know since its pluggable) of the config in question.
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.
An approach which I've proposed earlier, and I've seen used in the cloudproviders package:
Have a field config map[string]interface{}
on the KMSConfig
struct. Send it to the plugin factory. The plugin factory would use the mapstructure
library to parse it into a struct safely. This library is used in certain cloudproviders like openstack.
So this way you can support both config:
and configfile:
attributes on the kms
configuration.
May not be acceptable though, due to a point in the flow where the config is unstructured (it will still be read in a structured form later on). Just putting this out 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.
The reader interface lets you load a structured config from an external file or an inlined config. All our config files should be structured and versioned (see scheduler config, ABAC config, admission config, etc)
|
||
// splitStream reads the stream bytes and constructs two copies of it. | ||
func splitStream(config io.Reader) (io.Reader, io.Reader, error) { | ||
if config == nil || reflect.ValueOf(config).IsNil() { |
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 are we trying to protect ourselves against with this use of reflect? None of our other nil checks use it (other than the place we cut&pasted this code from). When we opened the config reader a nil check was sufficient. This object has not been copied/valueOf so I believe we are pulling in something we are better of without for no good reason.
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 are we trying to protect ourselves against with this use of reflect? None of our other nil checks use it (other than the place we cut&pasted this code from). When we opened the config reader a nil check was sufficient. This object has not been copied/valueOf so I believe we are pulling in something we are better of without for no good reason
Nil versus nil. Is it a nil interface or a non-nil interface with a nil value. It may drop out when these plugin paths are collapsed.
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.
Would like to see us fix config handling in a later release. Might be good to file an issue on it.
ead42cc
to
f354c62
Compare
One of the comments was not in the proper format, and this package was removed from Update: Something broke pull-kubernetes-bazel it appears. Will track submit queue and update this message when it is fixed. |
f354c62
to
68a32c0
Compare
/retest |
bump |
/test pull-kubernetes-unit |
Automatic merge from submit-queue |
Allows supporting KMS services as encryption providers using a plugin mechanism similar to admission plugins.
Simplifies #48574
Progresses #48522
@deads2k PTAL