Quick and dirty shell script to find unused certificates

Problem this snippet solves:

This has been edited quite a bit since I first posted so it's probably not as quick and dirty as it was before.

This in response to a question regarding removing unused certificates https://devcentral.f5.com/questions/how-to-find-the-unused-ssl-certificates-63166

The following bash script will output any installed certificate names to a file, then iterate over each line. If the certificate is not referenced in bigip.conf in either the /config/ or within a partition folder, then it can be reasonably assumed it is not in use and can be safely deleted.

The script will give you the option to delete any certs that are not in use and save a UCS archive (just in case)

If there are any keys associated with the certificate, this will be deleted too.

As the moment, the script will not look for keys without an equivalent cert, e.g. my-cert.key and my-cert.crt. So you many still end up with rouge keys. I'll look to get this updated eventually.


There is an array called ignoreCerts

ignoreCerts=("f5-irule.crt" "ca-bundle.crt")


Here you can add certificates you may want to ignore. For example, f5-irule.crt is used to sign F5 provided iRules and bigip.conf does not reference it.

Add any additional certs to this array to ensure they are not deleted


Script can be downloaded directly from GitLab using the link below

https://gitlab.com/stratalabs/f5-devcental/snippets/1863498/raw?inline=false


How to use this snippet:

  • paste into vi
  • chmod +x myScript.sh
  • ./myScript.sh


Code :

#!/bin/sh

function buildInstalledCertsArray {
    tmsh save sys config partitions all
    tmsh list sys file ssl-cert |  awk '/crt/ {print $4}' | sed '/^[[:space:]]*$/d' > /var/tmp/installedCerts.tmp

    # iterate over tmp file to create array of used certificates
    while read line; do
        for i in "${!ignoreCerts[@]}"; do
            if [[ $line = ${ignoreCerts[$i]} ]]; then
                ignore="true"
            else
                if [[ $ignore != "true" ]];then
                    ignore=""
                else
                    # do not add cert to array if already added
                    if [[ ! " ${instCertsArr[@]} " =~ " ${line} " ]]; then
                        instCertsArr+=("$line")
                    fi
                fi
            fi
        done
    done  /dev/null 2>&1)
        if ! [ -z "$hasKey" ];then
            deleteKeys+=("${cert%.*}.key")
        fi
    done
}

function deleteUnusedCerts {

    if [ ${#deleteCerts[@]} -eq 0 ]; then
        echo "-------------------------------------------------------------------------"
        echo "There are no unused certificates to delete, existing"
        echo "-------------------------------------------------------------------------"
        exit 0
    else
        echo "-------------------------------------------------------------------------"
        echo "The following keys are not in use can can be deleted:"
        for cert in "${deleteCerts[@]}"; do
            echo "   ${cert}"
        done
        echo "-------------------------------------------------------------------------"
        read -p "would you like to delete these unused certificates? (y/n)?" answer
        case ${answer:0:1} in
            y|Y )
                createUcsArchive
                echo "-------------------------------------------------------------------------"
                echo "deleting certs..."
                for cert in "${deleteCerts[@]}"; do
                    delete sys file ssl-key $cert
                    echo "    $cert"
                done

                if [ ${#deleteKeys[@]} -eq 0 ]; then
                echo "-------------------------------------------------------------------------"
                    echo "no associated keys to delete, exiting"
                    exit 0
                else
                    echo "-------------------------------------------------------------------------"
                    echo "deleting keys..."
                    for key in "${deleteKeys[@]}"; do
                        delete sys file ssl-key $cert
                        echo "$key"
                        exit 0
                    done
                fi
                ;;
            * )
                exit 0
                ;;
        esac
    fi
}

function createUcsArchive {
    echo
    today=`date +%Y-%m-%d.%H.%M.%S`
    echo "Creating UCS archive auto.${today}.ucs"
    tmsh save sys ucs ${today}.ucs
}

# initialise vars
instCertsArr=()
deleteCerts=()

# ignore certs defined here - f5-irile.crt is used to sign F5 iRules
ignoreCerts=("f5-irule.crt" "ca-bundle.crt")

# build installed certificates array - excluding certs to ignore
buildInstalledCertsArray

# check if installed certs are used in bigip.conf (including partitions) - ltm sys files are exluded from results
buildDeleteCertsArray

# build list of associated keys (not all certs will have keys)
buildDeleteKeysArray

# optionally delete unused certs
deleteUnusedCerts

Tested this on version:

No Version Found
Published May 16, 2019
Version 1.0
  • Hi Lee!! Thanks for your fantastic work!

     

    I'm trying to execute the script but seems the ignoreCerts array is not working as expected. For example, it always found "f5-irule.crt" as a certificate to be deleted. If I add any other certificate in the chain, then all the certificates in the chain are selected to be deleted.

     

    Is it something that I'm doing wrong or it's a bug in the script?

     

    Thanks for your great work!

  • i see three errors when i run the script, i updated with corrections.

  • #!/bin/sh

     

    function buildInstalledCertsArray {

      tmsh save sys config partitions all

      tmsh list sys file ssl-cert | awk '/crt/ {print $4}' | sed '/^[[:space:]]*$/d' > /var/tmp/installedCerts.tmp

     

      # iterate over tmp file to create array of used certificates

      while read line; do

        for i in "${!ignoreCerts[@]}"; do

          if [[ $line = ${ignoreCerts[$i]} ]]; then

            ignore="true"

          else

            if [[ $ignore != "true" ]];then

              ignore=""

            else

              # do not add cert to array if already added

              if [[ ! " ${instCertsArr[@]} " =~ " ${line} " ]]; then

                instCertsArr+=("$line")

              fi

            fi

          fi

        done

      done </var/tmp/installedCerts.tmp

      rm /var/tmp/installedCerts.tmp

    }

     

    function buildDeleteCertsArray {

      # populate deleteCerts array

      for cert in "${instCertsArr[@]}"; do

        isUsed=$(grep $cert /config/bigip.conf /config/partitions/*/bigip.conf | grep -v -e "sys file ssl-cert" -e cache-path)

        if [ -z "$isUsed" ];then

          deleteCerts+=("$cert")

        fi

      done

    }

     

    function buildDeleteKeysArray {

      # delete any associated keys

      for cert in "${deleteCerts[@]}"; do

        #hasKey=$(tmsh list sys file ssl-key ${cert%.*}.key > /dev/null 2>&1)

        hasKey=$(tmsh list sys file ssl-key ${cert%.*}.key 2> /dev/null)

        if [ ! -z "$hasKey" ];then

          deleteKeys+=("${cert%.*}.key")

        fi

      done

    }

     

    function deleteUnusedCerts {

     

      if [ ${#deleteCerts[@]} -eq 0 ]; then

        echo "-------------------------------------------------------------------------"

        echo "There are no unused certificates to delete, existing"

        echo "-------------------------------------------------------------------------"

        exit 0

      else

        echo "-------------------------------------------------------------------------"

        echo "The following keys are not in use can can be deleted:"

        for cert in "${deleteCerts[@]}"; do

          echo "  ${cert}"

        done

        echo "-------------------------------------------------------------------------"

        read -p "would you like to delete these unused certificates? (y/n)?" answer

        case ${answer:0:1} in

          y|Y )

            createUcsArchive

            echo "-------------------------------------------------------------------------"

            echo "deleting certs..."

            for cert in "${deleteCerts[@]}"; do

              tmsh delete sys file ssl-cert $cert

              echo "$cert"

            done

     

            if [ ${#deleteKeys[@]} -eq 0 ]; then

            echo "-------------------------------------------------------------------------"

              echo "no associated keys to delete, exiting"

              exit 0

            else

              echo "-------------------------------------------------------------------------"

              echo "deleting keys..."

              for key in "${deleteKeys[@]}"; do

                tmsh delete sys file ssl-key $key

                echo "$key"

              #  exit 0

              done

            fi

            ;;

          * )

            exit 0

            ;;

        esac

      fi

    }

     

    function createUcsArchive {

      echo

      today=`date +%Y-%m-%d.%H.%M.%S`

      echo "Creating UCS archive auto.${today}.ucs"

      tmsh save sys ucs ${today}.ucs

    }

     

    # initialise vars

    instCertsArr=()

    deleteCerts=()

     

    # ignore certs defined here - f5-irile.crt is used to sign F5 iRules

    ignoreCerts=("f5-irule.crt" "ca-bundle.crt")

     

    # build installed certificates array - excluding certs to ignore

    buildInstalledCertsArray

     

    # check if installed certs are used in bigip.conf (including partitions) - ltm sys files are exluded from results

    buildDeleteCertsArray

     

    # build list of associated keys (not all certs will have keys)

    buildDeleteKeysArray

     

    # optionally delete unused certs

    deleteUnusedCerts

  •   thanks for the suggestion, the original code snippet was just cobbled together very quickly for a DC question so hadn't considered this point.

    I'll update the codeshare with your suggestion.

  • This is great, but one pre-requisite could be added too.

    • By default, save-on-auto-sync is disabled (false). So make sure you run the save sys config command before executing the script. Else the running config may not be saved on the stored config file & the output could be misleading.
  • About the non-default partitions, you could use the following:

    #!/bin/sh
     
    tmsh list sys file ssl-cert |  awk '/crt/ {print $4}' | sed '/^[[:space:]]*$/d' > /var/tmp/installedCerts.tmp
     
    while read cert; do
      isUsed=$(find /config/ -xdev -type f -name bigip.conf -exec grep $cert {} +)
      if [ -z "$isUsed" ];then
          echo "$cert is not used"
      fi
    done </var/tmp/installedCerts.tmp
     
    rm /var/tmp/installedCerts.tmp