Repository: tektoncd/operator
Pull request #257 (2021-03-12 13:13:24)

Add ca cert volume mounts to taskrun pods
This will add the volume mounts for internal registry cert
and https proxy cert to the pods created by taskrun.
Configmap of these certs was created already during installation
This will mount them in pod if the configmap exist in namespace

# Submitter Checklist

These are the criteria that every PR should meet, please check them off as you
review them:

- [x] Includes [tests](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if functionality changed/added)
- [ ] Includes [docs](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if user facing)
- [x] Commit messages follow [commit message best practices](https://github.com/tektoncd/community/blob/master/standards.md#commit-messages)

_See [the contribution guide](https://github.com/tektoncd/operator/blob/master/CONTRIBUTING.md) for more details._

# Release Notes

```release-note
Add ca cert volume mounts to taskrun pods
```


tekton-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **nikhil-thomas**
You can assign the PR to them by writing `/assign @nikhil-thomas` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=tektoncd%2Foperator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/tektoncd/operator/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["nikhil-thomas"]} -->
tekton-robot: @piyush-garg: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-build-tests | 00626d20b9f91811755ae45236ae24458ca20128 | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/257/pull-tekton-operator-build-tests/1370362344474939393/) | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://tekton-releases.appspot.com/pr/tektoncd_operator/257). [Your PR dashboard](https://prow.tekton.dev/pr/piyush-garg).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: @piyush-garg: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-build-tests | 00626d20b9f91811755ae45236ae24458ca20128 | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/257/pull-tekton-operator-build-tests/1370362344474939393/) | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://tekton-releases.appspot.com/pr/tektoncd_operator/257). [Your PR dashboard](https://prow.tekton.dev/pr/piyush-garg).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: @piyush-garg: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-build-tests | d76d52cb252ee3ba4517e4a412285edc3ecc4ad4 | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/257/pull-tekton-operator-build-tests/1370975760692547584/) | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://tekton-releases.appspot.com/pr/tektoncd_operator/257). [Your PR dashboard](https://prow.tekton.dev/pr/piyush-garg).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: @piyush-garg: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-build-tests | d76d52cb252ee3ba4517e4a412285edc3ecc4ad4 | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/257/pull-tekton-operator-build-tests/1370975760692547584/) | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://tekton-releases.appspot.com/pr/tektoncd_operator/257). [Your PR dashboard](https://prow.tekton.dev/pr/piyush-garg).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/proxy/proxy.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/257/pull-tekton-operator-go-coverage/1371316756789858305/artifacts/line-cov.html#file0) | Do not exist | 8.3% | 

nikhil-thomas: /approve
/lgtm
tekton-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/tektoncd/operator/pull/257#issuecomment-799094268" title="LGTM">nikhil-thomas</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=tektoncd%2Foperator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/tektoncd/operator/blob/main/OWNERS)~~ [nikhil-thomas]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/pkg/reconciler/proxy/proxy.go b/pkg/reconciler/proxy/proxy.go
index acf801994..f7998cca7 100644
--- a/pkg/reconciler/proxy/proxy.go
+++ b/pkg/reconciler/proxy/proxy.go
@@ -22,6 +22,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"os"
+	"path/filepath"
 	"strings"
 
 	"github.com/markbates/inflect"
@@ -30,6 +31,7 @@ import (
 	admissionv1 "k8s.io/api/admission/v1"
 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/types"
@@ -48,6 +50,18 @@ import (
 	certresources "knative.dev/pkg/webhook/certificates/resources"
 )
 
+const (
+	// user-provided and system CA certificates
+	trustedCAConfigMapName   = "config-trusted-cabundle"
+	trustedCAConfigMapVolume = "config-trusted-cabundle-volume"
+	trustedCAKey             = "ca-bundle.crt"
+
+	// service serving certificates (required to talk to the internal registry)
+	serviceCAConfigMapName   = "config-service-cabundle"
+	serviceCAConfigMapVolume = "config-service-cabundle-volume"
+	serviceCAKey             = "service-ca.crt"
+)
+
 // reconciler implements the AdmissionController for resources
 type reconciler struct {
 	webhook.StatelessAdmissionImpl
@@ -255,7 +269,7 @@ func (ac *reconciler) mutate(ctx context.Context, req *admissionv1.AdmissionRequ
 	ctx = apis.WithUserInfo(ctx, &req.UserInfo)
 
 	// Default the new object.
-	if patches, err = setDefaults(ctx, patches, newObj); err != nil {
+	if patches, err = setDefaults(ac.client, ctx, patches, newObj); err != nil {
 		logger.Errorw("Failed the resource specific defaulter", zap.Error(err))
 		// Return the error message as-is to give the defaulter callback
 		// discretion over (our portion of) the message that the user sees.
@@ -284,7 +298,7 @@ func roundTripPatch(bytes []byte, unmarshalled interface{}) (duck.JSONPatch, err
 }
 
 // setDefaults simply leverages apis.Defaultable to set defaults.
-func setDefaults(ctx context.Context, patches duck.JSONPatch, pod corev1.Pod) (duck.JSONPatch, error) {
+func setDefaults(client kubernetes.Interface, ctx context.Context, patches duck.JSONPatch, pod corev1.Pod) (duck.JSONPatch, error) {
 	before, after := pod.DeepCopyObject(), pod
 
 	var proxyEnv = []corev1.EnvVar{{
@@ -305,6 +319,22 @@ func setDefaults(ctx context.Context, patches duck.JSONPatch, pod corev1.Pod) (d
 		}
 	}
 
+	exist, err := checkConfigMapExist(client, ctx, after.Namespace, trustedCAConfigMapName)
+	if err != nil {
+		return nil, err
+	}
+	if exist {
+		after = updateVolume(after, trustedCAConfigMapVolume, trustedCAConfigMapName, trustedCAKey)
+	}
+
+	exist, err = checkConfigMapExist(client, ctx, after.Namespace, serviceCAConfigMapName)
+	if err != nil {
+		return nil, err
+	}
+	if exist {
+		after = updateVolume(after, serviceCAConfigMapVolume, serviceCAConfigMapName, serviceCAKey)
+	}
+
 	patch, err := duck.CreatePatch(before, after)
 	if err != nil {
 		return nil, err
@@ -313,6 +343,90 @@ func setDefaults(ctx context.Context, patches duck.JSONPatch, pod corev1.Pod) (d
 	return append(patches, patch...), nil
 }
 
+// Ensure Configmap exist or not
+func checkConfigMapExist(client kubernetes.Interface, ctx context.Context, ns string, name string) (bool, error) {
+	logger := logging.FromContext(ctx)
+	logger.Info("finding configmap: %s/%s", ns, name)
+	_, err := client.CoreV1().ConfigMaps(ns).Get(ctx, name, metav1.GetOptions{})
+	if err != nil && errors.IsNotFound(err) {
+		return false, nil
+	}
+	if err != nil && !errors.IsNotFound(err) {
+		return false, err
+	}
+	return true, nil
+}
+
+// update volume and volume mounts to mount the certs configmap
+func updateVolume(pod corev1.Pod, volumeName, configmapName, key string) corev1.Pod {
+	volumes := pod.Spec.Volumes
+
+	for i, v := range volumes {
+		if v.Name == volumeName {
+			volumes = append(volumes[:i], volumes[i+1:]...)
+			break
+		}
+	}
+
+	// Let's add the trusted and service CA bundle ConfigMaps as a volume in
+	// the PodSpec which will later be mounted to add certs in the pod.
+	volumes = append(volumes,
+		// Add trusted CA bundle
+		corev1.Volume{
+			Name: volumeName,
+			VolumeSource: corev1.VolumeSource{
+				ConfigMap: &corev1.ConfigMapVolumeSource{
+					LocalObjectReference: corev1.LocalObjectReference{Name: configmapName},
+					Items: []corev1.KeyToPath{
+						{
+							Key:  key,
+							Path: key,
+						},
+					},
+				},
+			},
+		},
+	)
+	pod.Spec.Volumes = volumes
+
+	// Now that the injected certificates have been added as a volume, let's
+	// mount them via volumeMounts in the containers
+	for i, c := range pod.Spec.Containers {
+		volumeMounts := c.VolumeMounts
+
+		// If volume mounts for injected certificates already exist then remove them
+		for i, vm := range volumeMounts {
+			if vm.Name == volumeName {
+				volumeMounts = append(volumeMounts[:i], volumeMounts[i+1:]...)
+				break
+			}
+		}
+
+		// /etc/ssl/certs is the default place where CA certs reside in *nix
+		// however this can be overridden using SSL_CERT_DIR, let's check for
+		// that here.
+		sslCertDir := "/etc/ssl/certs"
+		for _, env := range c.Env {
+			if env.Name == "SSL_CERT_DIR" {
+				sslCertDir = env.Value
+			}
+		}
+
+		// Let's mount the certificates now.
+		volumeMounts = append(volumeMounts,
+			corev1.VolumeMount{
+				Name:      volumeName,
+				MountPath: filepath.Join(sslCertDir, key),
+				SubPath:   key,
+				ReadOnly:  true,
+			},
+		)
+		c.VolumeMounts = volumeMounts
+		pod.Spec.Containers[i] = c
+	}
+	return pod
+}
+
 // updateAndMergeEnv will merge two slices of env
 // precedence will be given to second input if exist with same name key
 func updateAndMergeEnv(containerenvs []corev1.EnvVar, proxyEnv []corev1.EnvVar) []corev1.EnvVar {


Test patch:
diff --git a/pkg/reconciler/proxy/proxy_test.go b/pkg/reconciler/proxy/proxy_test.go
new file mode 100644
index 000000000..de3020b32
--- /dev/null
+++ b/pkg/reconciler/proxy/proxy_test.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2020 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package proxy
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+	v1 "k8s.io/api/core/v1"
+)
+
+func TestUpdateVolume(t *testing.T) {
+	pod := v1.Pod{
+		Spec: v1.PodSpec{
+			Volumes: []v1.Volume{},
+			Containers: []v1.Container{
+				{
+					Name:  "testc",
+					Image: "testi",
+				},
+			},
+		},
+	}
+	podUpdated := updateVolume(pod, "testv", "testcm", "testkey")
+	assert.DeepEqual(t, len(podUpdated.Spec.Volumes), 1)
+	assert.DeepEqual(t, podUpdated.Spec.Volumes[0].Name, "testv")
+	assert.DeepEqual(t, podUpdated.Spec.Volumes[0].ConfigMap.Name, "testcm")
+	assert.DeepEqual(t, len(podUpdated.Spec.Containers[0].VolumeMounts), 1)
+	assert.DeepEqual(t, podUpdated.Spec.Containers[0].VolumeMounts[0].Name, "testv")
+	assert.DeepEqual(t, podUpdated.Spec.Containers[0].VolumeMounts[0].SubPath, "testkey")
+}