F5 Script — List Unused SSL Certificates

Quick post, script on F5 using bash and TMSH to show unused certs. Use at your own risk, take a backup first!

Listing Unused Certificates via TMSH

Unused Certificates For Loop…

for cert in $(tmsh list sys file ssl-cert | grep "sys file ssl-cert" | awk '{print $4}'); do
    if ! tmsh list ltm profile client-ssl | grep -q $cert; then
        echo "Unused certificate: $cert"
    fi
done

{{output}}
Unused certificate: ca-bundle.crt
Unused certificate: f5-ca-bundle.crt
Unused certificate: f5-irule.crt
Unused certificate: f5_api_com.crt
Unused certificate: test30.infotechguy.dev_2025_112491.crt
Unused certificate: test30.infotechguy.dev_2025_140516.crt
Unused certificate: test30.infotechguy.dev_2025_196380.crt
Unused certificate: test30.infotechguy.dev_2025_827939.crt
Unused certificate: test31.infotechguy.dev_2025_112491.crt
Unused certificate: test31.infotechguy.dev_2025_140516.crt
Unused certificate: test31.infotechguy.dev_2025_196380.crt
Unused certificate: test31.infotechguy.dev_2025_827939.crt
Unused certificate: test32.infotechguy.dev_2025_112491.crt
Unused certificate: test32.infotechguy.dev_2025_140516.crt
Unused certificate: test32.infotechguy.dev_2025_196380.crt
Unused certificate: test32.infotechguy.dev_2025_827939.crt

Cool, lets take this further. let’s put each entry (take certificates loop) into an array so we can manipulate it later, in a deletion loop.

# Declare an array to store unused certificates
unused_certs=()

# List of certificates to exclude (exclude these system certs)
exclude_list=("ca-bundle.crt" "f5-ca-bundle.crt" "f5-irule.crt" "f5_api_com.crt")

# Loop through each certificate found in BIG-IP
for cert in $(tmsh list sys file ssl-cert | grep "sys file ssl-cert" | awk '{print $4}'); do
    # Skip certificates in the exclude list
    if [[ " ${exclude_list[@]} " =~ " $cert " ]]; then
        continue
    fi

    if ! tmsh list ltm profile client-ssl | grep -q $cert; then
        unused_certs+=("$cert")  # Add unused cert to array
    fi
done

# Dry run: Print the certificates that would be deleted
echo "Dry Run: The following unused certificates would be deleted:"
for cert in "${unused_certs[@]}"; do
    echo "$cert"
done

{{output}}
test30.infotechguy.dev_2025_112491.crt
test30.infotechguy.dev_2025_140516.crt
test30.infotechguy.dev_2025_196380.crt
test30.infotechguy.dev_2025_827939.crt
test31.infotechguy.dev_2025_112491.crt
test31.infotechguy.dev_2025_140516.crt
test31.infotechguy.dev_2025_196380.crt
test31.infotechguy.dev_2025_827939.crt
test32.infotechguy.dev_2025_112491.crt
test32.infotechguy.dev_2025_140516.crt
test32.infotechguy.dev_2025_196380.crt
test32.infotechguy.dev_2025_827939.crt

Nice! Now let’s paste in the delete loop.

# Delete each unused certificate
for cert in "${unused_certs[@]}"; do
    echo "Deleting unused certificate: $cert"
    tmsh delete sys file ssl-cert "$cert"
done

{{output}}
Deleting unused certificate: test30.infotechguy.dev_2025_112491.crt
Deleting unused certificate: test30.infotechguy.dev_2025_140516.crt
Deleting unused certificate: test30.infotechguy.dev_2025_196380.crt
Deleting unused certificate: test30.infotechguy.dev_2025_827939.crt
Deleting unused certificate: test31.infotechguy.dev_2025_112491.crt
Deleting unused certificate: test31.infotechguy.dev_2025_140516.crt
Deleting unused certificate: test31.infotechguy.dev_2025_196380.crt
Deleting unused certificate: test31.infotechguy.dev_2025_827939.crt
Deleting unused certificate: test32.infotechguy.dev_2025_112491.crt
Deleting unused certificate: test32.infotechguy.dev_2025_140516.crt
Deleting unused certificate: test32.infotechguy.dev_2025_196380.crt
Deleting unused certificate: test32.infotechguy.dev_2025_827939.crt

 

Listing Unused Keys via TMSH

List Unused Keys For Loop, ssl-key

# Declare an array to store unused SSL keys
unused_keys=()

# List of keys to exclude
exclude_key_list=("f5_api_com.key")

# Loop through each SSL key found in BIG-IP
for key in $(tmsh list sys file ssl-key | grep "sys file ssl-key" | awk '{print $4}'); do
    # Skip keys in the exclude list
    if [[ " ${exclude_key_list[@]} " =~ " $key " ]]; then
        continue
    fi

    if ! tmsh list ltm profile client-ssl | grep -q $key; then
        unused_keys+=("$key")  # Add unused key to array
    fi
done

# Dry run: Print the SSL keys that would be deleted
echo "Dry Run: The following unused SSL keys would be deleted (excluding system keys):"
for key in "${unused_keys[@]}"; do
    echo "$key"
done

{{output}}
test30.infotechguy.dev_2025_112491.key
test30.infotechguy.dev_2025_140516.key
test30.infotechguy.dev_2025_196380.key
test30.infotechguy.dev_2025_827939.key
test31.infotechguy.dev_2025_112491.key
test31.infotechguy.dev_2025_140516.key
test31.infotechguy.dev_2025_196380.key
test31.infotechguy.dev_2025_827939.key
test32.infotechguy.dev_2025_112491.key
test32.infotechguy.dev_2025_140516.key
test32.infotechguy.dev_2025_196380.key
test32.infotechguy.dev_2025_827939.key

Looks good, let’s nuk’em.

# Delete each unused SSL key
for key in "${unused_keys[@]}"; do
    echo "Deleting unused SSL key: $key"
    tmsh delete sys file ssl-key "$key"
done

{{output}}
Deleting unused SSL key: test30.infotechguy.dev_2025_112491.key
Deleting unused SSL key: test30.infotechguy.dev_2025_140516.key
Deleting unused SSL key: test30.infotechguy.dev_2025_196380.key
Deleting unused SSL key: test30.infotechguy.dev_2025_827939.key
Deleting unused SSL key: test31.infotechguy.dev_2025_112491.key
Deleting unused SSL key: test31.infotechguy.dev_2025_140516.key
Deleting unused SSL key: test31.infotechguy.dev_2025_196380.key
Deleting unused SSL key: test31.infotechguy.dev_2025_827939.key
Deleting unused SSL key: test32.infotechguy.dev_2025_112491.key
Deleting unused SSL key: test32.infotechguy.dev_2025_140516.key
Deleting unused SSL key: test32.infotechguy.dev_2025_196380.key
Deleting unused SSL key: test32.infotechguy.dev_2025_827939.key


Sweet!

Hope this is a quick find for someone in the same circumstance, or until F5 makes it easier to do via the GUI.

Tools used:

  • VS Code Bash
  • F5 VE v17
  • OpenAI to help me with my loop logic.