Skip to content

Commit

Permalink
Add Tinc (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
NightTsarina authored Nov 5, 2024
2 parents bed5453 + 4ab6cb7 commit 8bfa42f
Show file tree
Hide file tree
Showing 17 changed files with 401 additions and 1 deletion.
9 changes: 9 additions & 0 deletions .mailmap
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Martina Ferrari <tina@tina.pm>
Martina Ferrari <tina@tina.pm> <tina@debian.org>
#
Martina Ferrari <tincho@debian.org>
Martina Ferrari <tina@tincho.org>
Martina Ferrari <tincho@tincho.org>
Martina Ferrari <tina@tina.pm> <tincho@debian.org>
Martina Ferrari <tina@tina.pm> <tina@tincho.org>
Martina Ferrari <tina@tina.pm> <tincho@tincho.org>
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.2.0 - 2024-11-01

New release adding tinc role.

## 1.1.0 - 2024-10-23

New release adding libvirt-host, libvirt-vm, and ntp roles.
Expand Down
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ License: MIT
Copyright: 2016 Andrew J Huffman
Comment: https://github.com/ahuffman/ansible-resolv

Files: roles/tinc/*
License: UNKNOWN
Copyright: 2015-2016 Curtis Cullicut
2016 Mitchell Anicas
2019-2024 Martina Ferrari
Comment: Based on https://github.com/thisismitch/ansible-tinc

License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace: tina_pm
name: third_party
version: 1.1.0
version: 1.2.0

authors:
- Adeodato Simó
Expand Down
47 changes: 47 additions & 0 deletions roles/tinc/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# vim:ts=2:sw=2:et:ai:sts=2

# Set to True to disable and remove tinc from a host.
tinc__remove: false

tinc__netname: tinc

# Configuration for hosts not present in the ansible inventory.
# Format:
# tinc__external_hosts:
# windows_host1:
# tinc__public_addresses:
# - 1.2.3.4
# tinc__vpn_addresses:
# - 192.168.128.1/32
# tinc__allow_incoming_connections: true
# tinc__host_conf: |
# Address = 1.2.3.4
# Subnet = 192.168.128.1/32
#
# -----BEGIN RSA PUBLIC KEY-----
# ...
tinc__external_hosts: {}

# Per-host
tinc__public_addresses: '{{ [ansible_host] }}'
tinc__port: 655
tinc__allow_incoming_connections: true

tinc__vpn_interface: '{{ tinc__netname }}'

# IP addresses to assign to the VPN interface.
tinc__vpn_addresses: []

# Export the local IP addresses as single-host networks.
tinc__vpn_local_subnets:
'{{ tinc__vpn_addresses | ipaddr("address") | ipaddr("host") }}'

# Extra networks to export.
tinc__vpn_extra_subnets:

# Install ferm service configuration file.
tinc__install_ferm_svc: false

# Command paths.
tinc__iproute2_path: /usr/bin/ip
21 changes: 21 additions & 0 deletions roles/tinc/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
# vim:ts=2:sw=2:et:ai:sts=2

- name: Reload tinc
ansible.builtin.service:
name: '{{ tinc__service_name }}'
state: reloaded

- name: Restart tinc
ansible.builtin.service:
name: '{{ tinc__service_name }}'
state: restarted

- name: Reload systemd
ansible.builtin.systemd:
daemon_reload: true

- name: Reload ferm
ansible.builtin.service:
name: ferm
state: reloaded
8 changes: 8 additions & 0 deletions roles/tinc/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# vim:ts=2:sw=2:et:ai:sts=2

- ansible.builtin.include_tasks: remove.yml # noqa: name[missing]
when: tinc__remove

- ansible.builtin.include_tasks: setup.yml # noqa: name[missing]
when: not tinc__remove
43 changes: 43 additions & 0 deletions roles/tinc/tasks/remove.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
# vim:ts=2:sw=2:et:ai:sts=2

- name: Check tinc uses systemd units
ansible.builtin.stat:
path: /lib/systemd/system/tinc@.service
register: tinc__tinc_unit

- name: Set fact about systemd unit
ansible.builtin.set_fact:
tinc__use_systemd: false
when: not tinc__tinc_unit.stat.exists

- name: Stop and disable tinc
ansible.builtin.service:
name: '{{ tinc__service_name }}'
enabled: false
state: stopped

- name: Delete tinc netname directory
ansible.builtin.file:
path: /etc/tinc/{{ tinc__netname }}
state: absent

- name: Delete nets.boot
ansible.builtin.lineinfile:
dest: /etc/tinc/nets.boot
line: '{{ tinc__netname }}'
state: absent

- name: Delete systemd unit override
ansible.builtin.file:
path: /etc/systemd/system/{{ tinc__service_name }}.service.d/override.conf
state: absent
notify:
- reload systemd
when: tinc__use_systemd

- name: Delete local configuration copy
ansible.builtin.file:
path: fetch/{{ tinc__netname }}/{{ inventory_hostname }}
state: absent
delegate_to: localhost
161 changes: 161 additions & 0 deletions roles/tinc/tasks/setup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
# vim:ts=2:sw=2:et:ai:sts=2

- name: Install tinc
ansible.builtin.package:
name: tinc
state: present

- name: Check tinc uses systemd units
ansible.builtin.stat:
path: /lib/systemd/system/tinc@.service
register: tinc__tinc_unit

- name: Set fact about systemd unit
ansible.builtin.set_fact:
tinc__use_systemd: false
when: not tinc__tinc_unit.stat.exists

- name: Set daemon parameters in /etc/default/tinc
ansible.builtin.lineinfile:
dest: /etc/default/tinc
line: EXTRA='-d -L'
regexp: '^EXTRA\s*='
insertbefore: BOF
create: false
notify:
- restart tinc

- name: Ensure tinc network directory exists
ansible.builtin.file:
path: /etc/tinc/{{ tinc__netname }}/hosts
recurse: true
state: directory

- name: Add network to /etc/tinc/nets.boot
ansible.builtin.lineinfile:
dest: /etc/tinc/nets.boot
line: '{{ tinc__netname }}'
mode: '0644'
create: true
notify:
- restart tinc
when: not tinc__use_systemd

- name: Create tinc.conf file from template
ansible.builtin.template:
src: tinc.conf.j2
dest: /etc/tinc/{{ tinc__netname }}/tinc.conf
mode: '0644'
notify:
- reload tinc

- name: Create network configuration scripts
ansible.builtin.template:
src: '{{ item }}.j2'
dest: /etc/tinc/{{ tinc__netname }}/{{ item }}
mode: '0755'
loop:
- tinc-up
- tinc-down
- subnet-up
- subnet-down
notify:
- restart tinc

- name: Check for crypto key pair
ansible.builtin.command: >-
awk '/^-----BEGIN RSA PUBLIC KEY-----$/,/^-----END RSA PUBLIC KEY-----$/'
/etc/tinc/{{ tinc__netname }}/hosts/{{ inventory_hostname }}
register: tinc__public_key
changed_when: >
not tinc__public_key.stdout.endswith('-----END RSA PUBLIC KEY-----')
failed_when: tinc__public_key.rc not in (0, 1, 2)
check_mode: false

- name: Set host parameters
ansible.builtin.template:
src: host.conf.j2
dest: /etc/tinc/{{ tinc__netname }}/hosts/{{ inventory_hostname }}
mode: '0644'
notify:
- restart tinc

# this is necessary because the public key will not be generated
# (non-interactively) if the private key already exists
- name: Delete private key and regenerate keypair # noqa: no-handler
ansible.builtin.file:
path: /etc/tinc/{{ tinc__netname }}/rsa_key.priv
state: absent
when: tinc__public_key.changed
notify:
- restart tinc

- name: Delete private key and regenerate keypair # noqa: no-handler
ansible.builtin.command: tincd -n {{ tinc__netname }} -K4096
args:
creates: /etc/tinc/{{ tinc__netname }}/rsa_key.priv
when: tinc__public_key.changed
notify:
- restart tinc

- name: Find obsolete tinc host files
ansible.builtin.command: ls /etc/tinc/{{ tinc__netname }}/hosts/
register: tinc__host_files
changed_when: false
check_mode: false

- name: Remove obsolete tinc host files
ansible.builtin.file:
path: /etc/tinc/{{ tinc__netname }}/hosts/{{ item }}
state: absent
with_items: '{{ tinc__host_files.stdout_lines }}'
when: >-
item not in tinc__hostvars or tinc__hostvars[item].tinc__remove
- name: Fetch tinc hosts file after key creation
ansible.builtin.fetch:
src: /etc/tinc/{{ tinc__netname }}/hosts/{{ inventory_hostname }}
dest: fetch/{{ tinc__netname }}/{{ inventory_hostname }}
flat: true

- name: Create tinc hosts file for hosts outside of ansible
ansible.builtin.copy:
dest: /etc/tinc/{{ item.value.tinc__netname }}/hosts/{{ item.key }}
content: '{{ item.value.tinc__host_conf }}'
mode: '0644'
with_dict: '{{ tinc__external_hosts }}'
when: >-
item.value.tinc__host_conf is defined and
item.value.tinc__netname is defined
- name: Sync the fetched tinc hosts files on each host
ansible.builtin.copy:
src: fetch/{{ tinc__netname }}/
dest: /etc/tinc/{{ tinc__netname }}/hosts/
mode: '0644'
notify:
- reload tinc

- name: Ensure tinc meta-service is started
ansible.builtin.service:
name: tinc
enabled: true
state: started
when: tinc__use_systemd

- name: Ensure tinc is started
ansible.builtin.service:
name: '{{ tinc__service_name }}'
enabled: true
state: started

- name: Install ferm configuration
ansible.builtin.template:
src: ferm.conf.j2
dest: /etc/ferm/ferm.d/tinc.conf
owner: root
group: adm
mode: '0644'
notify: reload ferm
when: tinc__install_ferm_svc and tinc__allow_incoming_connections
10 changes: 10 additions & 0 deletions roles/tinc/templates/ferm.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# {{ ansible_managed }}
{% with -%}
{% set saddr = tinc__other_public_addresses %}
{% set saddr = saddr if saddr is string else saddr | join(' ') %}
domain (ip ip6) table filter chain INPUT {
proto tcp
saddr @ipfilter(({{ saddr }}))
dport {{ tinc__port }} ACCEPT;
}
{%- endwith %}
11 changes: 11 additions & 0 deletions roles/tinc/templates/host.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# {{ ansible_managed }}
{% for addr in tinc__public_addresses %}
Address = {{ addr }} {{ tinc__port }}
{% endfor %}
{% for item in (
(tinc__vpn_local_subnets or []) + (tinc__vpn_extra_subnets or [])
) %}
Subnet = {{ item }}
{% endfor %}

{{ tinc__public_key.stdout }}
8 changes: 8 additions & 0 deletions roles/tinc/templates/subnet-down.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
# vim:ts=4:sw=4:et:ai:sts=4

echo "subnet-down for $NODE/$NETNAME" >&2

if [ "$NODE" != "$NAME" ]; then
{{ tinc__iproute2_path }} route del $SUBNET dev $INTERFACE
fi
8 changes: 8 additions & 0 deletions roles/tinc/templates/subnet-up.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
# vim:ts=4:sw=4:et:ai:sts=4

echo "subnet-up for $NODE/$NETNAME" >&2

if [ "$NODE" != "$NAME" ]; then
{{ tinc__iproute2_path }} route add $SUBNET dev $INTERFACE
fi
7 changes: 7 additions & 0 deletions roles/tinc/templates/tinc-down.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
# {{ ansible_managed }}

{% for ADDR in tinc__vpn_addresses %}
{{ tinc__iproute2_path }} addr del dev {{ tinc__vpn_interface }} {{ ADDR }}
{% endfor %}
{{ tinc__iproute2_path }} link set dev {{ tinc__vpn_interface }} down
7 changes: 7 additions & 0 deletions roles/tinc/templates/tinc-up.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
# {{ ansible_managed }}

{{ tinc__iproute2_path }} link set dev {{ tinc__vpn_interface }} up
{% for ADDR in tinc__vpn_addresses %}
{{ tinc__iproute2_path }} addr add dev {{ tinc__vpn_interface }} {{ ADDR }}
{% endfor %}
14 changes: 14 additions & 0 deletions roles/tinc/templates/tinc.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# {{ ansible_managed }}
Name = {{ inventory_hostname }}
#AddressFamily = ipv4
Interface = {{ tinc__vpn_interface }}
{% for host, config in tinc__hostvars | dictsort %}
{% if inventory_hostname != host and (
config.tinc__allow_incoming_connections
if config.tinc__allow_incoming_connections is not none else True) and
not config.tinc__remove and
tinc__netname == (config.tinc__netname or tinc__netname)
%}
ConnectTo = {{ host }}
{% endif %}
{% endfor %}
Loading

0 comments on commit 8bfa42f

Please sign in to comment.