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 2020/02/26 18:34:47 UTC

[camel-k] 04/15: feat(buildah): Auto-configure OpenShift internal registry certificate authority

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 69e73491e9a2d8bca7ed55673eb48bd9d11afd92
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Mon Feb 24 16:21:32 2020 +0100

    feat(buildah): Auto-configure OpenShift internal registry certificate authority
---
 pkg/apis/camel/v1/integrationplatform_types.go |  1 +
 pkg/platform/defaults.go                       | 26 ++++++++
 pkg/trait/builder.go                           | 84 +++++++++++++++++++++++---
 3 files changed, 104 insertions(+), 7 deletions(-)

diff --git a/pkg/apis/camel/v1/integrationplatform_types.go b/pkg/apis/camel/v1/integrationplatform_types.go
index ff9afbb..ad00423 100644
--- a/pkg/apis/camel/v1/integrationplatform_types.go
+++ b/pkg/apis/camel/v1/integrationplatform_types.go
@@ -121,6 +121,7 @@ type IntegrationPlatformRegistrySpec struct {
 	Insecure     bool   `json:"insecure,omitempty"`
 	Address      string `json:"address,omitempty"`
 	Secret       string `json:"secret,omitempty"`
+	CA           string `json:"ca,omitempty"`
 	Organization string `json:"organization,omitempty"`
 }
 
diff --git a/pkg/platform/defaults.go b/pkg/platform/defaults.go
index caffed1..e04d3ef 100644
--- a/pkg/platform/defaults.go
+++ b/pkg/platform/defaults.go
@@ -90,6 +90,13 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *v1.IntegrationPl
 		p.Status.Build.Registry.Address == "" {
 		p.Status.Build.Registry.Address = "image-registry.openshift-image-registry.svc:5000"
 
+		// OpenShift automatically injects the service CA certificate into the service-ca.crt key on the ConfigMap
+		cm, err := createServiceCaBundleConfigMap(ctx, c, p)
+		if err != nil {
+			return err
+		}
+		p.Status.Build.Registry.CA = cm.Name
+
 		// Default to using the registry secret that's configured for the builder service account
 		if p.Status.Build.Registry.Secret == "" {
 			sa := corev1.ServiceAccount{}
@@ -229,3 +236,22 @@ func createDefaultMavenSettingsConfigMap(ctx context.Context, client client.Clie
 
 	return nil
 }
+
+func createServiceCaBundleConfigMap(ctx context.Context, client client.Client, p *v1.IntegrationPlatform) (*corev1.ConfigMap, error) {
+	cm := &corev1.ConfigMap{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "camel-k-builder-ca",
+			Namespace: p.Namespace,
+			Annotations: map[string]string{
+				"service.beta.openshift.io/inject-cabundle": "true",
+			},
+		},
+	}
+
+	err := client.Create(ctx, cm)
+	if err != nil && !k8serrors.IsAlreadyExists(err) {
+		return nil, err
+	}
+
+	return cm, nil
+}
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index 1a49ee6..72919c8 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -211,6 +211,8 @@ func (t *builderTrait) builderTask(e *Environment) *v1.BuilderTask {
 func (t *builderTrait) buildahTask(e *Environment) (*v1.ImageTask, error) {
 	image := getImageName(e)
 
+	auth := []string{""}
+
 	bud := []string{
 		"buildah",
 		"bud",
@@ -236,15 +238,22 @@ func (t *builderTrait) buildahTask(e *Environment) (*v1.ImageTask, error) {
 		push = append(push[:2], append([]string{"--log-level=debug"}, push[2:]...)...)
 	}
 
-	args := []string{
-		strings.Join(bud, " "),
-		strings.Join(push, " "),
-	}
-
 	env := make([]corev1.EnvVar, 0)
 	volumes := make([]corev1.Volume, 0)
 	volumeMounts := make([]corev1.VolumeMount, 0)
 
+	if e.Platform.Status.Build.Registry.CA != "" {
+		config, err := getRegistryConfigMapFor(e, buildahRegistryConfigMaps)
+		if err != nil {
+			return nil, err
+		}
+		mountRegistryConfigMap(e.Platform.Status.Build.Registry.CA, config, &volumes, &volumeMounts)
+		// This is easier to use the --cert-dir option, otherwise Buildah defaults to looking up certificates
+		//into a directory named after the registry address
+		bud = append(bud[:2], append([]string{"--cert-dir=/etc/containers/certs.d"}, bud[2:]...)...)
+		push = append(push[:2], append([]string{"--cert-dir=/etc/containers/certs.d"}, push[2:]...)...)
+	}
+
 	if e.Platform.Status.Build.Registry.Secret != "" {
 		secret, err := getRegistrySecretFor(e, buildahRegistrySecrets)
 		if err != nil {
@@ -252,10 +261,9 @@ func (t *builderTrait) buildahTask(e *Environment) (*v1.ImageTask, error) {
 		}
 		if secret == plainDockerBuildahRegistrySecret {
 			// Handle old format and make it compatible with Buildah
-			auth := []string{
+			auth = []string{
 				"(echo '{ \"auths\": ' ; cat /buildah/.docker/config.json ; echo \"}\") > /tmp/.dockercfg",
 			}
-			args = append([]string{strings.Join(auth, " ")}, args...)
 			env = append(env, corev1.EnvVar{
 				Name:  "REGISTRY_AUTH_FILE",
 				Value: "/tmp/.dockercfg",
@@ -269,6 +277,12 @@ func (t *builderTrait) buildahTask(e *Environment) (*v1.ImageTask, error) {
 
 	env = append(env, proxySecretEnvVars(e)...)
 
+	args := []string{
+		strings.Join(auth, " "),
+		strings.Join(bud, " "),
+		strings.Join(push, " "),
+	}
+
 	return &v1.ImageTask{
 		ContainerTask: v1.ContainerTask{
 			BaseTask: v1.BaseTask{
@@ -384,6 +398,24 @@ var (
 	}
 )
 
+type registryConfigMap struct {
+	fileName    string
+	mountPath   string
+	destination string
+}
+
+var (
+	serviceCABuildahRegistryConfigMap = registryConfigMap{
+		fileName:    "service-ca.crt",
+		mountPath:   "/etc/containers/certs.d",
+		destination: "service-ca.crt",
+	}
+
+	buildahRegistryConfigMaps = []registryConfigMap{
+		serviceCABuildahRegistryConfigMap,
+	}
+)
+
 func proxySecretEnvVars(e *Environment) []corev1.EnvVar {
 	if e.Platform.Status.Build.HTTPProxySecret == "" {
 		return []corev1.EnvVar{}
@@ -455,6 +487,44 @@ func mountRegistrySecret(name string, secret registrySecret, volumes *[]corev1.V
 	}
 }
 
+func getRegistryConfigMapFor(e *Environment, registryConfigMaps []registryConfigMap) (registryConfigMap, error) {
+	config := corev1.ConfigMap{}
+	err := e.Client.Get(e.C, client.ObjectKey{Namespace: e.Platform.Namespace, Name: e.Platform.Status.Build.Registry.CA}, &config)
+	if err != nil {
+		return registryConfigMap{}, err
+	}
+	for _, k := range registryConfigMaps {
+		if _, ok := config.Data[k.fileName]; ok {
+			return k, nil
+		}
+	}
+	return registryConfigMap{}, errors.New("unsupported registry config map")
+}
+
+func mountRegistryConfigMap(name string, config registryConfigMap, volumes *[]corev1.Volume, volumeMounts *[]corev1.VolumeMount) {
+	*volumes = append(*volumes, corev1.Volume{
+		Name: "registry-config",
+		VolumeSource: corev1.VolumeSource{
+			ConfigMap: &corev1.ConfigMapVolumeSource{
+				LocalObjectReference: corev1.LocalObjectReference{
+					Name: name,
+				},
+				Items: []corev1.KeyToPath{
+					{
+						Key:  config.fileName,
+						Path: config.destination,
+					},
+				},
+			},
+		},
+	})
+
+	*volumeMounts = append(*volumeMounts, corev1.VolumeMount{
+		Name:      "registry-config",
+		MountPath: config.mountPath,
+	})
+}
+
 func getImageName(e *Environment) string {
 	organization := e.Platform.Status.Build.Registry.Organization
 	if organization == "" {