- Posted on
- • Artificial Intelligence
Artificial Intelligence SSL Certificate Management
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence SSL Certificate Management with Bash: Never Miss an Expiry Again
If you’ve ever been paged at 3 a.m. because a certificate expired, you know the pain: frantic grepping through configs, openssl one‑liners, and piecing together renewal plans from tribal knowledge. It doesn’t have to be like this. By combining a small amount of Bash with an AI assistant, you can continuously inventory certificates, predict risk, and generate clear, prioritized remediation steps—before users or revenue feel it.
This article shows you how to:
Build a reliable SSL/TLS certificate inventory (local and remote) with Bash.
Use an AI model to triage risks and recommend fixes.
Automate renewals and alerts with cron or systemd.
Avoid common pitfalls like missing intermediate chains or non‑ACME endpoints.
Why this matters now
Certificate sprawl is real: edge/CDN, Kubernetes ingresses, appliances, legacy VMs, load balancers, staging environments—each with different renewal paths.
ACME is great, but not universal: private PKI, device certs, mutual TLS, and air‑gapped systems still need manual workflows.
AI can help you reason across disparate signals: it can group duplicates, flag chain issues, surface short key lengths, suggest appropriate ACME strategies, and produce human‑readable runbooks for your environment.
Treat AI as an assistant, not an authority—verify before you act—but let it handle the heavy lifting of pattern recognition and prioritization.
1) Prerequisites: install the tooling
We’ll use common, auditable tools: bash, openssl, jq, curl, and optionally certbot for ACME renewals.
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y curl jq openssl certbot cron
- Fedora/RHEL/CentOS Stream (dnf):
sudo dnf install -y curl jq openssl certbot cronie
- openSUSE Leap/Tumbleweed (zypper):
sudo zypper refresh
sudo zypper install -y curl jq openssl certbot cron
Notes:
- On Fedora/RHEL, the cron service is provided by cronie. Enable it if you plan to use cron:
sudo systemctl enable --now crond
If you prefer systemd timers over cron, you don’t need to enable cron.
certbotis optional but recommended for ACME‑capable domains.
Optional: If you prefer a local LLM instead of a cloud API, consider installing a local model runtime like Ollama (see their docs). The scripts below will work with either a cloud API or a local model that speaks an OpenAI‑compatible HTTP interface.
2) Build a Bash certificate inventory (local files + remote endpoints)
Create a file listing remote domains you want to check:
sudo mkdir -p /etc/ssl/ai
sudo tee /etc/ssl/ai/domains.txt >/dev/null <<'EOF'
example.com
api.example.com
internal.example.lan:8443
EOF
Now drop in an audit script that:
Scans common local cert paths.
Probes remote TLS endpoints.
Normalizes everything into JSON so it’s easy to analyze (or feed into AI).
Save as /usr/local/bin/ssl_audit.sh:
#!/usr/bin/env bash
set -euo pipefail
DOMAINS_FILE="${1:-/etc/ssl/ai/domains.txt}"
OUT_JSON="${2:-/var/tmp/ssl_audit.json}"
NOW_EPOCH="$(date +%s)"
# Helper: parse X.509 PEM to fields
parse_cert() {
local src="$1" src_type="$2" id="$3"
local subj issuer not_before not_after nb_epoch na_epoch days_left status
subj="$(openssl x509 -noout -subject -nameopt RFC2253 -in "$src" 2>/dev/null | sed 's/^subject=//')"
issuer="$(openssl x509 -noout -issuer -nameopt RFC2253 -in "$src" 2>/dev/null | sed 's/^issuer=//')"
not_before="$(openssl x509 -noout -startdate -in "$src" 2>/dev/null | sed 's/^notBefore=//')"
not_after="$(openssl x509 -noout -enddate -in "$src" 2>/dev/null | sed 's/^notAfter=//')"
nb_epoch="$(date -d "$not_before" +%s 2>/dev/null || echo 0)"
na_epoch="$(date -d "$not_after" +%s 2>/dev/null || echo 0)"
if [[ "$na_epoch" -gt 0 ]]; then
days_left=$(( (na_epoch - NOW_EPOCH) / 86400 ))
else
days_left=-9999
fi
if (( days_left < 0 )); then status="expired"
elif (( days_left <= 7 )); then status="critical"
elif (( days_left <= 30 )); then status="warning"
else status="ok"
fi
jq -n --arg id "$id" \
--arg type "$src_type" \
--arg subject "$subj" \
--arg issuer "$issuer" \
--arg not_before "$not_before" \
--arg not_after "$not_after" \
--argjson not_before_epoch "$nb_epoch" \
--argjson not_after_epoch "$na_epoch" \
--argjson days_left "${days_left:-0}" \
--arg status "$status" \
'{id:$id,type:$type,subject:$subject,issuer:$issuer,not_before:$not_before,not_after:$not_after,not_before_epoch:$not_before_epoch,not_after_epoch:$not_after_epoch,days_left:$days_left,status:$status}'
}
# Collect local PEM certs (adjust paths to your environment)
mapfile -t LOCAL_CERTS < <(find /etc/ssl /etc/pki /etc/letsencrypt -type f -maxdepth 6 -name '*.pem' -o -name '*.crt' 2>/dev/null | sort -u)
# For Nginx/Apache, you can also parse configured cert paths:
# nginx -T 2>/dev/null | awk '/ssl_certificate /{print $2}' | tr -d ';'
# apachectl -t -D DUMP_VHOSTS 2>/dev/null | awk '/SSLCertificateFile/{print $2}'
# Probe remote endpoints
probe_remote() {
local target="$1"
local host port
if [[ "$target" == *:* ]]; then
host="${target%%:*}"; port="${target##*:}"
else
host="$target"; port=443
fi
# Extract leaf certificate
local tmpcert
tmpcert="$(mktemp)"
if timeout 10s openssl s_client -servername "$host" -connect "$host:$port" -showcerts </dev/null 2>/dev/null \
| awk 'BEGIN{c=0} /BEGIN CERTIFICATE/{c=1} {if(c) print} /END CERTIFICATE/{exit}' \
| openssl x509 -outform pem >"$tmpcert" 2>/dev/null; then
parse_cert "$tmpcert" "remote" "${host}:${port}"
else
jq -n --arg id "${host}:${port}" --arg type "remote" \
--arg status "unreachable" \
'{id:$id,type:$type,status:$status}'
fi
rm -f "$tmpcert"
}
# Build JSON array
{
echo "["
first=1
# Local certs
for f in "${LOCAL_CERTS[@]}"; do
[[ -r "$f" ]] || continue
item="$(parse_cert "$f" "local" "$f" || true)"
if [[ -n "$item" ]]; then
(( first )) || echo ","
echo "$item"
first=0
fi
done
# Remote
if [[ -f "$DOMAINS_FILE" ]]; then
while IFS= read -r d || [[ -n "$d" ]]; do
[[ -z "$d" || "$d" =~ ^# ]] && continue
item="$(probe_remote "$d" || true)"
if [[ -n "$item" ]]; then
(( first )) || echo ","
echo "$item"
first=0
fi
done <"$DOMAINS_FILE"
fi
echo "]"
} | jq '.' >"$OUT_JSON"
echo "Wrote inventory to $OUT_JSON"
Make it executable:
sudo chmod +x /usr/local/bin/ssl_audit.sh
Run it:
/usr/local/bin/ssl_audit.sh /etc/ssl/ai/domains.txt /var/tmp/ssl_audit.json
You now have a normalized JSON inventory at /var/tmp/ssl_audit.json, with status per certificate (ok, warning, critical, expired, or unreachable).
3) Let AI triage and propose a remediation plan
You can use either:
A cloud AI API (OpenAI‑compatible), or
A local model that exposes an OpenAI‑compatible endpoint, or
A CLI runner like
ollama.
Set environment variables for an OpenAI‑compatible API:
export AI_API_BASE="https://api.openai.com" # or your gateway/local endpoint
export AI_MODEL="gpt-4o-mini" # or any deployed model name
export AI_API_KEY="YOUR_API_KEY"
Ask the model to analyze your inventory:
REPORT_OUT="/var/tmp/ssl_ai_report.txt"
PROMPT_FILE="$(mktemp)"
cat >/dev/null <<'EOF' >/dev/null
EOF
cat >"$PROMPT_FILE" <<'EOF'
You are a senior SRE focused on TLS hygiene. Given a JSON array of certificates with fields:
id,type,subject,issuer,not_before,not_after,days_left,status
1) Summarize overall risk in 3–5 bullet points.
2) List the top 10 items needing action with concrete steps (include chain fixes if likely).
3) Identify candidates for ACME automation vs. manual/PKI renewal.
4) Suggest a 30/7/3 day alert policy and validation checks.
Keep it concise, command-ready, and distro-agnostic.
EOF
curl -sS "${AI_API_BASE}/v1/chat/completions" \
-H "Authorization: Bearer ${AI_API_KEY}" \
-H "Content-Type: application/json" \
-d @- <<JSON >"$REPORT_OUT"
{
"model": "${AI_MODEL}",
"temperature": 0.2,
"messages": [
{"role": "system", "content": "You are a helpful, security-focused Linux SRE who writes actionable runbooks."},
{"role": "user", "content": $(jq -Rs . <"$PROMPT_FILE")},
{"role": "user", "content": $(jq -c . </var/tmp/ssl_audit.json | jq -Rs .)}
]
}
JSON
echo "AI report written to $REPORT_OUT"
Prefer a local model? With Ollama:
ollama run llama3 "Analyze the following JSON and produce an actionable TLS remediation plan: $(cat /var/tmp/ssl_audit.json)"
Security tip:
Do not paste private keys into prompts.
If using a cloud API, avoid sending internal hostnames if that violates policy; sanitize first or run locally.
4) Automate renewals and alerts
- ACME renewals with Certbot:
- Debian/Ubuntu (apt):
sudo apt install -y certbot - Fedora/RHEL/CentOS Stream (dnf):
sudo dnf install -y certbot - openSUSE (zypper):
sudo zypper install -y certbot
- Debian/Ubuntu (apt):
Request a cert (generic webroot example):
sudo certbot certonly --agree-tos --email you@example.com --webroot -w /var/www/html -d example.com -d www.example.com
Enable scheduled renewals (systemd timer on many distros):
sudo systemctl enable --now certbot.timer
- Hook in a daily AI‑assisted audit with cron:
sudo crontab -e
Add:
0 3 * * * /usr/local/bin/ssl_audit.sh /etc/ssl/ai/domains.txt /var/tmp/ssl_audit.json && \
/bin/bash -lc 'source /etc/profile; export AI_API_BASE="https://api.openai.com"; export AI_MODEL="gpt-4o-mini"; export AI_API_KEY="$AI_API_KEY"; /usr/bin/curl -sS "${AI_API_BASE}/v1/chat/completions" -H "Authorization: Bearer ${AI_API_KEY}" -H "Content-Type: application/json" -d "{\"model\":\"${AI_MODEL}\",\"temperature\":0.2,\"messages\":[{\"role\":\"system\",\"content\":\"You are a helpful, security-focused Linux SRE.\"},{\"role\":\"user\",\"content\":\"Summarize and prioritize actions for this JSON:\"},{\"role\":\"user\",\"content\":\"$(jq -c . </var/tmp/ssl_audit.json | sed "s/\"/\\\\\"/g")\"}]}" | tee -a /var/log/ssl_ai_report.json' >/dev/null 2>&1
- Prefer systemd timers to cron? Create
/etc/systemd/system/ssl-audit.service:
[Unit]
Description=AI-assisted SSL audit
[Service]
Type=oneshot
ExecStart=/usr/local/bin/ssl_audit.sh /etc/ssl/ai/domains.txt /var/tmp/ssl_audit.json
And /etc/systemd/system/ssl-audit.timer:
[Unit]
Description=Run AI-assisted SSL audit daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Enable:
sudo systemctl daemon-reload
sudo systemctl enable --now ssl-audit.timer
- Send a webhook alert if anything is critical/expired:
ALERT_WEBHOOK="https://hooks.example.com/your-webhook"
if jq -e '.[] | select(.status=="critical" or .status=="expired")' /var/tmp/ssl_audit.json >/dev/null; then
payload="$(jq -n --arg text "TLS Alert: One or more certificates need attention." '{text:$text}')"
curl -sS -X POST -H "Content-Type: application/json" -d "$payload" "$ALERT_WEBHOOK" >/dev/null
fi
5) Real-world checks and quick wins
Missing intermediate chain:
- Symptom: Older Android/macOS clients fail;
openssl s_clientshowsVerify return code: 21 (unable to verify the first certificate). - Fix: Serve the full chain (
fullchain.pem) not just the leaf. AI can detect the pattern froms_clientoutput and suggest the config line to fix (e.g.,ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;in Nginx).
- Symptom: Older Android/macOS clients fail;
Non‑ACME endpoints (appliances, private PKI):
- Tag them in your inventory with
type: localandissuerpattern. - Ask AI to generate a recurring runbook with commands and owners; store it in your repo alongside the JSON snapshot.
- Tag them in your inventory with
Consolidate SANs:
- AI can flag multiple similar leaf certs with overlapping SANs—migrate to a single SAN cert per tier and reduce operational noise.
Frequently asked questions
Is feeding JSON to an AI safe?
- Treat it like any other third‑party dependency. Redact sensitive hostnames or run a local model. Never include private keys.
What about ciphers, protocols, HSTS, OCSP?
- Extend the audit script to capture
s_client -tls1_2/-tls1_3details or integrate with specialized scanners. Feed those findings into the same AI flow for combined triage.
- Extend the audit script to capture
Conclusion and next steps
You now have a practical, auditable path to AI‑assisted SSL certificate management:
A Bash script to build a reliable inventory.
An AI prompt to triage risk and produce clear actions.
Automated checks and renewals with cron/systemd and Certbot.
Next steps:
Roll this out to a staging environment.
Add your real domains and services, including load balancers and internal VMs.
Wire the alert to your chat/incident system.
Iterate: include cipher/protocol checks and Kubernetes ingress certs.
If you’d like, paste your first AI report (minus sensitive details) into your team wiki and make “TLS hygiene” a non‑event going forward.