-
Notifications
You must be signed in to change notification settings - Fork 199
WIP: Kms plugin pod mutation #2056
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 9 commits
a18b914
624030c
24fe3aa
c551337
d5f4c15
2063dbe
84d193c
3771bd4
96cd753
a846a94
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 |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ import ( | |
| "github.com/openshift/cluster-kube-apiserver-operator/pkg/cmd/resourcegraph" | ||
| "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator" | ||
| "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/startupmonitorreadiness" | ||
| "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/targetconfigcontroller" | ||
| "github.com/openshift/cluster-kube-apiserver-operator/pkg/version" | ||
| ) | ||
|
|
||
|
|
@@ -48,9 +49,10 @@ func NewOperatorCommand(ctx context.Context) *cobra.Command { | |
| cmd.Version = v | ||
| } | ||
|
|
||
| opts := installerpod.NewInstallOptions().WithPodMutationFactory(targetconfigcontroller.AddKMSPluginToPodSpecFn) | ||
| cmd.AddCommand(installerpod.NewInstallerWithInstallOptions(ctx, opts)) | ||
| cmd.AddCommand(operatorcmd.NewOperator()) | ||
| cmd.AddCommand(render.NewRenderCommand()) | ||
| cmd.AddCommand(installerpod.NewInstaller(ctx)) | ||
| cmd.AddCommand(prune.NewPrune()) | ||
| cmd.AddCommand(resourcegraph.NewResourceChainCommand()) | ||
| cmd.AddCommand(certsyncpod.NewCertSyncControllerCommand(operator.CertConfigMaps, operator.CertSecrets)) | ||
|
|
@@ -67,3 +69,7 @@ func NewOperatorCommand(ctx context.Context) *cobra.Command { | |
|
|
||
| return cmd | ||
| } | ||
|
|
||
| func ptrBool(b bool) *bool { | ||
| return &b | ||
| } | ||
|
Comment on lines
+72
to
+75
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. 🧩 Analysis chain🏁 Script executed: rg -n "ptrBool" --type goRepository: openshift/cluster-kube-apiserver-operator Length of output: 414 🏁 Script executed: head -20 cmd/cluster-kube-apiserver-operator/main.goRepository: openshift/cluster-kube-apiserver-operator Length of output: 833 Remove unused This helper function is defined but never called in this file. Since 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| package targetconfigcontroller | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "github.com/openshift/library-go/pkg/operator/configobserver/featuregates" | ||
| "github.com/openshift/library-go/pkg/operator/staticpod/installerpod" | ||
| corev1 "k8s.io/api/core/v1" | ||
| v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| corev1listers "k8s.io/client-go/listers/core/v1" | ||
| "k8s.io/klog/v2" | ||
| ) | ||
|
|
||
| // AddKMSPluginToPodSpec conditionally adds the KMS plugin volume mount to the specified container. | ||
| // It assumes the pod spec does not already contain the KMS volume or mount; no deduplication is performed. | ||
| // Deprecated: this is a temporary solution to get KMS TP v1 out. We should come up with a different approach afterwards. | ||
| func AddKMSPluginToPodSpec(podSpec *corev1.PodSpec, featureGateAccessor featuregates.FeatureGateAccess, secretLister corev1listers.SecretLister, targetNamespace string, kmsPluginImage string) error { | ||
| if podSpec == nil { | ||
| return fmt.Errorf("pod spec cannot be nil") | ||
| } | ||
|
|
||
| // if !featureGateAccessor.AreInitialFeatureGatesObserved() { | ||
| // return nil | ||
| // } | ||
| // | ||
| // featureGates, err := featureGateAccessor.CurrentFeatureGates() | ||
| // if err != nil { | ||
| // return fmt.Errorf("failed to get feature gates: %w", err) | ||
| // } | ||
| // | ||
| // if !featureGates.Enabled(features.FeatureGateKMSEncryption) { | ||
| // klog.Infof("kms is disabled: feature gate %s is disabled", features.FeatureGateKMSEncryption) | ||
| // return nil | ||
| // } | ||
|
|
||
| creds, err := secretLister.Secrets(targetNamespace).Get("vault-kms-credentials") | ||
| if err != nil { | ||
| klog.Infof("kms is disabled: could not get vault-kms-credentials secret: %v", err) | ||
| return nil | ||
|
Comment on lines
+37
to
+40
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. Handle non-NotFound secret retrieval errors explicitly. This currently treats every secret retrieval error as “KMS disabled,” which can silently bypass KMS on transient API/cache failures. Only “not found” should be treated as disabled; other errors should fail fast. 🔧 Proposed fix+import apierrors "k8s.io/apimachinery/pkg/api/errors"
...
creds, err := secretLister.Secrets(targetNamespace).Get("vault-kms-credentials")
if err != nil {
- klog.Infof("kms is disabled: could not get vault-kms-credentials secret: %v", err)
- return nil
+ if apierrors.IsNotFound(err) {
+ klog.Infof("kms is disabled: could not get vault-kms-credentials secret: %v", err)
+ return nil
+ }
+ return fmt.Errorf("failed to get vault-kms-credentials secret: %w", err)
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| // At this point we know we should deploy the KMS plugin | ||
| if err := addKMSPluginSidecarToPodSpec(podSpec, "kms-plugin", kmsPluginImage, creds); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := addKMSPluginVolumeAndMountToPodSpec(podSpec, "kms-plugin"); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := addKMSPluginVolumeAndMountToPodSpec(podSpec, "kube-apiserver"); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func addKMSPluginSidecarToPodSpec(podSpec *corev1.PodSpec, containerName string, image string, creds *corev1.Secret) error { | ||
| if podSpec == nil { | ||
| return fmt.Errorf("pod spec cannot be nil") | ||
| } | ||
|
|
||
| podSpec.Containers = append(podSpec.Containers, corev1.Container{ | ||
| Name: containerName, | ||
| Image: image, | ||
| ImagePullPolicy: corev1.PullAlways, | ||
| Command: []string{"/bin/sh", "-c"}, | ||
| Args: []string{fmt.Sprintf(` | ||
| echo "%s" > /tmp/secret-id | ||
|
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. some "secrets" should not be visible in the pod template.
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. discussed offline, but just for context: right, this implementation is just a poc, once openshift/enhancements#1960 is implemented we'll be able to access the credentials as a mounted secret |
||
| exec /vault-kube-kms \ | ||
| -listen-address=unix:///var/run/kmsplugin/kms.sock \ | ||
| -vault-address=%s \ | ||
| -vault-namespace=%s \ | ||
| -transit-mount=transit \ | ||
| -transit-key=%s \ | ||
| -log-level=debug-extended \ | ||
| -approle-role-id=%s \ | ||
| -approle-secret-id-path=/tmp/secret-id`, | ||
| string(creds.Data["VAULT_SECRET_ID"]), | ||
|
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. what is
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. it's like an api key |
||
| string(creds.Data["VAULT_ADDR"]), | ||
| string(creds.Data["VAULT_NAMESPACE"]), | ||
| string(creds.Data["VAULT_KEY_NAME"]), | ||
| string(creds.Data["VAULT_ROLE_ID"])), | ||
|
Comment on lines
+69
to
+84
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. Missing validation for required secret keys. The code assumes all required keys ( 🛡️ Suggested validationfunc validateCredentials(creds *corev1.Secret) error {
requiredKeys := []string{"VAULT_SECRET_ID", "VAULT_ADDR", "VAULT_NAMESPACE", "VAULT_KEY_NAME", "VAULT_ROLE_ID"}
for _, key := range requiredKeys {
if _, ok := creds.Data[key]; !ok {
return fmt.Errorf("missing required key %q in vault-kms-credentials secret", key)
}
}
return nil
}🤖 Prompt for AI Agents |
||
| }, | ||
| SecurityContext: &corev1.SecurityContext{ | ||
| Privileged: ptrBool(true), | ||
| }, | ||
| }) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func addKMSPluginVolumeAndMountToPodSpec(podSpec *corev1.PodSpec, containerName string) error { | ||
| containerIndex := -1 | ||
| for i, container := range podSpec.Containers { | ||
| if container.Name == containerName { | ||
| containerIndex = i | ||
| break | ||
| } | ||
| } | ||
|
|
||
| if containerIndex < 0 { | ||
| return fmt.Errorf("container %s not found", containerName) | ||
| } | ||
|
|
||
| container := &podSpec.Containers[containerIndex] | ||
| container.VolumeMounts = append(container.VolumeMounts, | ||
| corev1.VolumeMount{ | ||
| Name: "kms-plugin-socket", | ||
| MountPath: "/var/run/kmsplugin", | ||
| }, | ||
| ) | ||
|
|
||
| foundVolumeMount := false | ||
| for _, volumeMount := range podSpec.Volumes { | ||
| if volumeMount.Name == "kms-plugin-socket" { | ||
| foundVolumeMount = true | ||
| } | ||
| } | ||
|
|
||
| if !foundVolumeMount { | ||
| directoryOrCreate := corev1.HostPathDirectoryOrCreate | ||
| podSpec.Volumes = append(podSpec.Volumes, | ||
| corev1.Volume{ | ||
| Name: "kms-plugin-socket", | ||
| VolumeSource: corev1.VolumeSource{ | ||
| HostPath: &corev1.HostPathVolumeSource{ | ||
| Path: "/var/run/kmsplugin", | ||
| Type: &directoryOrCreate, | ||
| }, | ||
| }, | ||
| }, | ||
| ) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func ptrBool(b bool) *bool { | ||
| return &b | ||
| } | ||
|
|
||
| func AddKMSPluginToPodSpecFn(o *installerpod.InstallOptions) installerpod.PodMutationFunc { | ||
| return func(pod *corev1.Pod) error { | ||
| creds, err := o.KubeClient.CoreV1().Secrets("openshift-kube-apiserver").Get(context.TODO(), "vault-kms-credentials", v1.GetOptions{}) | ||
| if err != nil { | ||
| klog.Infof("kms is disabled: could not get vault-kms-credentials secret: %v", err) | ||
| return nil | ||
| } | ||
| klog.Infof("kms is ENABLED") | ||
|
|
||
| pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{ | ||
| Name: "kms-plugin", | ||
| Image: "quay.io/bertinatto/vault:v1", | ||
| ImagePullPolicy: corev1.PullAlways, | ||
| Command: []string{"/bin/sh", "-c"}, | ||
| Args: []string{fmt.Sprintf(` | ||
| echo "%s" > /tmp/secret-id | ||
| exec /vault-kube-kms \ | ||
| -listen-address=unix:///var/run/kmsplugin/kms.sock \ | ||
| -vault-address=%s \ | ||
| -vault-namespace=%s \ | ||
| -transit-mount=transit \ | ||
| -transit-key=%s \ | ||
| -log-level=debug-extended \ | ||
| -approle-role-id=%s \ | ||
| -approle-secret-id-path=/tmp/secret-id`, | ||
| string(creds.Data["VAULT_SECRET_ID"]), | ||
| string(creds.Data["VAULT_ADDR"]), | ||
| string(creds.Data["VAULT_NAMESPACE"]), | ||
| string(creds.Data["VAULT_KEY_NAME"]), | ||
| string(creds.Data["VAULT_ROLE_ID"])), | ||
| }, | ||
| SecurityContext: &corev1.SecurityContext{ | ||
| Privileged: ptrBool(true), | ||
| }, | ||
| }) | ||
|
|
||
| return nil | ||
|
Comment on lines
+144
to
+168
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. Pod mutation path is incomplete and can produce a non-functional KMS setup.
♻️ Proposed consolidation/fix-func AddKMSPluginToPodSpecFn(o *installerpod.InstallOptions) installerpod.PodMutationFunc {
+func AddKMSPluginToPodSpecFn(o *installerpod.InstallOptions, kmsPluginImage string) installerpod.PodMutationFunc {
return func(pod *corev1.Pod) error {
+ if pod == nil {
+ return fmt.Errorf("pod cannot be nil")
+ }
creds, err := o.KubeClient.CoreV1().Secrets("openshift-kube-apiserver").Get(context.TODO(), "vault-kms-credentials", v1.GetOptions{})
if err != nil {
klog.Infof("kms is disabled: could not get vault-kms-credentials secret: %v", err)
return nil
}
- klog.Infof("kms is ENABLED")
-
- pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{
- Name: "kms-plugin",
- Image: "quay.io/bertinatto/vault:v1",
- ImagePullPolicy: corev1.PullAlways,
- Command: []string{"/bin/sh", "-c"},
- Args: []string{...},
- SecurityContext: &corev1.SecurityContext{
- Privileged: ptrBool(true),
- },
- })
+ if err := addKMSPluginSidecarToPodSpec(&pod.Spec, "kms-plugin", kmsPluginImage, creds); err != nil {
+ return err
+ }
+ if err := addKMSPluginVolumeAndMountToPodSpec(&pod.Spec, "kms-plugin"); err != nil {
+ return err
+ }
+ if err := addKMSPluginVolumeAndMountToPodSpec(&pod.Spec, "kube-apiserver"); err != nil {
+ return err
+ }
return nil
}
}🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
🧩 Analysis chain
🏁 Script executed:
Repository: openshift/cluster-kube-apiserver-operator
Length of output: 1363
🏁 Script executed:
Repository: openshift/cluster-kube-apiserver-operator
Length of output: 3423
🏁 Script executed:
Repository: openshift/cluster-kube-apiserver-operator
Length of output: 414
Remove unused
ptrBoolfunction and fix installer wiring.The installer command wiring at lines 52-53 is correct—
AddKMSPluginToPodSpecFnis properly defined in the targetconfigcontroller package with the correct signature and integrates the KMS sidecar injection pathway as expected.However, the
ptrBoolfunction at lines 73-75 is dead code and should be removed. It is not called anywhere in this file. (Note: a separateptrBoolfunction exists inkms_sidecar.goand is used there, but the one inmain.goserves no purpose.)🤖 Prompt for AI Agents