e7ba68790b
New deployments/squid/: an explicit forward proxy with SSL-bump TLS interception (local CA, generated on first deploy) and hostname-targeted static-content caching. Unlike the other stacks it is a forward proxy, not a Caddy/Let's-Encrypt inbound site. - Self-built minimal Alpine image (apk squid ships ssl-bump); entrypoint renders squid.conf and generates the cache policy from the domain lists. - Wildcard hostname caching (cache-domains.txt leading-dot + optional cache-domains.regex); boost vs strict-allowlist toggle (CACHE_ONLY_LISTED). - Storage gate never caches HTML or dynamic content; query strings exempt on boosted domains so versioned static assets still cache. - splice-domains.txt passthrough for pinned/banking domains. - Deny-by-default http_access (TRUSTED_CIDR) + BIND_ADDR pinning; CA key 0600 on host, never embedded, git-ignored. - Wired into automations.sh, README, .gitignore; cloud-init for fresh VMs.
146 lines
6.1 KiB
Bash
146 lines
6.1 KiB
Bash
#!/bin/sh
|
|
#
|
|
# entrypoint.sh -- container start-up for the Squid SSL-bump caching proxy.
|
|
#
|
|
# 1. Render /etc/squid/squid.conf from squid.conf.tmpl (@VAR@ -> env).
|
|
# 2. Generate the cache-policy include from cache-domains.txt / .regex and the
|
|
# CACHE_ONLY_LISTED toggle (boost ACLs, storage gate, per-domain TTLs).
|
|
# 3. Stage the CA into a squid-readable tmpfs copy (host key stays 0600 root).
|
|
# 4. Init the dynamic-cert DB + cache_dir structure (idempotent).
|
|
# 5. Validate the config, then exec squid in the foreground.
|
|
#
|
|
# Runs as root (needs chown/install); squid then drops to cache_effective_user.
|
|
|
|
set -eu
|
|
|
|
TMPL=/etc/squid/squid.conf.tmpl
|
|
CONF=/etc/squid/squid.conf
|
|
GEN_DIR=/etc/squid/conf.d
|
|
GEN="$GEN_DIR/cache-policy.conf"
|
|
SSL_SRC=/etc/squid/ssl
|
|
SSL_RUN=/run/squid
|
|
SSL_DB=/var/lib/squid/ssl_db
|
|
CACHE_DOMAINS=/etc/squid/cache-domains.txt
|
|
CACHE_REGEX=/etc/squid/cache-domains.regex
|
|
|
|
# Tunables -- docker-compose passes these from .env; defaults keep the image
|
|
# runnable on its own for a smoke test.
|
|
: "${TRUSTED_CIDR:=127.0.0.1/32}"
|
|
: "${CACHE_SIZE_MB:=5000}"
|
|
: "${MAX_OBJECT_SIZE_MB:=256}"
|
|
: "${CACHE_MEM_MB:=256}"
|
|
: "${DYNAMIC_CERT_MEM_MB:=8}"
|
|
: "${CACHE_ONLY_LISTED:=0}"
|
|
: "${VISIBLE_HOSTNAME:=squid-proxy}"
|
|
|
|
log() { printf '[entrypoint] %s\n' "$*" >&2; }
|
|
|
|
# A list file "has entries" if it holds >=1 non-blank, non-comment line.
|
|
has_entries() { [ -f "$1" ] && grep -qE '^[[:space:]]*[^#[:space:]]' "$1"; }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Render the static config from the template (@VAR@ placeholders).
|
|
# ---------------------------------------------------------------------------
|
|
sed \
|
|
-e "s|@TRUSTED_CIDR@|${TRUSTED_CIDR}|g" \
|
|
-e "s|@CACHE_SIZE_MB@|${CACHE_SIZE_MB}|g" \
|
|
-e "s|@MAX_OBJECT_SIZE_MB@|${MAX_OBJECT_SIZE_MB}|g" \
|
|
-e "s|@CACHE_MEM_MB@|${CACHE_MEM_MB}|g" \
|
|
-e "s|@DYNAMIC_CERT_MEM_MB@|${DYNAMIC_CERT_MEM_MB}|g" \
|
|
-e "s|@VISIBLE_HOSTNAME@|${VISIBLE_HOSTNAME}|g" \
|
|
"$TMPL" > "$CONF"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Generate the cache-policy include from the domain lists + toggle.
|
|
# Storage gate runs first (whether to store); per-domain refresh_patterns
|
|
# only tune freshness of what survived the gate.
|
|
# ---------------------------------------------------------------------------
|
|
mkdir -p "$GEN_DIR"
|
|
{
|
|
echo "# AUTO-GENERATED by entrypoint.sh at container start -- do not edit."
|
|
echo "# Source: cache-domains.txt / cache-domains.regex + CACHE_ONLY_LISTED."
|
|
echo
|
|
|
|
# Boost ACLs are only emitted when their backing file is non-empty, else
|
|
# squid would error on an empty ACL.
|
|
exc=""
|
|
if has_entries "$CACHE_DOMAINS"; then
|
|
echo 'acl boost dstdomain "/etc/squid/cache-domains.txt"'
|
|
exc="$exc !boost"
|
|
fi
|
|
if has_entries "$CACHE_REGEX"; then
|
|
echo 'acl boost_re dstdom_regex "/etc/squid/cache-domains.regex"'
|
|
exc="$exc !boost_re"
|
|
fi
|
|
|
|
cat <<'ACLS'
|
|
acl has_query urlpath_regex \?
|
|
acl dyn_ext urlpath_regex (/cgi-bin/|\.(cgi|php|aspx?|jsp)$)
|
|
acl html_ext urlpath_regex \.html?(\?|$)
|
|
acl html_ct rep_mime_type -i ^text/html
|
|
|
|
# Storage gate: never store HTML (by ext or content-type) or dynamic content.
|
|
cache deny html_ext
|
|
cache deny dyn_ext
|
|
ACLS
|
|
# Query strings are dynamic EXCEPT on boosted domains (versioned static
|
|
# assets like app.js?v=123 should still cache there).
|
|
echo "cache deny has_query${exc}"
|
|
echo 'store_miss deny html_ct'
|
|
|
|
if [ "$CACHE_ONLY_LISTED" = "1" ]; then
|
|
echo
|
|
echo "# CACHE_ONLY_LISTED=1: store ONLY the listed domains."
|
|
if has_entries "$CACHE_DOMAINS"; then echo 'cache allow boost'; fi
|
|
if has_entries "$CACHE_REGEX"; then echo 'cache allow boost_re'; fi
|
|
echo 'cache deny all'
|
|
fi
|
|
|
|
if has_entries "$CACHE_DOMAINS"; then
|
|
echo
|
|
echo "# Boost: long TTL + force-cache for each listed wildcard domain."
|
|
grep -E '^[[:space:]]*[^#[:space:]]' "$CACHE_DOMAINS" | while read -r dom _rest; do
|
|
# ".example.com" / "example.com" -> "example[.]com" ([.] matches a
|
|
# literal dot portably -- avoids sed backslash-escaping quirks).
|
|
d=$(printf '%s' "$dom" | sed 's/^\.//; s/\./[.]/g')
|
|
printf 'refresh_pattern -i %s 1440 100%% 43200 override-expire ignore-private ignore-no-store override-lastmod\n' \
|
|
"^https?://([^/]+[.])?${d}/"
|
|
done
|
|
fi
|
|
} > "$GEN"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Stage the CA into a squid-readable tmpfs copy. The host key is 0600 root
|
|
# (mounted read-only); root copies it to /run owned by squid so the signer
|
|
# can read it without loosening the host file.
|
|
# ---------------------------------------------------------------------------
|
|
if [ ! -f "$SSL_SRC/squid-ca-cert.pem" ] || [ ! -f "$SSL_SRC/squid-ca-key.pem" ]; then
|
|
log "FATAL: CA missing in $SSL_SRC (need squid-ca-cert.pem + squid-ca-key.pem)."
|
|
exit 1
|
|
fi
|
|
install -d -m 0710 -o squid -g squid "$SSL_RUN"
|
|
install -m 0444 -o squid -g squid "$SSL_SRC/squid-ca-cert.pem" "$SSL_RUN/ca-cert.pem"
|
|
install -m 0400 -o squid -g squid "$SSL_SRC/squid-ca-key.pem" "$SSL_RUN/ca-key.pem"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Init the dynamic-cert DB + cache_dir structure (idempotent).
|
|
# ---------------------------------------------------------------------------
|
|
if [ ! -s "$SSL_DB/index.txt" ]; then
|
|
log "Initializing TLS cert DB at $SSL_DB..."
|
|
find "$SSL_DB" -mindepth 1 -delete 2>/dev/null || true
|
|
/usr/lib/squid/security_file_certgen -c -s "$SSL_DB" -M "${DYNAMIC_CERT_MEM_MB}MB"
|
|
fi
|
|
chown -R squid:squid "$SSL_DB" /var/cache/squid /var/log/squid 2>/dev/null || true
|
|
|
|
if [ ! -d /var/cache/squid/00 ]; then
|
|
log "Initializing cache_dir structure..."
|
|
squid -f "$CONF" -z --foreground || squid -f "$CONF" -z || true
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 5. Validate the rendered + generated config, then hand off to squid.
|
|
# ---------------------------------------------------------------------------
|
|
squid -k parse -f "$CONF"
|
|
log "Starting squid (visible_hostname=${VISIBLE_HOSTNAME})..."
|
|
exec squid -N -f "$CONF" "$@"
|