Repository: tektoncd/operator
Pull request #648 (2022-03-03 15:25:52)

Mount CA bundles in Tekton components as well
# Changes

Prior to this commit, the CA bundles were:
- mounted inside containers
- exposed via VolumeMounts and SSL_CERT_DIR
only in TaskRun pods via `pkg/reconciler/proxy/proxy.go` but were not
exposed in Tekton components controllers like pipelines, triggers and
chains via `pkg/reconciler/openshift/common/cabundle.go`.

This meant that these Tekton components could not talk to internal
OpenShift services or to hosts for which users added certificates to the
cluster via CA bundles.

One case where this is a problem is when the Chains controller wants to
pull images from the internal OpenShift registry to sign and then push
the signatures, attestations back to it since it does not have access to
the Service CA Bundle.

This commit abstracts away the exposure of certificates via Volumes,
VolumeMounts and SSL_CERT_DIR in `pkg/reconciler/common/certificates.go`
and makes this behavior the same for both TaskRuns and controllers which
want to mount these certificates.
# 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)
- [x] 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-note
NONE
```

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 **vdemeester**
You can assign the PR to them by writing `/assign @vdemeester` 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":["vdemeester"]} -->
tekton-robot: @concaf: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-unit-tests | 3640c3530f7a330421cc96efbc062ce31e24865c | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-unit-tests/1499405844599541760/) | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | 3640c3530f7a330421cc96efbc062ce31e24865c | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-build-tests/1499405844599541761/) | `/test pull-tekton-operator-build-tests`

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

<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: @concaf: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-unit-tests | 3640c3530f7a330421cc96efbc062ce31e24865c | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-unit-tests/1499405844599541760/) | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | 3640c3530f7a330421cc96efbc062ce31e24865c | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-build-tests/1499405844599541761/) | `/test pull-tekton-operator-build-tests`

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

<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/common/certificates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499652596518883329/artifacts/line-cov.html#file0) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/common/cabundle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499652596518883329/artifacts/line-cov.html#file1) | 67.5% | 77.3% | 9.8

tekton-robot: @concaf: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-build-tests | 3640c3530f7a330421cc96efbc062ce31e24865c | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-build-tests/1499405844599541761/) | `/test pull-tekton-operator-build-tests`
pull-tekton-operator-unit-tests | 76b14311bd6894fa5a50abd9233b3a97559d75ba | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-unit-tests/1499652596518883330/) | `/test pull-tekton-operator-unit-tests`

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

<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: @concaf: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-unit-tests | 76b14311bd6894fa5a50abd9233b3a97559d75ba | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-unit-tests/1499652596518883330/) | `/test pull-tekton-operator-unit-tests`

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

<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: @concaf: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-unit-tests | 76b14311bd6894fa5a50abd9233b3a97559d75ba | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-unit-tests/1499652596518883330/) | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | 76b14311bd6894fa5a50abd9233b3a97559d75ba | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-build-tests/1499652596518883328/) | `/test pull-tekton-operator-build-tests`

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

<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: @concaf: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-unit-tests | 76b14311bd6894fa5a50abd9233b3a97559d75ba | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-unit-tests/1499652596518883330/) | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | 76b14311bd6894fa5a50abd9233b3a97559d75ba | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-build-tests/1499652596518883328/) | `/test pull-tekton-operator-build-tests`

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

<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/common/certificates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499657755105955840/artifacts/line-cov.html#file0) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/common/cabundle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499657755105955840/artifacts/line-cov.html#file1) | 67.5% | 77.3% | 9.8
[pkg/reconciler/proxy/proxy.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499657755105955840/artifacts/line-cov.html#file2) | 11.2% | 3.7% | -7.6

tekton-robot: @concaf: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-integration-tests | 8a95b19a9f25fcf36b4c080ba0bed6145442b174 | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-integration-tests/1499657755105955843/) | `/test pull-tekton-operator-integration-tests`

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

<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: @concaf: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-tekton-operator-integration-tests | 8a95b19a9f25fcf36b4c080ba0bed6145442b174 | [link](https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-integration-tests/1499657755105955843/) | `/test pull-tekton-operator-integration-tests`

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

<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 -->
concaf: /retest
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/common/certificates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499675119822311425/artifacts/line-cov.html#file0) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/common/cabundle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499675119822311425/artifacts/line-cov.html#file1) | 67.5% | 77.3% | 9.8
[pkg/reconciler/proxy/proxy.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499675119822311425/artifacts/line-cov.html#file2) | 11.2% | 3.7% | -7.6

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/common/certificates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499711484077281281/artifacts/line-cov.html#file0) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/common/cabundle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499711484077281281/artifacts/line-cov.html#file1) | 67.5% | 77.3% | 9.8
[pkg/reconciler/proxy/proxy.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/648/pull-tekton-operator-go-coverage/1499711484077281281/artifacts/line-cov.html#file2) | 11.2% | 3.7% | -7.6

sm43: LGTM :)

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

This pull-request has been approved by: *<a href="https://github.com/tektoncd/operator/pull/648#pullrequestreview-900139520" title="Approved">vdemeester</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)~~ [vdemeester]

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: /lgtm

Patch:
diff --git a/pkg/reconciler/common/certificates.go b/pkg/reconciler/common/certificates.go
new file mode 100644
index 000000000..391786793
--- /dev/null
+++ b/pkg/reconciler/common/certificates.go
@@ -0,0 +1,153 @@
+/*
+Copyright 2022 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 common
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	"path/filepath"
+	"strings"
+)
+
+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"
+)
+
+// newVolumeWithConfigMap creates a new volume with the given ConfigMap
+func newVolumeWithConfigMap(volumeName, configMapName, configMapKey, configMapPath string) corev1.Volume {
+	return corev1.Volume{
+		Name: volumeName,
+		VolumeSource: corev1.VolumeSource{
+			ConfigMap: &corev1.ConfigMapVolumeSource{
+				LocalObjectReference: corev1.LocalObjectReference{Name: configMapName},
+				Items: []corev1.KeyToPath{
+					{
+						Key:  configMapKey,
+						Path: configMapPath,
+					},
+				},
+			},
+		},
+	}
+}
+
+// AddCABundleConfigMapsToVolumes adds the config-trusted-cabundle and config-service-cabundle
+// ConfigMaps to the given list of volumes and removes duplicates, if any
+func AddCABundleConfigMapsToVolumes(volumes []corev1.Volume) []corev1.Volume {
+	// If CA bundle volumes already exists in the pod's volumes, then remove it
+	for _, volumeName := range []string{TrustedCAConfigMapVolume, ServiceCAConfigMapVolume} {
+		for i, v := range volumes {
+			if v.Name == volumeName {
+				volumes = append(volumes[:i], volumes[i+1:]...)
+				break
+			}
+		}
+	}
+
+	return append(
+		volumes,
+		newVolumeWithConfigMap(TrustedCAConfigMapVolume, TrustedCAConfigMapName, TrustedCAKey, TrustedCAKey),
+		newVolumeWithConfigMap(ServiceCAConfigMapVolume, ServiceCAConfigMapName, ServiceCAKey, ServiceCAKey),
+	)
+}
+
+// AddCABundlesToContainerVolumes adds the CA bundles to the container via VolumeMounts.
+// SSL_CERT_DIR environment variable is also set if it does not exist already.
+func AddCABundlesToContainerVolumes(c *corev1.Container) {
+	volumeMounts := c.VolumeMounts
+
+	// If volume mounts for CA bundles already exist then remove them
+	for _, volumeName := range []string{TrustedCAConfigMapVolume, ServiceCAConfigMapVolume} {
+		for i, vm := range volumeMounts {
+			if vm.Name == volumeName {
+				volumeMounts = append(volumeMounts[:i], volumeMounts[i+1:]...)
+				break
+			}
+		}
+	}
+
+	// We will mount the certs at /tekton-custom-certs so we don't override the existing certs
+	sslCertDir := "/tekton-custom-certs"
+	certEnvAvailable := false
+
+	for _, env := range c.Env {
+		// If SSL_CERT_DIR env var already exists, then we don't mess with
+		// it and simply carry it forward as it is
+		if env.Name == "SSL_CERT_DIR" {
+			sslCertDir = env.Value
+			certEnvAvailable = true
+			break
+		}
+	}
+
+	if !certEnvAvailable {
+		// Here, we need to set the default value for SSL_CERT_DIR.
+		// Keep in mind that if SSL_CERT_DIR is set, then it overrides the
+		// system default, i.e. the system default directories will "NOT"
+		// be scanned for certificates. This is risky and we don't want to
+		// do this because users mount certificates at these locations or
+		// build images with certificates "in" them and expect certificates
+		// to get picked up, and rightfully so since this is the documented
+		// way of achieving this.
+		// So, let's keep the system wide default locations in place and
+		// "append" our custom location to those.
+		//
+		// certDirectories copied from
+		// https://golang.org/src/crypto/x509/root_linux.go
+		var certDirectories = []string{
+			// Ordering is important here - we will be using the "first"
+			// element in SSL_CERT_DIR to do the volume mounts.
+			sslCertDir,                     // /tekton-custom-certs
+			"/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
+			"/etc/pki/tls/certs",           // Fedora/RHEL
+			"/system/etc/security/cacerts", // Android
+		}
+
+		// SSL_CERT_DIR accepts a colon separated list of directories
+		sslCertDir = strings.Join(certDirectories, ":")
+		c.Env = append(c.Env, corev1.EnvVar{
+			Name:  "SSL_CERT_DIR",
+			Value: sslCertDir,
+		})
+	}
+
+	// Let's mount the certificates now.
+	volumeMounts = append(volumeMounts,
+		corev1.VolumeMount{
+			Name: TrustedCAConfigMapVolume,
+			// We only want the first entry in SSL_CERT_DIR for the mount
+			MountPath: filepath.Join(strings.Split(sslCertDir, ":")[0], TrustedCAKey),
+			SubPath:   TrustedCAKey,
+			ReadOnly:  true,
+		},
+		corev1.VolumeMount{
+			Name: ServiceCAConfigMapVolume,
+			// We only want the first entry in SSL_CERT_DIR for the mount
+			MountPath: filepath.Join(strings.Split(sslCertDir, ":")[0], ServiceCAKey),
+			SubPath:   ServiceCAKey,
+			ReadOnly:  true,
+		},
+	)
+	c.VolumeMounts = volumeMounts
+}
diff --git a/pkg/reconciler/openshift/common/cabundle.go b/pkg/reconciler/openshift/common/cabundle.go
index f6252c0bf..15a10f543 100644
--- a/pkg/reconciler/openshift/common/cabundle.go
+++ b/pkg/reconciler/openshift/common/cabundle.go
@@ -18,28 +18,14 @@ package common
 
 import (
 	"encoding/json"
-	"path/filepath"
-	"strings"
 
+	"github.com/tektoncd/operator/pkg/reconciler/common"
 	appsv1 "k8s.io/api/apps/v1"
-	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/client-go/kubernetes/scheme"
 )
 
-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"
-)
-
 // ApplyCABundles is a transformer that add the trustedCA volume, mount and
 // environment variables so that the deployment uses it.
 func ApplyCABundles(u *unstructured.Unstructured) error {
@@ -53,94 +39,14 @@ func ApplyCABundles(u *unstructured.Unstructured) error {
 		return err
 	}
 
-	volumes := deployment.Spec.Template.Spec.Volumes
-
-	// If CA bundle volumes already exists in the PodSpec, then remove it
-	for _, volumeName := range []string{trustedCAConfigMapVolume, serviceCAConfigMapVolume} {
-		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: trustedCAConfigMapVolume,
-			VolumeSource: corev1.VolumeSource{
-				ConfigMap: &corev1.ConfigMapVolumeSource{
-					LocalObjectReference: corev1.LocalObjectReference{Name: trustedCAConfigMapName},
-					Items: []corev1.KeyToPath{
-						{
-							Key:  trustedCAKey,
-							Path: trustedCAKey,
-						},
-					},
-				},
-			},
-		},
-		// Add service serving certificates bundle
-		corev1.Volume{
-			Name: serviceCAConfigMapVolume,
-			VolumeSource: corev1.VolumeSource{
-				ConfigMap: &corev1.ConfigMapVolumeSource{
-					LocalObjectReference: corev1.LocalObjectReference{Name: serviceCAConfigMapName},
-					Items: []corev1.KeyToPath{
-						{
-							Key:  serviceCAKey,
-							Path: serviceCAKey,
-						},
-					},
-				},
-			},
-		})
-	deployment.Spec.Template.Spec.Volumes = volumes
+	deployment.Spec.Template.Spec.Volumes = common.AddCABundleConfigMapsToVolumes(deployment.Spec.Template.Spec.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 deployment.Spec.Template.Spec.Containers {
-		volumeMounts := c.VolumeMounts
-
-		// If volume mounts for injected certificates already exist then remove them
-		for _, volumeName := range []string{trustedCAConfigMapVolume, serviceCAConfigMapVolume} {
-			for i, vm := range volumeMounts {
-				if vm.Name == volumeName {
-					volumeMounts = append(volumeMounts[:i], volumeMounts[i+1:]...)
-					break
-				}
-			}
-		}
-
-		// We will mount the certs at this location so we don't override the existing certs
-		sslCertDir := "/tekton-custom-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: trustedCAConfigMapVolume,
-				// We only want the first entry in SSL_CERT_DIR for the mount
-				MountPath: filepath.Join(strings.Split(sslCertDir, ":")[0], trustedCAKey),
-				SubPath:   trustedCAKey,
-				ReadOnly:  true,
-			},
-			corev1.VolumeMount{
-				Name: serviceCAConfigMapVolume,
-				// We only want the first entry in SSL_CERT_DIR for the mount
-				MountPath: filepath.Join(strings.Split(sslCertDir, ":")[0], serviceCAKey),
-				SubPath:   serviceCAKey,
-				ReadOnly:  true,
-			},
-		)
-		c.VolumeMounts = volumeMounts
+		common.AddCABundlesToContainerVolumes(&c)
 		deployment.Spec.Template.Spec.Containers[i] = c
 	}
 
diff --git a/pkg/reconciler/proxy/proxy.go b/pkg/reconciler/proxy/proxy.go
index 2ca6ce1e6..794a0d2ca 100644
--- a/pkg/reconciler/proxy/proxy.go
+++ b/pkg/reconciler/proxy/proxy.go
@@ -21,8 +21,8 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
 	"os"
-	"path/filepath"
 	"strings"
 
 	"github.com/markbates/inflect"
@@ -50,18 +50,6 @@ 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
@@ -319,22 +307,17 @@ func setDefaults(client kubernetes.Interface, ctx context.Context, patches duck.
 		}
 	}
 
-	exist, err := checkConfigMapExist(client, ctx, after.Namespace, trustedCAConfigMapName)
+	trustedConfigMapExists, err := checkConfigMapExist(client, ctx, after.Namespace, common.TrustedCAConfigMapName)
 	if err != nil {
 		return nil, err
 	}
-	if exist {
-		after = updateVolume(after, trustedCAConfigMapVolume, trustedCAConfigMapName, trustedCAKey)
-	}
-
-	exist, err = checkConfigMapExist(client, ctx, after.Namespace, serviceCAConfigMapName)
+	serviceConfigMapExists, err := checkConfigMapExist(client, ctx, after.Namespace, common.ServiceCAConfigMapName)
 	if err != nil {
 		return nil, err
 	}
-	if exist {
-		after = updateVolume(after, serviceCAConfigMapVolume, serviceCAConfigMapName, serviceCAKey)
+	if trustedConfigMapExists && serviceConfigMapExists {
+		after = updateVolume(after)
 	}
-
 	patch, err := duck.CreatePatch(before, after)
 	if err != nil {
 		return nil, err
@@ -358,104 +341,15 @@ func checkConfigMapExist(client kubernetes.Interface, ctx context.Context, ns st
 }
 
 // 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
-		}
-	}
-
+func updateVolume(pod corev1.Pod) corev1.Pod {
 	// 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
+	// the PodSpec which will later be mounted to add certs in the pod
+	pod.Spec.Volumes = common.AddCABundleConfigMapsToVolumes(pod.Spec.Volumes)
 
-	// Now that the injected certificates have been added as a volume, let's
-	// mount them via volumeMounts in the containers
+	// Now that the ConfigMaps have been added as volumes, 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
-			}
-		}
-
-		// We will mount the certs at this location so we don't override the existing certs
-		sslCertDir := "/tekton-custom-certs"
-		certEnvAvaiable := false
-
-		for _, env := range c.Env {
-			// If SSL_CERT_DIR env var already exists, then we don't mess with
-			// it and simply carry it forward as it is
-			if env.Name == "SSL_CERT_DIR" {
-				sslCertDir = env.Value
-				certEnvAvaiable = true
-			}
-		}
-
-		if !certEnvAvaiable {
-			// Here, we need to set the default value for SSL_CERT_DIR.
-			// Keep in mind that if SSL_CERT_DIR is set, then it overrides the
-			// system default, i.e. the system default directories will "NOT"
-			// be scanned for certificates. This is risky and we don't want to
-			// do this because users mount certificates at these locations or
-			// build images with certificates "in" them and expect certificates
-			// to get picked up, and rightfully so since this is the documented
-			// way of achieving this.
-			// So, let's keep the system wide default locations in place and
-			// "append" our custom location to those.
-			//
-			// Copied from https://golang.org/src/crypto/x509/root_linux.go
-			var certDirectories = []string{
-				// Ordering is important here - we will be using the "first"
-				// element in SSL_CERT_DIR to do the volume mounts.
-				sslCertDir,                     // /tekton-custom-certs
-				"/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
-				"/etc/pki/tls/certs",           // Fedora/RHEL
-				"/system/etc/security/cacerts", // Android
-			}
-
-			// SSL_CERT_DIR accepts a colon separated list of directories
-			sslCertDir = strings.Join(certDirectories, ":")
-			c.Env = append(c.Env, corev1.EnvVar{
-				Name:  "SSL_CERT_DIR",
-				Value: sslCertDir,
-			})
-		}
-
-		// Let's mount the certificates now.
-		volumeMounts = append(volumeMounts,
-			corev1.VolumeMount{
-				Name: volumeName,
-				// We only want the first entry in SSL_CERT_DIR for the mount
-				MountPath: filepath.Join(strings.Split(sslCertDir, ":")[0], key),
-				SubPath:   key,
-				ReadOnly:  true,
-			},
-		)
-		c.VolumeMounts = volumeMounts
+		common.AddCABundlesToContainerVolumes(&c)
 		pod.Spec.Containers[i] = c
 	}
 	return pod


Test patch:
diff --git a/pkg/reconciler/openshift/common/cabundle_test.go b/pkg/reconciler/openshift/common/cabundle_test.go
index ca0b87892..226f3c599 100644
--- a/pkg/reconciler/openshift/common/cabundle_test.go
+++ b/pkg/reconciler/openshift/common/cabundle_test.go
@@ -18,6 +18,7 @@ package common
 
 import (
 	"encoding/json"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
 	"path/filepath"
 	"testing"
 
@@ -32,29 +33,35 @@ import (
 func TestApplyCABundles(t *testing.T) {
 	actual := unstructuredDeployment(t)
 	expected := unstructuredDeployment(t,
+		withEnvs(
+			corev1.EnvVar{
+				Name:  "SSL_CERT_DIR",
+				Value: "/tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts",
+			},
+		),
 		withVolumes(corev1.Volume{
-			Name: trustedCAConfigMapVolume,
+			Name: common.TrustedCAConfigMapVolume,
 			VolumeSource: corev1.VolumeSource{
 				ConfigMap: &corev1.ConfigMapVolumeSource{
-					LocalObjectReference: corev1.LocalObjectReference{Name: trustedCAConfigMapName},
+					LocalObjectReference: corev1.LocalObjectReference{Name: common.TrustedCAConfigMapName},
 					Items: []corev1.KeyToPath{
 						{
-							Key:  trustedCAKey,
-							Path: trustedCAKey,
+							Key:  common.TrustedCAKey,
+							Path: common.TrustedCAKey,
 						},
 					},
 				},
 			},
 		},
 			corev1.Volume{
-				Name: serviceCAConfigMapVolume,
+				Name: common.ServiceCAConfigMapVolume,
 				VolumeSource: corev1.VolumeSource{
 					ConfigMap: &corev1.ConfigMapVolumeSource{
-						LocalObjectReference: corev1.LocalObjectReference{Name: serviceCAConfigMapName},
+						LocalObjectReference: corev1.LocalObjectReference{Name: common.ServiceCAConfigMapName},
 						Items: []corev1.KeyToPath{
 							{
-								Key:  serviceCAKey,
-								Path: serviceCAKey,
+								Key:  common.ServiceCAKey,
+								Path: common.ServiceCAKey,
 							},
 						},
 					},
@@ -62,15 +69,15 @@ func TestApplyCABundles(t *testing.T) {
 			}),
 		withVolumeMounts(
 			corev1.VolumeMount{
-				Name:      trustedCAConfigMapVolume,
-				MountPath: filepath.Join("/tekton-custom-certs", trustedCAKey),
-				SubPath:   trustedCAKey,
+				Name:      common.TrustedCAConfigMapVolume,
+				MountPath: filepath.Join("/tekton-custom-certs", common.TrustedCAKey),
+				SubPath:   common.TrustedCAKey,
 				ReadOnly:  true,
 			},
 			corev1.VolumeMount{
-				Name:      serviceCAConfigMapVolume,
-				MountPath: filepath.Join("/tekton-custom-certs", serviceCAKey),
-				SubPath:   serviceCAKey,
+				Name:      common.ServiceCAConfigMapVolume,
+				MountPath: filepath.Join("/tekton-custom-certs", common.ServiceCAKey),
+				SubPath:   common.ServiceCAKey,
 				ReadOnly:  true,
 			},
 		),
@@ -133,6 +140,15 @@ func unstructuredDeployment(t *testing.T, modifiers ...deploymentModifier) *unst
 	return ud
 }
 
+func withEnvs(envs ...corev1.EnvVar) func(*appsv1.Deployment) {
+	return func(d *appsv1.Deployment) {
+		for i, c := range d.Spec.Template.Spec.Containers {
+			c.Env = append(c.Env, envs...)
+			d.Spec.Template.Spec.Containers[i] = c
+		}
+	}
+}
+
 func withVolumes(volumes ...corev1.Volume) func(*appsv1.Deployment) {
 	return func(d *appsv1.Deployment) {
 		d.Spec.Template.Spec.Volumes = append(d.Spec.Template.Spec.Volumes, volumes...)
diff --git a/pkg/reconciler/proxy/proxy_test.go b/pkg/reconciler/proxy/proxy_test.go
index c626cb97c..57a3f4024 100644
--- a/pkg/reconciler/proxy/proxy_test.go
+++ b/pkg/reconciler/proxy/proxy_test.go
@@ -35,14 +35,20 @@ func TestUpdateVolume(t *testing.T) {
 			},
 		},
 	}
-	podUpdated := updateVolume(pod, "testv", "testcm", "testkey")
-	assert.DeepEqual(t, len(podUpdated.Spec.Volumes), 1)
+	podUpdated := updateVolume(pod)
 	assert.DeepEqual(t, len(podUpdated.Spec.Containers[0].Env), 1)
 	assert.DeepEqual(t, podUpdated.Spec.Containers[0].Env[0].Name, "SSL_CERT_DIR")
 	assert.DeepEqual(t, podUpdated.Spec.Containers[0].Env[0].Value, "/tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts")
-	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")
+
+	assert.DeepEqual(t, len(podUpdated.Spec.Volumes), 2)
+	assert.DeepEqual(t, podUpdated.Spec.Volumes[0].Name, "config-trusted-cabundle-volume")
+	assert.DeepEqual(t, podUpdated.Spec.Volumes[0].ConfigMap.Name, "config-trusted-cabundle")
+	assert.DeepEqual(t, podUpdated.Spec.Volumes[1].Name, "config-service-cabundle-volume")
+	assert.DeepEqual(t, podUpdated.Spec.Volumes[1].ConfigMap.Name, "config-service-cabundle")
+
+	assert.DeepEqual(t, len(podUpdated.Spec.Containers[0].VolumeMounts), 2)
+	assert.DeepEqual(t, podUpdated.Spec.Containers[0].VolumeMounts[0].Name, "config-trusted-cabundle-volume")
+	assert.DeepEqual(t, podUpdated.Spec.Containers[0].VolumeMounts[0].SubPath, "ca-bundle.crt")
+	assert.DeepEqual(t, podUpdated.Spec.Containers[0].VolumeMounts[1].Name, "config-service-cabundle-volume")
+	assert.DeepEqual(t, podUpdated.Spec.Containers[0].VolumeMounts[1].SubPath, "service-ca.crt")
 }