Tinc VPN - setting up a mesh network
Have you ever wanted to connect up your home network, your personal servers, your laptop, and maybe some virtual machines running inside your laptop? I’ve always used OpenVPN for production networks, however, tinc is extremely convenient. It sets up a mesh between all of the members of the network. Instead of re-routing all traffic through a central server, this node to node connection decreases the latency. Tinc’s configuration is a bit painful though, so here comes a post about ansible…again.
The role is available on github at: https://github.com/tjheeta/ansible-tinc-role
To get a tunnel setup inside a container, you’ll have to add the /dev/net device. Also, it may need to be run in privileged mode.
mkdir /dev/net
mknod /dev/net/tun c 10 200
chmod 0666 /dev/net/tun
I’ve setup an ansible playbook that uses the static binary compiled against musl for x86_64 from my slashpackage post . It is compiled against libressl and musl and comes out to be 1.5 meg and works over all distributions. Kind of handy if you have a bunch of heterogeneous machines.
Now for something here that you can do with ansible that you can’t do with any other configuration management. Since all the inventory management is done locally, we can pre-assign all the ipaddresses for all the servers. This means no race-conditions with chef search, no manually setting ip’s in configuration files, and all the other rigamarole that goes with this. On top of that, it will setup hosts file entries for each of the nodes that you specify. In the role, it runs a script called setup.py which looks for the hosts and assigns them ip addresses. This is done by judacious use of delegate_to:
# Fetch the ip addresses and keys from the hosts
- fetch: src=/etc/tinc/{{ tinc_netname }}/ansible_ipaddress dest={{ tinc_tmpdir }}/{{ tinc_netname }}/ip/{{ ansible_hostname }} flat=yes
ignore_errors: yes
- fetch: src=/etc/tinc/{{ tinc_netname }}/rsa_key.pub dest={{ tinc_tmpdir }}/{{ tinc_netname }}/pubkeys/{{ ansible_hostname }} flat=yes
ignore_errors: yes
# Set an ipaddress for each host in set if they don't have already
- script: setip.py {{ tinc_tmpdir }}/{{ tinc_netname }}/pubkeys {{ tinc_tmpdir }}/{{ tinc_netname }}/ip {{ tinc_subnet }}
tags: test
register: ip_output
delegate_to: localhost
- template: src=host_configuration.j2 dest="{{ tinc_tmpdir }}/{{ tinc_netname }}/current/{{ ansible_hostname }}"
tags: test
delegate_to: localhost
For instance, let’s say you want to install it on a few hosts, and in your ansible hosts file you have a single public host, let’s call it publichost. Here’s a sample playbook. Runit is required, you can either install the package or use the runit role.
---
- name: Setup tinc
hosts: tinc_hosts
sudo: true
gather_facts: true
vars:
tinc_netname: mesh
tinc_connectto:
publichost1: 1.2.3.4
publichost2: 1.2.3.5
tinc_subnet: 10.11.0.0/24
tinc_port: 2005
tinc_state: present
tinc_static_binary: true
roles:
- tinc
tl;dr - tinc sets up a mesh vpn, binary works on all x86_64 distros, ansible assigns all ip addresses