Deploy a Service on K8S Using CSR Provide TLS
Table of Contents
Transport Layer Security (TLS) encrypts data sent over the Internet to ensure that eavesdroppers and hackers are unable to see what you transmit which is particularly useful for private and sensitive information such as passwords, credit card numbers, and personal correspondence.
CertificateSigningRequest
Kubernetes CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued.
Kubelets use this API to obtain:
- client certificates to authenticate to kube-apiserver (with the
kubernetes.io/kube-apiserver-client-kubelet
signerName). - serving certificates for TLS endpoints kube-apiserver can connect to securely (with the
kubernetes.io/kubelet-serving
signerName).
This API can be used to request client certificates to authenticate to kube-apiserver (with the kubernetes.io/kube-apiserver-client
signerName), or to obtain certificates from custom non-Kubernetes signers.
Generate a Self-Signed Certificate
Create a private key for the certificate:
openssl genrsa -out myservice.key 2048
Generate a Certificate Signing Request (CSR) using the private key:
openssl req -new -key myservice.key -out myservice.csr -subj "/CN=myservice.default.svc.cluster.local"
Replace
myservice.default.svc.cluster.local
with the fully qualified domain name (FQDN) of your service.
Create a CSR YAML file, e.g., myservice-csr.yaml
:
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: myservice
spec:
request: <base64-encoded-csr>
signerName: kubernetes.io/kube-apiserver-client
usages:
- digital signature
- key encipherment
- client auth
Replace
<base64-encoded-csr>
with the Base64-encoded CSR:
cat myservice.csr | base64 | tr -d '\n'
Apply the CSR YAML file and approve the CSR:
kubectl apply -f myservice-csr.yaml
kubectl certificate approve myservice
Retrieve the issued certificate:
kubectl get csr myservice -o jsonpath='{.status.certificate}' | base64 --decode > myservice.crt
Create a Kubernetes secret containing the private key and the issued certificate:
kubectl create secret tls myservice-tls --cert=myservice.crt --key=myservice.key
That’s it. Our TLS certificate is ready.
Deploy Service and Use Self-Signed Certificate
Update our service deployment to use the secret for TLS termination. Modify our Kubernetes deployment YAML file to include the secret and the appropriate volume mounts
apiVersion: apps/v1
kind: Deployment
metadata:
name: myservice
spec:
replicas: 1
selector:
matchLabels:
app: myservice
template:
metadata:
labels:
app: myservice
spec:
containers:
- name: myservice-container
image: myservice-image
ports:
- containerPort: 8443
volumeMounts:
- name: myservice-tls
mountPath: "/etc/tls"
readOnly: true
volumes:
- name: myservice-tls
secret:
secretName: myservice-tls
Deploy the updated service:
kubectl apply -f myservice-deployment.yaml
Verification
Use the following command for verification:
echo | openssl s_client -showcerts -servername myservice.default.svc.cluster.local -connect myservice.default.svc.cluster.local:443
We should see the following output:
depth=0 CN = myservice.default.svc.cluster.local
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = myservice.default.svc.cluster.local
verify error:num=26:unsupported certificate purpose
verify return:1
depth=0 CN = myservice.default.svc.cluster.local
verify error:num=21:unable to verify the first certificate
verify return:1
write W BLOCK
---
Certificate chain
0 s:/CN=myservice.default.svc.cluster.local
i:/CN=kubernetes
-----BEGIN CERTIFICATE-----
MIIDJDCCAgygAwIBAgIRAJT0AGOQv8KhD6VUrbPMB/owDQYJKoZIhvcNAQELBQAw
...
98/yeCTMfkYsjgAUlkisaC1KkEg3ROsYbEkWowUqj8E2gdGd7AMtSQ==
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=myservice.default.svc.cluster.local
issuer=/CN=kubernetes
---
No client certificate CA names sent
Server Temp Key: ECDH, X25519, 253 bits
---
SSL handshake has read 1368 bytes and written 411 bytes
---
New, TLSv1/SSLv3, Cipher is AEAD-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.3
Cipher : AEAD-AES256-GCM-SHA384
Session-ID:
Session-ID-ctx:
Master-Key:
Start Time: 1679662991
Timeout : 7200 (sec)
Verify return code: 21 (unable to verify the first certificate)
---
DONE
We can see that the issuer is Kubernetes
. It was great. It was just right!
Conclusion
This article introduces how to use CertificateSigningRequest for our application to generate the self-signed certificates.
While the self-signed certificates should not be used in production, they provide an easy way to test the apps you deploy with Kubernetes.