diff --git a/example/porter.yaml b/example/porter.yaml index 9c06135..fb01065 100644 --- a/example/porter.yaml +++ b/example/porter.yaml @@ -12,7 +12,7 @@ registry: getporter credentials: - name: kubeconfig - path: /root/.kube/config + path: /home/nonroot/.kube/config - name: helm-registry-password env: HELM_REGISTRY_PASSWORD diff --git a/pkg/helm3/build.go b/pkg/helm3/build.go index 9af1d49..49b446c 100644 --- a/pkg/helm3/build.go +++ b/pkg/helm3/build.go @@ -83,8 +83,11 @@ func (m *Mixin) Build() error { fmt.Fprintf(m.Out, "\nRUN tar -xvf helm3.tar.gz && rm helm3.tar.gz") fmt.Fprintf(m.Out, "\nRUN mv linux-amd64/helm /usr/local/bin/helm3") fmt.Fprintf(m.Out, "\nRUN curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1.22.1/bin/linux/amd64/kubectl &&\\") - fmt.Fprintf(m.Out, "\n mv kubectl /usr/local/bin && chmod a+x /usr/local/bin/kubectl") + fmt.Fprintf(m.Out, "\n mv kubectl /usr/local/bin && chmod a+x /usr/local/bin/kubectl\n") if len(input.Config.Repositories) > 0 { + // Switch to a non-root user so helm is configured for the user the container will execute as + fmt.Fprintln(m.Out, "USER ${BUNDLE_USER}") + // Go through repositories names := make([]string, 0, len(input.Config.Repositories)) for name := range input.Config.Repositories { @@ -94,15 +97,20 @@ func (m *Mixin) Build() error { for _, name := range names { url := input.Config.Repositories[name].URL repositoryCommand, err := getRepositoryCommand(name, url) - if err != nil && m.Debug { - fmt.Fprintf(m.Err, "DEBUG: addition of repository failed: %s\n", err.Error()) + if err != nil { + if m.Debug { + fmt.Fprintf(m.Err, "DEBUG: addition of repository failed: %s\n", err.Error()) + } } else { - fmt.Fprintf(m.Out, strings.Join(repositoryCommand, " ")) + fmt.Fprintln(m.Out, strings.Join(repositoryCommand, " ")) } } // Make sure we update the helm repositories // So we don\'t have to do it later - fmt.Fprintf(m.Out, "\nRUN helm3 repo update") + fmt.Fprintln(m.Out, "RUN helm3 repo update") + + // Switch back to root so that subsequent mixins can install things + fmt.Fprintln(m.Out, "USER root") } return nil @@ -116,7 +124,7 @@ func getRepositoryCommand(name, url string) (repositoryCommand []string, err err return commandBuilder, fmt.Errorf("repository url must be supplied") } - commandBuilder = append(commandBuilder, "\nRUN", "helm3", "repo", "add", name, url) + commandBuilder = append(commandBuilder, "RUN", "helm3", "repo", "add", name, url) return commandBuilder, nil } diff --git a/pkg/helm3/build_test.go b/pkg/helm3/build_test.go index 59429e2..96c49b4 100644 --- a/pkg/helm3/build_test.go +++ b/pkg/helm3/build_test.go @@ -22,7 +22,8 @@ RUN curl https://get.helm.sh/helm-%s-%s-%s.tar.gz --output helm3.tar.gz RUN tar -xvf helm3.tar.gz && rm helm3.tar.gz RUN mv linux-amd64/helm /usr/local/bin/helm3 RUN curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1.22.1/bin/linux/amd64/kubectl &&\ - mv kubectl /usr/local/bin && chmod a+x /usr/local/bin/kubectl` + mv kubectl /usr/local/bin && chmod a+x /usr/local/bin/kubectl +` t.Run("build with a valid config", func(t *testing.T) { b, err := ioutil.ReadFile("testdata/build-input-with-valid-config.yaml") @@ -36,9 +37,11 @@ RUN curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1 require.NoError(t, err, "build failed") wantOutput := fmt.Sprintf(buildOutput, m.HelmClientVersion, m.HelmClientPlatfrom, m.HelmClientArchitecture) + - "\nRUN helm3 repo add stable kubernetes-charts" + - "\nRUN helm3 repo update" - + `USER ${BUNDLE_USER} +RUN helm3 repo add stable kubernetes-charts +RUN helm3 repo update +USER root +` gotOutput := m.TestContext.GetOutput() assert.Equal(t, wantOutput, gotOutput) }) @@ -55,10 +58,13 @@ RUN curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1 require.NoError(t, err, "build failed") wantOutput := fmt.Sprintf(buildOutput, m.HelmClientVersion, m.HelmClientPlatfrom, m.HelmClientArchitecture) + - "\nRUN helm3 repo add harbor https://helm.getharbor.io" + - "\nRUN helm3 repo add jetstack https://charts.jetstack.io" + - "\nRUN helm3 repo add stable kubernetes-charts" + - "\nRUN helm3 repo update" + `USER ${BUNDLE_USER} +RUN helm3 repo add harbor https://helm.getharbor.io +RUN helm3 repo add jetstack https://charts.jetstack.io +RUN helm3 repo add stable kubernetes-charts +RUN helm3 repo update +USER root +` gotOutput := m.TestContext.GetOutput() assert.Equal(t, wantOutput, gotOutput) }) @@ -74,7 +80,10 @@ RUN curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1 err = m.Build() require.NoError(t, err, "build failed") wantOutput := fmt.Sprintf(buildOutput, m.HelmClientVersion, m.HelmClientPlatfrom, m.HelmClientArchitecture) + - "\nRUN helm3 repo update" + `USER ${BUNDLE_USER} +RUN helm3 repo update +USER root +` gotOutput := m.TestContext.GetOutput() assert.Equal(t, wantOutput, gotOutput) }) diff --git a/pkg/helm3/execute.go b/pkg/helm3/execute.go index 0bc1027..e45f618 100644 --- a/pkg/helm3/execute.go +++ b/pkg/helm3/execute.go @@ -30,7 +30,7 @@ func (m *Mixin) Execute() error { return errors.Wrapf(err, "invocation of action %s failed", action) } - kubeClient, err := m.getKubernetesClient("/root/.kube/config") + kubeClient, err := m.getKubernetesClient() if err != nil { return errors.Wrap(err, "couldn't get kubernetes client") } diff --git a/pkg/helm3/helm3.go b/pkg/helm3/helm3.go index 32a4d6a..87d148f 100644 --- a/pkg/helm3/helm3.go +++ b/pkg/helm3/helm3.go @@ -81,6 +81,6 @@ func (m *Mixin) ValidatePayload(b []byte) error { return nil } -func (m *Mixin) getKubernetesClient(kubeconfig string) (k8s.Interface, error) { - return m.ClientFactory.GetClient(kubeconfig) +func (m *Mixin) getKubernetesClient() (k8s.Interface, error) { + return m.ClientFactory.GetClient() } diff --git a/pkg/helm3/helpers.go b/pkg/helm3/helpers.go index 006a3a0..1c27a1a 100644 --- a/pkg/helm3/helpers.go +++ b/pkg/helm3/helpers.go @@ -18,7 +18,7 @@ type TestMixin struct { type testKubernetesFactory struct { } -func (t *testKubernetesFactory) GetClient(configPath string) (kubernetes.Interface, error) { +func (t *testKubernetesFactory) GetClient() (kubernetes.Interface, error) { return testclient.NewSimpleClientset(), nil } diff --git a/pkg/helm3/install.go b/pkg/helm3/install.go index 5ed283c..92f3352 100644 --- a/pkg/helm3/install.go +++ b/pkg/helm3/install.go @@ -45,7 +45,7 @@ func (m *Mixin) Install() error { return err } - kubeClient, err := m.getKubernetesClient("/root/.kube/config") + kubeClient, err := m.getKubernetesClient() if err != nil { return errors.Wrap(err, "couldn't get kubernetes client") } diff --git a/pkg/helm3/outputs.go b/pkg/helm3/outputs.go index 36baae3..b141618 100644 --- a/pkg/helm3/outputs.go +++ b/pkg/helm3/outputs.go @@ -2,6 +2,7 @@ package helm3 import ( "fmt" + "os" "strings" "github.com/pkg/errors" @@ -10,17 +11,21 @@ import ( "k8s.io/client-go/kubernetes" ) -func getSecret(client kubernetes.Interface, namespace, name, key string) ([]byte, error) { +func (m *Mixin) getSecret(client kubernetes.Interface, namespace, name, key string) ([]byte, error) { if namespace == "" { namespace = "default" } + if m.Debug { + fmt.Fprintf(os.Stderr, "Retrieving secret %s/%s and using key %s as an output\n", namespace, name, key) + } + secret, err := client.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { - return nil, fmt.Errorf("error getting secret %s from namespace %s: %s", name, namespace, err) + return nil, fmt.Errorf("error getting secret %s/%s: %s", namespace, name, err) } val, ok := secret.Data[key] if !ok { - return nil, fmt.Errorf("couldn't find key %s in secret", key) + return nil, fmt.Errorf("couldn't find key %s in secret %s/%s", key, namespace, name) } return val, nil } @@ -52,7 +57,7 @@ func (m *Mixin) handleOutputs(client kubernetes.Interface, namespace string, out namespace = output.Namespace } - val, err := getSecret(client, namespace, output.Secret, output.Key) + val, err := m.getSecret(client, namespace, output.Secret, output.Key) if err != nil { return err diff --git a/pkg/helm3/upgrade.go b/pkg/helm3/upgrade.go index f9e48f3..563dbe9 100644 --- a/pkg/helm3/upgrade.go +++ b/pkg/helm3/upgrade.go @@ -48,7 +48,7 @@ func (m *Mixin) Upgrade() error { return err } - kubeClient, err := m.getKubernetesClient("/root/.kube/config") + kubeClient, err := m.getKubernetesClient() if err != nil { return errors.Wrap(err, "couldn't get kubernetes client") } diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 4c118de..09929d6 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -13,7 +13,7 @@ import ( // ClientFactory is an interface that knows how to create Kubernetes Clients type ClientFactory interface { - GetClient(configPath string) (k8s.Interface, error) + GetClient() (k8s.Interface, error) } // ClientFactory struct @@ -21,9 +21,8 @@ type clientFactory struct { } // GetClient: Read the config and create Kubernetes Clients -func (f *clientFactory) GetClient(configPath string) (k8s.Interface, error) { - - config, err := clientcmd.BuildConfigFromFlags("", configPath) +func (f *clientFactory) GetClient() (k8s.Interface, error) { + config, err := clientcmd.DefaultClientConfig.ClientConfig() if err != nil { return nil, fmt.Errorf("couldn't build kubernetes config: %s", err) }