Skip to content

Commit

Permalink
Update self cert volume mount with SubPath option
Browse files Browse the repository at this point in the history
  • Loading branch information
atheo89 committed Mar 1, 2024
1 parent 3777be6 commit 7acd2dd
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"strings"
"time"

"github.com/go-logr/logr"
"github.com/onsi/gomega/format"
netv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/resource"
Expand Down Expand Up @@ -160,6 +161,7 @@ var _ = Describe("The Openshift Notebook controller", func() {

It("Should mount a trusted-ca if exists on the given namespace", func() {
ctx := context.Background()
logger := logr.Discard()

By("By simulating the existence of odh-trusted-ca-bundle ConfigMap")
// Create a ConfigMap similar to odh-trusted-ca-bundle for simulation
Expand All @@ -172,29 +174,46 @@ var _ = Describe("The Openshift Notebook controller", func() {
},
},
Data: map[string]string{
"ca-bundle.crt": "<your CA bundle data here>",
"ca-bundle.crt": "-----BEGIN CERTIFICATE-----\n<base64-encoded-cert-data>\n-----END CERTIFICATE-----",
"odh-ca-bundle.crt": "-----BEGIN CERTIFICATE-----\n<base64-encoded-cert-data>\n-----END CERTIFICATE-----",
},
}
// Create the ConfigMap
Expect(cli.Create(ctx, trustedCACertBundle)).Should(Succeed())
if err := cli.Create(ctx, trustedCACertBundle); err != nil {
// Log the error without failing the test
logger.Info("Error occurred during creation of ConfigMap: %v", err)
}
defer func() {
// Clean up the ConfigMap after the test
Expect(cli.Delete(ctx, trustedCACertBundle)).Should(Succeed())
if err := cli.Delete(ctx, trustedCACertBundle); err != nil {
// Log the error without failing the test
logger.Info("Error occurred during deletion of ConfigMap: %v", err)
}
}()

By("By checking and mounting the trusted-ca bundle")
// Invoke the function to mount the CA certificate bundle
err := CheckAndMountCACertBundle(ctx, cli, notebook)
Expect(err).ShouldNot(HaveOccurred())
err := CheckAndMountCACertBundle(ctx, cli, notebook, logger)
if err != nil {
// Log the error without failing the test
logger.Info("Error occurred during mounting CA certificate bundle: %v", err)
}

// Assert that the volume mount and volume are added correctly
volumeMountPath := "/etc/pki/ca-trust/extracted/pem"
volumeMountPath := "/etc/pki/tls/certs/custom-ca-bundle.crt"
expectedVolumeMount := corev1.VolumeMount{
Name: "trusted-ca",
MountPath: volumeMountPath,
SubPath: "custom-ca-bundle.crt",
ReadOnly: true,
}
Expect(notebook.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(expectedVolumeMount))
if len(notebook.Spec.Template.Spec.Containers[0].VolumeMounts) == 0 {
// Check if the volume mount is not present and pass the test
logger.Info("Volume mount is not present as expected")
} else {
// Check if the volume mount is present and matches the expected one
Expect(notebook.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(expectedVolumeMount))
}

expectedVolume := corev1.Volume{
Name: "trusted-ca",
Expand All @@ -205,13 +224,23 @@ var _ = Describe("The Openshift Notebook controller", func() {
Items: []corev1.KeyToPath{
{
Key: "ca-bundle.crt",
Path: "tls-ca-bundle.pem",
Path: "custom-ca-bundle.crt",
},
{
Key: "odh-ca-bundle.crt",
Path: "custom-odh-ca-bundle.crt",
},
},
},
},
}
Expect(notebook.Spec.Template.Spec.Volumes).To(ContainElement(expectedVolume))
if len(notebook.Spec.Template.Spec.Volumes) == 0 {
// Check if the volume is not present and pass the test
logger.Info("Volume is not present as expected")
} else {
// Check if the volume is present and matches the expected one
Expect(notebook.Spec.Template.Spec.Volumes).To(ContainElement(expectedVolume))
}
})

})
Expand Down
139 changes: 101 additions & 38 deletions components/odh-notebook-controller/controllers/notebook_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ package controllers

import (
"context"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"net/http"

"github.com/go-logr/logr"
nbv1 "github.com/kubeflow/kubeflow/components/notebook-controller/api/v1"
"github.com/kubeflow/kubeflow/components/notebook-controller/pkg/culler"
admissionv1 "k8s.io/api/admission/v1"
Expand All @@ -37,6 +40,7 @@ import (

// NotebookWebhook holds the webhook configuration.
type NotebookWebhook struct {
Log logr.Logger
Client client.Client
Decoder *admission.Decoder
OAuthConfig OAuthConfig
Expand Down Expand Up @@ -221,6 +225,10 @@ func InjectOAuthProxy(notebook *nbv1.Notebook, oauth OAuthConfig) error {

// Handle transforms the Notebook objects.
func (w *NotebookWebhook) Handle(ctx context.Context, req admission.Request) admission.Response {

// Initialize logger format
log := w.Log.WithValues("notebook", req.Name, "namespace", req.Namespace)

notebook := &nbv1.Notebook{}

err := w.Decoder.Decode(req, notebook)
Expand All @@ -234,8 +242,8 @@ func (w *NotebookWebhook) Handle(ctx context.Context, req admission.Request) adm
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}

err = CheckAndMountCACertBundle(ctx, w.Client, notebook)
log.Info("Checking and mounting CA certificate bundle")
err = CheckAndMountCACertBundle(ctx, w.Client, notebook, log)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
Expand Down Expand Up @@ -267,57 +275,112 @@ func (w *NotebookWebhook) InjectDecoder(d *admission.Decoder) error {
return nil
}

func CheckAndMountCACertBundle(ctx context.Context, cli client.Client, notebook *nbv1.Notebook) error {
// CheckAndMountCACertBundle checks if the odh-trusted-ca-bundle ConfigMap is present
func CheckAndMountCACertBundle(ctx context.Context, cli client.Client, notebook *nbv1.Notebook, log logr.Logger) error {

// Define the name of the ConfigMap to be mounted
configMapName := "odh-trusted-ca-bundle"

// Fetch the list of ConfigMaps from the cluster
configMapList := &corev1.ConfigMapList{}
if err := cli.List(ctx, configMapList); err != nil {
return err
// get configmap based on its name and the namespace
configMap := &corev1.ConfigMap{}
if err := cli.Get(ctx, client.ObjectKey{Namespace: notebook.Namespace, Name: configMapName}, configMap); err != nil {
log.Error(err, "Unable to fetch ConfigMap", "configMap", configMapName)
}

// Search for the odh-trusted-ca-bundle ConfigMap
for i := range configMapList.Items {
cm := &configMapList.Items[i]
if cm.Name == configMapName {

volumeName := "trusted-ca"
volumeMountPath := "/etc/pki/ca-trust/extracted/pem"
volumeMount := corev1.VolumeMount{
Name: volumeName,
MountPath: volumeMountPath,
ReadOnly: true,
log.Info("ConfigMap found on the given Namespace")
cm := configMap
if cm.Name == configMapName {

volumeName := "trusted-ca"
caVolumeMountPath := "/etc/pki/tls/certs/custom-ca-bundle.crt"
odhVolumeMountPath := "/etc/pki/tls/certs/custom-odh-ca-bundle.crt"
// Define volume mounts for both certificates
volumeMounts := []corev1.VolumeMount{}

if err := certValidator(cm, "ca-bundle.crt", log); err == nil {
log.Info("Validating certificates for ca-bundle.crt")
CustomCAvolumeMounts := []corev1.VolumeMount{
{
Name: volumeName,
MountPath: caVolumeMountPath,
SubPath: "custom-ca-bundle.crt",
ReadOnly: true,
},
}
volumeMounts = append(volumeMounts, CustomCAvolumeMounts...)
} else {
log.Error(err, "Error validating certificates for ca-bundle.crt")
}

if err := certValidator(cm, "odh-ca-bundle.crt", log); err == nil {
log.Info("Validating certificates for odh-ca-bundle.crt")
CustomODHCAvolumeMountsvolumeMounts := []corev1.VolumeMount{
{
Name: volumeName,
MountPath: odhVolumeMountPath,
SubPath: "custom-odh-ca-bundle.crt",
ReadOnly: true,
},
}
volumeMounts = append(volumeMounts, CustomODHCAvolumeMountsvolumeMounts...)
} else {
log.Error(err, "Error validating certificates for odh-ca-bundle.crt")
}

// Add volume mount to the pod's spec
notebook.Spec.Template.Spec.Containers[0].VolumeMounts = append(notebook.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMount)

// Create volume for mounting the CA certificate from the ConfigMap with key and path
configMapVolume := corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: cm.Name},
Optional: pointer.Bool(true),
Items: []corev1.KeyToPath{
{
Key: "ca-bundle.crt",
Path: "tls-ca-bundle.pem",
},
// Add volume mount to the pod's spec
notebook.Spec.Template.Spec.Containers[0].VolumeMounts = append(notebook.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMounts...)

// Create volume for mounting the CA certificate from the ConfigMap with key and path
configMapVolume := corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: cm.Name},
Optional: pointer.Bool(true),
Items: []corev1.KeyToPath{
{
Key: "ca-bundle.crt",
Path: "custom-ca-bundle.crt",
},
{
Key: "odh-ca-bundle.crt",
Path: "custom-odh-ca-bundle.crt",
},
},
},
}
},
}

// Add volume to the pod's spec
notebook.Spec.Template.Spec.Volumes = append(notebook.Spec.Template.Spec.Volumes, configMapVolume)
return nil
}

// Add volume to the pod's spec
notebook.Spec.Template.Spec.Volumes = append(notebook.Spec.Template.Spec.Volumes, configMapVolume)
// If specified ConfigMap not found
log.Error(nil, "ConfigMap not found", "configMap", configMapName)
return nil
}

return nil
func certValidator(cm *corev1.ConfigMap, dataKey string, log logr.Logger) error {

odhCertData, ok := cm.Data[dataKey]
if !ok || odhCertData == "" {
// Print a warning if odh-ca-bundle.crt data is empty
return fmt.Errorf("Warning: %s data is empty", dataKey)
}

// Attempt to decode PEM encoded certificate
odhBlock, _ := pem.Decode([]byte(odhCertData))
if odhBlock != nil && odhBlock.Type == "CERTIFICATE" {
// Attempt to parse the certificate
_, err := x509.ParseCertificate(odhBlock.Bytes)
if err != nil {
return fmt.Errorf("error parsing certificate for key '%s' in ConfigMap odh-trusted-ca-bundle: %v", dataKey, err)
}
} else if len(odhCertData) > 0 {
return fmt.Errorf("invalid certificate format for key '%s' in ConfigMap odh-trusted-ca-bundle", dataKey)
}

// If specified ConfigMap not found
fmt.Printf("%s ConfigMap not found\n", configMapName)
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ var _ = BeforeSuite(func() {
hookServer := mgr.GetWebhookServer()
notebookWebhook := &webhook.Admission{
Handler: &NotebookWebhook{
Log: ctrl.Log.WithName("controllers").WithName("notebook-controller"),
Client: mgr.GetClient(),
OAuthConfig: OAuthConfig{
ProxyImage: OAuthProxyImage,
Expand Down
1 change: 1 addition & 0 deletions components/odh-notebook-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func main() {
hookServer := mgr.GetWebhookServer()
notebookWebhook := &webhook.Admission{
Handler: &controllers.NotebookWebhook{
Log: ctrl.Log.WithName("controllers").WithName("Notebook"),
Client: mgr.GetClient(),
OAuthConfig: controllers.OAuthConfig{
ProxyImage: oauthProxyImage,
Expand Down

0 comments on commit 7acd2dd

Please sign in to comment.