#!/bin/bash # masoara-apache-haproxy-rpc2.sh (PE rpc2, copiat cu scp si chemat pe nume): retetele `apache` si `haproxy` ale remedierii # (cloud-gateway/control-plane/remediere.mjs, GENERATOARE.apache / GENERATOARE.haproxy) masurate pe servere REALE, in containere # (httpd:alpine, haproxy:alpine, fiecare cu OpenSSL-ul lui Alpine), publicate NUMAI pe 127.0.0.1 (8447 Apache, 8448 HAProxy; nimic pe # porturile gazdei), cu EXACT fragmentele retetei pentru hndl-exposed + tls12-accepted + hsts-missing: # apache: SSLOpenSSLConfCmd Groups X25519MLKEM768:X25519 / SSLProtocol -all +TLSv1.3 / Header always set Strict-Transport-Security "max-age=31536000" # haproxy: ssl-default-bind-curves X25519MLKEM768:X25519 / ssl-default-bind-options ssl-min-ver TLSv1.3 / http-response set-header Strict-Transport-Security "max-age=31536000" # Preconditiile retetei se citesc cum le cere ea (randul de pornire al lui Apache cu OpenSSL/; `haproxy -vv` "Running on OpenSSL"), si # comenzile ei de verificare ruleaza in container (`httpd -t` = apachectl configtest; `haproxy -c -f`). Sonde: node 24 de pe rpc2 # (/root/reteta-sonda.mjs: hibrid singur, clasic singur, hibrid+clasic, TLS 1.2 refuzat), HSTS prin curl -k. Containere si imagini sterse # la sfarsit; RPC-ul local cronometrat inainte si dupa. Iesire 0 = 8 din 8 sonde cum trebuie, 1 altfel. set -u D=/root/reteta-ah; rm -rf "$D"; mkdir -p "$D/certs" "$D/apache" "$D/haproxy"; cd "$D" || exit 2 N=/opt/node24/bin/node; S=/root/reteta-sonda.mjs [ -x "$N" ] || { echo "NEMASURAT: node 24 lipseste la $N"; exit 2; } [ -f "$S" ] || { echo "NEMASURAT: sonda lipseste la $S"; exit 2; } rpc() { local t0=$(date +%s%N); curl -s -m 5 -H 'content-type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' http://127.0.0.1:8545 | grep -o '"result":"0x[0-9a-f]*"' | head -1; echo " ($(( ($(date +%s%N) - t0) / 1000000 )) ms)"; } echo "== RPC inainte: $(rpc)" openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -keyout certs/privkey.pem -out certs/fullchain.pem -days 2 -subj '/CN=proba.local' > /dev/null 2>&1 && cat certs/privkey.pem certs/fullchain.pem > certs/proba.pem && chmod 644 certs/*.pem && echo "cert ok (autosemnat, 2 zile)" rele=0 cere() { local nume="$1" ast="$2"; shift 2; out=$("$@" 2>&1); c=$?; if [ "$c" = "$ast" ]; then echo " OK $nume -> cod $c: $(printf '%s' "$out" | cut -c1-170)"; else echo " RAU $nume -> cod $c (asteptat $ast): $(printf '%s' "$out" | cut -c1-170)"; rele=$((rele + 1)); fi; } sonde() { local port="$1" nume="$2" cere "$nume: hibrid singur (X25519MLKEM768)" 0 $N $S 127.0.0.1 $port X25519MLKEM768 cere "$nume: clasic singur (X25519, rezerva din reteta)" 0 $N $S 127.0.0.1 $port X25519 cere "$nume: hibrid + clasic (preferinta)" 0 $N $S 127.0.0.1 $port X25519MLKEM768:X25519 cere "$nume: client TLS 1.2 (refuz)" 1 $N $S 127.0.0.1 $port X25519 TLSv1.2 echo " -- $nume: HSTS (curl -k)"; curl -sk -m 10 -D - -o /dev/null https://127.0.0.1:$port/ | grep -iE '^(strict-transport-security|HTTP)' | tr -d '\r' | sed 's/^/ /'; } # ------------------------------------------------------------------ Apache httpd echo "== APACHE: imaginea httpd:alpine"; docker pull -q httpd:alpine > /dev/null 2>&1; docker image inspect httpd:alpine --format 'imagine: {{.Id}} {{.Size}} octeti' | cut -c1-90 docker run --rm httpd:alpine httpd -v 2>&1 | head -2 | sed 's/^/ /' # httpd.conf al imaginii + modulele cerute de reteta (ssl, socache, headers) + gazda virtuala cu EXACT fragmentul retetei docker run --rm httpd:alpine cat /usr/local/apache2/conf/httpd.conf > apache/httpd.conf 2>/dev/null sed -i -e 's/^#LoadModule ssl_module/LoadModule ssl_module/' -e 's/^#LoadModule socache_shmcb_module/LoadModule socache_shmcb_module/' -e 's/^#LoadModule headers_module/LoadModule headers_module/' apache/httpd.conf cat >> apache/httpd.conf <<'EOF' # ---- proba retetei AERE (remediere.mjs, profilul apache) ---- Listen 8447 ServerName proba.local DocumentRoot "/usr/local/apache2/htdocs" SSLEngine on SSLCertificateFile /usr/local/apache2/conf/certs/fullchain.pem SSLCertificateKeyFile /usr/local/apache2/conf/certs/privkey.pem # EXACT fragmentul retetei: SSLOpenSSLConfCmd Groups X25519MLKEM768:X25519 SSLProtocol -all +TLSv1.3 Header always set Strict-Transport-Security "max-age=31536000" EOF grep -c 'LoadModule ssl_module' apache/httpd.conf | sed 's/^/ LoadModule ssl_module randuri: /' docker rm -f apache-reteta > /dev/null 2>&1 docker run -d --name apache-reteta -p 127.0.0.1:8447:8447 -v "$D/apache/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -v "$D/certs:/usr/local/apache2/conf/certs:ro" httpd:alpine > /dev/null; sleep 3 docker ps --filter name=apache-reteta --format ' container: {{.Status}}' echo " -- verificarea retetei: httpd -t (apachectl configtest) in container"; docker exec apache-reteta httpd -t 2>&1 | tail -1 | sed 's/^/ /' echo " -- preconditia retetei: randul de pornire cu OpenSSL/ (jurnalul serverului)"; docker logs apache-reteta 2>&1 | grep -i 'openssl/' | tail -1 | cut -c1-160 | sed 's/^/ /' sonde 8447 apache docker logs apache-reteta 2>&1 | grep -iE 'error|emerg' | grep -v 'AH00558' | head -3 | sed 's/^/ jurnal: /' # ------------------------------------------------------------------ HAProxy echo "== HAPROXY: imaginea haproxy:alpine"; docker pull -q haproxy:alpine > /dev/null 2>&1; docker image inspect haproxy:alpine --format 'imagine: {{.Id}} {{.Size}} octeti' | cut -c1-90 echo " -- preconditia retetei: haproxy -vv | grep -i 'running on openssl'"; docker run --rm haproxy:alpine haproxy -vv 2>&1 | grep -iE 'HAProxy version|running on openssl|built with openssl' | cut -c1-120 | sed 's/^/ /' cat > haproxy/haproxy.cfg <<'EOF' global # EXACT fragmentul retetei (sectiunea global): ssl-default-bind-curves X25519MLKEM768:X25519 ssl-default-bind-options ssl-min-ver TLSv1.3 defaults mode http timeout connect 5s timeout client 10s timeout server 10s frontend proba bind :8448 ssl crt /usr/local/etc/haproxy/certs/proba.pem # EXACT fragmentul retetei (frontend-ul HTTPS): http-response set-header Strict-Transport-Security "max-age=31536000" http-request return status 200 content-type text/plain string "ok\n" EOF docker rm -f haproxy-reteta > /dev/null 2>&1 echo " -- verificarea retetei: haproxy -c -f"; docker run --rm -v "$D/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro" -v "$D/certs:/usr/local/etc/haproxy/certs:ro" haproxy:alpine haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg 2>&1 | tail -2 | sed 's/^/ /' docker run -d --name haproxy-reteta -p 127.0.0.1:8448:8448 -v "$D/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro" -v "$D/certs:/usr/local/etc/haproxy/certs:ro" haproxy:alpine > /dev/null; sleep 3 docker ps --filter name=haproxy-reteta --format ' container: {{.Status}}' sonde 8448 haproxy docker logs haproxy-reteta 2>&1 | grep -iE 'alert|error|emerg' | head -3 | sed 's/^/ jurnal: /' echo "== curatenie"; docker rm -f apache-reteta haproxy-reteta > /dev/null 2>&1; docker rmi httpd:alpine haproxy:alpine > /dev/null 2>&1 && echo " imaginile sterse" cd /root && rm -rf "$D"; docker ps -a --format '{{.Names}}' | grep -cE 'apache-reteta|haproxy-reteta' | sed 's/^/ containere ramase: /' echo "== RPC dupa: $(rpc)" echo "retetele apache + haproxy: $((8 - rele)) din 8 sonde cum trebuie" [ "$rele" = 0 ] && exit 0 || exit 1