532 lines
19 KiB
YAML
532 lines
19 KiB
YAML
---
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: amneziawg-scripts
|
|
data:
|
|
firewall-up.sh: |
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
PORT="${1:-5847}"
|
|
VPN_CIDR="${2:-10.8.0.0/16}"
|
|
POLICY_FILE="${3:-/run/amnezia/policy/policy.conf}"
|
|
FORWARD_CHAIN="AMNEZIAWG-FORWARD"
|
|
POLICY_CHAIN_A="AMNEZIAWG-POLICY-A"
|
|
POLICY_CHAIN_B="AMNEZIAWG-POLICY-B"
|
|
IPTABLES=(iptables -w 30)
|
|
|
|
external_interface() {
|
|
ip route get 1.1.1.1 | awk '{for (i=1;i<=NF;i++) if ($i=="dev") {print $(i+1); exit}}'
|
|
}
|
|
|
|
ensure_rule() {
|
|
local mode="$1"
|
|
shift
|
|
local table_args=()
|
|
if [ "${1:-}" = "-t" ]; then
|
|
table_args=("$1" "$2")
|
|
shift 2
|
|
fi
|
|
|
|
local chain="$1"
|
|
shift
|
|
|
|
if ! "${IPTABLES[@]}" "${table_args[@]}" -C "${chain}" "$@" >/dev/null 2>&1; then
|
|
"${IPTABLES[@]}" "${table_args[@]}" "${mode}" "${chain}" "$@"
|
|
fi
|
|
}
|
|
|
|
delete_rule() {
|
|
local table_args=()
|
|
if [ "${1:-}" = "-t" ]; then
|
|
table_args=("$1" "$2")
|
|
shift 2
|
|
fi
|
|
|
|
local chain="$1"
|
|
shift
|
|
|
|
while "${IPTABLES[@]}" "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do
|
|
true
|
|
done
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
sysctl -w net.ipv4.conf.awg0.send_redirects=0
|
|
|
|
# Remove rules written by older revisions. In particular, the unqualified
|
|
# tailscale UDP DROP also blocks Flannel VXLAN (UDP/8472).
|
|
delete_rule INPUT -i tailscale0 -p udp -m comment --comment amneziawg-block-tailscale -j DROP
|
|
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
|
|
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
|
|
|
|
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}"
|
|
|
|
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}"
|
|
|
|
firewall-down.sh: |
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
PORT="${1:-5847}"
|
|
VPN_CIDR="${2:-10.8.0.0/16}"
|
|
FORWARD_CHAIN="AMNEZIAWG-FORWARD"
|
|
POLICY_CHAIN_A="AMNEZIAWG-POLICY-A"
|
|
POLICY_CHAIN_B="AMNEZIAWG-POLICY-B"
|
|
IPTABLES=(iptables -w 30)
|
|
|
|
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
|
|
|
|
while "${IPTABLES[@]}" "${table_args[@]}" -D "${chain}" "$@" >/dev/null 2>&1; do
|
|
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
|
|
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 -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
|
|
delete_rule INPUT -i tailscale0 -p udp -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
|
|
delete_rule INPUT -m comment --comment amneziawg-input-jump -j AMNEZIAWG-INPUT
|
|
delete_rule FORWARD -m comment --comment amneziawg-forward-jump -j "${FORWARD_CHAIN}"
|
|
|
|
"${IPTABLES[@]}" -F AMNEZIAWG-INPUT >/dev/null 2>&1 || true
|
|
"${IPTABLES[@]}" -X AMNEZIAWG-INPUT >/dev/null 2>&1 || true
|
|
"${IPTABLES[@]}" -F "${FORWARD_CHAIN}" >/dev/null 2>&1 || true
|
|
"${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
|
|
"${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
|
|
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
|
|
|
|
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
|
|
|
|
"${IPTABLES[@]}" -t nat -C POSTROUTING -s "${VPN_CIDR}" -o "${EXT_IF}" -m comment --comment amneziawg-masquerade -j MASQUERADE
|
|
[ "$(sysctl -n net.ipv4.conf.awg0.send_redirects)" = "0" ]
|
|
awg show awg0 >/dev/null 2>&1
|
|
|
|
run.sh: |
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SERVER_CONFIG="/etc/amnezia/server/awg0.conf"
|
|
CLIENTS_DIR="${AMNEZIAWG_CLIENTS_DIR:-/run/amnezia/clients}"
|
|
POLICY_FILE="${AMNEZIAWG_POLICY_FILE:-/run/amnezia/policy/policy.conf}"
|
|
CONFIG_GENERATION="${AMNEZIAWG_CONFIG_GENERATION:-/run/amnezia/config-generation}"
|
|
RUNTIME_CONFIG="/run/amnezia/awg0.conf"
|
|
SYNC_CONFIG="/run/amnezia/awg0.sync.conf"
|
|
STATUS_FILE="/run/amnezia/reload-status"
|
|
RELOAD_INTERVAL="${AMNEZIAWG_RELOAD_INTERVAL:-10}"
|
|
|
|
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}")"
|
|
local tmp_config="${RUNTIME_CONFIG}.tmp"
|
|
cp "${SERVER_CONFIG}" "${tmp_config}"
|
|
chmod 0600 "${tmp_config}"
|
|
|
|
local clients_found=0
|
|
for client_config in "${CLIENTS_DIR}"/*; do
|
|
[ -f "${client_config}" ] || continue
|
|
[ -s "${client_config}" ] || continue
|
|
printf '\n' >> "${tmp_config}"
|
|
cat "${client_config}" >> "${tmp_config}"
|
|
clients_found=1
|
|
done
|
|
|
|
if [ "${clients_found}" = "0" ]; then
|
|
echo "No client peer configs found in ${CLIENTS_DIR}; starting without peers"
|
|
fi
|
|
|
|
mv "${tmp_config}" "${RUNTIME_CONFIG}"
|
|
chmod 0600 "${RUNTIME_CONFIG}"
|
|
}
|
|
|
|
runtime_config_hash() {
|
|
if [ -f "${CONFIG_GENERATION}" ]; then
|
|
sha256sum "${CONFIG_GENERATION}" | awk '{print $1}'
|
|
else
|
|
printf 'missing\n'
|
|
fi
|
|
}
|
|
|
|
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() {
|
|
# 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
|
|
render_config
|
|
awg-quick strip "${RUNTIME_CONFIG}" > "${SYNC_CONFIG}"
|
|
chmod 0600 "${SYNC_CONFIG}"
|
|
awg syncconf awg0 "${SYNC_CONFIG}"
|
|
/scripts/firewall-up.sh 5847 10.8.0.0/16 "${POLICY_FILE}"
|
|
}
|
|
|
|
watch_client_config() {
|
|
local last_hash="${1}"
|
|
while true; do
|
|
sleep "${RELOAD_INTERVAL}" &
|
|
wait "$!" || return 0
|
|
|
|
local current_hash
|
|
current_hash="$(runtime_config_hash)"
|
|
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
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
trap 'exit 0' TERM INT
|
|
|
|
initial_hash="$(runtime_config_hash)"
|
|
render_config
|
|
cleanup
|
|
awg-quick up "${RUNTIME_CONFIG}"
|
|
awg show awg0 || true
|
|
write_reload_status applied "${initial_hash}"
|
|
watch_client_config "${initial_hash}"
|
|
|
|
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"
|
|
POLICY_FILE="${AMNEZIAWG_POLICY_FILE:-/run/amnezia/policy/policy.conf}"
|
|
CONFIG_GENERATION="${AMNEZIAWG_CONFIG_GENERATION:-/run/amnezia/config-generation}"
|
|
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
|
|
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}"
|
|
}
|
|
|
|
sync_once() {
|
|
mkdir -p "${CLIENTS_DIR}"
|
|
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
|
|
|
|
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
|
|
echo "WARN: failed to read Secret ${NAMESPACE}/${CLIENT_SECRET}; keeping current peers" >&2
|
|
rm -f "${snapshot}"
|
|
write_empty_once
|
|
return 0
|
|
fi
|
|
|
|
peers_encoded="$(sed -n '1p' "${snapshot}")"
|
|
policy_encoded="$(sed -n '2p' "${snapshot}")"
|
|
rm -f "${snapshot}"
|
|
|
|
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}"
|
|
return 0
|
|
fi
|
|
|
|
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}"
|
|
}
|
|
|
|
if [ "${1:-}" = "once" ]; then
|
|
sync_once
|
|
exit 0
|
|
fi
|
|
|
|
while true; do
|
|
sync_once || true
|
|
sleep "${SYNC_INTERVAL}"
|
|
done
|
|
|
|
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}\"}}}"
|
|
}
|
|
|
|
while true; do
|
|
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}"
|
|
done
|