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.