sslazure-devopsopensslazure-api-management

How to check SSL certificate validity Azure APIM Custom domain hostnames


We were trying to automate the Certificate expiry of our azure APIM instance custom domain certificates added to the host using an Azure Devops pipeline. With below automation we were able to get the hostnames associated with the custom domain, but we're not able to fetch the certificates and their expiry details. The code is returning blank output. Any guidance, please?

parameters:
  - name: apimName
    type: string
    default: 'myapim'
  - name: resourceGroup
    type: string
    default: 'myapim-rg'
  - name: thresholdDays
    type: string
    default: 60

jobs:
  - job: CheckAPIMSSL
    displayName: 'Check SSL Certificate Expiry for APIM Custom Domains'
    steps:
      - task: AzureCLI@2
        displayName: 'Check SSL Certificate Expiry'
        inputs:
          azureSubscription: 'mysubscription'
          scriptType: bash
          scriptLocation: inlineScript
          inlineScript: |
            APIM_NAME='${{ parameters.apimName }}'
            RESOURCE_GROUP='${{ parameters.resourceGroup }}'
            THRESHOLD_DAYS=${{ parameters.thresholdDays }}
            EXPIRED=0
            
            echo "Fetching custom domain details for APIM: $APIM_NAME"
            customDomains=$(az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP --query "hostnameConfigurations[].hostName" -o tsv)
            
            for DOMAIN in $customDomains
            do
              echo "Checking SSL certificate for custom domain: $DOMAIN"
              EXPIRY_DATE=$(az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP --query "hostnameConfigurations[?hostName=='$DOMAIN'].certificate.expirationDate" -o tsv)
              
              if [ -z "$EXPIRY_DATE" ]; then
                echo "ERROR: Could not retrieve SSL certificate info for $DOMAIN"
                EXPIRED=1
                continue
              fi
              
              EXPIRY_TIMESTAMP=$(date -d "$EXPIRY_DATE" +%s)
              CURRENT_TIMESTAMP=$(date +%s)
              DAYS_LEFT=$(( (EXPIRY_TIMESTAMP - CURRENT_TIMESTAMP) / 86400 ))
              
              echo "SSL certificate for $DOMAIN expires in $DAYS_LEFT days."
              
              if [ "$DAYS_LEFT" -lt "$THRESHOLD_DAYS" ]; then
                echo "ALERT: SSL certificate for $DOMAIN is expiring in less than $THRESHOLD_DAYS days!"
                EXPIRED=1
              else
                echo "SSL certificate for $DOMAIN is valid for more than $THRESHOLD_DAYS days."
              fi
            done
            
            if [ "$EXPIRED" -eq 1 ]; then
              echo "certificates are expiring soon in XX days."
              exit 1
            else
              echo "All certificates are valid for more than $THRESHOLD_DAYS days."
            fi

Solution

  • Breaking down the script you were using, when I ran az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP, the response clearly showed that the expiry date of the certificate bound to each domain was under the certificate.expiry property within the hostnameConfigurations node. The issue with your script is that it references a non-existent certificate.expirationDate property.

    Here is a sample response you would get when running the az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP command:

    ...
      "hostnameConfigurations": [
        {
          "certificate": null,
          "certificatePassword": null,
          "certificateSource": "BuiltIn",
          "certificateStatus": null,
          "defaultSslBinding": false,
          "encodedCertificate": null,
          "hostName": "xxxapimxxx.azure-api.net",
          "identityClientId": null,
          "keyVaultId": null,
          "negotiateClientCertificate": false,
          "type": "Proxy"
        },
        {
          "certificate": {
            "expiry": "2025-12-26T06:43:41+00:00",
            "subject": "CN=mydomain.com",
            "thumbprint": "799FXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2CD9"
          },
          "certificatePassword": null,
          "certificateSource": "Custom",
          "certificateStatus": null,
          "defaultSslBinding": true,
          "encodedCertificate": null,
          "hostName": "www.mydomain.com",
          "identityClientId": null,
          "keyVaultId": null,
          "negotiateClientCertificate": false,
          "type": "Proxy"
        }
      ],
    ...
    

    As you can see, the expiry date is available under the certificate.expiry field, not certificate.expirationDate. Therefore, you may test this sample script below outside the pipelines first, as it helps validate the functionality before automating it.

    echo "Fetching custom domain details for APIM: $APIM_NAME"
    customDomains=$(az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP --query "hostnameConfigurations[].hostName" -o tsv)
    echo $customDomains
    for DOMAIN in $customDomains
    do
        echo "Checking SSL certificate for custom domain: $DOMAIN"
        # EXPIRY_DATE=$(az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP --query "hostnameConfigurations[?hostName=='$DOMAIN'].certificate.expirationDate" -o tsv)
        EXPIRY_DATE=$(az apim show --name $APIM_NAME --resource-group $RESOURCE_GROUP --query "hostnameConfigurations[?hostName=='$DOMAIN'].certificate.expiry" -o tsv)
        echo $EXPIRY_DATE
    done
    

    cloudshell