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 <anto...@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 == "" {