Skip to content

Commit 23458cd

Browse files
committed
OCPBUGS-59768: metrics endpoints security - add client cert auth to kube-rbac-proxy
**Problem:** OLM metrics endpoints were exposed without proper authentication, allowing unauthorized access to sensitive operational data. **Root Cause:** kube-rbac-proxy configuration was missing critical authentication argument `--client-ca-file` **Solution:** - Add missing authentication argument to kube-rbac-proxy in package-server-manager - Mount client CA certificate from new `metrics-client-ca` ConfigMap - Update ServiceMonitors to use `scrapeClass: tls-client-certificate-auth` - Create ConfigMap with service CA injection for automatic CA bundle sync **Security Impact:** - **Before:** Any HTTPS client could access metrics endpoints - **After:** Only authorized Prometheus service account (`system:serviceaccount:openshift-monitoring:prometheus-k8s`) can access metrics
1 parent e53cf30 commit 23458cd

23 files changed

+1071
-46
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRole
3+
metadata:
4+
name: system:openshift:operator:olm-extension-apiserver-authentication
5+
annotations:
6+
include.release.openshift.io/self-managed-high-availability: "true"
7+
include.release.openshift.io/ibm-cloud-managed: "true"
8+
capability.openshift.io/name: "OperatorLifecycleManager"
9+
include.release.openshift.io/hypershift: "true"
10+
rules:
11+
- apiGroups: [""]
12+
resources: ["configmaps"]
13+
resourceNames: ["extension-apiserver-authentication"]
14+
verbs: ["get", "list", "watch"]
15+
---
16+
apiVersion: rbac.authorization.k8s.io/v1
17+
kind: ClusterRoleBinding
18+
metadata:
19+
name: system:openshift:operator:olm-extension-apiserver-authentication
20+
annotations:
21+
include.release.openshift.io/self-managed-high-availability: "true"
22+
include.release.openshift.io/ibm-cloud-managed: "true"
23+
capability.openshift.io/name: "OperatorLifecycleManager"
24+
include.release.openshift.io/hypershift: "true"
25+
roleRef:
26+
apiGroup: rbac.authorization.k8s.io
27+
kind: ClusterRole
28+
name: system:openshift:operator:olm-extension-apiserver-authentication
29+
subjects:
30+
- kind: ServiceAccount
31+
name: olm-operator-serviceaccount
32+
namespace: openshift-operator-lifecycle-manager
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: extension-apiserver-authentication
5+
namespace: openshift-operator-lifecycle-manager
6+
annotations:
7+
include.release.openshift.io/self-managed-high-availability: "true"
8+
include.release.openshift.io/ibm-cloud-managed: "true"
9+
capability.openshift.io/name: "OperatorLifecycleManager"
10+
include.release.openshift.io/hypershift: "true"
11+
data:
12+
client-ca-file: ""

manifests/0000_50_olm_03-services.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ spec:
1717
- name: https-metrics
1818
port: 8443
1919
protocol: TCP
20-
targetPort: 8443
20+
targetPort: https-metrics
2121
selector:
2222
app: olm-operator
2323
---
@@ -40,6 +40,6 @@ spec:
4040
- name: https-metrics
4141
port: 8443
4242
protocol: TCP
43-
targetPort: 8443
43+
targetPort: https-metrics
4444
selector:
4545
app: catalog-operator

manifests/0000_50_olm_06-psm-operator.deployment.ibm-cloud-managed.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,46 @@ spec:
2929
type: RuntimeDefault
3030
serviceAccountName: olm-operator-serviceaccount
3131
priorityClassName: "system-cluster-critical"
32+
initContainers:
33+
- name: copy-extension-apiserver-authentication
34+
image: quay.io/openshift/origin-cli:latest
35+
command:
36+
- /bin/sh
37+
- -c
38+
- |
39+
set -euo pipefail
40+
echo "Copying extension-apiserver-authentication ConfigMap data..."
41+
42+
# Get the client-ca-file from kube-system/extension-apiserver-authentication
43+
# This must succeed or the deployment should fail
44+
CLIENT_CA_DATA=$(oc get configmap extension-apiserver-authentication -n kube-system -o jsonpath='{.data.client-ca-file}')
45+
46+
if [ -z "$CLIENT_CA_DATA" ]; then
47+
echo "ERROR: client-ca-file is empty in kube-system/extension-apiserver-authentication ConfigMap"
48+
echo "Cannot proceed without valid client CA certificate"
49+
exit 1
50+
fi
51+
52+
echo "Retrieved client CA data (${#CLIENT_CA_DATA} bytes)"
53+
54+
# Update our local ConfigMap with the client CA data
55+
# Use --from-literal to avoid JSON escaping issues with newlines
56+
oc create configmap extension-apiserver-authentication -n openshift-operator-lifecycle-manager --from-literal=client-ca-file="$CLIENT_CA_DATA" --dry-run=client -o yaml | oc apply -f -
57+
58+
echo "Successfully updated extension-apiserver-authentication ConfigMap"
59+
securityContext:
60+
allowPrivilegeEscalation: false
61+
readOnlyRootFilesystem: true
62+
runAsNonRoot: true
63+
capabilities:
64+
drop: ["ALL"]
3265
containers:
3366
- args:
3467
- --secure-listen-address=0.0.0.0:8443
3568
- --upstream=http://127.0.0.1:9090/
3669
- --tls-cert-file=/etc/tls/private/tls.crt
3770
- --tls-private-key-file=/etc/tls/private/tls.key
71+
- --client-ca-file=/etc/tls/client/client-ca-file
3872
- --logtostderr=true
3973
image: quay.io/openshift/origin-kube-rbac-proxy:latest
4074
imagePullPolicy: IfNotPresent
@@ -57,6 +91,9 @@ spec:
5791
volumeMounts:
5892
- mountPath: /etc/tls/private
5993
name: package-server-manager-serving-cert
94+
- mountPath: /etc/tls/client
95+
name: extension-apiserver-authentication
96+
readOnly: true
6097
- name: package-server-manager
6198
securityContext:
6299
allowPrivilegeEscalation: false
@@ -120,3 +157,6 @@ spec:
120157
- name: package-server-manager-serving-cert
121158
secret:
122159
secretName: package-server-manager-serving-cert
160+
- name: extension-apiserver-authentication
161+
configMap:
162+
name: extension-apiserver-authentication

manifests/0000_50_olm_06-psm-operator.deployment.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,46 @@ spec:
2929
type: RuntimeDefault
3030
serviceAccountName: olm-operator-serviceaccount
3131
priorityClassName: "system-cluster-critical"
32+
initContainers:
33+
- name: copy-extension-apiserver-authentication
34+
image: quay.io/openshift/origin-cli:latest
35+
command:
36+
- /bin/sh
37+
- -c
38+
- |
39+
set -euo pipefail
40+
echo "Copying extension-apiserver-authentication ConfigMap data..."
41+
42+
# Get the client-ca-file from kube-system/extension-apiserver-authentication
43+
# This must succeed or the deployment should fail
44+
CLIENT_CA_DATA=$(oc get configmap extension-apiserver-authentication -n kube-system -o jsonpath='{.data.client-ca-file}')
45+
46+
if [ -z "$CLIENT_CA_DATA" ]; then
47+
echo "ERROR: client-ca-file is empty in kube-system/extension-apiserver-authentication ConfigMap"
48+
echo "Cannot proceed without valid client CA certificate"
49+
exit 1
50+
fi
51+
52+
echo "Retrieved client CA data (${#CLIENT_CA_DATA} bytes)"
53+
54+
# Update our local ConfigMap with the client CA data
55+
# Use --from-literal to avoid JSON escaping issues with newlines
56+
oc create configmap extension-apiserver-authentication -n openshift-operator-lifecycle-manager --from-literal=client-ca-file="$CLIENT_CA_DATA" --dry-run=client -o yaml | oc apply -f -
57+
58+
echo "Successfully updated extension-apiserver-authentication ConfigMap"
59+
securityContext:
60+
allowPrivilegeEscalation: false
61+
readOnlyRootFilesystem: true
62+
runAsNonRoot: true
63+
capabilities:
64+
drop: ["ALL"]
3265
containers:
3366
- args:
3467
- --secure-listen-address=0.0.0.0:8443
3568
- --upstream=http://127.0.0.1:9090/
3669
- --tls-cert-file=/etc/tls/private/tls.crt
3770
- --tls-private-key-file=/etc/tls/private/tls.key
71+
- --client-ca-file=/etc/tls/client/client-ca-file
3872
- --logtostderr=true
3973
image: quay.io/openshift/origin-kube-rbac-proxy:latest
4074
imagePullPolicy: IfNotPresent
@@ -57,6 +91,9 @@ spec:
5791
volumeMounts:
5892
- mountPath: /etc/tls/private
5993
name: package-server-manager-serving-cert
94+
- mountPath: /etc/tls/client
95+
name: extension-apiserver-authentication
96+
readOnly: true
6097
- name: package-server-manager
6198
securityContext:
6299
allowPrivilegeEscalation: false
@@ -121,3 +158,6 @@ spec:
121158
- name: package-server-manager-serving-cert
122159
secret:
123160
secretName: package-server-manager-serving-cert
161+
- name: extension-apiserver-authentication
162+
configMap:
163+
name: extension-apiserver-authentication

manifests/0000_50_olm_07-olm-operator.deployment.ibm-cloud-managed.yaml

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ spec:
3838
secretName: pprof-cert
3939
- name: tmpfs
4040
emptyDir: {}
41+
- name: olm-operator-serving-cert
42+
secret:
43+
secretName: olm-operator-serving-cert
44+
- name: extension-apiserver-authentication
45+
configMap:
46+
name: extension-apiserver-authentication
4147
containers:
4248
- name: olm-operator
4349
securityContext:
@@ -74,18 +80,18 @@ spec:
7480
image: quay.io/operator-framework/olm@sha256:de396b540b82219812061d0d753440d5655250c621c753ed1dc67d6154741607
7581
imagePullPolicy: IfNotPresent
7682
ports:
77-
- containerPort: 8443
83+
- containerPort: 9090
7884
name: metrics
7985
livenessProbe:
8086
httpGet:
8187
path: /healthz
82-
port: 8443
83-
scheme: HTTPS
88+
port: 9090
89+
scheme: HTTP
8490
readinessProbe:
8591
httpGet:
8692
path: /healthz
87-
port: 8443
88-
scheme: HTTPS
93+
port: 9090
94+
scheme: HTTP
8995
terminationMessagePolicy: FallbackToLogsOnError
9096
env:
9197
- name: OPERATOR_NAMESPACE
@@ -100,6 +106,30 @@ spec:
100106
requests:
101107
cpu: 10m
102108
memory: 160Mi
109+
- name: kube-rbac-proxy
110+
image: quay.io/openshift/origin-kube-rbac-proxy:latest
111+
args:
112+
- --secure-listen-address=0.0.0.0:8443
113+
- --upstream=http://127.0.0.1:9090/
114+
- --tls-cert-file=/etc/tls/private/tls.crt
115+
- --tls-private-key-file=/etc/tls/private/tls.key
116+
- --client-ca-file=/etc/tls/client/client-ca-file
117+
- --logtostderr=true
118+
ports:
119+
- containerPort: 8443
120+
name: https-metrics
121+
securityContext:
122+
allowPrivilegeEscalation: false
123+
readOnlyRootFilesystem: true
124+
runAsNonRoot: true
125+
capabilities:
126+
drop: ["ALL"]
127+
volumeMounts:
128+
- mountPath: /etc/tls/private
129+
name: olm-operator-serving-cert
130+
- mountPath: /etc/tls/client
131+
name: extension-apiserver-authentication
132+
readOnly: true
103133
nodeSelector:
104134
kubernetes.io/os: linux
105135
tolerations:
@@ -115,3 +145,37 @@ spec:
115145
operator: Exists
116146
tolerationSeconds: 120
117147
priorityClassName: system-cluster-critical
148+
initContainers:
149+
- name: copy-extension-apiserver-authentication
150+
image: quay.io/openshift/origin-cli:latest
151+
command:
152+
- /bin/sh
153+
- -c
154+
- |
155+
set -euo pipefail
156+
echo "Copying extension-apiserver-authentication ConfigMap data..."
157+
158+
# Get the client-ca-file from kube-system/extension-apiserver-authentication
159+
# This must succeed or the deployment should fail
160+
CLIENT_CA_DATA=$(oc get configmap extension-apiserver-authentication -n kube-system -o jsonpath='{.data.client-ca-file}')
161+
162+
if [ -z "$CLIENT_CA_DATA" ]; then
163+
echo "ERROR: client-ca-file is empty in kube-system/extension-apiserver-authentication ConfigMap"
164+
echo "Cannot proceed without valid client CA certificate"
165+
exit 1
166+
fi
167+
168+
echo "Retrieved client CA data (${#CLIENT_CA_DATA} bytes)"
169+
170+
# Update our local ConfigMap with the client CA data
171+
# Use --from-literal to avoid JSON escaping issues with newlines
172+
oc create configmap extension-apiserver-authentication -n openshift-operator-lifecycle-manager \
173+
--from-literal=client-ca-file="$CLIENT_CA_DATA" --dry-run=client -o yaml | oc apply -f -
174+
175+
echo "Successfully updated extension-apiserver-authentication ConfigMap"
176+
securityContext:
177+
allowPrivilegeEscalation: false
178+
readOnlyRootFilesystem: true
179+
runAsNonRoot: true
180+
capabilities:
181+
drop: ["ALL"]

0 commit comments

Comments
 (0)