Skip to content

Commit

Permalink
Automatically detect cert-manager and use it to provision certificates
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
  • Loading branch information
daniel-weisse committed Jan 31, 2024
1 parent 4f83269 commit 84d8190
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 60 deletions.
30 changes: 22 additions & 8 deletions cli/internal/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"
"io"

"github.com/cert-manager/cert-manager/pkg/util/cmapichecker"
"github.com/edgelesssys/marblerun/cli/internal/helm"
"github.com/edgelesssys/marblerun/cli/internal/kube"
"github.com/edgelesssys/marblerun/util/k8sutil"
Expand Down Expand Up @@ -72,12 +73,16 @@ func runInstall(cmd *cobra.Command, _ []string) error {
if err != nil {
return err
}
cmChecker, err := kube.NewCertManagerChecker()
if err != nil {
return err
}

return cliInstall(cmd, helmClient, kubeClient, namespace)
return cliInstall(cmd, helmClient, kubeClient, cmChecker, namespace)
}

// cliInstall installs MarbleRun on the cluster.
func cliInstall(cmd *cobra.Command, helmClient *helm.Client, kubeClient kubernetes.Interface, namespace string) error {
func cliInstall(cmd *cobra.Command, helmClient *helm.Client, kubeClient kubernetes.Interface, cmChecker cmapichecker.Interface, namespace string) error {
flags, err := parseInstallFlags(cmd)
if err != nil {
return fmt.Errorf("parsing install flags: %w", err)
Expand All @@ -95,9 +100,14 @@ func cliInstall(cmd *cobra.Command, helmClient *helm.Client, kubeClient kubernet
}
}

// verify namespace exists, if not create it
if err := verifyNamespace(cmd.Context(), namespace, kubeClient); err != nil {
return err
}

var webhookSettings []string
if !flags.disableInjection {
webhookSettings, err = installWebhook(cmd, kubeClient, namespace)
webhookSettings, err = installWebhook(cmd, kubeClient, cmChecker, namespace)
if err != nil {
return errorAndCleanup(cmd.Context(), fmt.Errorf("installing webhook certs: %w", err), kubeClient, namespace)
}
Expand Down Expand Up @@ -130,13 +140,17 @@ func cliInstall(cmd *cobra.Command, helmClient *helm.Client, kubeClient kubernet
}

// installWebhook enables a mutating admission webhook to allow automatic injection of values into pods.
func installWebhook(cmd *cobra.Command, kubeClient kubernetes.Interface, namespace string) ([]string, error) {
// verify 'marblerun' namespace exists, if not create it
if err := verifyNamespace(cmd.Context(), namespace, kubeClient); err != nil {
return nil, err
func installWebhook(cmd *cobra.Command, kubeClient kubernetes.Interface, cmChecker cmapichecker.Interface, namespace string) ([]string, error) {
cmd.Print("Setting up MarbleRun Webhook")

if err := cmChecker.Check(cmd.Context()); err == nil {
cmd.Printf("... Done\n")
return []string{
fmt.Sprintf("marbleInjector.start=%t", true),
fmt.Sprintf("marbleInjector.useCertManager=%t", true),
}, nil
}

cmd.Print("Setting up MarbleRun Webhook")
certificateHandler, err := getCertificateHandler(cmd.OutOrStdout(), kubeClient, namespace)
if err != nil {
return nil, err
Expand Down
64 changes: 50 additions & 14 deletions cli/internal/cmd/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,23 +118,51 @@ func TestVerifyNamespace(t *testing.T) {
}

func TestInstallWebhook(t *testing.T) {
assert := assert.New(t)

testClient := fake.NewSimpleClientset()
testClient.Discovery().(*fakediscovery.FakeDiscovery).FakedServerVersion = &version.Info{
Major: "1",
Minor: "18",
GitVersion: "v1.18.4",
testCases := map[string]struct {
kubeClient *fake.Clientset
cmChecker stubCMChecker
assert func(t *testing.T, values []string, err error)
}{
"set up webhook certs": {
kubeClient: func() *fake.Clientset {
testClient := fake.NewSimpleClientset()
testClient.Discovery().(*fakediscovery.FakeDiscovery).FakedServerVersion = &version.Info{
Major: "1",
Minor: "18",
GitVersion: "v1.18.4",
}
return testClient
}(),
cmChecker: stubCMChecker{err: assert.AnError},
assert: func(t *testing.T, values []string, err error) {
assert.NoError(t, err)
require.Len(t, values, 2)
assert.Equal(t, "marbleInjector.start=true", values[0], "failed to set start to true")
assert.Contains(t, values[1], "LS0t", "failed to set CABundle")
},
},
"use cert-manager": {
kubeClient: fake.NewSimpleClientset(),
cmChecker: stubCMChecker{err: nil},
assert: func(t *testing.T, values []string, err error) {
assert.NoError(t, err)
require.Len(t, values, 2)
assert.Equal(t, "marbleInjector.start=true", values[0], "failed to set start to true")
assert.Equal(t, "marbleInjector.useCertManager=true", values[1], "failed to set useCertManager to true")
},
},
}

cmd := &cobra.Command{}
var out bytes.Buffer
cmd.SetOut(&out)
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
cmd := &cobra.Command{}
var out bytes.Buffer
cmd.SetOut(&out)

testValues, err := installWebhook(cmd, testClient, helm.Namespace)
assert.NoError(err)
assert.Equal("marbleInjector.start=true", testValues[0], "failed to set start to true")
assert.Contains(testValues[1], "LS0t", "failed to set CABundle")
testValues, err := installWebhook(cmd, tc.kubeClient, tc.cmChecker, helm.Namespace)
tc.assert(t, testValues, err)
})
}
}

func TestGetSGXResourceKey(t *testing.T) {
Expand Down Expand Up @@ -207,3 +235,11 @@ func TestErrorAndCleanup(t *testing.T) {
_, err = testClient.CertificatesV1().CertificateSigningRequests().Get(context.TODO(), webhookDNSName(helm.Namespace), metav1.GetOptions{})
assert.True(kubeErrors.IsNotFound(err))
}

type stubCMChecker struct {
err error
}

func (s stubCMChecker) Check(_ context.Context) error {
return s.err
}
37 changes: 27 additions & 10 deletions cli/internal/kube/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,20 @@ import (
"os"
"path/filepath"

"github.com/cert-manager/cert-manager/pkg/util/cmapichecker"
"github.com/edgelesssys/marblerun/cli/internal/helm"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

const versionLabel = "app.kubernetes.io/version"

// NewClient returns the kubernetes Clientset to interact with the k8s API.
func NewClient() (*kubernetes.Clientset, error) {
path := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
if path == "" {
homedir, err := os.UserHomeDir()
if err != nil {
return nil, err
}
path = filepath.Join(homedir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName)
}

kubeConfig, err := clientcmd.BuildConfigFromFlags("", path)
kubeConfig, err := getRestConfig()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -62,3 +56,26 @@ func CoordinatorVersion(ctx context.Context, namespace string) (string, error) {
}
return version, nil
}

// NewCertManagerChecker checks if cert-manager is installed in the cluster.
func NewCertManagerChecker() (cmapichecker.Interface, error) {
kubeConfig, err := getRestConfig()
if err != nil {
return nil, err
}

return cmapichecker.New(kubeConfig, runtime.NewScheme(), "default")
}

func getRestConfig() (*rest.Config, error) {
path := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
if path == "" {
homedir, err := os.UserHomeDir()
if err != nil {
return nil, err
}
path = filepath.Join(homedir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName)
}

return clientcmd.BuildConfigFromFlags("", path)
}
20 changes: 12 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/edgelesssys/marblerun
go 1.20

require (
github.com/cert-manager/cert-manager v1.13.3
github.com/edgelesssys/ego v1.4.1
github.com/edgelesssys/era v0.3.3
github.com/fatih/color v1.16.0
Expand Down Expand Up @@ -50,7 +51,7 @@ require (
github.com/containerd/containerd v1.7.6 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/cli v24.0.6+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.7+incompatible // indirect
Expand All @@ -60,10 +61,11 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
Expand Down Expand Up @@ -111,7 +113,7 @@ require (
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rubenv/sql-migrate v1.5.2 // indirect
Expand All @@ -125,8 +127,9 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.opentelemetry.io/otel v1.20.0 // indirect
go.opentelemetry.io/otel/metric v1.20.0 // indirect
go.opentelemetry.io/otel/trace v1.20.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.19.0 // indirect
Expand All @@ -146,12 +149,13 @@ require (
k8s.io/cli-runtime v0.28.4 // indirect
k8s.io/component-base v0.28.4 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
k8s.io/kube-openapi v0.0.0-20230905202853-d090da108d2f // indirect
k8s.io/kubectl v0.28.4 // indirect
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
oras.land/oras-go v1.2.4 // indirect
sigs.k8s.io/gateway-api v0.8.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
)
Loading

0 comments on commit 84d8190

Please sign in to comment.