diff --git a/.kres.yaml b/.kres.yaml index 3414f82a..a4dbdaa4 100644 --- a/.kres.yaml +++ b/.kres.yaml @@ -4,6 +4,7 @@ spec: targets: - amazon-ena - amdgpu + - amneziawg - amd-ucode - binfmt-misc - bird2 diff --git a/network/amneziawg/README.md b/network/amneziawg/README.md new file mode 100644 index 00000000..4dfdcc94 --- /dev/null +++ b/network/amneziawg/README.md @@ -0,0 +1,99 @@ +# AmneziaWG + +Adds [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) VPN interfaces as system extensions. +AmneziaWG is a WireGuard-based VPN protocol with DPI bypass capabilities through traffic obfuscation (header randomization, packet padding, jitter). + +## Installation + +See [Installing Extensions](https://github.com/siderolabs/extensions#installing-extensions). + +## Usage + +Configure the extension via `ExtensionServiceConfig` document. + +```yaml +--- +apiVersion: v1alpha1 +kind: ExtensionServiceConfig +name: amneziawg +configFiles: + - content: | + [Interface] + PrivateKey = + ListenPort = 51820 + Address = 10.0.0.1/24 + Jc = 5 + Jmin = 50 + Jmax = 1000 + S1 = 52 + S2 = 52 + H1 = 12345678 + H2 = 87654321 + H3 = 11223344 + H4 = 44332211 + + [Peer] + PublicKey = + Endpoint = vpn.example.com:51820 + AllowedIPs = 0.0.0.0/0 + PersistentKeepalive = 25 + mountPath: /etc/amneziawg/awg0.conf +``` + +Then apply the patch to your node's MachineConfigs +```bash +talosctl patch mc -p @amneziawg-config.yaml +``` + +You will then be able to verify that it is in place with the following command +```bash +talosctl get extensionserviceconfigs + +NODE NAMESPACE TYPE ID VERSION +mynode runtime ExtensionServiceConfig amneziawg 1 +``` + +## Configuration + +The config file follows the standard WireGuard format with additional AmneziaWG-specific parameters for DPI obfuscation: + +| Parameter | Description | +|-----------|-------------| +| `Jc` | Junk packet count | +| `Jmin` | Minimum junk packet size | +| `Jmax` | Maximum junk packet size | +| `S1` | Init packet padding size | +| `S2` | Response packet padding size | +| `H1` | Init packet header value | +| `H2` | Response packet header value | +| `H3` | Cookie packet header value | +| `H4` | Transport packet header value | + +All standard WireGuard fields (`PrivateKey`, `ListenPort`, `Address`, `PublicKey`, `Endpoint`, `AllowedIPs`, `PersistentKeepalive`, `MTU`, `PostUp`, `PostDown`) are also supported. + +### Environment overrides + +Environment variables can be set via `ExtensionServiceConfig`: + +```yaml +--- +apiVersion: v1alpha1 +kind: ExtensionServiceConfig +name: amneziawg +environment: + - AWG_INTERFACE=awg0 + - AWG_CONFIG=/etc/amneziawg/awg0.conf + - AWG_LOG_LEVEL=verbose +configFiles: + - content: | + ... + mountPath: /etc/amneziawg/awg0.conf +``` + +| Variable | Default | Description | +|----------|---------|-------------| +| `AWG_INTERFACE` | `awg0` | Network interface name | +| `AWG_CONFIG` | `/etc/amneziawg/awg0.conf` | Path to config file | +| `AWG_LOG_LEVEL` | `info` | Log level (`info` or `verbose`) | + +For more information see https://docs.amnezia.org/documentation/amnezia-wg/ diff --git a/network/amneziawg/amneziawg.yaml b/network/amneziawg/amneziawg.yaml new file mode 100644 index 00000000..19ba4191 --- /dev/null +++ b/network/amneziawg/amneziawg.yaml @@ -0,0 +1,31 @@ +name: amneziawg +depends: + - network: + - addresses + - connectivity + - configuration: true +container: + entrypoint: /usr/local/bin/entrypoint.sh + environment: + - PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin + - WG_SOCKET_DIR=/run/amneziawg + - AWG_INTERFACE=awg0 + - AWG_CONFIG=/etc/amneziawg/awg0.conf + - AWG_LOG_LEVEL=info + security: + writeableRootfs: false + writeableSysfs: true + mounts: + - source: /dev/net/tun + destination: /dev/net/tun + type: bind + options: + - bind + - rw + - source: /run/amneziawg + destination: /run/amneziawg + type: bind + options: + - bind + - rw +restart: always diff --git a/network/amneziawg/entrypoint.sh b/network/amneziawg/entrypoint.sh new file mode 100644 index 00000000..0473aa5d --- /dev/null +++ b/network/amneziawg/entrypoint.sh @@ -0,0 +1,114 @@ +#!/bin/sh +set -e + +AWG_INTERFACE="${AWG_INTERFACE:-awg0}" +AWG_CONFIG="${AWG_CONFIG:-/etc/amneziawg/${AWG_INTERFACE}.conf}" +AWG_LOG_LEVEL="${AWG_LOG_LEVEL:-info}" + +export WG_SOCKET_DIR=/run/amneziawg + +log() { echo "[amneziawg] $*"; } + +if [ ! -f "$AWG_CONFIG" ]; then + log "ERROR: config file not found: $AWG_CONFIG" + log "Provide config via ExtensionServiceConfig:" + log "" + log " apiVersion: v1alpha1" + log " kind: ExtensionServiceConfig" + log " name: amneziawg" + log " configFiles:" + log " - content: |" + log " [Interface]" + log " PrivateKey = " + log " ListenPort = 51820" + log " Address = 10.0.0.1/24" + log " Jc = 5" + log " Jmin = 50" + log " Jmax = 1000" + log " S1 = 0" + log " S2 = 0" + log " H1 = 1" + log " H2 = 2" + log " H3 = 3" + log " H4 = 4" + log " [Peer]" + log " PublicKey = " + log " Endpoint = :51820" + log " AllowedIPs = 0.0.0.0/0" + log " mountPath: /etc/amneziawg/awg0.conf" + exit 1 +fi + +parse_field() { + grep -i "^${1} *=" "$2" | head -1 | sed "s/^[^ ]* *= *//" +} + +collect_field() { + grep -i "^${1} *=" "$2" | sed "s/^[^ ]* *= *//" | tr '\n' ' ' +} + +ADDRESSES=$(collect_field Address "$AWG_CONFIG") +MTU=$(parse_field MTU "$AWG_CONFIG") + +STRIPPED_CONF=$(mktemp) +grep -iv "^\(Address\|DNS\|MTU\|Table\|PreUp\|PostUp\|PreDown\|PostDown\|SaveConfig\) *=" "$AWG_CONFIG" > "$STRIPPED_CONF" + +log "Starting amneziawg-go on interface $AWG_INTERFACE" +export LOG_LEVEL="$AWG_LOG_LEVEL" + +mkdir -p /run/amneziawg +amneziawg-go "$AWG_INTERFACE" & +AWG_PID=$! + +SOCK="/run/amneziawg/${AWG_INTERFACE}.sock" +for i in $(seq 1 50); do + [ -S "$SOCK" ] && break + sleep 0.1 +done + +if [ ! -S "$SOCK" ]; then + log "ERROR: UAPI socket did not appear at $SOCK" + kill $AWG_PID 2>/dev/null + exit 1 +fi + +awg setconf "$AWG_INTERFACE" "$STRIPPED_CONF" +rm -f "$STRIPPED_CONF" +log "Configuration applied from $AWG_CONFIG" + +for addr in $ADDRESSES; do + ip addr add "$addr" dev "$AWG_INTERFACE" 2>/dev/null || true + log "Address $addr added" +done + +if [ -n "$MTU" ]; then + ip link set mtu "$MTU" dev "$AWG_INTERFACE" + log "MTU set to $MTU" +fi + +ip link set "$AWG_INTERFACE" up +log "Interface $AWG_INTERFACE is UP" + +POST_UP=$(grep -i "^PostUp *=" "$AWG_CONFIG" | sed "s/^[^ ]* *= *//" || true) +if [ -n "$POST_UP" ]; then + log "Running PostUp" + eval "$POST_UP" || true +fi + +cleanup() { + log "Shutting down $AWG_INTERFACE" + POST_DOWN=$(grep -i "^PostDown *=" "$AWG_CONFIG" | sed "s/^[^ ]* *= *//" || true) + if [ -n "$POST_DOWN" ]; then + log "Running PostDown" + eval "$POST_DOWN" || true + fi + ip link set "$AWG_INTERFACE" down 2>/dev/null || true + ip link delete "$AWG_INTERFACE" 2>/dev/null || true + kill $AWG_PID 2>/dev/null +} +trap cleanup TERM INT + +log "AmneziaWG is running:" +awg show "$AWG_INTERFACE" + +wait $AWG_PID diff --git a/network/amneziawg/manifest.yaml.tmpl b/network/amneziawg/manifest.yaml.tmpl new file mode 100644 index 00000000..1bf20a97 --- /dev/null +++ b/network/amneziawg/manifest.yaml.tmpl @@ -0,0 +1,10 @@ +version: v1alpha1 +metadata: + name: amneziawg + version: "{{ .VERSION }}" + author: masterbpro + description: | + [{{ .TIER }}] AmneziaWG is a WireGuard-based VPN protocol with DPI bypass capabilities through traffic obfuscation. + compatibility: + talos: + version: ">= v1.7.0" diff --git a/network/amneziawg/pkg.yaml b/network/amneziawg/pkg.yaml new file mode 100644 index 00000000..5f4ffd9b --- /dev/null +++ b/network/amneziawg/pkg.yaml @@ -0,0 +1,72 @@ +name: amneziawg +variant: scratch +shell: /bin/bash +dependencies: + - stage: base + - image: "{{ .BUILD_ARG_PKGS_PREFIX }}/fhs:{{ .BUILD_ARG_PKGS }}" + from: / + to: /rootfs/usr/local/lib/containers/amneziawg +steps: + - env: + GOPATH: /tmp/go + CGO_ENABLED: 0 + - cachePaths: + - /.cache/go-build + - /tmp/go/pkg + sources: + - url: https://github.com/amnezia-vpn/amneziawg-go/archive/refs/tags/v{{ .AMNEZIAWG_GO_VERSION }}.tar.gz + destination: amneziawg-go.tar.gz + sha256: {{ .AMNEZIAWG_GO_SHA256 }} + sha512: {{ .AMNEZIAWG_GO_SHA512 }} + - url: https://github.com/amnezia-vpn/amneziawg-tools/archive/refs/tags/v{{ .AMNEZIAWG_TOOLS_VERSION }}.tar.gz + destination: amneziawg-tools.tar.gz + sha256: {{ .AMNEZIAWG_TOOLS_SHA256 }} + sha512: {{ .AMNEZIAWG_TOOLS_SHA512 }} + - network: default + prepare: + - | + mkdir amneziawg-go amneziawg-tools + tar -xzf amneziawg-go.tar.gz --strip-components=1 -C amneziawg-go + tar -xzf amneziawg-tools.tar.gz --strip-components=1 -C amneziawg-tools + - | + cd amneziawg-go + go mod download + - network: none + build: + - | + cd amneziawg-go + CGO_ENABLED=0 go build -v -o ../amneziawg-go-bin . + - | + cd amneziawg-tools/src + make CC="gcc -static" WITH_WGQUICK=yes + install: + - | + mkdir -p /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/ + cp -p amneziawg-go-bin /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/amneziawg-go + cp -p amneziawg-tools/src/wg /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/awg + cp -p amneziawg-tools/src/wg-quick/linux.bash /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/awg-quick + chmod +x /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/* + - | + cp -p /pkg/entrypoint.sh /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/entrypoint.sh + chmod +x /rootfs/usr/local/lib/containers/amneziawg/usr/local/bin/entrypoint.sh + - | + mkdir -p /rootfs/usr/local/lib/containers/amneziawg/sbin + cp /sbin/ip /rootfs/usr/local/lib/containers/amneziawg/sbin/ip 2>/dev/null || true + - | + mkdir -p /rootfs/usr/local/etc/containers + cp /pkg/amneziawg.yaml /rootfs/usr/local/etc/containers/ + - | + mkdir -p /rootfs/usr/local/bin + cp -p amneziawg-go-bin /rootfs/usr/local/bin/amneziawg-go + cp -p amneziawg-tools/src/wg /rootfs/usr/local/bin/awg + test: + - | + mkdir -p /extensions-validator-rootfs + cp -r /rootfs/ /extensions-validator-rootfs/rootfs + cp /pkg/manifest.yaml /extensions-validator-rootfs/manifest.yaml + /extensions-validator validate --rootfs=/extensions-validator-rootfs --pkg-name="${PKG_NAME}" +finalize: + - from: /rootfs + to: /rootfs + - from: /pkg/manifest.yaml + to: / diff --git a/network/amneziawg/vars.yaml b/network/amneziawg/vars.yaml new file mode 100644 index 00000000..1c1ddae5 --- /dev/null +++ b/network/amneziawg/vars.yaml @@ -0,0 +1,2 @@ +VERSION: "{{ .AMNEZIAWG_GO_VERSION }}" +TIER: "contrib" diff --git a/network/vars.yaml b/network/vars.yaml index e23a21ff..5f042900 100644 --- a/network/vars.yaml +++ b/network/vars.yaml @@ -1,3 +1,11 @@ +# renovate: datasource=github-releases extractVersion=^v(?.*)$ depName=amnezia-vpn/amneziawg-go +AMNEZIAWG_GO_VERSION: 0.2.16 +AMNEZIAWG_GO_SHA256: 8327a22c7bcf4f6b05585d4b9536759c1e11fcc1e6830e5186fd55a14255eae1 +AMNEZIAWG_GO_SHA512: 40f438307bbdc760c58a0a692c08a64bdbdbd4468ccaf67f687a08f6ef3a3b102b8fe2103da61475074a472758db68c2d6e73786206c6deb355da0ee6dce6409 +# renovate: datasource=github-releases extractVersion=^v(?.*)$ depName=amnezia-vpn/amneziawg-tools +AMNEZIAWG_TOOLS_VERSION: 1.0.20260223 +AMNEZIAWG_TOOLS_SHA256: ab09cfafe6c1e9a6260964a8ba5cb2d657cc23862eb0c29253305e532ac40a16 +AMNEZIAWG_TOOLS_SHA512: 591afaef659e26be16c8d883da8d8ff026f855f60c9887440b566ef18b9948ca57754673d833f27e77d8c05f7e354f37b49adc9f5467334eeb7eda7165960c54 # renovate: datasource=github-releases extractVersion=^v(?.*)$ depName=tailscale/tailscale TAILSCALE_VERSION: 1.94.2 TAILSCALE_SHA256: c45975beb4cb7bab8047cfba77ec8b170570d184f3c806258844f3e49c60d7aa