Home › CKA › Topics › Practice tasks › TLS Configuration
CKA · Services & Networking

Restrict a Web Server to TLS 1.3 Only

The secure-web Deployment in namespace secure-space uses a ConfigMap tls-config that currently supports both TLS 1.2 and TLS 1.3. Task: Modify the configuration so that only TLS 1.3 is supported.

Check live lab access → All CKA tasks

Live lab access

This task description is public. Its live lab requires full access; six other CKA labs are available in Free Practice with AI Lab Coach.

Create an account to continue →

Explore the six free labs with AI Lab Coach →

Read the brief on any device. Use a desktop or laptop for the terminal lab. Nothing starts until you choose Start.

The task

The secure-web Deployment in namespace secure-space uses a ConfigMap tls-config that currently supports both TLS 1.2 and TLS 1.3.

Task: Modify the configuration so that only TLS 1.3 is supported.

Note: ConfigMaps are immutable - you must delete and recreate it, then restart the Deployment.

Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. You also need openssl on the machine where you run kubectl.

Changing TLS versions in nginx when the ConfigMap is immutable

Which TLS versions a web server accepts is plain server configuration: in nginx it is the ssl_protocols directive (default TLSv1.2 TLSv1.3 in current releases). In Kubernetes that file usually arrives through a ConfigMap volume, and three layers then decide whether a change takes effect: whether the ConfigMap can be edited at all, whether the Pod sees the new file, and whether nginx rereads it. An immutable ConfigMap closes the first door, so you need a different path.

ConfigMap (immutable: true) ──→ volume in Pod ──→ /etc/nginx/conf.d/vault.conf ──→ nginx reads it at start
change = new ConfigMap + new Pods, never an in-place edit

1. Deploy a server that only speaks TLS 1.2

Save this as tls-vault.yaml. The official nginx image includes every /etc/nginx/conf.d/*.conf file inside its http block, so mounting the ConfigMap there is enough.

apiVersion: v1
kind: ConfigMap
metadata:
  name: vault-nginx-v1
  namespace: prepium-tutorial
immutable: true
data:
  vault.conf: |
    server {
      listen 8443 ssl;
      ssl_certificate     /etc/nginx/tls/tls.crt;
      ssl_certificate_key /etc/nginx/tls/tls.key;
      ssl_protocols       TLSv1.2;
      location / { return 200 "vault ok\n"; }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vault
  namespace: prepium-tutorial
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vault
  template:
    metadata:
      labels:
        app: vault
    spec:
      containers:
      - name: web
        image: nginx:1.27-alpine
        ports:
        - containerPort: 8443
        volumeMounts:
        - name: conf
          mountPath: /etc/nginx/conf.d     # included by the image's nginx.conf
        - name: tls
          mountPath: /etc/nginx/tls
          readOnly: true
      volumes:
      - name: conf
        configMap:
          name: vault-nginx-v1
      - name: tls
        secret:
          secretName: vault-cert
kubectl create namespace prepium-tutorial
openssl req -x509 -newkey rsa:2048 -noenc -days 7 -keyout vault.key -out vault.crt -subj "/CN=vault.local"
kubectl -n prepium-tutorial create secret tls vault-cert --cert=vault.crt --key=vault.key
kubectl apply -f tls-vault.yaml
kubectl -n prepium-tutorial rollout status deployment/vault

2. Test each version explicitly

kubectl -n prepium-tutorial port-forward deployment/vault 8443:8443 &
openssl s_client -connect 127.0.0.1:8443 -tls1_2 -brief </dev/null
openssl s_client -connect 127.0.0.1:8443 -tls1_3 -brief </dev/null

A plain connection would negotiate the highest version both sides share, which proves little. Forcing a version does: the TLS 1.2 attempt completes and the brief summary names the protocol, while the TLS 1.3 attempt fails the handshake with an error. Test both directions every time, the allowed version and the refused one.

3. Try to edit, and see why you cannot

kubectl -n prepium-tutorial edit configmap vault-nginx-v1

Change the protocol line and save: the API server refuses, because once immutable: true is set neither data nor binaryData can change, and the flag itself cannot be switched back. The payoff is that the kubelet stops watching the object, which reduces API server load in large clusters.

4. Roll out a new version

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: vault-nginx-v2
  namespace: prepium-tutorial
immutable: true
data:
  vault.conf: |
    server {
      listen 8443 ssl;
      ssl_certificate     /etc/nginx/tls/tls.crt;
      ssl_certificate_key /etc/nginx/tls/tls.key;
      ssl_protocols       TLSv1.2 TLSv1.3;
      location / { return 200 "vault ok\n"; }
    }
EOF
kubectl -n prepium-tutorial patch deployment vault --type=json \
  -p='[{"op":"replace","path":"/spec/template/spec/volumes/0/configMap/name","value":"vault-nginx-v2"}]'
kubectl -n prepium-tutorial rollout status deployment/vault

Pointing the Pod template at a new name is a template change, so the Deployment rolls out fresh Pods by itself, and vault-nginx-v1 stays behind for an instant rollback. Restart the port-forward (it was attached to a Pod that has now been replaced) and repeat both s_client tests: now both versions succeed.

The alternative is to delete the ConfigMap and recreate it under the same name. Running Pods keep their existing mount, and nginx only rereads configuration on reload or restart, so you must follow with kubectl rollout restart deployment/vault. The Kubernetes documentation recommends recreating Pods after replacing an immutable ConfigMap for exactly this reason.

Common mistakes

Example checkEvidence
Config holds the intended directivekubectl get configmap -o yaml shows the ssl_protocols line and immutable: true
Pods use the current configPod start times are after the change; the volume names the intended ConfigMap
Allowed version worksopenssl s_client -tls1_2 or -tls1_3 completes the handshake as intended
Refused version is refusedThe forced handshake for the excluded version fails

Cleanup: stop the port-forward, then kubectl delete namespace prepium-tutorial and rm vault.key vault.crt. References: ConfigMaps, nginx ssl module, openssl s_client. Next, try TLS Secrets or TLS termination with Gateway API.

Exam
CKA
Domain
Services & Networking
Grading
Programmatic · partial credit

What this tests

Expose workloads with services and ingress, and restrict traffic with network policies. On the CKA exam, Services & Networking tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.

Practice it for real

The public description lets you study the task before signing up. Full access includes every live lab. Six selected CKA scenarios are included in Free Practice, with five shared sessions each week. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.

Related CKA tasks