- Jinja 100%
| assets | ||
| group_vars | ||
| host_vars | ||
| roles | ||
| .gitignore | ||
| bootstrap.yml | ||
| inventory-bootstrap.yml | ||
| inventory.yml | ||
| README.md | ||
| router.yml | ||
What does this repo do?
It provides a collection of playbooks and roles that make it easy to deploy a DN42 gateway fully automated.
Featureset as of now:
- create a gateway from a blank VM
- add new peers
- create a more complex setup with gateways and routers
Build from scratch
To make a Gateway out of a blank VM, edit the host_vars and group_vars files, rename them appropriately and edit the
inventory files.
Once this happened, decide if you have a simple or complex setup in mind.
Decisions, decisions . . .
Simple means:
- A local gateway
- Peers connected directly to this gateway
- No drop pods (aka separate routers)
- Clients are connected directly to this gateway
Complex means:
- Separate routers and gateways
- peers are connected to gateways
- routers connect to gateways and only route internal traffic
- clients connect to routers
Network Graph for a complex setup - development env this collection was created in
Bill of materials and prerequisites
For a successful deployment, the following things are required:
- Hashicorp Vault or OpenBao
- Local Python environment with these packages:
- ansible
- hvac
- passlib
Complex Setup:
- 2 VPS Instances (this Ansible collection was developed and tested with Debian)
- 1 Machine that acts as a local router
Note: this is a separate VM or machine, not an OPNsense or FritzBox or anything like that - 2 Domains or Subdomains
- 7 Wireguard configs and thus 7 keypairs for:
- 2x Communication between gateways ("east-west")
- 2x Communication "down" from gateway to router ("north-south")
- 2x Communication "up" from router to gateways ("north-south")
- 1x for clients on the router
- Management wireguard tunnel for monitoring and metrics
Simple Setup:
- VM
- 1 wireguard config for clients
- Optional: Domain
Aides
How to make it yours
This lump of yaml files was written with universal usage in mind. This means that you only have to change the variable files in group_vars and host_vars plus the inventory files.
Wireguard configs
Here is a template to create a new wg config for infra components:
[Interface]
PrivateKey =
ListenPort = PORT
PostUp = /sbin/ip addr add dev %i TUNNEL_ADDR/64 peer PEER_TUNNEL_ADDR/64
Table = off
[Peer]
# friendly_name = new-u-station
PublicKey =
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepAlive = 5
You can generate keys in stdout without writing any files like this:
wg genkey --> copy this privatekey
wg pubkey --> paste key in here, press enter and then ctrl-d
Vault/OpenBao structure
Due to the rather many secrets in need of storing for the complex setup, a well-structured directory tree helps a lot to find things. An idea for how this could be structured is this:
DN42:
passwords:
machine1:
initial_root_pw
root_pw
remote
machine2:
initial_root_pw
root_pw
remote
machine3:
initial_root_pw
root_pw
remote
wireguard_configs:
gateways:
machine1:
to_2
to_router
management
machine2:
to_1
to_router
management
routers:
router1:
to_1
to_2
clients
(management)
peers:
peer1
peer2
peer3
Misc:
ssh_keys:
authorized_keys
Commands
To create a simple setup, execute this:
ansible-playbook bootstrap.yml -i inventory-bootstrap.yml --skip-tags complex
For a complex setup, run these commands in order:
ansible-playbook bootstrap.yml -i inventory-bootstrap.yml --skip-tags simple
ansible-playbook router.yml -i inventory-bootstrap.yml --skip-tags simple
Lifecycle
A setup lives and breathes over time. Two situations are covered by this repo as of now:
adding new peers
running tasks after the initial setup
The other inventory file
Since some properties about the hosts change after the initial setup (namely passwords and ssh ports), this needs to be reflected in the inventory. To avoid editing an inventory file over and over again back and forth, this repo contains two inventory files. One for the initial setup and one for after that. Look at the file and check if the password, paths in Vault, users, ssh ports and so on changed.
Adding a new peer
The most regular change is most likely the addition of a new peer.
This step is still half manual, due to the fact that the wireguard config needs to be in Vault for this playbook to work.
Here is a template to create a new wg config:
[Interface]
PrivateKey = MY_PRIVKEY
PostUp = /sbin/ip addr add dev %i MY_TUNNEL_ADDR/128 peer PEER_TUNNEL_ADDR/128
Table = off
ListenPort = PORT
[Peer]
# friendly_name = PEERNAME
PublicKey = PEER_PUBKEY
Endpoint = PEER_ENDPOINT:PEER_PORT
AllowedIPs = 172.16.0.0/12, 10.0.0.0/8, fd00::/8, fe80::/10
PersistentKeepAlive = 10
You can generate keys in stdout without writing any files like this:
wg genkey --> copy this privatekey
wg pubkey --> paste key in here, press enter and then ctrl-d
Once this is done, edit the host vars of your gateway and add the ASN, peer tunnel address and Port of your new peer. Afterward execute this command:
ansible-playbook bootstrap.yml -i inventory.yml --tags new_peer
Adding a new client
Fortunately, a client needs very little config. Normally, all it should take is this wireguard config.
[Interface]
PrivateKey =
PostUp = /sbin/ip addr add dev %i DN42_ADDR/128 peer ROUTER_AREA_IP/56
[Peer]
PublicKey = ROUTER_PUBKEY
Endpoint = [fd00:ULA_ADDR_OF_ROUTER]:9000
AllowedIPs = 172.16.0.0/12, 10.0.0.0/8, fd00::/8, fe80::/10
PersistentKeepalive = 10
Troubleshooting
If the client isn't able to ping for example door.cccda.de, these troubleshooting ideas may help:
- check if client and router report a handshake with
wgorwg show $INTERFACE_NAME- if not, make sure both can ping each other (VLAN, routing)
- check routing on the client with
ip r g $IP_ADDRto make sure the kernel chooses the correct route. Add static routes if necessary - use
tcpdump -ni $INTERFACEalong the way to find out what gets lost where - check firewalls