Files
homelab/k8s/apps/amnezia/configmap-scripts.yaml
T

532 lines
19 KiB
YAML
Raw Normal View History

2026-06-16 02:27:29 +01:00
---
apiVersion: v1
kind: ConfigMap
metadata:
name: amneziawg-scripts
data:
firewall-up.sh: |
#!/usr/bin/env bash
set -euo pipefail
PORT="${1:-5847}"
2026-06-16 03:48:41 +01:00
VPN_CIDR="${2:-10.8.0.0/16}"
2026-07-30 23:16:36 +01:00
POLICY_FILE="${3:-/run/amnezia/policy/policy.conf}"
2026-07-28 13:04:19 +01:00
FORWARD_CHAIN="AMNEZIAWG-FORWARD"
2026-07-30 23:16:36 +01:00
POLICY_CHAIN_A="AMNEZIAWG-POLICY-A"
POLICY_CHAIN_B="AMNEZIAWG-POLICY-B"
2026-07-28 13:04:19 +01:00
IPTABLES=(iptables -w 30)
2026-06-16 02:27:29 +01:00
external_interface() {
ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}'
}
2026-07-28 13:04:19 +01:00
ensure_rule() {
local mode="$1"
shift
2026-06-16 02:27:29 +01:00
local table_args=()
if [ "${1:-}" = "-t" ]; then
table_args=("$1" "$2")
shift 2
fi
local chain="$1"
shift
2026-07-28 13:04:19 +01:00
if ! "${IPTABLES[@]}" "${table_args[@]}" -C "${chain}" "$@" >/dev/null 2>&1; then
"${IPTABLES[@]}" "${table_args[@]}" "${mode}" "${chain}" "$@"
2026-06-16 02:27:29 +01:00
fi
}
2026-06-18 00:06:14 +01:00
delete_rule() {
local table_args=()
if [ "${1:-}" = "-t" ]; then
table_args=("$1" "$2")
shift 2
fi
local chain="$1"
shift
2026-07-28 13:04:19 +01:00
while "${IPTABLES[@]}" "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do
2026-06-18 00:06:14 +01:00
true
done
}
2026-07-30 23:16:36 +01:00
ensure_chain() {
"${IPTABLES[@]}" -N "$1" >/dev/null 2>&1 || true
}
valid_ipv4_32() {
local value="$1"
[[ "${value}" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/32$ ]] || return 1
local address="${value%/32}"
local octet
IFS=. read -r -a octets <<< "${address}"
[ "${#octets[@]}" -eq 4 ] || return 1
for octet in "${octets[@]}"; do
[[ "${octet}" =~ ^[0-9]+$ ]] || return 1
[ "${octet}" -le 255 ] || return 1
done
}
routed_through_awg0() {
ip -4 route get "${1%/32}" 2>/dev/null | grep -Eq '(^|[[:space:]])dev awg0([[:space:]]|$)'
}
active_policy_chain() {
"${IPTABLES[@]}" -S "${FORWARD_CHAIN}" 2>/dev/null \
| awk '$1 == "-A" && $3 == "-j" && $4 ~ /^AMNEZIAWG-POLICY-[AB]$/ { print $4; exit }'
}
apply_policy() {
local active inactive source destination extra
active="$(active_policy_chain || true)"
if [ "${active}" = "${POLICY_CHAIN_A}" ]; then
inactive="${POLICY_CHAIN_B}"
else
inactive="${POLICY_CHAIN_A}"
fi
ensure_chain "${inactive}"
"${IPTABLES[@]}" -F "${inactive}"
if [ -f "${POLICY_FILE}" ]; then
while read -r source destination extra; do
[ -n "${source:-}" ] || continue
[[ "${source}" == \#* ]] && continue
if [ -n "${extra:-}" ] \
|| ! valid_ipv4_32 "${source}" \
|| ! valid_ipv4_32 "${destination:-}" \
|| ! routed_through_awg0 "${source}" \
|| ! routed_through_awg0 "${destination}"; then
echo "Invalid or out-of-tunnel policy line: ${source:-} ${destination:-} ${extra:-}" >&2
"${IPTABLES[@]}" -F "${inactive}"
return 1
fi
"${IPTABLES[@]}" -A "${inactive}" \
-i awg0 -o awg0 -s "${source}" -d "${destination}" \
-m comment --comment amneziawg-group-pair -j ACCEPT
done < "${POLICY_FILE}"
fi
# This DROP is deliberately restricted to packets entering and leaving
# awg0. It cannot match Kubernetes, CNI, kubelet, Tailscale, or host traffic.
"${IPTABLES[@]}" -A "${inactive}" \
-i awg0 -o awg0 -s "${VPN_CIDR}" -d "${VPN_CIDR}" \
-m comment --comment amneziawg-client-isolation -j DROP
"${IPTABLES[@]}" -A "${inactive}" \
-i awg0 -o "${EXT_IF}" -s "${VPN_CIDR}" \
-m conntrack --ctstate NEW,ESTABLISHED,RELATED \
-m comment --comment amneziawg-internet-out -j ACCEPT
"${IPTABLES[@]}" -A "${inactive}" \
-i "${EXT_IF}" -o awg0 -d "${VPN_CIDR}" \
-m conntrack --ctstate ESTABLISHED,RELATED \
-m comment --comment amneziawg-internet-return -j ACCEPT
"${IPTABLES[@]}" -A "${inactive}" -j RETURN
# Insert the complete new policy before removing the old jump. There is
# never a window with a partially built or absent active policy.
"${IPTABLES[@]}" -I "${FORWARD_CHAIN}" 1 -j "${inactive}"
if [ -n "${active}" ]; then
"${IPTABLES[@]}" -D "${FORWARD_CHAIN}" -j "${active}"
fi
2026-06-16 02:27:29 +01:00
}
EXT_IF="$(external_interface || true)"
if [ -z "${EXT_IF}" ]; then
EXT_IF="$(ip route show default | awk '{print $5; exit}')"
fi
if [ -z "${EXT_IF}" ]; then
echo "Unable to detect external interface"
exit 1
fi
sysctl -w net.ipv4.ip_forward=1
2026-07-30 23:16:36 +01:00
sysctl -w net.ipv4.conf.awg0.send_redirects=0
2026-06-16 02:27:29 +01:00
2026-07-28 13:04:19 +01:00
# Remove rules written by older revisions. In particular, the unqualified
# tailscale UDP DROP also blocks Flannel VXLAN (UDP/8472).
2026-06-18 00:06:14 +01:00
delete_rule INPUT -i tailscale0 -p udp -m comment --comment amneziawg-block-tailscale -j DROP
2026-07-28 13:04:19 +01:00
delete_rule INPUT -i "${EXT_IF}" -p udp -m comment --comment amneziawg-allow-external -j ACCEPT
delete_rule INPUT -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT
delete_rule INPUT -i tailscale0 -p udp --dport "${PORT}" -m comment --comment amneziawg-block-tailscale -j DROP
delete_rule INPUT -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT
delete_rule FORWARD -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT
delete_rule FORWARD -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT
2026-07-28 13:17:12 +01:00
delete_rule INPUT -m comment --comment amneziawg-input-jump -j AMNEZIAWG-INPUT
"${IPTABLES[@]}" -F AMNEZIAWG-INPUT >/dev/null 2>&1 || true
"${IPTABLES[@]}" -X AMNEZIAWG-INPUT >/dev/null 2>&1 || true
2026-07-28 13:04:19 +01:00
2026-07-30 23:16:36 +01:00
ensure_chain "${FORWARD_CHAIN}"
ensure_chain "${POLICY_CHAIN_A}"
ensure_chain "${POLICY_CHAIN_B}"
if ! "${IPTABLES[@]}" -S "${FORWARD_CHAIN}" 2>/dev/null | grep -q -- '-j RETURN'; then
"${IPTABLES[@]}" -A "${FORWARD_CHAIN}" -j RETURN
fi
apply_policy
delete_rule "${FORWARD_CHAIN}" -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT
delete_rule "${FORWARD_CHAIN}" -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT
# The jump is first, but non-awg traffic immediately RETURNs to the original
# host FORWARD chain without an ACCEPT or DROP decision.
delete_rule FORWARD -m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}"
"${IPTABLES[@]}" -I FORWARD 1 \
-m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}"
2026-07-28 13:04:19 +01:00
ensure_rule -A -t nat POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE
/scripts/firewall-check.sh "${PORT}" "${VPN_CIDR}"
2026-06-16 02:27:29 +01:00
firewall-down.sh: |
#!/usr/bin/env bash
set -euo pipefail
PORT="${1:-5847}"
2026-06-16 03:48:41 +01:00
VPN_CIDR="${2:-10.8.0.0/16}"
2026-07-28 13:04:19 +01:00
FORWARD_CHAIN="AMNEZIAWG-FORWARD"
2026-07-30 23:16:36 +01:00
POLICY_CHAIN_A="AMNEZIAWG-POLICY-A"
POLICY_CHAIN_B="AMNEZIAWG-POLICY-B"
2026-07-28 13:04:19 +01:00
IPTABLES=(iptables -w 30)
2026-06-16 02:27:29 +01:00
external_interface() {
ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}'
}
delete_rule() {
local table_args=()
if [ "${1:-}" = "-t" ]; then
table_args=("$1" "$2")
shift 2
fi
local chain="$1"
shift
2026-07-28 13:04:19 +01:00
while "${IPTABLES[@]}" "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do
2026-06-16 02:27:29 +01:00
true
done
}
EXT_IF="$(external_interface || true)"
if [ -z "${EXT_IF}" ]; then
EXT_IF="$(ip route show default | awk '{print $5; exit}')"
fi
if [ -n "${EXT_IF}" ]; then
2026-07-28 13:04:19 +01:00
delete_rule INPUT -i "${EXT_IF}" -p udp -m comment --comment amneziawg-allow-external -j ACCEPT
2026-06-16 02:27:29 +01:00
delete_rule INPUT -i "${EXT_IF}" -p udp --dport "${PORT}" -m comment --comment amneziawg-allow-external -j ACCEPT
delete_rule -t nat POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE
fi
delete_rule INPUT -i tailscale0 -p udp --dport "${PORT}" -m comment --comment amneziawg-block-tailscale -j DROP
2026-06-18 00:06:14 +01:00
delete_rule INPUT -i tailscale0 -p udp -m comment --comment amneziawg-block-tailscale -j DROP
2026-06-16 02:27:29 +01:00
delete_rule INPUT -i awg0 -m comment --comment amneziawg-awg-input -j ACCEPT
delete_rule FORWARD -i awg0 -m comment --comment amneziawg-forward-in -j ACCEPT
delete_rule FORWARD -o awg0 -m comment --comment amneziawg-forward-out -j ACCEPT
2026-07-28 13:17:12 +01:00
delete_rule INPUT -m comment --comment amneziawg-input-jump -j AMNEZIAWG-INPUT
2026-07-28 13:04:19 +01:00
delete_rule FORWARD -m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}"
2026-07-28 13:17:12 +01:00
"${IPTABLES[@]}" -F AMNEZIAWG-INPUT >/dev/null 2>&1 || true
"${IPTABLES[@]}" -X AMNEZIAWG-INPUT >/dev/null 2>&1 || true
2026-07-28 13:04:19 +01:00
"${IPTABLES[@]}" -F "${FORWARD_CHAIN}" >/dev/null 2>&1 || true
2026-07-30 23:16:36 +01:00
"${IPTABLES[@]}" -F "${POLICY_CHAIN_A}" >/dev/null 2>&1 || true
"${IPTABLES[@]}" -F "${POLICY_CHAIN_B}" >/dev/null 2>&1 || true
"${IPTABLES[@]}" -X "${POLICY_CHAIN_A}" >/dev/null 2>&1 || true
"${IPTABLES[@]}" -X "${POLICY_CHAIN_B}" >/dev/null 2>&1 || true
2026-07-28 13:04:19 +01:00
"${IPTABLES[@]}" -X "${FORWARD_CHAIN}" >/dev/null 2>&1 || true
firewall-check.sh: |
#!/usr/bin/env bash
set -euo pipefail
PORT="${1:-5847}"
VPN_CIDR="${2:-10.8.0.0/16}"
FORWARD_CHAIN="AMNEZIAWG-FORWARD"
IPTABLES=(iptables -w 5)
external_interface() {
ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}'
}
EXT_IF="$(external_interface || true)"
if [ -z "${EXT_IF}" ]; then
EXT_IF="$(ip route show default | awk '{print $5; exit}')"
fi
if [ -z "${EXT_IF}" ]; then
echo "Unable to detect external interface" >&2
exit 1
fi
if "${IPTABLES[@]}" -C INPUT -i tailscale0 -p udp -m comment --comment amneziawg-block-tailscale -j DROP >/dev/null 2>&1; then
echo "Unsafe broad UDP DROP on tailscale0 is present" >&2
exit 1
fi
if "${IPTABLES[@]}" -C INPUT -i "${EXT_IF}" -p udp -m comment --comment amneziawg-allow-external -j ACCEPT >/dev/null 2>&1; then
echo "Unsafe broad UDP ACCEPT on ${EXT_IF} is present" >&2
exit 1
fi
2026-07-28 13:17:12 +01:00
if "${IPTABLES[@]}" -C INPUT -m comment --comment amneziawg-input-jump -j AMNEZIAWG-INPUT >/dev/null 2>&1; then
echo "Unexpected AmneziaWG INPUT chain is present" >&2
exit 1
fi
2026-07-28 13:04:19 +01:00
2026-07-30 23:16:36 +01:00
FIRST_FORWARD_RULE="$("${IPTABLES[@]}" -S FORWARD | grep '^-A FORWARD ' | sed -n '1p')"
[[ "${FIRST_FORWARD_RULE}" == *"--comment amneziawg-forward-jump"* ]]
[[ "${FIRST_FORWARD_RULE}" == *"-j ${FORWARD_CHAIN}"* ]]
ACTIVE_POLICY="$("${IPTABLES[@]}" -S "${FORWARD_CHAIN}" 2>/dev/null \
| awk '$1 == "-A" && $3 == "-j" && $4 ~ /^AMNEZIAWG-POLICY-[AB]$/ { print $4; exit }')"
[ -n "${ACTIVE_POLICY}" ]
"${IPTABLES[@]}" -C "${ACTIVE_POLICY}" \
-i awg0 -o awg0 -s "${VPN_CIDR}" -d "${VPN_CIDR}" \
-m comment --comment amneziawg-client-isolation -j DROP
"${IPTABLES[@]}" -C "${ACTIVE_POLICY}" \
-i awg0 -o "${EXT_IF}" -s "${VPN_CIDR}" \
-m conntrack --ctstate NEW,ESTABLISHED,RELATED \
-m comment --comment amneziawg-internet-out -j ACCEPT
"${IPTABLES[@]}" -C "${ACTIVE_POLICY}" \
-i "${EXT_IF}" -o awg0 -d "${VPN_CIDR}" \
-m conntrack --ctstate ESTABLISHED,RELATED \
-m comment --comment amneziawg-internet-return -j ACCEPT
2026-07-28 13:04:19 +01:00
"${IPTABLES[@]}" -t nat -C POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE
2026-07-30 23:16:36 +01:00
[ "$(sysctl -n net.ipv4.conf.awg0.send_redirects)" = "0" ]
2026-07-28 13:04:19 +01:00
awg show awg0 >/dev/null 2>&1
2026-06-16 02:27:29 +01:00
run.sh: |
#!/usr/bin/env bash
set -euo pipefail
SERVER_CONFIG="/etc/amnezia/server/awg0.conf"
2026-06-29 21:00:55 +03:00
CLIENTS_DIR="${AMNEZIAWG_CLIENTS_DIR:-/run/amnezia/clients}"
2026-07-30 23:16:36 +01:00
POLICY_FILE="${AMNEZIAWG_POLICY_FILE:-/run/amnezia/policy/policy.conf}"
CONFIG_GENERATION="${AMNEZIAWG_CONFIG_GENERATION:-/run/amnezia/config-generation}"
2026-06-16 02:27:29 +01:00
RUNTIME_CONFIG="/run/amnezia/awg0.conf"
2026-06-29 20:46:07 +03:00
SYNC_CONFIG="/run/amnezia/awg0.sync.conf"
STATUS_FILE="/run/amnezia/reload-status"
RELOAD_INTERVAL="${AMNEZIAWG_RELOAD_INTERVAL:-10}"
2026-06-16 02:27:29 +01:00
cleanup() {
if awg show awg0 >/dev/null 2>&1; then
awg-quick down "${RUNTIME_CONFIG}" || ip link delete awg0 || true
fi
}
render_config() {
mkdir -p "$(dirname "${RUNTIME_CONFIG}")"
2026-06-29 20:46:07 +03:00
local tmp_config="${RUNTIME_CONFIG}.tmp"
cp "${SERVER_CONFIG}" "${tmp_config}"
chmod 0600 "${tmp_config}"
2026-06-16 02:27:29 +01:00
local clients_found=0
for client_config in "${CLIENTS_DIR}"/*; do
[ -f "${client_config}" ] || continue
[ -s "${client_config}" ] || continue
2026-06-29 20:46:07 +03:00
printf '\n' >> "${tmp_config}"
cat "${client_config}" >> "${tmp_config}"
2026-06-16 02:27:29 +01:00
clients_found=1
done
if [ "${clients_found}" = "0" ]; then
echo "No client peer configs found in ${CLIENTS_DIR}; starting without peers"
fi
2026-06-29 20:46:07 +03:00
mv "${tmp_config}" "${RUNTIME_CONFIG}"
chmod 0600 "${RUNTIME_CONFIG}"
}
2026-07-30 23:16:36 +01:00
runtime_config_hash() {
if [ -f "${CONFIG_GENERATION}" ]; then
sha256sum "${CONFIG_GENERATION}" | awk '{print $1}'
else
printf 'missing\n'
fi
2026-06-29 20:46:07 +03:00
}
write_reload_status() {
local state="${1}"
local hash="${2:-}"
local applied_at_ms=""
if [ "${state}" = "applied" ]; then
applied_at_ms="$(($(date +%s) * 1000))"
fi
mkdir -p "$(dirname "${STATUS_FILE}")"
{
printf 'state=%s\n' "${state}"
printf 'hash=%s\n' "${hash}"
printf 'applied_at_ms=%s\n' "${applied_at_ms}"
} > "${STATUS_FILE}.tmp"
mv "${STATUS_FILE}.tmp" "${STATUS_FILE}"
}
apply_live_config() {
2026-07-30 23:16:36 +01:00
# Fail closed during a peer/key and policy transition. /dev/null produces
# an Internet-only policy with all awg0-to-awg0 traffic isolated.
/scripts/firewall-up.sh 5847 10.8.0.0/16 /dev/null
2026-06-29 20:46:07 +03:00
render_config
awg-quick strip "${RUNTIME_CONFIG}" > "${SYNC_CONFIG}"
chmod 0600 "${SYNC_CONFIG}"
awg syncconf awg0 "${SYNC_CONFIG}"
2026-07-30 23:16:36 +01:00
/scripts/firewall-up.sh 5847 10.8.0.0/16 "${POLICY_FILE}"
2026-06-29 20:46:07 +03:00
}
watch_client_config() {
local last_hash="${1}"
while true; do
sleep "${RELOAD_INTERVAL}" &
wait "$!" || return 0
local current_hash
2026-07-30 23:16:36 +01:00
current_hash="$(runtime_config_hash)"
2026-06-29 20:46:07 +03:00
if [ "${current_hash}" = "${last_hash}" ]; then
continue
fi
echo "Detected AmneziaWG client peer config change; applying with awg syncconf"
if apply_live_config; then
last_hash="${current_hash}"
write_reload_status applied "${current_hash}"
awg show awg0 || true
else
echo "ERROR: failed to hot-reload AmneziaWG client peer config" >&2
write_reload_status error "${current_hash}"
fi
done
2026-06-16 02:27:29 +01:00
}
trap cleanup EXIT
trap 'exit 0' TERM INT
2026-07-30 23:16:36 +01:00
initial_hash="$(runtime_config_hash)"
2026-06-16 02:27:29 +01:00
render_config
cleanup
awg-quick up "${RUNTIME_CONFIG}"
awg show awg0 || true
2026-06-29 20:46:07 +03:00
write_reload_status applied "${initial_hash}"
watch_client_config "${initial_hash}"
2026-06-29 21:00:55 +03:00
client-secret-sync.sh: |
#!/usr/bin/env bash
set -euo pipefail
CLIENT_SECRET="${AMNEZIAWG_CLIENT_SECRET:-amneziawg-clients}"
CLIENT_SECRET_KEY="${AMNEZIAWG_CLIENT_SECRET_KEY:-peers.conf}"
CLIENTS_DIR="${AMNEZIAWG_CLIENTS_DIR:-/run/amnezia/clients}"
PEERS_FILE="${CLIENTS_DIR}/peers.conf"
2026-07-30 23:16:36 +01:00
POLICY_FILE="${AMNEZIAWG_POLICY_FILE:-/run/amnezia/policy/policy.conf}"
CONFIG_GENERATION="${AMNEZIAWG_CONFIG_GENERATION:-/run/amnezia/config-generation}"
2026-06-29 21:00:55 +03:00
SYNC_INTERVAL="${AMNEZIAWG_CLIENT_SECRET_SYNC_INTERVAL:-5}"
NAMESPACE="${POD_NAMESPACE:-$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)}"
write_empty_once() {
mkdir -p "${CLIENTS_DIR}"
if [ ! -f "${PEERS_FILE}" ]; then
: > "${PEERS_FILE}"
chmod 0600 "${PEERS_FILE}"
fi
2026-07-30 23:16:36 +01:00
mkdir -p "$(dirname "${POLICY_FILE}")"
if [ ! -f "${POLICY_FILE}" ]; then
: > "${POLICY_FILE}"
chmod 0600 "${POLICY_FILE}"
fi
{
sha256sum "${PEERS_FILE}"
sha256sum "${POLICY_FILE}"
} | sha256sum | awk '{print $1}' > "${CONFIG_GENERATION}"
2026-06-29 21:00:55 +03:00
}
sync_once() {
mkdir -p "${CLIENTS_DIR}"
2026-07-30 23:16:36 +01:00
mkdir -p "$(dirname "${POLICY_FILE}")"
local snapshot="${CONFIG_GENERATION}.snapshot"
local peers_tmp="${PEERS_FILE}.tmp"
local policy_tmp="${POLICY_FILE}.tmp"
local peers_encoded policy_encoded generation
2026-06-29 21:00:55 +03:00
2026-07-30 23:16:36 +01:00
if ! kubectl get secret "${CLIENT_SECRET}" -n "${NAMESPACE}" \
-o "go-template={{ with index .data \"${CLIENT_SECRET_KEY}\" }}{{ . }}{{ end }}{{ \"\n\" }}{{ with index .data \"policy.conf\" }}{{ . }}{{ end }}{{ \"\n\" }}" \
> "${snapshot}" 2>/dev/null; then
2026-06-29 21:00:55 +03:00
echo "WARN: failed to read Secret ${NAMESPACE}/${CLIENT_SECRET}; keeping current peers" >&2
2026-07-30 23:16:36 +01:00
rm -f "${snapshot}"
2026-06-29 21:00:55 +03:00
write_empty_once
return 0
fi
2026-07-30 23:16:36 +01:00
peers_encoded="$(sed -n '1p' "${snapshot}")"
policy_encoded="$(sed -n '2p' "${snapshot}")"
rm -f "${snapshot}"
2026-06-29 21:00:55 +03:00
2026-07-30 23:16:36 +01:00
if [ -n "${peers_encoded}" ]; then
printf '%s' "${peers_encoded}" | base64 -d > "${peers_tmp}"
else
: > "${peers_tmp}"
fi
if [ -n "${policy_encoded}" ]; then
printf '%s' "${policy_encoded}" | base64 -d > "${policy_tmp}"
else
# Missing policy is fail-closed: no client-to-client pairs are allowed.
: > "${policy_tmp}"
fi
chmod 0600 "${peers_tmp}" "${policy_tmp}"
generation="$({
sha256sum "${peers_tmp}"
sha256sum "${policy_tmp}"
} | sha256sum | awk '{print $1}')"
if [ -f "${CONFIG_GENERATION}" ] \
&& [ "$(sed -n '1p' "${CONFIG_GENERATION}")" = "${generation}" ]; then
rm -f "${peers_tmp}" "${policy_tmp}"
2026-06-29 21:00:55 +03:00
return 0
fi
2026-07-30 23:16:36 +01:00
mv "${policy_tmp}" "${POLICY_FILE}"
mv "${peers_tmp}" "${PEERS_FILE}"
printf '%s\n' "${generation}" > "${CONFIG_GENERATION}.tmp"
mv "${CONFIG_GENERATION}.tmp" "${CONFIG_GENERATION}"
echo "Synced AmneziaWG peers and policy from Secret ${NAMESPACE}/${CLIENT_SECRET}"
2026-06-29 21:00:55 +03:00
}
if [ "${1:-}" = "once" ]; then
sync_once
exit 0
fi
while true; do
sync_once || true
sleep "${SYNC_INTERVAL}"
done
2026-06-29 20:46:07 +03:00
status-patch.sh: |
#!/usr/bin/env bash
set -euo pipefail
STATUS_FILE="/run/amnezia/reload-status"
PATCH_INTERVAL="${AMNEZIAWG_STATUS_PATCH_INTERVAL:-5}"
NAMESPACE="${POD_NAMESPACE:-$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)}"
: "${POD_NAME:?POD_NAME is required}"
last_file_hash=""
patch_status() {
local state="unknown"
local hash=""
local applied_at_ms=""
# The file is generated by run.sh and contains only shell assignments.
# shellcheck disable=SC1090
source "${STATUS_FILE}"
kubectl patch pod "${POD_NAME}" -n "${NAMESPACE}" --type merge -p "{\"metadata\":{\"annotations\":{\"amnezia-fellow.hexor.cy/client-secret-reload-status\":\"${state}\",\"amnezia-fellow.hexor.cy/client-secret-applied-at-ms\":\"${applied_at_ms}\",\"amnezia-fellow.hexor.cy/client-secret-applied-hash\":\"${hash}\"}}}"
}
2026-06-16 02:27:29 +01:00
while true; do
2026-06-29 20:46:07 +03:00
if [ -f "${STATUS_FILE}" ]; then
file_hash="$(sha256sum "${STATUS_FILE}" | awk '{print $1}')"
if [ "${file_hash}" != "${last_file_hash}" ]; then
patch_status || true
last_file_hash="${file_hash}"
fi
fi
sleep "${PATCH_INTERVAL}"
2026-06-16 02:27:29 +01:00
done