aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/action.yml
blob: f276af5bfcbade6365e1108d66da4a005d260076 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
name: Set up WireGuard
description: Set up WireGuard connection

inputs:
  endpoint:
    description: Endpoint in the HOST:PORT format
    required: true
  endpoint_public_key:
    description: Public key of the endpoint
    required: true
  ips:
    description: Comma-separated list of IP addresses
    required: true
  allowed_ips:
    description: Comma-separated list of netmasks
    required: true
  private_key:
    description: Private key
    required: true
  preshared_key:
    description: Preshared key
    required: false
  keepalive:
    description: Useful for NAT traversal
    required: false

runs:
  using: composite
  steps:
    - run: |
        set -o errexit -o pipefail -o nounset

        readonly endpoint='${{ inputs.endpoint }}'
        readonly endpoint_public_key='${{ inputs.endpoint_public_key }}'
        readonly ips='${{ inputs.ips }}'
        readonly allowed_ips='${{ inputs.allowed_ips }}'
        readonly private_key='${{ inputs.private_key }}'
        readonly preshared_key='${{ inputs.preshared_key }}'
        readonly keepalive='${{ inputs.keepalive }}'

        readonly minport=51000
        readonly maxport=51999

        ifname="wg$( openssl rand -hex 4 )"
        readonly ifname
        port="$( shuf "--input-range=$minport-$maxport" --head-count=1 )"
        readonly port

        via_systemd() {
            local netdev_path
            netdev_path="/etc/systemd/network/$ifname.netdev"
            local network_path
            network_path="/etc/systemd/network/$ifname.network"

            local netdev_contents
            netdev_contents="
            [NetDev]
            Name=$ifname
            Kind=wireguard
            Description=WireGuard tunnel $ifname

            [WireGuard]
            ListenPort=$port
            PrivateKey=$private_key

            [WireGuardPeer]
            Endpoint=$endpoint
            PublicKey=$endpoint_public_key
            AllowedIPs = $allowed_ips"

            if [ -n "$preshared_key" ]; then
                netdev_contents="$netdev_contents
            PresharedKey=$preshared_key"
            fi

            if [ -n "$keepalive" ]; then
                netdev_contents="$netdev_contents
            PersistentKeepalive=$keepalive"
            fi

            local network_contents
            network_contents="
            [Match]
            Name=$ifname

            [Network]"

            local delim=,
            local ip
            while IFS= read -d "$delim" -r ip; do
                network_contents="$network_contents
                Address=$ip"
            done < <( printf -- "%s$delim\\0" "$ips" )

            sudo touch -- "$netdev_path"
            sudo chown -- root:systemd-network "$netdev_path"
            sudo chmod -- 0640 "$netdev_path"
            sudo touch -- "$network_path"
            echo "$netdev_contents" | sudo tee -- "$netdev_path" > /dev/null
            echo "$network_contents" | sudo tee -- "$network_path" > /dev/null

            sudo systemctl restart systemd-networkd
            sudo systemctl status systemd-networkd
        }

        install_wg_tools() {
            sudo apt-get update
            sudo DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends wireguard-tools
        }

        readonly private_key_path=/tmp/private.key
        readonly preshared_key_path=/tmp/preshared.key

        wg_tools_cleanup() {
            rm -f -- "$private_key_path"
            rm -f -- "$preshared_key_path"
        }

        via_wg_tools() {
            install_wg_tools
            trap wg_tools_cleanup EXIT

            (
                set -o errexit -o nounset -o pipefail
                umask 0077
                echo "$private_key" > "$private_key_path"
                if [ -n "$preshared_key" ]; then
                    echo "$preshared_key" > "$preshared_key_path"
                fi
            )

            sudo ip link add dev "$ifname" type wireguard

            local delim=,
            local ip
            while IFS= read -d "$delim" -r ip; do
                sudo ip addr add "$ip" dev "$ifname"
            done < <( printf -- "%s$delim\\0" "$ips" )

            sudo wg set "$ifname" \
                listen-port "$port" \
                private-key "$private_key_path"

            additional_wg_args=()

            if [ -n "$preshared_key" ]; then
                additional_wg_args+=(preshared-key "${preshared_key_path}")
            fi

            if [ -n "$keepalive" ]; then
                additional_wg_args+=(persistent-keepalive "${keepalive}")
            fi

            sudo wg set "$ifname" \
                peer "$endpoint_public_key" \
                endpoint "$endpoint" \
                allowed-ips "$allowed_ips" \
                ${additional_wg_args[@]+"${additional_wg_args[@]}"}

            sudo ip link set "$ifname" up

            # Add routes for allowed_ips
            for i in ${allowed_ips//,/ }; do sudo ip route replace "$i" dev "$ifname"; done
        }

        # systemd-networkd greets me with 'Temporary failure in name
        # resolution' on Bionic when using a hostname instead of an IP address
        # for endpoint. God knows why!
        #via_systemd
        via_wg_tools
      shell: bash

branding:
  icon: star
  color: green