-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup-fakevpc.yaml
431 lines (375 loc) · 13.1 KB
/
setup-fakevpc.yaml
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
---
- name: single-file ansible script for fakevpc creation
hosts: localhost
connection: local
vars:
update_upgrade_servers: false
iface_ip_offset: 1 # increase as needed in case 192.168.1.0/24 is taken
servers:
server1:
address: 10.0.2.2
ssh_port: 5001
wg_port: 51821
server2:
address: 10.0.2.2
ssh_port: 5002
wg_port: 51822
server3:
address: 10.0.2.2
ssh_port: 5003
wg_port: 51823
tasks:
# ---
# prepare wireguard keys
- name: install wireguard (to generate keys)
become: true
apt:
pkg:
- wireguard
- name: get a plain list of hosts
set_fact:
server_list: "{{ servers.keys() | list }}"
- name: generate wg private keys if not available
block:
- name: stat wg private file
stat:
path: "{{ item }}-wg-key-private"
register: wg_key_private_file
loop: "{{ server_list }}"
- name: generate private wg key if file missing
command: wg genkey
register: wg_genkey_cmd
when: not wg_key_private_file.results[index].stat.exists
loop: "{{ server_list }}"
loop_control:
index_var: index
- name: Save private key
copy:
content: "{{ wg_genkey_cmd.results[index].stdout }}"
dest: "{{ item }}-wg-key-private"
mode: '0600'
when: not wg_key_private_file.results[index].stat.exists
loop: "{{ server_list }}"
loop_control:
index_var: index
- name: generate public wg key
shell: wg pubkey < {{ item }}-wg-key-private
register: wg_pubkey_cmd
loop: "{{ server_list }}"
- name: read wg private keys
set_fact:
wg_key_private: "{{ wg_key_private|default([]) + [ lookup('ansible.builtin.file', item + '-wg-key-private') ] }}"
loop: "{{ server_list }}"
- name: map wg public keys
set_fact:
wg_key_public: "{{ wg_pubkey_cmd.results | map(attribute='stdout') | list }}"
# ---
# configure ansible hosts (dynamically)
- name: add hosts to inventory
add_host:
name: "{{ item.key }}"
ansible_connection: ssh
ansible_host: "{{ item.value.address }}"
ansible_port: "{{ item.value.ssh_port }}"
ansible_user: ubuntu
ansible_ssh_private_key_file: sshkey
ansible_ssh_common_args: -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
ansible_python_interpreter: /usr/bin/python3
with_dict: "{{ servers }}"
- name: gather facts
delegate_to: "{{ item }}"
setup:
loop: "{{ server_list }}"
# ---
# update servers
- name: update and upgrade if needed
when: update_upgrade_servers
block:
- name: update apt cache
delegate_to: "{{ item }}"
become: true
apt:
update_cache: true
loop: "{{ server_list }}"
- name: apt upgrade
delegate_to: "{{ item }}"
become: true
apt:
upgrade: true
register: upgrade_result
loop: "{{ server_list }}"
- name: apt autoremove
delegate_to: "{{ item }}"
become: true
apt:
autoremove: true
register: autoremove_result
loop: "{{ server_list }}"
- name: reboot if updated
delegate_to: "{{ item }}"
become: true
reboot:
when: upgrade_result.results[index].changed or autoremove_result.results[index].changed
loop: "{{ server_list }}"
loop_control:
index_var: index
# ---
# install packages
- name: Install packages
delegate_to: "{{ item }}"
become: true
apt:
pkg:
- wireguard
- socat
- netcat
loop: "{{ server_list }}"
# ---
# wireguard servers setup
- name: create wireguard server configurations
delegate_to: "{{ item }}"
become: true
copy:
dest: /etc/wireguard/vpcs.conf
content: |
[Interface]
PrivateKey = {{ wg_key_private[index] }}
Address = 192.168.{{ index + iface_ip_offset }}.1/24
ListenPort = {{ servers[item].wg_port }}
{% for peer_idx in range(index + 1, server_list | length) %}
[Peer]
PublicKey = {{ wg_key_public[peer_idx] }}
AllowedIPs = 192.168.{{ index + iface_ip_offset }}.{{ peer_idx + 1 }}/32
{% endfor %}
register: server_config
loop: "{{ server_list }}"
loop_control:
index_var: index
- name: restart the servers if the configuration has changed
delegate_to: "{{ item }}"
become: true
service:
name: wg-quick@vpcs
state: restarted
when: server_config.results[index].changed
loop: "{{ server_list }}"
loop_control:
index_var: index
- name: make sure that the servers are started and enabled
delegate_to: "{{ item }}"
become: true
service:
name: wg-quick@vpcs
state: started
enabled: true
loop: "{{ server_list }}"
# ---
# wireguard clients setup
- name: create wireguard client configurations
delegate_to: "{{ server_list[item[1]] }}"
become: true
when: item[1] > item[0]
copy:
dest: /etc/wireguard/vpcc_{{ server_list[item[0]] }}.conf
content: |
[Interface]
PrivateKey = {{ wg_key_private[item[1]] }}
Address = 192.168.{{ item[0] + iface_ip_offset }}.{{ item[1] + 1 }}/24
[Peer]
PublicKey = {{ wg_key_public[item[0]] }}
AllowedIPs = 192.168.{{ item[0] + iface_ip_offset }}.1/32
Endpoint = {{ servers[server_list[item[0]]].address }}:{{ servers[server_list[item[0]]].wg_port }}
PersistentKeepalive = 10
register: client_config
with_nested:
- "{{ range(0, server_list | length) }}"
- "{{ range(0, server_list | length) }}"
- name: restart the clients if the configuration has changed
delegate_to: "{{ server_list[item.item[1]] }}"
become: true
service:
name: wg-quick@vpcc_{{ server_list[item.item[0]] }}
state: restarted
when: (not (item.skipped | default(false))) and item.changed
loop: "{{ client_config.results }}"
- name: make sure that the clients are started and enabled
delegate_to: "{{ server_list[item.item[1]] }}"
become: true
service:
name: wg-quick@vpcc_{{ server_list[item.item[0]] }}
state: started
enabled: true
when: not (item.skipped | default(false))
loop: "{{ client_config.results }}"
# ---
# /etc/hosts setup
- name: add server names to /etc/hosts to use VPC IPs (for clients)
delegate_to: "{{ server_list[item[1]] }}"
become: true
when: item[1] > item[0] # item[0] is the wg server
lineinfile:
path: /etc/hosts
line: 192.168.{{ item[0] + iface_ip_offset }}.1 {{ server_list[item[0]] }} {{ server_list[item[0]] }}.vpcdomain
state: present
regexp: '.*{{ server_list[item[0]] }}.*$'
with_nested:
- "{{ range(0, server_list | length) }}"
- "{{ range(0, server_list | length) }}"
- name: add server names to /etc/hosts to use VPC IPs (for servers)
delegate_to: "{{ server_list[item[1]] }}"
become: true
when: item[1] < item[0] # item[1] is the wg server
lineinfile:
path: /etc/hosts
line: 192.168.{{ item[1] + iface_ip_offset }}.{{ item[0] + 1 }} {{ server_list[item[0]] }} {{ server_list[item[0]] }}.vpcdomain
state: present
regexp: '.*{{ server_list[item[0]] }}.*$'
with_nested:
- "{{ range(0, server_list | length) }}"
- "{{ range(0, server_list | length) }}"
- name: add self name (qualified) to /etc/hosts
delegate_to: "{{ item }}"
become: true
lineinfile:
path: /etc/hosts
line: 127.0.0.1 {{ item }}.vpcdomain
state: present
regexp: '.*{{ item }}\.vpcdomain.*$'
loop: "{{ server_list }}"
# ---
# create a VPC-only echo service on server2, accessible from
# all other VPC servers
- name: get index of server2 (redundant really)
set_fact:
server_name: server2
server_idx: "{{ lookup('ansible.utils.index_of', server_list, 'eq', 'server2') }}"
- name: create server executable on server2
delegate_to: "{{ server_name }}"
become: true
copy:
dest: /usr/local/bin/myecho-server.py
mode: '0755'
content: |
#!/usr/bin/env python3
import asyncio
async def handler(reader, writer):
data = await reader.read()
writer.write(data)
await writer.drain()
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(handler, '127.0.0.1', 8888)
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
print(f'Serving on {addrs}')
async with server:
await server.serve_forever()
asyncio.run(main())
register: myecho_file
- name: create systemd echo service on server2
delegate_to: "{{ server_name }}"
become: true
copy:
dest: /etc/systemd/system/myecho.service
content: |
[Unit]
Description=myecho service
Requires=network-online.target
After=network-online.target
[Service]
Type=simple
DynamicUser=yes
ExecStart=/usr/local/bin/myecho-server.py
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
register: myecho_service
- name: create socat services for redirecting requests as client
delegate_to: "{{ server_name }}"
become: true
copy:
dest: /etc/systemd/system/myecho-socat-from-{{ server_list[item] }}.service
content: |
[Unit]
Description=myecho socat from {{ server_list[item] }}
Requires=network-online.target
After=network-online.target
[Service]
Type=simple
DynamicUser=yes
ExecStart=socat TCP-LISTEN:8888,bind=192.168.{{ item + iface_ip_offset }}.{{ server_idx|int + 1 }},reuseaddr,fork TCP:127.0.0.1:8888
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
loop: "{{ range(0, server_idx|int) }}"
register: myecho_socat_client_services
- name: create socat services for redirecting requests as server
delegate_to: "{{ server_name }}"
become: true
copy:
dest: /etc/systemd/system/myecho-socat-from-{{ server_name }}.service
content: |
[Unit]
Description=myecho socat from {{ server_name }}
Requires=network-online.target
After=network-online.target
[Service]
Type=simple
DynamicUser=yes
ExecStart=socat TCP-LISTEN:8888,bind=192.168.{{ server_idx|int + iface_ip_offset }}.1,reuseaddr,fork TCP:127.0.0.1:8888
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
register: myecho_socat_server_service
- name: systemd reload daemon to get the service changes on server2
delegate_to: "{{ server_name }}"
become: true
systemd:
daemon_reload: true
- name: restart myecho service if the configuration has changed
delegate_to: "{{ server_name }}"
become: true
service:
name: myecho
state: restarted
when: myecho_file.changed or myecho_service.changed
- name: make sure that myecho service is started and enabled
delegate_to: "{{ server_name }}"
become: true
service:
name: myecho
state: started
enabled: true
- name: restart socat forwarders (as client) if the configuration has changed
delegate_to: "{{ server_name }}"
become: true
when: myecho_socat_client_services.results[item].changed
service:
name: myecho-socat-from-{{ server_list[item] }}
state: restarted
loop: "{{ range(0, server_idx|int) }}"
- name: make myecho socat services (as client) are started and enabled
delegate_to: "{{ server_name }}"
become: true
service:
name: myecho-socat-from-{{ server_list[item] }}
state: started
enabled: true
loop: "{{ range(0, server_idx|int) }}"
- name: restart socat forwarders (as server) if the configuration has changed
delegate_to: "{{ server_name }}"
become: true
when: myecho_socat_server_service.changed
service:
name: myecho-socat-from-{{ server_name }}
state: restarted
- name: make myecho socat services (as server) are started and enabled
delegate_to: "{{ server_name }}"
become: true
service:
name: myecho-socat-from-{{ server_name }}
state: started
enabled: true