Inhaltsverzeichnis

Inventura certifikatov

Kompleksnost: Nizka
Trajanje: 1-4 ure (odvisno od velikosti)
Predpogoj: Dostop do vseh sistemov

Popoln popis vseh certifikatov kot osnova za migracijo.


Zakaj inventura?

Razlog Opis
——–——
Obseg Koliko certifikatov je treba migrirati?
Algoritmi Kateri algoritmi so v uporabi?
Datumi izteka Kdaj lahko certifikate migriramo ob obnovi?
Odvisnosti Kateri sistemi so medsebojno povezani?
Tveganja Kje so kritični certifikati?

Viri inventure

flowchart TB subgraph LOCAL["LOKALNO"] L1[Datotečni sistem] L2[Shrambe certifikatov] L3[Konfiguracijske datoteke] end subgraph NETWORK["OMREŽJE"] N1[TLS končne točke] N2[LDAP/AD] N3[HSM] end subgraph MGMT["UPRAVLJANJE"] M1[CA baza podatkov] M2[CMDB] M3[Nadzor] end subgraph OUTPUT["IZHOD"] O[Inventura-CSV] end L1 & L2 & L3 --> O N1 & N2 & N3 --> O M1 & M2 & M3 --> O


Linux: Pregled datotečnega sistema

#!/bin/bash
# cert-inventory-linux.sh
 
OUTPUT="inventory-linux-$(hostname)-$(date +%Y%m%d).csv"
echo "Pot,Subject,Issuer,Algoritem,Dolzina_kljuca,Veljavno_od,Veljavno_do,Dni_preostalo,Serial,SAN" > "$OUTPUT"
 
# Standardni imeniki
CERT_DIRS=(
    "/etc/ssl/certs"
    "/etc/pki/tls/certs"
    "/etc/nginx/ssl"
    "/etc/apache2/ssl"
    "/opt/*/ssl"
    "/var/lib/docker/volumes/*/ssl"
)
 
for dir in "${CERT_DIRS[@]}"; do
    for cert in $(find $dir -name "*.pem" -o -name "*.crt" -o -name "*.cer" 2>/dev/null); do
        # Samo certifikati (ne ključi/CSR)
        openssl x509 -in "$cert" -noout 2>/dev/null || continue
 
        subject=$(openssl x509 -in "$cert" -subject -noout | sed 's/subject=//' | tr ',' ';')
        issuer=$(openssl x509 -in "$cert" -issuer -noout | sed 's/issuer=//' | tr ',' ';')
        algo=$(openssl x509 -in "$cert" -text -noout | grep "Signature Algorithm" | head -1 | awk '{print $3}')
        keysize=$(openssl x509 -in "$cert" -text -noout | grep "Public-Key:" | grep -oP '\d+')
        not_before=$(openssl x509 -in "$cert" -startdate -noout | cut -d= -f2)
        not_after=$(openssl x509 -in "$cert" -enddate -noout | cut -d= -f2)
        days_left=$(( ($(date -d "$not_after" +%s) - $(date +%s)) / 86400 ))
        serial=$(openssl x509 -in "$cert" -serial -noout | cut -d= -f2)
        sans=$(openssl x509 -in "$cert" -text -noout | grep -A1 "Subject Alternative Name" | tail -1 | tr ',' ';')
 
        echo "\"$cert\",\"$subject\",\"$issuer\",\"$algo\",\"$keysize\",\"$not_before\",\"$not_after\",\"$days_left\",\"$serial\",\"$sans\"" >> "$OUTPUT"
    done
done
 
echo "Inventura končana: $OUTPUT"
echo "Najdenih certifikatov: $(tail -n +2 "$OUTPUT" | wc -l)"

Windows: Pregled shrambe certifikatov

# Cert-Inventory-Windows.ps1
 
param(
    [string]$OutputPath = "inventory-windows-$env:COMPUTERNAME-$(Get-Date -Format 'yyyyMMdd').csv"
)
 
$results = @()
 
# Pregled vseh shrambenih mest certifikatov
$stores = @(
    @{ Location = "LocalMachine"; Name = "My" },
    @{ Location = "LocalMachine"; Name = "Root" },
    @{ Location = "LocalMachine"; Name = "CA" },
    @{ Location = "LocalMachine"; Name = "WebHosting" },
    @{ Location = "CurrentUser"; Name = "My" }
)
 
foreach ($store in $stores) {
    $storePath = "Cert:\$($store.Location)\$($store.Name)"
 
    Get-ChildItem $storePath -ErrorAction SilentlyContinue | ForEach-Object {
        $cert = $_
        $daysLeft = ($cert.NotAfter - (Get-Date)).Days
 
        # Ekstrakcija SAN
        $sanExt = $cert.Extensions | Where-Object { $_.Oid.Value -eq "2.5.29.17" }
        $sans = if ($sanExt) { $sanExt.Format($false) } else { "" }
 
        $results += [PSCustomObject]@{
            Store = "$($store.Location)\$($store.Name)"
            Subject = $cert.Subject
            Issuer = $cert.Issuer
            Algorithm = $cert.SignatureAlgorithm.FriendlyName
            KeySize = $cert.PublicKey.Key.KeySize
            NotBefore = $cert.NotBefore
            NotAfter = $cert.NotAfter
            DaysLeft = $daysLeft
            Serial = $cert.SerialNumber
            Thumbprint = $cert.Thumbprint
            SANs = $sans
            HasPrivateKey = $cert.HasPrivateKey
        }
    }
}
 
$results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
Write-Host "Inventura končana: $OutputPath"
Write-Host "Najdenih certifikatov: $($results.Count)"

Omrežje: Pregled TLS končnih točk

#!/bin/bash
# cert-inventory-network.sh
 
OUTPUT="inventory-network-$(date +%Y%m%d).csv"
ENDPOINTS_FILE="endpoints.txt"
 
echo "Koncna_tocka,Subject,Issuer,Algoritem,Dolzina_kljuca,Veljavno_do,Dni,Serial" > "$OUTPUT"
 
# Končne točke iz datoteke ali CMDB/DNS
# Format: hostname:port
cat "$ENDPOINTS_FILE" | while read endpoint; do
    host=${endpoint%:*}
    port=${endpoint#*:}
    [ -z "$port" ] && port=443
 
    echo "Preglejujem $host:$port..."
 
    cert_info=$(echo | openssl s_client -connect "$host:$port" -servername "$host" 2>/dev/null | openssl x509 -text -noout 2>/dev/null)
 
    if [ -n "$cert_info" ]; then
        subject=$(echo "$cert_info" | grep "Subject:" | head -1 | sed 's/.*Subject: //' | tr ',' ';')
        issuer=$(echo "$cert_info" | grep "Issuer:" | head -1 | sed 's/.*Issuer: //' | tr ',' ';')
        algo=$(echo "$cert_info" | grep "Signature Algorithm" | head -1 | awk '{print $3}')
        keysize=$(echo "$cert_info" | grep "Public-Key:" | grep -oP '\d+')
        not_after=$(echo | openssl s_client -connect "$host:$port" -servername "$host" 2>/dev/null | openssl x509 -enddate -noout | cut -d= -f2)
        days_left=$(( ($(date -d "$not_after" +%s) - $(date +%s)) / 86400 ))
        serial=$(echo | openssl s_client -connect "$host:$port" -servername "$host" 2>/dev/null | openssl x509 -serial -noout | cut -d= -f2)
 
        echo "\"$endpoint\",\"$subject\",\"$issuer\",\"$algo\",\"$keysize\",\"$not_after\",\"$days_left\",\"$serial\"" >> "$OUTPUT"
    else
        echo "\"$endpoint\",\"POVEZAVA NEUSPEŠNA\",\"\",\"\",\"\",\"\",\"\",\"\"" >> "$OUTPUT"
    fi
done
 
echo "Omrežna inventura končana: $OUTPUT"

Inventura CA baze podatkov

#!/bin/bash
# cert-inventory-ca.sh - Iz OpenSSL CA indeksa
 
CA_INDEX="/etc/pki/CA/index.txt"
OUTPUT="inventory-ca-$(date +%Y%m%d).csv"
 
echo "Status,Serial,Iztece,Subject,Datoteka" > "$OUTPUT"
 
while IFS=$'\t' read -r status expiry revoke serial unknown subject; do
    # Status: V=Veljaven, R=Preklican, E=Potekel
    status_text=""
    case "$status" in
        V) status_text="Veljaven" ;;
        R) status_text="Preklican" ;;
        E) status_text="Potekel" ;;
    esac
 
    # Pretvorba datuma izteka (format YYMMDDHHMMSSZ)
    expiry_formatted=$(date -d "20${expiry:0:2}-${expiry:2:2}-${expiry:4:2}" +%Y-%m-%d 2>/dev/null)
 
    # Datoteka certifikata
    cert_file="/etc/pki/CA/newcerts/${serial}.pem"
 
    echo "\"$status_text\",\"$serial\",\"$expiry_formatted\",\"$subject\",\"$cert_file\"" >> "$OUTPUT"
done < "$CA_INDEX"
 
echo "CA inventura končana: $OUTPUT"
echo "Certifikati:"
echo "  Veljavni:   $(grep -c "^\"Veljaven\"" "$OUTPUT")"
echo "  Preklicani: $(grep -c "^\"Preklican\"" "$OUTPUT")"
echo "  Potekli:    $(grep -c "^\"Potekel\"" "$OUTPUT")"

Analiza in poročanje

#!/usr/bin/env python3
# analyze-inventory.py
 
import pandas as pd
from datetime import datetime
 
# Nalaganje vseh inventurnih datotek
df = pd.concat([
    pd.read_csv('inventory-linux*.csv'),
    pd.read_csv('inventory-windows*.csv'),
    pd.read_csv('inventory-network*.csv')
])
 
# Analiza
print("=== Povzetek inventure ===\n")
 
print(f"Skupno število certifikatov: {len(df)}")
 
print("\n--- Po algoritmu ---")
print(df['Algoritem'].value_counts())
 
print("\n--- Po dolžini ključa ---")
print(df['Dolzina_kljuca'].value_counts())
 
print("\n--- Analiza izteka ---")
df['Dni_preostalo'] = pd.to_numeric(df['Dni_preostalo'], errors='coerce')
print(f"Potekli:          {len(df[df['Dni_preostalo'] < 0])}")
print(f"< 30 dni:         {len(df[(df['Dni_preostalo'] >= 0) & (df['Dni_preostalo'] < 30)])}")
print(f"30-90 dni:        {len(df[(df['Dni_preostalo'] >= 30) & (df['Dni_preostalo'] < 90)])}")
print(f"90-365 dni:       {len(df[(df['Dni_preostalo'] >= 90) & (df['Dni_preostalo'] < 365)])}")
print(f"> 1 leto:         {len(df[df['Dni_preostalo'] >= 365])}")
 
print("\n--- Potencial migracije ---")
rsa = len(df[df['Algoritem'].str.contains('rsa', case=False, na=False)])
ecdsa = len(df[df['Algoritem'].str.contains('ecdsa|ec', case=False, na=False)])
hybrid = len(df[df['Algoritem'].str.contains('ml-dsa|hybrid', case=False, na=False)])
print(f"RSA (za migracijo):     {rsa}")
print(f"ECDSA (za migracijo):   {ecdsa}")
print(f"Hibridno (že):          {hybrid}")
 
# Izvoz za načrtovanje migracije
df.to_excel('inventory-complete.xlsx', index=False)
print("\nPolna inventura izvožena: inventory-complete.xlsx")

Predloga nadzorne plošče

Kategorija Število Migracija
——————————–
Algoritem
RSA-2048 150 → Hibridno
RSA-4096 30 → Hibridno
ECDSA P-256 80 → Hibridno
ECDSA P-384 20 → Hibridno
ML-DSA/Hibridno 5 Končano
Iztece
< 30 dni 12 Takoj migrirati
30-90 dni 25 Faza 1
90-365 dni 100 Faza 2
> 1 leto 148 Faza 3
Kritičnost
Zunanji 40 Prioriteta 1
Notranji kritični 80 Prioriteta 2
Razvoj 165 Prioriteta 3

Kontrolni seznam

# Kontrolna točka
—————–
1 Vsi Linux strežniki pregledani
2 Vsi Windows strežniki pregledani
3 Vse TLS končne točke pregledane
4 CA baza podatkov izvožena
5 Podatki konsolidirani
6 Analiza izvedena
7 Načrt migracije ustvarjen

Povezana dokumentacija


« ← Strategija povrnitve | → Scenariji za operaterje »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional