You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2021/03/30 17:20:43 UTC

[camel-k] 01/20: feat(build): Add CA cert from user Secret into Maven build JVM trust store

This is an automated email from the ASF dual-hosted git repository.

astefanutti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit e913ccf5a26c783ca843f527240433c0c98043e9
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Mon Mar 22 15:57:54 2021 +0100

    feat(build): Add CA cert from user Secret into Maven build JVM trust store
---
 pkg/apis/camel/v1/common_types.go  |  7 ++---
 pkg/builder/project.go             | 36 +++++++++++++++++++++++++-
 pkg/builder/quarkus.go             |  4 +++
 pkg/builder/types.go               |  5 ++--
 pkg/trait/quarkus_test.go          |  2 +-
 pkg/util/kubernetes/core_client.go | 52 +++++++++++++++++++++++---------------
 pkg/util/kubernetes/util.go        |  2 --
 pkg/util/maven/maven.go            | 25 +++++++++++++++---
 pkg/util/maven/maven_types.go      | 11 ++++----
 9 files changed, 104 insertions(+), 40 deletions(-)

diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go
index d772e77..ae0413b 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -83,9 +83,10 @@ type PlatformInjectable interface {
 
 // MavenSpec --
 type MavenSpec struct {
-	LocalRepository string           `json:"localRepository,omitempty"`
-	Settings        ValueSource      `json:"settings,omitempty"`
-	Timeout         *metav1.Duration `json:"timeout,omitempty"`
+	LocalRepository string                    `json:"localRepository,omitempty"`
+	Settings        ValueSource               `json:"settings,omitempty"`
+	CaCert          *corev1.SecretKeySelector `json:"caCert,omitempty"`
+	Timeout         *metav1.Duration          `json:"timeout,omitempty"`
 }
 
 // ValueSource --
diff --git a/pkg/builder/project.go b/pkg/builder/project.go
index 1bd363f..27e20fe 100644
--- a/pkg/builder/project.go
+++ b/pkg/builder/project.go
@@ -18,19 +18,24 @@ limitations under the License.
 package builder
 
 import (
+	"fmt"
 	"os"
+	"os/exec"
+	"path"
+	"strings"
 
+	"github.com/apache/camel-k/pkg/util"
 	"github.com/apache/camel-k/pkg/util/camel"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
-
 func init() {
 	registerSteps(Steps)
 }
 
 type steps struct {
 	CleanUpBuildDir         Step
+	GenerateJavaKeystore    Step
 	GenerateProjectSettings Step
 	InjectDependencies      Step
 	SanitizeDependencies    Step
@@ -40,6 +45,7 @@ type steps struct {
 
 var Steps = steps{
 	CleanUpBuildDir:         NewStep(ProjectGenerationPhase-1, cleanUpBuildDir),
+	GenerateJavaKeystore:    NewStep(ProjectGenerationPhase, generateJavaKeystore),
 	GenerateProjectSettings: NewStep(ProjectGenerationPhase+1, generateProjectSettings),
 	InjectDependencies:      NewStep(ProjectGenerationPhase+2, injectDependencies),
 	SanitizeDependencies:    NewStep(ProjectGenerationPhase+3, sanitizeDependencies),
@@ -49,6 +55,7 @@ var Steps = steps{
 
 var DefaultSteps = []Step{
 	Steps.CleanUpBuildDir,
+	Steps.GenerateJavaKeystore,
 	Steps.GenerateProjectSettings,
 	Steps.InjectDependencies,
 	Steps.SanitizeDependencies,
@@ -63,6 +70,33 @@ func cleanUpBuildDir(ctx *builderContext) error {
 	return os.RemoveAll(ctx.Build.BuildDir)
 }
 
+func generateJavaKeystore(ctx *builderContext) error {
+	if ctx.Build.Maven.CaCert == nil {
+		return nil
+	}
+
+	certData, err := kubernetes.GetSecretRefData(ctx.C, ctx.Client, ctx.Namespace, ctx.Build.Maven.CaCert)
+	if err != nil {
+		return err
+	}
+
+	certPath := ctx.Build.Maven.CaCert.Key
+	if err := util.WriteFileWithContent(ctx.Path, certPath, certData); err != nil {
+		return err
+	}
+
+	keystore := "trust.jks"
+	ctx.Maven.TrustStorePath = path.Join(ctx.Path, keystore)
+
+	args := strings.Fields(fmt.Sprintf("-importcert -alias maven -file %s -keystore %s", certPath, keystore))
+	cmd := exec.CommandContext(ctx.C, "keytool", args...)
+	cmd.Dir = ctx.Path
+	cmd.Stderr = os.Stderr
+	cmd.Stdout = os.Stdout
+
+	return cmd.Run()
+}
+
 func generateProjectSettings(ctx *builderContext) error {
 	val, err := kubernetes.ResolveValueSource(ctx.C, ctx.Client, ctx.Namespace, &ctx.Build.Maven.Settings)
 	if err != nil {
diff --git a/pkg/builder/quarkus.go b/pkg/builder/quarkus.go
index 23ef90a..028b919 100644
--- a/pkg/builder/quarkus.go
+++ b/pkg/builder/quarkus.go
@@ -147,6 +147,10 @@ func buildQuarkusRunner(ctx *builderContext) error {
 	mc.LocalRepository = ctx.Build.Maven.LocalRepository
 	mc.Timeout = ctx.Build.Maven.GetTimeout().Duration
 
+	if ctx.Maven.TrustStorePath != "" {
+		mc.ExtraMavenOpts = append(mc.ExtraMavenOpts, "-Djavax.net.ssl.trustStore="+path.Join(ctx.Path, ctx.Maven.TrustStorePath))
+	}
+
 	err := BuildQuarkusRunnerCommon(mc)
 	if err != nil {
 		return err
diff --git a/pkg/builder/types.go b/pkg/builder/types.go
index 471ab88..776e8a0 100644
--- a/pkg/builder/types.go
+++ b/pkg/builder/types.go
@@ -88,7 +88,8 @@ type builderContext struct {
 	SelectedArtifacts []v1.Artifact
 	Resources         []resource
 	Maven             struct {
-		Project      maven.Project
-		SettingsData []byte
+		Project        maven.Project
+		SettingsData   []byte
+		TrustStorePath string
 	}
 }
diff --git a/pkg/trait/quarkus_test.go b/pkg/trait/quarkus_test.go
index 9061f57..181ba78 100644
--- a/pkg/trait/quarkus_test.go
+++ b/pkg/trait/quarkus_test.go
@@ -62,7 +62,7 @@ func TestQuarkusTraitAddBuildStepsShouldSucceed(t *testing.T) {
 
 	quarkusTrait.addBuildSteps(&steps)
 
-	assert.Len(t, steps, 9)
+	assert.Len(t, steps, len(builder.DefaultSteps)+len(builder.QuarkusSteps))
 }
 
 func createNominalQuarkusTest() (*quarkusTrait, *Environment) {
diff --git a/pkg/util/kubernetes/core_client.go b/pkg/util/kubernetes/core_client.go
index 822b209..621a90f 100644
--- a/pkg/util/kubernetes/core_client.go
+++ b/pkg/util/kubernetes/core_client.go
@@ -23,15 +23,16 @@ import (
 
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 
 	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/pkg/client"
 )
 
 // GetIntegrationPlatform --
-func GetIntegrationPlatform(context context.Context, client k8sclient.Reader, name string, namespace string) (*v1.IntegrationPlatform, error) {
-	key := k8sclient.ObjectKey{
+func GetIntegrationPlatform(context context.Context, client ctrl.Reader, name string, namespace string) (*v1.IntegrationPlatform, error) {
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -46,8 +47,8 @@ func GetIntegrationPlatform(context context.Context, client k8sclient.Reader, na
 }
 
 // GetIntegrationKit --
-func GetIntegrationKit(context context.Context, client k8sclient.Reader, name string, namespace string) (*v1.IntegrationKit, error) {
-	key := k8sclient.ObjectKey{
+func GetIntegrationKit(context context.Context, client ctrl.Reader, name string, namespace string) (*v1.IntegrationKit, error) {
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -62,8 +63,8 @@ func GetIntegrationKit(context context.Context, client k8sclient.Reader, name st
 }
 
 // GetIntegration --
-func GetIntegration(context context.Context, client k8sclient.Reader, name string, namespace string) (*v1.Integration, error) {
-	key := k8sclient.ObjectKey{
+func GetIntegration(context context.Context, client ctrl.Reader, name string, namespace string) (*v1.Integration, error) {
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -79,7 +80,7 @@ func GetIntegration(context context.Context, client k8sclient.Reader, name strin
 
 // GetBuild --
 func GetBuild(context context.Context, client client.Client, name string, namespace string) (*v1.Build, error) {
-	key := k8sclient.ObjectKey{
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -94,8 +95,8 @@ func GetBuild(context context.Context, client client.Client, name string, namesp
 }
 
 // GetConfigMap --
-func GetConfigMap(context context.Context, client k8sclient.Reader, name string, namespace string) (*corev1.ConfigMap, error) {
-	key := k8sclient.ObjectKey{
+func GetConfigMap(context context.Context, client ctrl.Reader, name string, namespace string) (*corev1.ConfigMap, error) {
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -119,8 +120,8 @@ func GetConfigMap(context context.Context, client k8sclient.Reader, name string,
 }
 
 // GetSecret --
-func GetSecret(context context.Context, client k8sclient.Reader, name string, namespace string) (*corev1.Secret, error) {
-	key := k8sclient.ObjectKey{
+func GetSecret(context context.Context, client ctrl.Reader, name string, namespace string) (*corev1.Secret, error) {
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -144,8 +145,8 @@ func GetSecret(context context.Context, client k8sclient.Reader, name string, na
 }
 
 // GetService --
-func GetService(context context.Context, client k8sclient.Reader, name string, namespace string) (*corev1.Service, error) {
-	key := k8sclient.ObjectKey{
+func GetService(context context.Context, client ctrl.Reader, name string, namespace string) (*corev1.Service, error) {
+	key := ctrl.ObjectKey{
 		Name:      name,
 		Namespace: namespace,
 	}
@@ -168,22 +169,31 @@ func GetService(context context.Context, client k8sclient.Reader, name string, n
 	return &answer, nil
 }
 
-// GetSecretRefValue returns the value of a secret in the supplied namespace --
-func GetSecretRefValue(ctx context.Context, client k8sclient.Reader, namespace string, selector *corev1.SecretKeySelector) (string, error) {
-	secret, err := GetSecret(ctx, client, selector.Name, namespace)
+// GetSecretRefValue returns the value of a secret in the supplied namespace
+func GetSecretRefValue(ctx context.Context, client ctrl.Reader, namespace string, selector *corev1.SecretKeySelector) (string, error) {
+	data, err := GetSecretRefData(ctx, client, namespace, selector)
 	if err != nil {
 		return "", err
 	}
+	return string(data), nil
+}
+
+// GetSecretRefData returns the value of a secret in the supplied namespace
+func GetSecretRefData(ctx context.Context, client ctrl.Reader, namespace string, selector *corev1.SecretKeySelector) ([]byte, error) {
+	secret, err := GetSecret(ctx, client, selector.Name, namespace)
+	if err != nil {
+		return nil, err
+	}
 
 	if data, ok := secret.Data[selector.Key]; ok {
-		return string(data), nil
+		return data, nil
 	}
 
-	return "", fmt.Errorf("key %s not found in secret %s", selector.Key, selector.Name)
+	return nil, fmt.Errorf("key %s not found in secret %s", selector.Key, selector.Name)
 }
 
 // GetConfigMapRefValue returns the value of a configmap in the supplied namespace
-func GetConfigMapRefValue(ctx context.Context, client k8sclient.Reader, namespace string, selector *corev1.ConfigMapKeySelector) (string, error) {
+func GetConfigMapRefValue(ctx context.Context, client ctrl.Reader, namespace string, selector *corev1.ConfigMapKeySelector) (string, error) {
 	cm, err := GetConfigMap(ctx, client, selector.Name, namespace)
 	if err != nil {
 		return "", err
@@ -197,7 +207,7 @@ func GetConfigMapRefValue(ctx context.Context, client k8sclient.Reader, namespac
 }
 
 // ResolveValueSource --
-func ResolveValueSource(ctx context.Context, client k8sclient.Reader, namespace string, valueSource *v1.ValueSource) (string, error) {
+func ResolveValueSource(ctx context.Context, client ctrl.Reader, namespace string, valueSource *v1.ValueSource) (string, error) {
 	if valueSource.ConfigMapKeyRef != nil && valueSource.SecretKeyRef != nil {
 		return "", fmt.Errorf("value source has bot config map and secret configured")
 	}
diff --git a/pkg/util/kubernetes/util.go b/pkg/util/kubernetes/util.go
index 23d3401..232cf85 100644
--- a/pkg/util/kubernetes/util.go
+++ b/pkg/util/kubernetes/util.go
@@ -24,12 +24,10 @@ import (
 	"github.com/apache/camel-k/pkg/util"
 )
 
-// ToJSON --
 func ToJSON(value runtime.Object) ([]byte, error) {
 	return json.Marshal(value)
 }
 
-// ToYAML --
 func ToYAML(value runtime.Object) ([]byte, error) {
 	data, err := ToJSON(value)
 	if err != nil {
diff --git a/pkg/util/maven/maven.go b/pkg/util/maven/maven.go
index 067feca..f49658f 100644
--- a/pkg/util/maven/maven.go
+++ b/pkg/util/maven/maven.go
@@ -35,10 +35,8 @@ import (
 	"github.com/apache/camel-k/pkg/util/log"
 )
 
-// Log --
 var Log = log.WithName("maven")
 
-// GenerateProjectStructure --
 func GenerateProjectStructure(context Context) error {
 	if err := util.WriteFileWithBytesMarshallerContent(context.Path, "pom.xml", context.Project); err != nil {
 		return err
@@ -78,7 +76,6 @@ func GenerateProjectStructure(context Context) error {
 	return nil
 }
 
-// Run --
 func Run(ctx Context) error {
 	if err := GenerateProjectStructure(ctx); err != nil {
 		return err
@@ -127,7 +124,27 @@ func Run(ctx Context) error {
 		cmd.Stdout = os.Stdout
 	}
 
-	Log.WithValues("timeout", timeout.String()).Infof("executing: %s", strings.Join(cmd.Args, " "))
+	mavenOpts, ok := os.LookupEnv("MAVEN_OPTS")
+	// FIXME: do not override duplicated Maven options
+	mavenOpts = strings.Join(append(strings.Fields(mavenOpts), ctx.ExtraMavenOpts...), " ")
+
+	// Inherit the parent process environment
+	env := os.Environ()
+	if !ok {
+		env = append(env, mavenOpts)
+	} else {
+		for i, e := range env {
+			if strings.HasPrefix(e, "MAVEN_OPTS=") {
+				env[i] = mavenOpts
+				break
+			}
+		}
+	}
+
+	cmd.Env = env
+
+	Log.WithValues("timeout", timeout.String(), "env", env).
+		Infof("executing: %s", strings.Join(cmd.Args, " "))
 
 	return cmd.Run()
 }
diff --git a/pkg/util/maven/maven_types.go b/pkg/util/maven/maven_types.go
index 3b7dba5..3bac740 100644
--- a/pkg/util/maven/maven_types.go
+++ b/pkg/util/maven/maven_types.go
@@ -43,10 +43,10 @@ type RepositoryPolicy struct {
 
 // Mirror --
 type Mirror struct {
-	ID        string           `xml:"id"`
-	Name      string           `xml:"name,omitempty"`
-	URL       string           `xml:"url"`
-	MirrorOf  string           `xml:"mirrorOf"`
+	ID       string `xml:"id"`
+	Name     string `xml:"name,omitempty"`
+	URL      string `xml:"url"`
+	MirrorOf string `xml:"mirrorOf"`
 }
 
 // Build --
@@ -120,6 +120,7 @@ func NewContext(buildDir string, project Project) Context {
 type Context struct {
 	Path                string
 	Project             Project
+	ExtraMavenOpts      []string
 	SettingsContent     []byte
 	AdditionalArguments []string
 	AdditionalEntries   map[string]interface{}
@@ -244,5 +245,3 @@ type PropertyActivation struct {
 	Name  string `xml:"name"`
 	Value string `xml:"value"`
 }
-
-