Skip to content

Commit

Permalink
Create and mount service CA via ConfigMap
Browse files Browse the repository at this point in the history
Fixes #1123
  • Loading branch information
jpkrohling committed Jul 8, 2020
1 parent 1dce126 commit 50575c8
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 157 deletions.
110 changes: 108 additions & 2 deletions pkg/config/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ import (
"github.com/jaegertracing/jaeger-operator/pkg/util"
)

const (
serviceCAMountPath = "/etc/pki/ca-trust/source/service-ca"
serviceCAFile = "service-ca.crt"
caBundleMountPath = "/etc/pki/ca-trust/extracted/pem"

// ServiceCAPath represents the in-container full path to the service-ca file
ServiceCAPath = serviceCAMountPath + "/" + serviceCAFile
)

// GetTrustedCABundle returns a trusted CA bundle configmap if platform is OpenShift
func GetTrustedCABundle(jaeger *v1.Jaeger) *corev1.ConfigMap {
// Only configure the trusted CA if running in OpenShift
Expand Down Expand Up @@ -55,6 +64,47 @@ func GetTrustedCABundle(jaeger *v1.Jaeger) *corev1.ConfigMap {
}
}

// GetServiceCABundle returns a trusted CA bundle configmap if platform is OpenShift
func GetServiceCABundle(jaeger *v1.Jaeger) *corev1.ConfigMap {
// Only configure the trusted CA if running in OpenShift
if viper.GetString("platform") != v1.FlagPlatformOpenShift {
return nil
}

if !deployServiceCA(jaeger) {
jaeger.Logger().Debug("CA: Skip deploying the Jaeger instance's service CA configmap")
return nil
}

jaeger.Logger().Debug("CA: Creating the service CA configmap")
trueVar := true

name := ServiceCAName(jaeger)
annotations := map[string]string{
"service.beta.openshift.io/inject-cabundle": "true",
}

return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: jaeger.Namespace,
Labels: util.Labels(name, "service-ca-configmap", *jaeger),
Annotations: annotations,
OwnerReferences: []metav1.OwnerReference{{
APIVersion: jaeger.APIVersion,
Kind: jaeger.Kind,
Name: jaeger.Name,
UID: jaeger.UID,
Controller: &trueVar,
}},
},
}
}

// Update will modify the supplied common spec, to include
// trusted CA bundle volume and volumeMount, if running on OpenShift
func Update(jaeger *v1.Jaeger, commonSpec *v1.JaegerCommonSpec) {
Expand Down Expand Up @@ -85,7 +135,44 @@ func Update(jaeger *v1.Jaeger, commonSpec *v1.JaegerCommonSpec) {

volumeMount := corev1.VolumeMount{
Name: TrustedCAName(jaeger),
MountPath: "/etc/pki/ca-trust/extracted/pem",
MountPath: caBundleMountPath,
ReadOnly: true,
}

commonSpec.Volumes = util.RemoveDuplicatedVolumes(append(commonSpec.Volumes, volume))
commonSpec.VolumeMounts = util.RemoveDuplicatedVolumeMounts(append(commonSpec.VolumeMounts, volumeMount))
}

// AddServiceCA will modify the supplied common spec, to include
// the service CA volume and volumeMount, if running on OpenShift
func AddServiceCA(jaeger *v1.Jaeger, commonSpec *v1.JaegerCommonSpec) {
if viper.GetString("platform") != v1.FlagPlatformOpenShift {
return
}

if !deployServiceCA(jaeger) {
jaeger.Logger().Debug("CA: Skip adding the Jaeger instance's service CA volume")
return
}

volume := corev1.Volume{
Name: ServiceCAName(jaeger),
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: ServiceCAName(jaeger),
},
Items: []corev1.KeyToPath{{
Key: "service-ca.crt",
Path: "service-ca.crt",
}},
},
},
}

volumeMount := corev1.VolumeMount{
Name: ServiceCAName(jaeger),
MountPath: serviceCAMountPath,
ReadOnly: true,
}

Expand All @@ -95,7 +182,7 @@ func Update(jaeger *v1.Jaeger, commonSpec *v1.JaegerCommonSpec) {

func deployTrustedCA(jaeger *v1.Jaeger) bool {
for _, vm := range jaeger.Spec.JaegerCommonSpec.VolumeMounts {
if strings.HasPrefix(vm.MountPath, "/etc/pki/ca-trust/extracted/pem") {
if strings.HasPrefix(vm.MountPath, caBundleMountPath) {
// Volume Mount already exists, so don't create specific
// one for this Jaeger instance
return false
Expand All @@ -104,6 +191,15 @@ func deployTrustedCA(jaeger *v1.Jaeger) bool {
return true
}

func deployServiceCA(jaeger *v1.Jaeger) bool {
for _, vm := range jaeger.Spec.JaegerCommonSpec.VolumeMounts {
if strings.HasPrefix(vm.MountPath, serviceCAMountPath) {
return false
}
}
return true
}

// TrustedCAName returns the name of the trusted CA
func TrustedCAName(jaeger *v1.Jaeger) string {
return TrustedCANameFromString(jaeger.Name)
Expand All @@ -113,3 +209,13 @@ func TrustedCAName(jaeger *v1.Jaeger) string {
func TrustedCANameFromString(name string) string {
return fmt.Sprintf("%s-trusted-ca", name)
}

// ServiceCAName returns the name of the trusted CA
func ServiceCAName(jaeger *v1.Jaeger) string {
return ServiceCANameFromString(jaeger.Name)
}

// ServiceCANameFromString returns the name of the trusted CA
func ServiceCANameFromString(name string) string {
return fmt.Sprintf("%s-service-ca", name)
}
105 changes: 84 additions & 21 deletions pkg/config/ca/ca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,82 +12,145 @@ import (
)

func TestGetWithoutTrustedCA(t *testing.T) {
// prepare
viper.Set("platform", "other")
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestGetWithoutTrustedCA"})
jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})

cm := GetTrustedCABundle(jaeger)
assert.Nil(t, cm)
// test
trusted := GetTrustedCABundle(jaeger)
service := GetServiceCABundle(jaeger)

// verify
assert.Nil(t, trusted)
assert.Nil(t, service)
}

func TestGetWithTrustedCA(t *testing.T) {
// prepare
viper.Set("platform", v1.FlagPlatformOpenShift)
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestGetWithTrustedCA"})
jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})

// test
cm := GetTrustedCABundle(jaeger)

// verify
assert.NotNil(t, cm)
assert.Equal(t, "true", cm.Labels["config.openshift.io/inject-trusted-cabundle"])
assert.Equal(t, "", cm.Data["ca-bundle.crt"])
}

func TestGetWithServiceCA(t *testing.T) {
// prepare
viper.Set("platform", v1.FlagPlatformOpenShift)
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})

// test
cm := GetServiceCABundle(jaeger)

// verify
assert.NotNil(t, cm)
assert.Equal(t, "true", cm.Annotations["service.beta.openshift.io/inject-cabundle"])
}

func TestGetWithExistingTrustedCA(t *testing.T) {
// prepare
viper.Set("platform", v1.FlagPlatformOpenShift)
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestGetWithExistingTrustedCA"})
jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})
jaeger.Spec.JaegerCommonSpec.VolumeMounts = []corev1.VolumeMount{{
MountPath: "/etc/pki/ca-trust/extracted/pem",
MountPath: caBundleMountPath,
Name: "ExistingTrustedCA",
}}

// test
cm := GetTrustedCABundle(jaeger)

// verify
assert.Nil(t, cm)
}

func TestUpdateWithoutTrustedCA(t *testing.T) {
viper.Set("platform", "other")
func TestGetWithExistingServiceCA(t *testing.T) {
// prepare
viper.Set("platform", v1.FlagPlatformOpenShift)
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestUpdateWithoutTrustedCA"})
jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})
jaeger.Spec.JaegerCommonSpec.VolumeMounts = []corev1.VolumeMount{{
MountPath: serviceCAMountPath,
Name: "ExistingServiceCA",
}}

// test
cm := GetServiceCABundle(jaeger)

// verify
assert.Nil(t, cm)
}

func TestUpdateWithoutCAs(t *testing.T) {
// prepare
viper.Set("platform", "other")
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})
commonSpec := v1.JaegerCommonSpec{}

// test
Update(jaeger, &commonSpec)
AddServiceCA(jaeger, &commonSpec)

// verify
assert.Len(t, commonSpec.Volumes, 0)
assert.Len(t, commonSpec.VolumeMounts, 0)
}

func TestUpdateWithTrustedCA(t *testing.T) {
// prepare
viper.Set("platform", v1.FlagPlatformOpenShift)
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestUpdateWithTrustedCA"})

jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})
commonSpec := v1.JaegerCommonSpec{}

// test
Update(jaeger, &commonSpec)
assert.Len(t, commonSpec.Volumes, 1)
assert.Equal(t, commonSpec.Volumes[0].Name, TrustedCAName(jaeger))
assert.Len(t, commonSpec.VolumeMounts, 1)
assert.Equal(t, commonSpec.VolumeMounts[0].Name, TrustedCAName(jaeger))
AddServiceCA(jaeger, &commonSpec)

// verify
assert.Len(t, commonSpec.Volumes, 2)
assert.Len(t, commonSpec.VolumeMounts, 2)
}

func TestUpdateWithExistingTrustedCA(t *testing.T) {
// prepare
viper.Set("platform", v1.FlagPlatformOpenShift)
defer viper.Reset()

jaeger := v1.NewJaeger(types.NamespacedName{Name: "TestUpdateWithExistingTrustedCA"})
jaeger.Spec.JaegerCommonSpec.VolumeMounts = []corev1.VolumeMount{{
MountPath: "/etc/pki/ca-trust/extracted/pem",
Name: "ExistingTrustedCA",
}}

jaeger := v1.NewJaeger(types.NamespacedName{Name: "my-instance"})
jaeger.Spec.JaegerCommonSpec.VolumeMounts = []corev1.VolumeMount{
{
MountPath: caBundleMountPath,
Name: "ExistingTrustedCA",
},
{
MountPath: serviceCAMountPath,
Name: "ExistingServiceCA",
},
}
commonSpec := v1.JaegerCommonSpec{}

// test
Update(jaeger, &commonSpec)
AddServiceCA(jaeger, &commonSpec)

// verify
assert.Len(t, commonSpec.Volumes, 0)
assert.Len(t, commonSpec.VolumeMounts, 0)
}
13 changes: 13 additions & 0 deletions pkg/controller/deployment/deployment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,19 @@ func (r *ReconcileDeployment) Reconcile(request reconcile.Request) (reconcile.Re
return reconcile.Result{}, tracing.HandleError(err, span)
}
}

if cm := ca.GetServiceCABundle(jaeger); cm != nil {
// Update the namespace to be the same as the Deployment being injected
cm.Namespace = request.Namespace
jaeger.Logger().WithFields(log.Fields{
"configMap": cm.Name,
"namespace": cm.Namespace,
}).Debug("creating service CA config map")
if err := r.client.Create(ctx, cm); err != nil && !errors.IsAlreadyExists(err) {
log.WithField("namespace", request.Namespace).WithError(err).Error("failed to create trusted CA bundle")
return reconcile.Result{}, tracing.HandleError(err, span)
}
}
}

// a suitable jaeger instance was found! let's inject a sidecar pointing to it then
Expand Down
19 changes: 9 additions & 10 deletions pkg/deployment/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (a *Agent) Get() *appsv1.DaemonSet {
if viper.GetString("platform") == v1.FlagPlatformOpenShift {
if len(util.FindItem("--reporter.type=grpc", args)) > 0 && len(util.FindItem("--reporter.grpc.tls=true", args)) == 0 {
args = append(args, "--reporter.grpc.tls.enabled=true")
args = append(args, "--reporter.grpc.tls.ca=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt")
args = append(args, fmt.Sprintf("--reporter.grpc.tls.ca=%s", ca.ServiceCAPath))
args = append(args, fmt.Sprintf("--reporter.grpc.tls.server-name=%s.%s.svc.cluster.local", service.GetNameForHeadlessCollectorService(a.jaeger), a.jaeger.Namespace))
}
}
Expand All @@ -80,6 +80,7 @@ func (a *Agent) Get() *appsv1.DaemonSet {
commonSpec := util.Merge([]v1.JaegerCommonSpec{a.jaeger.Spec.Agent.JaegerCommonSpec, a.jaeger.Spec.JaegerCommonSpec, baseCommonSpec})

ca.Update(a.jaeger, commonSpec)
ca.AddServiceCA(a.jaeger, commonSpec)

otelConf, err := a.jaeger.Spec.Agent.Config.GetMap()
if err != nil {
Expand All @@ -103,15 +104,13 @@ func (a *Agent) Get() *appsv1.DaemonSet {
Name: fmt.Sprintf("%s-agent-daemonset", a.jaeger.Name),
Namespace: a.jaeger.Namespace,
Labels: commonSpec.Labels,
OwnerReferences: []metav1.OwnerReference{
metav1.OwnerReference{
APIVersion: a.jaeger.APIVersion,
Kind: a.jaeger.Kind,
Name: a.jaeger.Name,
UID: a.jaeger.UID,
Controller: &trueVar,
},
},
OwnerReferences: []metav1.OwnerReference{{
APIVersion: a.jaeger.APIVersion,
Kind: a.jaeger.Kind,
Name: a.jaeger.Name,
UID: a.jaeger.UID,
Controller: &trueVar,
}},
},
Spec: appsv1.DaemonSetSpec{
Selector: &metav1.LabelSelector{
Expand Down
Loading

0 comments on commit 50575c8

Please sign in to comment.