Renew the TLS certificate

Last published : Oct 22, 2026
This page applies to the Contributor path, where you supplied the TLS certificate. On the Owner path, the certificate is renewed automatically. A renewal warning on the Owner path means automatic renewal is failing: check the NS delegation and any CAA record on the parent zone.
Important:
If the site is down, do not use the copy of this page at https://<hostname>/docs/. It is served through the certificate you are replacing.

When to renew

Renew at two thirds of the certificate's validity: day 60 of a 90-day Let's Encrypt certificate, or about twice a year for a six-month certificate. Re-issuing needs DNS changes that can take an hour to become visible, so do not wait for the expiry warning.
If the certificate has already expired, this procedure still works.

Get a new certificate

Follow Obtain a certificate again for the same two names. Then confirm that you received a new certificate, not the old one:
CERTDIR="$HOME/certbot/config/live/<hostname>"
openssl x509 -in "$CERTDIR/fullchain.pem" -noout -dates
notBefore must be today's date.

Install it from the platform

The usual route is the platform itself. Sign in as an administrator, go to System Configuration > Others > TLS certificate, and upload the new fullchain.pem and privkey.pem. The page checks the certificate before it applies it, and records the change in the audit log.
If you cannot use that page, for example because the certificate has already expired or the platform is not serving, install the certificate on the cluster directly, as described in the rest of this page.

Install it on the cluster

Get access to the cluster

Start from the managed application, so that you reach the right cluster:
az login
az account set --subscription <subscription-id>
az managedapp list --query "[].{name:name, resourceGroup:resourceGroup}" -o table
az managedapp show -g <resource-group> -n <name> --query managedResourceGroupId -o tsv
The managed resource group is the last segment of the ID. It contains one cluster:
MRG=<managed-resource-group>
CLUSTER=$(az aks list -g "$MRG" --query "[0].name" -o tsv)
az aks get-credentials -g "$MRG" -n "$CLUSTER"
kubectl get nodes
At least one node must be Ready. If az aks get-credentials is refused, ask in the SecurSpaces community forum.

Find the Secret and back it up

The deployment uses the Secret securspaces-cert in the namespace securspaces for both the portal and the workspaces. Confirm this before you change anything:
kubectl get ingress -A -o custom-columns=\
'NAMESPACE:.metadata.namespace,INGRESS:.metadata.name,HOSTS:.spec.tls[*].hosts[*],SECRET:.spec.tls[*].secretName'
If the two TLS rows name different Secrets, repeat the rest of this page for each one.
Back up the current certificate. It is your only way back:
NS=securspaces; SECRET=securspaces-cert; HOST=<hostname>
BACKUP="$HOME/securspaces-cert-backup"; mkdir -p "$BACKUP"
kubectl -n "$NS" get secret "$SECRET" -o go-template='{{index .data "tls.crt" | base64decode}}' \
  > "$BACKUP/previous-fullchain.pem" && openssl x509 -in "$BACKUP/previous-fullchain.pem" -noout -dates
kubectl -n "$NS" get secret "$SECRET" -o go-template='{{index .data "tls.key" | base64decode}}' \
  > "$BACKUP/previous-privkey.pem" && openssl pkey -in "$BACKUP/previous-privkey.pem" -noout -check
chmod 600 "$BACKUP/previous-privkey.pem"
The old dates and Key is valid must print. A mistyped name still creates an empty backup file.

Check the new certificate

diff <(openssl x509 -in "$CERTDIR/fullchain.pem" -noout -pubkey) \
     <(openssl pkey -in "$CERTDIR/privkey.pem" -pubout) && echo MATCH
openssl crl2pkcs7 -nocrl -certfile "$CERTDIR/fullchain.pem" | openssl pkcs7 -print_certs -noout
openssl x509 -in "$CERTDIR/fullchain.pem" -noout -ext subjectAltName
  • The first command must print MATCH.
  • In the chain, the first subject= is your hostname and every issuer= matches the next subject=.
  • The names must include both <hostname> and *.proxy.<hostname>.
kubectl checks only the first certificate in the file. It accepts a wrong or missing intermediate certificate, which stops port 443 from answering.

Apply it

Use this command and no other form:
kubectl -n "$NS" create secret tls "$SECRET" \
  --cert="$CERTDIR/fullchain.pem" --key="$CERTDIR/privkey.pem" \
  --dry-run=client -o yaml | kubectl -n "$NS" apply -f -
Important:
Do not delete the Secret first. Nothing breaks immediately, but the site goes down at the next unrelated pod restart. Do not apply a hand-written Secret YAML file either: it accepts a certificate and key that do not match.

Verify

The command prints configured whether or not the result works. Check over the network:
openssl s_client -connect "$HOST:443" -servername "$HOST" </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -dates
openssl s_client -connect "check.proxy.$HOST:443" -servername "check.proxy.$HOST" </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -dates
openssl s_client -connect "$HOST:443" -servername "$HOST" -showcerts </dev/null 2>/dev/null \
  | grep -c "BEGIN CERTIFICATE"
The first two commands must show the new dates. The last must print 2 or more; 1 means the chain is incomplete. The ingress controller picks up the new Secret in about 15 seconds, so wait a minute before you conclude that it failed. If your browser still shows the old certificate, open a private window.

If it went wrong

Restore the backup with the same command, then verify again:
kubectl -n "$NS" create secret tls "$SECRET" \
  --cert="$BACKUP/previous-fullchain.pem" --key="$BACKUP/previous-privkey.pem" \
  --dry-run=client -o yaml | kubectl -n "$NS" apply -f -
The ingress controller's nsic container log explains what failed:
kubectl get pods -A -o custom-columns=\
'NAMESPACE:.metadata.namespace,POD:.metadata.name,CONTAINERS:.spec.containers[*].name' | grep nsic
kubectl -n <namespace> logs <pod> -c nsic --tail=200
When the renewal is verified, delete the backup of the old private key.

If the private key was exposed

Replacing the certificate does not end the exposure. Whoever holds the old key can use the old certificate until it expires or is revoked.
  1. Get a certificate with a new private key. With certbot, add --new-key.
  2. Install and verify it as described on this page.
  3. Revoke the old certificate with your certificate authority. With certbot:
    openssl x509 -in <old-fullchain.pem> -out old-cert.pem
    "$CB" revoke --cert-path old-cert.pem --key-path <old-privkey.pem> --reason keycompromise
  4. Delete every copy of the old key, and review who holds Contributor on the managed resource group.
Do not restore the old certificate in this case, even if the new one fails. Fix the new one instead.