diff --git a/install/installer/pkg/common/ca.go b/install/installer/pkg/common/ca.go index b868495e3f7f96..42b5a0202d977c 100644 --- a/install/installer/pkg/common/ca.go +++ b/install/installer/pkg/common/ca.go @@ -64,3 +64,41 @@ func InternalCAContainer(ctx *RenderContext, mod ...func(*corev1.Container)) *co return res } + +// CustomCACertVolume produces the objects required to mount custom CA certificates +func CustomCACertVolume(ctx *RenderContext) (vol *corev1.Volume, mnt *corev1.VolumeMount, env *corev1.EnvVar, ok bool) { + if ctx.Config.CustomCACert == nil { + return nil, nil, nil, false + } + + const ( + volumeName = "custom-ca-cert" + mountPath = "/etc/ssl/certs/custom-ca.crt" + ) + vol = &corev1.Volume{ + Name: volumeName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: ctx.Config.CustomCACert.Name, + Items: []corev1.KeyToPath{ + { + Key: "ca.crt", + Path: "ca.crt", + }, + }, + }, + }, + } + mnt = &corev1.VolumeMount{ + Name: volumeName, + ReadOnly: true, + MountPath: mountPath, + SubPath: "ca.crt", + } + env = &corev1.EnvVar{ + Name: "NODE_EXTRA_CA_CERTS", + Value: mountPath, + } + ok = true + return +} diff --git a/install/installer/pkg/components/image-builder-mk3/deployment.go b/install/installer/pkg/components/image-builder-mk3/deployment.go index f5132a95ef552c..8888dd9d869932 100644 --- a/install/installer/pkg/components/image-builder-mk3/deployment.go +++ b/install/installer/pkg/components/image-builder-mk3/deployment.go @@ -6,6 +6,7 @@ package image_builder_mk3 import ( "fmt" + "github.com/gitpod-io/gitpod/installer/pkg/cluster" "github.com/gitpod-io/gitpod/installer/pkg/common" @@ -58,6 +59,57 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { return nil, err } + volumes := []corev1.Volume{ + { + Name: "configuration", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{Name: fmt.Sprintf("%s-config", Component)}, + }, + }, + }, + { + Name: "wsman-tls-certs", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: wsmanager.TLSSecretNameClient, + }, + }, + }, + { + Name: "pull-secret", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretName, + }, + }, + }, + *common.InternalCAVolume(), + *common.NewEmptyDirVolume("cacerts"), + } + volumeMounts := []corev1.VolumeMount{ + { + Name: "configuration", + MountPath: "/config/image-builder.json", + SubPath: "image-builder.json", + }, + { + Name: "wsman-tls-certs", + MountPath: "/wsman-certs", + ReadOnly: true, + }, + { + Name: "pull-secret", + MountPath: PullSecretFile, + SubPath: ".dockerconfigjson", + }, + *common.InternalCAVolumeMount(), + } + if vol, mnt, _, ok := common.CustomCACertVolume(ctx); ok { + volumes = append(volumes, *vol) + volumeMounts = append(volumeMounts, *mnt) + } + return []runtime.Object{&appsv1.Deployment{ TypeMeta: common.TypeMetaDeployment, ObjectMeta: metav1.ObjectMeta{ @@ -85,34 +137,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { DNSPolicy: "ClusterFirst", RestartPolicy: "Always", TerminationGracePeriodSeconds: pointer.Int64(30), - Volumes: append([]corev1.Volume{ - { - Name: "configuration", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{Name: fmt.Sprintf("%s-config", Component)}, - }, - }, - }, - { - Name: "wsman-tls-certs", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: wsmanager.TLSSecretNameClient, - }, - }, - }, - { - Name: "pull-secret", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, - }, - }, - }, - *common.InternalCAVolume(), - *common.NewEmptyDirVolume("cacerts"), - }), + Volumes: volumes, InitContainers: []corev1.Container{ *common.InternalCAContainer(ctx), }, @@ -143,24 +168,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { Privileged: pointer.Bool(false), RunAsUser: pointer.Int64(33333), }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "configuration", - MountPath: "/config/image-builder.json", - SubPath: "image-builder.json", - }, - { - Name: "wsman-tls-certs", - MountPath: "/wsman-certs", - ReadOnly: true, - }, - { - Name: "pull-secret", - MountPath: PullSecretFile, - SubPath: ".dockerconfigjson", - }, - *common.InternalCAVolumeMount(), - }, + VolumeMounts: volumeMounts, }, *common.KubeRBACProxyContainer(ctx), }, diff --git a/install/installer/pkg/components/server/deployment.go b/install/installer/pkg/components/server/deployment.go index 0ecfe9e7c33f90..f2243f680ed908 100644 --- a/install/installer/pkg/components/server/deployment.go +++ b/install/installer/pkg/components/server/deployment.go @@ -69,6 +69,55 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { } wsmanCfgManager := base64.StdEncoding.EncodeToString(fc) + env := common.MergeEnv( + common.DefaultEnv(&ctx.Config), + common.DatabaseEnv(&ctx.Config), + common.TracingEnv(ctx), + common.AnalyticsEnv(&ctx.Config), + common.MessageBusEnv(&ctx.Config), + []corev1.EnvVar{ + { + Name: "CONFIG_PATH", + Value: "/config/config.json", + }, + func() corev1.EnvVar { + envvar := corev1.EnvVar{ + Name: "GITPOD_LICENSE_TYPE", + } + + if ctx.Config.License == nil { + envvar.Value = string(configv1.LicensorTypeGitpod) + } else { + envvar.ValueFrom = &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: ctx.Config.License.Name}, + Key: "type", + Optional: pointer.Bool(true), + }, + } + } + + return envvar + }(), + { + Name: "IDE_CONFIG_PATH", + Value: "/ide-config/config.json", + }, + { + Name: "NODE_ENV", + Value: "production", // todo(sje): will we need to change this? + }, + { + Name: "SHLVL", + Value: "1", + }, + { + Name: "WSMAN_CFG_MANAGERS", + Value: wsmanCfgManager, + }, + }, + ) + volumes := make([]corev1.Volume, 0) volumeMounts := make([]corev1.VolumeMount, 0) if ctx.Config.License != nil { @@ -108,6 +157,12 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { } } + if vol, mnt, envv, ok := common.CustomCACertVolume(ctx); ok { + volumes = append(volumes, *vol) + volumeMounts = append(volumeMounts, *mnt) + env = append(env, *envv) + } + return []runtime.Object{ &appsv1.Deployment{ TypeMeta: common.TypeMetaDeployment, @@ -189,54 +244,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { ContainerPort: PrometheusPort, }}, // todo(sje): do we need to cater for serverContainer.env from values.yaml? - Env: common.MergeEnv( - common.DefaultEnv(&ctx.Config), - common.DatabaseEnv(&ctx.Config), - common.TracingEnv(ctx), - common.AnalyticsEnv(&ctx.Config), - common.MessageBusEnv(&ctx.Config), - []corev1.EnvVar{ - { - Name: "CONFIG_PATH", - Value: "/config/config.json", - }, - func() corev1.EnvVar { - envvar := corev1.EnvVar{ - Name: "GITPOD_LICENSE_TYPE", - } - - if ctx.Config.License == nil { - envvar.Value = string(configv1.LicensorTypeGitpod) - } else { - envvar.ValueFrom = &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{Name: ctx.Config.License.Name}, - Key: "type", - Optional: pointer.Bool(true), - }, - } - } - - return envvar - }(), - { - Name: "IDE_CONFIG_PATH", - Value: "/ide-config/config.json", - }, - { - Name: "NODE_ENV", - Value: "production", // todo(sje): will we need to change this? - }, - { - Name: "SHLVL", - Value: "1", - }, - { - Name: "WSMAN_CFG_MANAGERS", - Value: wsmanCfgManager, - }, - }, - ), + Env: env, // todo(sje): conditionally add github-app-cert-secret in // todo(sje): do we need to cater for serverContainer.volumeMounts from values.yaml? VolumeMounts: append( diff --git a/install/installer/pkg/components/ws-daemon/daemonset.go b/install/installer/pkg/components/ws-daemon/daemonset.go index 715b350f821920..a6c814fb248d92 100644 --- a/install/installer/pkg/components/ws-daemon/daemonset.go +++ b/install/installer/pkg/components/ws-daemon/daemonset.go @@ -340,6 +340,13 @@ fi return nil, err } + if vol, mnt, _, ok := common.CustomCACertVolume(ctx); ok { + podSpec.Volumes = append(podSpec.Volumes, *vol) + pod := podSpec.Containers[0] + pod.VolumeMounts = append(pod.VolumeMounts, *mnt) + podSpec.Containers[0] = pod + } + return []runtime.Object{&appsv1.DaemonSet{ TypeMeta: common.TypeMetaDaemonset, ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/config/v1/config.go b/install/installer/pkg/config/v1/config.go index 090eee253cb9b6..e112f040b76671 100644 --- a/install/installer/pkg/config/v1/config.go +++ b/install/installer/pkg/config/v1/config.go @@ -90,6 +90,8 @@ type Config struct { DisableDefinitelyGP bool `json:"disableDefinitelyGp"` + CustomCACert *ObjectRef `json:"customCACert,omitempty"` + Experimental *experimental.Config `json:"experimental,omitempty"` } diff --git a/install/installer/pkg/config/v1/validation.go b/install/installer/pkg/config/v1/validation.go index a22bd302a42b78..3e3c00d5dec130 100644 --- a/install/installer/pkg/config/v1/validation.go +++ b/install/installer/pkg/config/v1/validation.go @@ -211,6 +211,10 @@ func (v version) ClusterValidation(rcfg interface{}) cluster.ValidationChecks { }))) } + if cfg.CustomCACert != nil { + res = append(res, cluster.CheckSecret(cfg.CustomCACert.Name, cluster.CheckSecretRequiredData("ca.crt"))) + } + res = append(res, experimental.ClusterValidation(cfg.Experimental)...) return res