OKD OpenShift 4: Service Serving Certificate
In this Post I will show you how you can use Service Serving Certificate on OpenShift4.
What is Service Serving Certificate?
Service serving certificates are intended to support complex middleware applications that require encryption. Openshift automaticle generate a x509.SHA256WithRSA
signature CA certificate stored in service-ca
secret. These certificates are issued as TLS web server certificates. The service CA certificate, which issues the service certificates, is valid for 26 months and is automatically rotated when there is less than 13 months validity left. The generated certificate is only valid for the internal service DNS name <service.name>.<service.namespace>.svc
, and is only valid for internal communications.
OpenShift Service CA Operator
The openshift-service-ca-operator is an OpenShift Cluster Operator that runs in the cluster by default:
$ oc get co service-ca
NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE
service-ca 4.4.12 True False False 4d4h
The Service CA Operator runs the operator in the openshift-service-ca-operator namespace:
$ oc get pod
NAME READY STATUS RESTARTS AGE
service-ca-operator-5f596775f8-gwlpj 1/1 Running 1 2d7h
The OpenShift Service CA Operator runs the following OpenShift controllers:
$ oc get pod -n openshift-service-ca
NAME READY STATUS RESTARTS AGE
apiservice-cabundle-injector-64cfdd7645-h4dqf 1/1 Running 3 2d7h
configmap-cabundle-injector-67ffc677d5-prn7b 1/1 Running 3 2d7h
service-serving-cert-signer-b5665b6f5-lx7bl 1/1 Running 3 2d7h
For OpenShift 4.x the service ca certificates are managed by the service CA operator.
The key and certificate are in a secret in the namespace openshift-service-ca as signing-key secret:
$ oc get secrets -n openshift-service-ca signing-key -o "jsonpath={.data['tls\.crt']}" | base64 -d | openssl x509 -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1181511372096086528 (0x106592553fdf2200)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = openshift-service-serving-signer@1596638040
Validity
Not Before: Aug 5 14:34:00 2020 GMT
Not After : Oct 4 14:34:01 2022 GMT
Subject: CN = openshift-service-serving-signer@1596638040
...
How to use Service Serving Certificate?
To activate Service Serving Certificate you need to annotate the service with service.beta.openshift.io/serving-cert-secret-name
:
$ oc annotate service service-serving-cert service.beta.openshift.io/serving-cert-secret-name=service-serving-cert
Example Service:
apiVersion: v1
kind: Service
metadata:
name: service-serving-cert
annotations:
service.alpha.openshift.io/serving-cert-secret-name: service-serving-cert
spec:
ports:
- name: service-serving-cert
port: 443
targetPort: 8443
selector:
app: service-serving-cert
Check certificate:
$ oc get secret service-serving-cert -o json | jq -r '.data."tls.crt"' | base64 --decode > service-serving-cert.pem
$ openssl crl2pkcs7 -nocrl -certfile service-serving-cert.pem | openssl pkcs7 -print_certs -noout
subject=/CN=service-serving-cert.rbo.svc
issuer=/CN=openshift-service-serving-signer@1545507973
subject=/CN=openshift-service-serving-signer@1545507973
issuer=/CN=openshift-service-serving-signer@1545507973
Now the communication between the pods (truth a service as a proxy) is encrypted by a self signed certificate managed by Openshift. The applications wont see the certificate as valid because it is self signed. So we need to add the root certificate (CA) as trusted in the app. To do this you can generate and mount as configmap.
Add the service CA bundle to a config map
$ oc create -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: service-trustbundle-ca
annotations:
service.beta.openshift.io/inject-cabundle: "true"
data: {}
EOF
$ oc get configmap/service-trustbundle-ca -o jsonpath="{.data.service-ca\.crt}" | openssl x509 -noout -subject -issuer -dates
subject= /CN=openshift-service-serving-signer@1593524307
issuer= /CN=openshift-service-serving-signer@1593524307
notBefore=Jun 30 13:38:26 2020 GMT
notAfter=Aug 29 13:38:27 2022 GMT
Mount the configMap in your client container
You need to map the configMap in your client container which is service-A so that service-A gets access to client certificate.
apiVersion: apps/v1
kind: Deployment
metadata:
name: "my-service-a"
spec:
selector:
matchLabels:
app: service-a
template:
metadata:
labels:
app: service-a
spec:
volumes:
- name: client-certs-config
configMap:
name: "service-trustbundle-ca"
containers:
- name: service-a-pod
image: my-image-repo/my-image-name:my-image-tag
volumeMounts:
- mountPath: /etc/servicea/client-certs
name: client-certs-config
readOnly: true