Done — the Squid deployment is fully built, wired in, and statically verified on the feat/squid-proxy branch. ## What landed deployments/squid/ (13 files) plus wiring into [automations.sh](automations.sh:51), [README.md](README.md), and [.gitignore](.gitignore). All six approved design decisions are implemented: - **Self-built minimal Alpine image** — apk add squid (ssl-bump compiled in), openssl/tini. [entrypoint.sh](deployments/squid/entrypoint.sh) renders squid.conf and generates the cache policy from the lists at start. - **SSL-bump** peek→splice→bump with [splice-domains.txt](deployments/squid/splice-domains.txt) passthrough. - **Wildcard hostname caching** — leading-dot [cache-domains.txt](deployments/squid/cache-domains.txt) + optional regex; CACHE_ONLY_LISTED boost/allowlist toggle. - **HTML/dynamic storage gate**, with query strings exempt on boosted domains. - **CA lifecycle** — generated on first deploy via the built image, key 0600 on the host, staged to tmpfs for the container, never embedded, git-ignored. - **Deny-by-default http_access + BIND_ADDR pinning** as the real access gate (Docker bypasses INPUT). ## One bug caught & fixed The test of the entrypoint's policy generation showed it emitting ubuntu.com with an **unescaped dot** — the s/\./\\./g double-backslash is sed-implementation-dependent and silently failed. Switched to a [.] character class (ubuntu[.]com), portable across busybox/git-bash, re-embedded, re-audited. ✅ ## Verified vs. pending **Verified locally:** bash -n on all scripts, LF endings, launcher parses, embedded archive byte-matches the loose files, and the cache-policy generation produces correct Squid directives in both modes. **Pending a Docker host** (this Windows box has none, as the plan anticipated): the container functional smoke test — build, CA mint, a bumped HTTPS fetch, a TCP_HIT, and a splice check. A few version-sensitive specifics get confirmed there: tls-cert=/tls-key= option names, the security_file_certgen path, busybox install -o/-g, ssl::server_name subdomain matching, and the squid -z flag. (All isolated and easy to adjust if any differ.) ## Commit (for you to GPG-sign) Staged and ready. Per your convention I haven't committed — here's the message: `` feat(squid): add SSL-bump caching forward-proxy deployment 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. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> ` `bash git commit -S -F- <<'EOF' <paste message above> EOF ` Want me to **push feat/squid-proxy** once you've committed (you'd open the PR in Gitea), or hold? And if you can point me at a Docker host (or run docker compose build in /srv/squid` after a test deploy), I'll drive the functional smoke test and fix anything the live Squid version flags.
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.
This commit is contained in:
@@ -0,0 +1,453 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# deploy.sh -- deploy the Squid SSL-bump caching forward proxy.
|
||||
#
|
||||
# What this does:
|
||||
# 1. Installs docker + compose if missing.
|
||||
# 2. Lays down the stack files in $STACK_DIR and builds the local image.
|
||||
# 3. Generates the TLS interception CA on first run (never overwritten).
|
||||
# 4. Generates .env on first run; existing .env is never overwritten.
|
||||
# 5. Prompts for required values not preset (TRUSTED_CIDR).
|
||||
# 6. Registers the proxy port with the host firewall if present.
|
||||
# 7. Brings the stack up and waits for health.
|
||||
#
|
||||
# Role: this is a FORWARD proxy, not an inbound web service -- there is no
|
||||
# public hostname or Let's Encrypt cert. Clients set HTTP(S)_PROXY to this host
|
||||
# and trust the generated CA. Only run it on networks/devices you own.
|
||||
#
|
||||
# Idempotent: re-run to apply config changes / rebuild the image.
|
||||
#
|
||||
# Self-contained: the compose file, Dockerfile, entrypoint, config template and
|
||||
# domain lists are embedded as a base64 tar.gz at the bottom of this file.
|
||||
# Rebuild with build.sh after editing the loose source files.
|
||||
#
|
||||
# Usage:
|
||||
# bash deploy.sh # interactive prompts
|
||||
# TRUSTED_CIDR=10.0.0.0/8 BIND_ADDR=100.64.0.1 \
|
||||
# SKIP_PROMPTS=1 bash deploy.sh # non-interactive
|
||||
# STACK_DIR=/opt/squid bash deploy.sh
|
||||
# SKIP_DOCKER_INSTALL=1 bash deploy.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
: "${STACK_DIR:=/srv/squid}"
|
||||
: "${SKIP_DOCKER_INSTALL:=0}"
|
||||
: "${FORCE:=0}"
|
||||
: "${SKIP_PROMPTS:=0}" # non-interactive: require values via env, no prompts
|
||||
[[ "$SKIP_PROMPTS" == "1" ]] && FORCE=1
|
||||
: "${TRUSTED_CIDR:=}"
|
||||
: "${BIND_ADDR:=}"
|
||||
: "${PROXY_PORT:=3128}"
|
||||
: "${CACHE_SIZE_MB:=}"
|
||||
: "${CACHE_ONLY_LISTED:=}"
|
||||
: "${CA_CN:=Squid Proxy CA}"
|
||||
: "${CA_O:=automations}"
|
||||
: "${CA_DAYS:=3650}"
|
||||
: "${SQUID_IMAGE_TAG:=automations/squid:latest}"
|
||||
|
||||
log() { printf '\033[1;32m[+]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*" >&2; }
|
||||
die() { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
[[ $EUID -eq 0 ]] || die "Run as root."
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# OS detection + Docker install (Alpine / Debian / Alma). This deploy.sh is
|
||||
# self-contained (scp'd standalone), so the OS logic is inlined here instead
|
||||
# of sourced from scripts/oslib.sh.
|
||||
# ---------------------------------------------------------------------------
|
||||
osfam() {
|
||||
local id="" like=""
|
||||
if [[ -r /etc/os-release ]]; then
|
||||
id="$(. /etc/os-release 2>/dev/null && echo "${ID:-}")"
|
||||
like="$(. /etc/os-release 2>/dev/null && echo "${ID_LIKE:-}")"
|
||||
fi
|
||||
case " $id $like " in
|
||||
*" alpine "*) echo alpine ;;
|
||||
*" debian "*|*" ubuntu "*) echo debian ;;
|
||||
*" rhel "*|*" fedora "*|*" centos "*) echo rhel ;;
|
||||
*) echo "${id:-unknown}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_docker() {
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
log "Docker already installed: $(docker --version)"
|
||||
else
|
||||
log "Installing Docker (OS: $(osfam))..."
|
||||
case "$(osfam)" in
|
||||
alpine) apk add -q docker docker-cli-compose openrc ;;
|
||||
debian|rhel) command -v curl >/dev/null 2>&1 || \
|
||||
{ command -v apt-get >/dev/null 2>&1 && apt-get install -y -qq curl; } || \
|
||||
{ command -v dnf >/dev/null 2>&1 && dnf install -y -q curl; }
|
||||
curl -fsSL https://get.docker.com | sh ;;
|
||||
*) die "Unsupported OS for auto Docker install. Set SKIP_DOCKER_INSTALL=1 and install Docker yourself." ;;
|
||||
esac
|
||||
fi
|
||||
if command -v rc-update >/dev/null 2>&1; then
|
||||
rc-update add docker default >/dev/null 2>&1 || true
|
||||
rc-service docker status >/dev/null 2>&1 || rc-service docker start
|
||||
elif command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl enable --now docker >/dev/null 2>&1 || systemctl start docker || true
|
||||
fi
|
||||
}
|
||||
|
||||
open_proxy_port() {
|
||||
# Register the proxy port. Prefer the host firewall (harden-firewall.sh)
|
||||
# when present; else ufw/firewalld if active.
|
||||
#
|
||||
# NOTE: a Docker-published port reaches the host through nat/FORWARD and
|
||||
# BYPASSES the INPUT firewall, so this is belt-and-braces -- the real access
|
||||
# gate is Squid's http_access (TRUSTED_CIDR) plus pinning BIND_ADDR to a
|
||||
# trusted interface. The ports.d format is port-only (no source CIDR), so
|
||||
# restrict the source via BIND_ADDR / upstream firewalling, not here.
|
||||
local port="${PROXY_PORT:-3128}"
|
||||
if [[ -d /etc/firewall/ports.d && -x /usr/local/sbin/firewall-apply ]]; then
|
||||
log "Registering ${port}/tcp with host firewall..."
|
||||
printf '%s/tcp\n' "$port" > /etc/firewall/ports.d/squid.rule
|
||||
/usr/local/sbin/firewall-apply
|
||||
elif command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
|
||||
log "ufw active -- allowing ${port}/tcp..."
|
||||
ufw allow "${port}/tcp" >/dev/null
|
||||
elif command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
|
||||
log "firewalld active -- allowing ${port}/tcp..."
|
||||
firewall-cmd -q --add-port="${port}/tcp" --permanent
|
||||
firewall-cmd -q --reload
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Extract embedded archive
|
||||
# ----------------------------------------------------------------------------
|
||||
SCRIPT_DIR=$(mktemp -d -t squid-deploy.XXXXXX)
|
||||
trap 'rm -rf "$SCRIPT_DIR"' EXIT
|
||||
|
||||
extract_archive() {
|
||||
grep -a -A 9999999 '^__ARCHIVE_BELOW__$' "$0" \
|
||||
| tail -n +2 \
|
||||
| base64 -d \
|
||||
| tar -xz -C "$SCRIPT_DIR"
|
||||
}
|
||||
|
||||
if grep -q -a '^__ARCHIVE_BELOW__$' "$0"; then
|
||||
log "Extracting embedded deployment files..."
|
||||
extract_archive
|
||||
else
|
||||
die "No embedded archive found. Run build.sh to embed deployment files."
|
||||
fi
|
||||
|
||||
EMBEDDED=(docker-compose.yml Dockerfile entrypoint.sh squid.conf.tmpl
|
||||
splice-domains.txt cache-domains.txt cache-domains.regex .env.example)
|
||||
for f in "${EMBEDDED[@]}"; do
|
||||
[[ -f "$SCRIPT_DIR/$f" ]] || die "Embedded archive missing $f"
|
||||
done
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Prompt for required vars
|
||||
# ----------------------------------------------------------------------------
|
||||
prompt() {
|
||||
local varname="$1" message="$2"
|
||||
local -n ref="$varname"
|
||||
if [[ -z "${ref:-}" ]]; then
|
||||
[[ "$SKIP_PROMPTS" == "1" ]] && die "$varname required (set it in the environment; running with SKIP_PROMPTS=1)."
|
||||
read -r -p "$message: " ref
|
||||
[[ -n "$ref" ]] || die "$varname required."
|
||||
fi
|
||||
}
|
||||
|
||||
prompt TRUSTED_CIDR "Trusted client CIDR(s) allowed to use the proxy (e.g. 100.64.0.0/10)"
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Docker + firewall
|
||||
# ----------------------------------------------------------------------------
|
||||
if [[ "$SKIP_DOCKER_INSTALL" != "1" ]]; then
|
||||
install_docker
|
||||
fi
|
||||
open_proxy_port
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Stack directory + files
|
||||
# ----------------------------------------------------------------------------
|
||||
log "Setting up $STACK_DIR..."
|
||||
install -d -m 0750 "$STACK_DIR"
|
||||
install -m 0644 "$SCRIPT_DIR/docker-compose.yml" "$STACK_DIR/docker-compose.yml"
|
||||
install -m 0644 "$SCRIPT_DIR/Dockerfile" "$STACK_DIR/Dockerfile"
|
||||
install -m 0755 "$SCRIPT_DIR/entrypoint.sh" "$STACK_DIR/entrypoint.sh"
|
||||
install -m 0644 "$SCRIPT_DIR/squid.conf.tmpl" "$STACK_DIR/squid.conf.tmpl"
|
||||
install -m 0644 "$SCRIPT_DIR/splice-domains.txt" "$STACK_DIR/splice-domains.txt"
|
||||
install -m 0644 "$SCRIPT_DIR/cache-domains.txt" "$STACK_DIR/cache-domains.txt"
|
||||
install -m 0644 "$SCRIPT_DIR/cache-domains.regex" "$STACK_DIR/cache-domains.regex"
|
||||
|
||||
ENV_FILE="$STACK_DIR/.env"
|
||||
set_env() { # <KEY> <value>: update KEY in .env, or append if absent
|
||||
local key="$1" val="$2" esc
|
||||
esc=${val//\\/\\\\}; esc=${esc//|/\\|}; esc=${esc//&/\\&}
|
||||
if grep -qE "^${key}=" "$ENV_FILE"; then
|
||||
sed -i -e "s|^${key}=.*|${key}=${esc}|" "$ENV_FILE"
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$val" >> "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
log "Seeding $ENV_FILE..."
|
||||
install -m 0600 "$SCRIPT_DIR/.env.example" "$ENV_FILE"
|
||||
set_env TRUSTED_CIDR "$TRUSTED_CIDR"
|
||||
if [[ -n "${BIND_ADDR:-}" ]]; then set_env BIND_ADDR "$BIND_ADDR"; fi
|
||||
if [[ -n "${PROXY_PORT:-}" ]]; then set_env PROXY_PORT "$PROXY_PORT"; fi
|
||||
if [[ -n "${CACHE_SIZE_MB:-}" ]]; then set_env CACHE_SIZE_MB "$CACHE_SIZE_MB"; fi
|
||||
if [[ -n "${CACHE_ONLY_LISTED:-}" ]]; then set_env CACHE_ONLY_LISTED "$CACHE_ONLY_LISTED"; fi
|
||||
set_env CA_CN "$CA_CN"
|
||||
set_env CA_O "$CA_O"
|
||||
set_env SQUID_IMAGE_TAG "$SQUID_IMAGE_TAG"
|
||||
else
|
||||
log ".env exists; leaving it alone."
|
||||
fi
|
||||
|
||||
# Validate required value landed.
|
||||
grep -E "^TRUSTED_CIDR=.+$" "$ENV_FILE" >/dev/null || die "TRUSTED_CIDR missing in $ENV_FILE."
|
||||
|
||||
# Use the image tag actually recorded in .env (keeps build + CA-gen in sync).
|
||||
IMAGE=$(grep -E '^SQUID_IMAGE_TAG=' "$ENV_FILE" | head -n1 | cut -d= -f2-)
|
||||
IMAGE=${IMAGE:-$SQUID_IMAGE_TAG}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Confirm (interception is a big deal)
|
||||
# ----------------------------------------------------------------------------
|
||||
if [[ "$FORCE" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
About to build the Squid image and start an SSL-bump forward proxy from
|
||||
$STACK_DIR.
|
||||
|
||||
This generates a local CA and INTERCEPTS TLS for every client that trusts it
|
||||
(except spliced domains). Only do this on networks/devices you own and are
|
||||
authorized to inspect. Clients reach it at: http://<this-host>:${PROXY_PORT}
|
||||
|
||||
Continue? [y/N]
|
||||
EOF
|
||||
read -r ans
|
||||
[[ "${ans,,}" == "y" || "${ans,,}" == "yes" ]] || { warn "Aborted."; exit 0; }
|
||||
fi
|
||||
|
||||
cd "$STACK_DIR"
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Build image, then generate the CA (needs the built image's openssl)
|
||||
# ----------------------------------------------------------------------------
|
||||
log "Building image $IMAGE..."
|
||||
docker compose build
|
||||
|
||||
SSL_DIR="$STACK_DIR/ssl"
|
||||
install -d -m 0750 "$SSL_DIR"
|
||||
if [[ ! -f "$SSL_DIR/squid-ca-key.pem" || ! -f "$SSL_DIR/squid-ca-cert.pem" ]]; then
|
||||
log "Generating TLS interception CA (one-time; CN=${CA_CN})..."
|
||||
docker run --rm -v "$SSL_DIR:/out" --entrypoint openssl "$IMAGE" \
|
||||
req -x509 -newkey rsa:4096 -sha256 -days "$CA_DAYS" -nodes \
|
||||
-keyout /out/squid-ca-key.pem -out /out/squid-ca-cert.pem \
|
||||
-subj "/CN=${CA_CN}/O=${CA_O}" \
|
||||
-addext "basicConstraints=critical,CA:TRUE" \
|
||||
-addext "keyUsage=critical,keyCertSign,cRLSign"
|
||||
chmod 0600 "$SSL_DIR/squid-ca-key.pem"
|
||||
chmod 0644 "$SSL_DIR/squid-ca-cert.pem"
|
||||
log "CA created. Distribute $SSL_DIR/squid-ca-cert.pem to client trust stores."
|
||||
else
|
||||
log "CA already present in $SSL_DIR; leaving it."
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Bring up the stack
|
||||
# ----------------------------------------------------------------------------
|
||||
log "Starting stack..."
|
||||
docker compose up -d --remove-orphans
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Wait for health
|
||||
# ----------------------------------------------------------------------------
|
||||
log "Waiting for squid to become healthy (up to 120s)..."
|
||||
deadline=$(( $(date +%s) + 120 ))
|
||||
while (( $(date +%s) < deadline )); do
|
||||
status=$(docker compose ps --format '{{.Service}} {{.Health}}' 2>/dev/null || true)
|
||||
unhealthy=$(echo "$status" | awk '$2 != "healthy" && $2 != "" {print $1}')
|
||||
if [[ -z "$unhealthy" && -n "$status" ]]; then
|
||||
log "Squid healthy."
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
|
||||
echo
|
||||
log "Stack status:"
|
||||
docker compose ps
|
||||
echo
|
||||
CERT="$SSL_DIR/squid-ca-cert.pem"
|
||||
cat <<EOF
|
||||
================================================================
|
||||
DEPLOYED -- Squid SSL-bump caching forward proxy
|
||||
|
||||
Proxy: http://<this-host>:${PROXY_PORT}
|
||||
Stack dir: ${STACK_DIR}
|
||||
CA cert: ${CERT}
|
||||
|
||||
1. Point clients at the proxy:
|
||||
export http_proxy=http://<this-host>:${PROXY_PORT}
|
||||
export https_proxy=http://<this-host>:${PROXY_PORT}
|
||||
(apk: /etc/apk/repositories via http_proxy; apt: Acquire::http(s)::Proxy;
|
||||
dnf: proxy= in /etc/dnf/dnf.conf)
|
||||
|
||||
2. Trust the CA on each client (so bumped HTTPS validates):
|
||||
Debian/Ubuntu: cp ${CERT##*/} /usr/local/share/ca-certificates/squid-ca.crt && update-ca-certificates
|
||||
Alpine: cp ${CERT##*/} /usr/local/share/ca-certificates/squid-ca.crt && update-ca-certificates
|
||||
Alma/RHEL: cp ${CERT##*/} /etc/pki/ca-trust/source/anchors/squid-ca.pem && update-ca-trust
|
||||
Browsers/Java keep their own trust stores -- import there too if needed.
|
||||
|
||||
3. Tune behavior, then re-render (lists are bind-mounted):
|
||||
${STACK_DIR}/cache-domains.txt domains to cache hard (wildcards)
|
||||
${STACK_DIR}/cache-domains.regex glob/regex cache patterns (optional)
|
||||
${STACK_DIR}/splice-domains.txt domains to NOT decrypt
|
||||
edit, then: cd ${STACK_DIR} && docker compose restart
|
||||
|
||||
Logs / cache stats:
|
||||
docker compose logs -f
|
||||
docker exec squid squid -k parse # validate config
|
||||
docker exec squid tail -f /var/log/squid/access.log # TCP_HIT / TCP_MISS
|
||||
|
||||
Manage:
|
||||
docker compose pull >/dev/null; docker compose build && docker compose up -d # update
|
||||
docker compose down # stop, keep cache + CA
|
||||
docker compose down -v # stop, WIPE cache + leaf-cert DB (CA on host survives)
|
||||
|
||||
SECURITY: keep ${SSL_DIR}/squid-ca-key.pem secret (it can MITM every client
|
||||
that trusts it). It is 0600 root and never leaves this host. Only intercept
|
||||
traffic on networks/devices you own.
|
||||
|
||||
Or just re-run this script -- it's idempotent.
|
||||
================================================================
|
||||
EOF
|
||||
|
||||
# IMPORTANT: do not put any code below this exit. Everything after the
|
||||
# __ARCHIVE_BELOW__ marker is the embedded tar.gz payload (base64), appended by
|
||||
# build.sh.
|
||||
exit 0
|
||||
__ARCHIVE_BELOW__
|
||||
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
|
||||
Reference in New Issue
Block a user