Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persistent config on Qubes OS using debops.persistent_paths #2

Merged
merged 3 commits into from
Mar 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ Added
:command:`resolvconf` script when the network interfaces are configured
statically. [drybjed_]

- Support for persistent configuration of TemplateBasedVM on `Qubes OS`_ out of
the box using the debops.persistent_paths_ role. [ypid_]

Changed
~~~~~~~

Expand Down
6 changes: 3 additions & 3 deletions COPYRIGHT
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
debops.tinc - Configure tinc mesh VPN network

Copyright (C) 2015-2016 Maciej Delmanowski <[email protected]>
Copyright (C) 2016 Robin Schneider <[email protected]>
Copyright (C) 2015-2016 DebOps https://debops.org/
Copyright (C) 2015-2017 Maciej Delmanowski <[email protected]>
Copyright (C) 2016-2017 Robin Schneider <[email protected]>
Copyright (C) 2015-2017 DebOps https://debops.org/

This Ansible role is part of DebOps.

Expand Down
33 changes: 31 additions & 2 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,35 @@ tinc__etc_services__dependent_list: '{{ lookup("template",
tinc__ferm__dependent_rules: '{{ lookup("template",
"lookup/tinc__ferm__dependent_rules.j2",
convert_data=False) | from_yaml }}'

# ]]]
# ]]]
# ]]]
# .. envvar:: tinc__persistent_paths__dependent_paths [[[
#
# Configuration for the debops.persistent_paths_ Ansible role.
#
# Note that when the same network gets deleted and then added again to
# :envvar:`tinc__combined_networks`, the role might need two runs to also
# update the defaults file in the persistent location.
#
# Note that bind-dirs in Qubes OS currently does not restore symlinks (only their destination).
# (:file:`/etc/systemd/system/multi-user.target.wants/tinc.service` is a symlink).
# This works for ypid_ as he does not want auto start on Qubes OS AppVMs anyway.
# If you need it on Qubes OS, feel free to discuss and patch bind-dirs.
tinc__persistent_paths__dependent_paths:

'50_debops_tinc':
by_role: 'debops.tinc'
paths: |
{{ [
'/etc/tinc',
'/etc/systemd/system/tinc.service',
'/etc/systemd/system/[email protected]',
'/etc/systemd/system/multi-user.target.wants/tinc.service',
] + ((ansible_local.tinc.networks.keys() | map("regex_replace", "^", "/etc/default/tinc-") | list)
if (ansible_local|d() and ansible_local.tinc|d() and
ansible_local.tinc.networks|d())
else [])
}}
# ]]]
# ]]]
# ]]]
42 changes: 41 additions & 1 deletion docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,13 @@ generated from templates to other roles.
If you are using this role without DebOps, here's an example Ansible playbook
that uses the ``debops.tinc`` role:

.. literalinclude:: playbooks/tinc.yml
.. literalinclude:: playbooks/tinc-plain.yml
:language: yaml

If you are using this role without DebOps, here's an example Ansible playbook
that uses ``debops.tinc`` together with the debops.persistent_paths_ role:

.. literalinclude:: playbooks/tinc-persistent_paths.yml
:language: yaml

Static vs DHCP connection type
Expand Down Expand Up @@ -196,3 +202,37 @@ commands:
systemctl status tinc@mesh0
systemctl start tinc@mesh0
systemctl stop tinc@mesh0

debops.persistent_paths_ support
--------------------------------

In case the host in question happens to be a TemplateBasedVM on `Qubes OS`_ or
another system where persistence is not the default, it should be absent in
``debops_service_tinc`` and instead be added to the
``debops_service_tinc_persistent_paths`` Ansible inventory group
so that the changes can be made persistent:

.. code:: ini

[debops_service_tinc_persistent_paths]
hostname

Note that the :envvar:`tinc__user` (``tinc-vpn`` by default) created by the
role is not made persistent because making :file:`/etc/passwd` and related
files persistent might interfere with template changes.

You will need to ensure that the user exists by one of the following ways:

* Create the user in the template using :command:`useradd --system tinc-vpn --comment 'tinc VPN service' --home-dir '/etc/tinc' --shell '/bin/false'`
* Running the above command on start in the TemplateBasedVM
* Run the role against your template with the role configured in such a way
that it only creates the user.
Note that this is normally `discouraged on Qubes OS <https://www.qubes-os.org/doc/software-update-vm/#notes-on-trusting-your-templatevms>`_.

Besides that, the :envvar:`tinc__base_packages` are expected to be present (typically installed in the TemplateVM).

Also note that you will need to set ``core__unsafe_writes`` to ``True`` when you
attempt to update the configuration on a system that uses bind mounts for
persistence. You can set ``core__unsafe_writes`` directly in your inventory
without the need to run the ``debops.core`` role for this special case.
Refer to `Templating or updating persistent files`_ for details.
1 change: 1 addition & 0 deletions docs/includes/all.rst
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.. include:: includes/global.rst
.. include:: includes/role.rst
1 change: 1 addition & 0 deletions docs/includes/role.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. _Templating or updating persistent files: https://docs.debops.org/en/latest/ansible/roles/ansible-persistent_paths/docs/guides.html#templating-or-updating-persistent-files
37 changes: 37 additions & 0 deletions docs/playbooks/tinc-persistent_paths.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---

- name: Configure Tinc VPN and ensure persistence
hosts: [ 'debops_service_tinc_persistent_paths', 'debops_service_tinc_aux' ]
become: True

environment: '{{ inventory__environment | d({})
| combine(inventory__group_environment | d({}))
| combine(inventory__host_environment | d({})) }}'

roles:

- role: debops.tinc/env
tags: [ 'role::tinc', 'role::tinc:secret', 'role::secret', 'role::ferm' ]

- role: debops.secret
tags: [ 'role::secret', 'role::tinc:secret' ]
secret_directories: '{{ tinc__env_secret__directories }}'

- role: debops.apt_preferences
tags: [ 'role::apt_preferences' ]
apt_preferences__dependent_list: '{{ tinc__apt_preferences__dependent_list }}'

- role: debops.etc_services
tags: [ 'role::etc_services' ]
etc_services__dependent_list: '{{ tinc__env_etc_services__dependent_list }}'

- role: debops.ferm
tags: [ 'role::ferm' ]
ferm__dependent_rules: '{{ tinc__env_ferm__dependent_rules }}'

- role: debops.tinc
tags: [ 'role::tinc' ]

- role: debops.persistent_paths
tags: [ 'role::persistent_paths' ]
persistent_paths__dependent_paths: '{{ tinc__persistent_paths__dependent_paths }}'
33 changes: 33 additions & 0 deletions docs/playbooks/tinc-plain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---

- name: Configure Tinc VPN
hosts: [ 'debops_service_tinc', 'debops_service_tinc_aux' ]
become: True

environment: '{{ inventory__environment | d({})
| combine(inventory__group_environment | d({}))
| combine(inventory__host_environment | d({})) }}'

roles:

- role: debops.tinc/env
tags: [ 'role::tinc', 'role::tinc:secret', 'role::secret', 'role::ferm' ]

- role: debops.secret
tags: [ 'role::secret', 'role::tinc:secret' ]
secret_directories: '{{ tinc__env_secret__directories }}'

- role: debops.apt_preferences
tags: [ 'role::apt_preferences' ]
apt_preferences__dependent_list: '{{ tinc__apt_preferences__dependent_list }}'

- role: debops.etc_services
tags: [ 'role::etc_services' ]
etc_services__dependent_list: '{{ tinc__env_etc_services__dependent_list }}'

- role: debops.ferm
tags: [ 'role::ferm' ]
ferm__dependent_rules: '{{ tinc__env_ferm__dependent_rules }}'

- role: debops.tinc
tags: [ 'role::tinc' ]
32 changes: 2 additions & 30 deletions docs/playbooks/tinc.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
---

- name: Configure Tinc VPN
hosts: [ 'debops_service_tinc', 'debops_service_tinc_aux' ]
become: True
- include: tinc-plain.yml

environment: '{{ inventory__environment | d({})
| combine(inventory__group_environment | d({}))
| combine(inventory__host_environment | d({})) }}'

roles:

- role: debops.tinc/env
tags: [ 'role::tinc', 'role::tinc:secret', 'role::secret', 'role::ferm' ]

- role: debops.secret
tags: [ 'role::secret', 'role::tinc:secret' ]
secret_directories: '{{ tinc__env_secret__directories }}'

- role: debops.apt_preferences
tags: [ 'role::apt_preferences' ]
apt_preferences__dependent_list: '{{ tinc__apt_preferences__dependent_list }}'

- role: debops.etc_services
tags: [ 'role::etc_services' ]
etc_services__dependent_list: '{{ tinc__env_etc_services__dependent_list }}'

- role: debops.ferm
tags: [ 'role::ferm' ]
ferm__dependent_rules: '{{ tinc__env_ferm__dependent_rules }}'

- role: debops.tinc
tags: [ 'role::tinc' ]
- include: tinc-persistent_paths.yml
53 changes: 49 additions & 4 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
notify: [ 'Reload tinc' ]

- name: Disable tinc networks in systemd if requested
Expand Down Expand Up @@ -95,6 +97,8 @@
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
with_dict: '{{ tinc__combined_networks }}'
when: item.value.state|d('present') != 'absent' and item.value.tinc_options|d()
notify: [ 'Reload tinc' ]
Expand All @@ -111,6 +115,8 @@
owner: 'root'
group: '{{ tinc__group }}'
mode: '0750'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
with_dict: '{{ tinc__combined_networks }}'
when: (item.value.state|d('present') != 'absent' and item.value.generate_tinc_up|d(True)|bool)

Expand All @@ -121,6 +127,8 @@
owner: 'root'
group: '{{ tinc__group }}'
mode: '0750'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
with_dict: '{{ tinc__combined_networks }}'
when: (item.value.state|d('present') != 'absent' and item.value.generate_tinc_up|d(True)|bool)

Expand All @@ -131,8 +139,10 @@
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'

## RSA key management [[[1
# RSA key management [[[1

- name: Ensure that sensitive files are excluded from version control
template:
Expand All @@ -141,6 +151,8 @@
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'

- name: Initialize RSA key pairs
shell: yes | tincd -n {{ item.value.name | d(item.key) }} -K {{ item.value.rsa_key_length | d(tinc__rsa_key_length) }}
Expand All @@ -157,14 +169,16 @@
with_dict: '{{ tinc__combined_networks }}'
when: item.value.state|d('present') != 'absent'

## Tinc host configuration [[[1
# Tinc host configuration [[[1
- name: Generate host configuration file
template:
src: 'etc/tinc/network/hosts/host-config.j2'
dest: '/etc/tinc/{{ item.value.name | d(item.key) }}/hosts/{{ (item.value.hostname | d(tinc__hostname)) | replace("-","_") }}.d/00_host-config'
owner: 'root'
group: 'root'
mode: '0640'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
with_dict: '{{ tinc__combined_networks }}'
when: item.value.state|d('present') != 'absent'

Expand All @@ -179,7 +193,7 @@
when: item.value.state|d('present') != 'absent'
notify: [ 'Reload tinc' ]

## Tinc host configuration distribution [[[1
# Tinc host configuration distribution [[[1
- name: Upload public keys from hosts to Ansible Controller
fetch:
src: '/etc/tinc/{{ item.value.name | d(item.key) }}/hosts/{{ (item.value.hostname | d(tinc__hostname)) | replace("-","_") }}'
Expand Down Expand Up @@ -235,14 +249,16 @@
when: item.value.state|d('present') != 'absent'
notify: [ 'Reload tinc' ]

## systemd configuration [[[1
# systemd configuration [[[1
- name: Configure systemd default variables
template:
src: 'etc/default/tinc-network.j2'
dest: '/etc/default/tinc-{{ item.value.name | d(item.key) }}'
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
with_dict: '{{ tinc__combined_networks }}'
when: tinc__systemd|bool and item.value.state|d('present') != 'absent'
notify: [ 'Reload tinc' ]
Expand All @@ -254,6 +270,8 @@
owner: 'root'
group: 'root'
mode: '0755'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
when: tinc__systemd | bool

- name: Clean up old systemd configuration
Expand All @@ -268,6 +286,8 @@
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
with_items: [ 'tinc.service', '[email protected]' ]
register: tinc__register_systemd
when: tinc__systemd | bool
Expand All @@ -290,3 +310,28 @@
with_dict: '{{ tinc__combined_networks }}'
when: tinc__systemd|bool and item.value.state|d('present') != 'absent' and
item.value.port|d()

# Ansible facts [[[1

- name: Make sure Ansible fact directory exists
file:
path: '/etc/ansible/facts.d'
state: 'directory'
owner: 'root'
group: 'root'
mode: '0755'

- name: Create local facts of tinc
template:
src: 'etc/ansible/facts.d/tinc.fact.j2'
dest: '/etc/ansible/facts.d/tinc.fact'
owner: 'root'
group: 'root'
mode: '0644'
unsafe_writes: '{{ True if (core__unsafe_writes|d(True if (ansible_local|d() and ansible_local.core|d()
and ansible_local.core.unsafe_writes|d() | bool) else False) | bool) else omit }}'
register: tinc__register_facts

- name: Reload facts if they were modified
action: setup
when: tinc__register_facts|changed
4 changes: 4 additions & 0 deletions templates/etc/ansible/facts.d/tinc.fact.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{ ({
"enabled": True,
"networks": tinc__combined_networks,
}) | to_nice_json }}