From cc70c3640eeb06d9129cd624c0750f2db70648a7 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 4 Jan 2019 15:04:54 +0100 Subject: lxc-host: Major refactoring. o Removing radvd support, should be handled by itself. Better support for setting ipv6 addresses instead. o Moving out UFW stupport, should be moved to the ufw package. o Better variables, default and file names. --- ansible/roles/lxc-host/defaults/main.yml | 28 +++++ ansible/roles/lxc-host/handlers/main.yml | 5 + ansible/roles/lxc-host/tasks/main.yml | 99 ++++++++------- ansible/roles/lxc-host/tasks/networkd.yml | 97 +++++--------- ansible/roles/lxc-host/tasks/per-host.yml | 202 +++++++++++++++--------------- ansible/roles/lxc-host/tasks/radvd.yml | 44 +++++++ ansible/roles/lxc-host/tasks/ufw-nat.yml | 21 ++++ ansible/roles/lxc-host/tasks/ufw.yml | 25 ++++ 8 files changed, 312 insertions(+), 209 deletions(-) create mode 100644 ansible/roles/lxc-host/tasks/radvd.yml create mode 100644 ansible/roles/lxc-host/tasks/ufw-nat.yml create mode 100644 ansible/roles/lxc-host/tasks/ufw.yml (limited to 'ansible/roles/lxc-host') diff --git a/ansible/roles/lxc-host/defaults/main.yml b/ansible/roles/lxc-host/defaults/main.yml index 462ba8c..cf747f3 100644 --- a/ansible/roles/lxc-host/defaults/main.yml +++ b/ansible/roles/lxc-host/defaults/main.yml @@ -1 +1,29 @@ lxc_host__backing_store: dir +lxc_host__br_if: lxc0-br +lxc_host__internal_if: lxc0-int +lxc_host__default_container_if_name: veth0 +lxc_host__networkd_number: 50 + +# You have to fill the dict in host_vars/$hostname/lxc.yml +lxc_host__containers: +# test1: # The name of the container +# state: started # The state passed to lxc_container. +# interface: veth0 # The name of the ethernet interface inside the +# # container (optional) +# host_database: # The key used to look up IP info in the +# # global 'host_database' dict (optional, +# # defaults to the name of the container). + +# The host_database must have an entry that looks like: + +# my-container: +# interfaces: +# lxc0-int: # This key must be what is specified +# # by lxc_host__containers.$container.interface +# # or lxc_host__internal_if. +# ipv4: # Optional +# address: aa.bb.cc.dd +# netmask: 24 +# ipv6: # Optional +# address: aaaa::1 +# netmask: 64 diff --git a/ansible/roles/lxc-host/handlers/main.yml b/ansible/roles/lxc-host/handlers/main.yml index 7e7dc9c..aa399c7 100644 --- a/ansible/roles/lxc-host/handlers/main.yml +++ b/ansible/roles/lxc-host/handlers/main.yml @@ -20,3 +20,8 @@ become: yes ufw: state: reloaded + +- name: restart lxc_container + lxc_container: + name: "{{ name }}" + state: restarted diff --git a/ansible/roles/lxc-host/tasks/main.yml b/ansible/roles/lxc-host/tasks/main.yml index ab86969..25ff8ce 100644 --- a/ansible/roles/lxc-host/tasks/main.yml +++ b/ansible/roles/lxc-host/tasks/main.yml @@ -1,8 +1,7 @@ - name: Install packages tags: - lxc-host - - lxc-host-packages - - radvd + - packages become: yes apt: name: "{{ items }}" @@ -10,62 +9,78 @@ vars: items: - lxc + - lxc-templates + - debootstrap # For debian templates - python-lxc - - radvd #- debug: # msg: "item={{ item }}, host={{ host }}, lan={{ lan }}" # tags: # - lxc-host -# with_dict: "{{ lxc_host_containers }}" +# with_dict: "{{ lxc_host__containers }}" # vars: # i: "{{ item }}" # host: "{{ host_database[item.key] }}" # lan: "{{ host_database | json_query(item.key + '.interfaces | * | [?role==`lan`]') | first }}" -- name: Configure radvd - become: yes - tags: - - lxc-host - - radvd - vars: - ipv6: "{{ host_database[ansible_hostname].interfaces[lxc_host__internal_if].ipv6 }}" - notify: restart radvd - copy: - dest: /etc/radvd.conf - content: | - interface {{ lxc_host__br_if }} - { - AdvSendAdvert on; - MinRtrAdvInterval 5; - MaxRtrAdvInterval 10; - MinDelayBetweenRAs 1; - - AdvDefaultPreference medium; - AdvLinkMTU 1500; - - prefix {{ ipv6.address }}/{{ ipv6.netmask }} - { - AdvOnLink on; - AdvAutonomous on; - - AdvValidLifetime 14400; - AdvPreferredLifetime 3600; - AdvRouterAddr on; - }; - }; - - name: Configure host networking - when: lxc_host__enable_network_cfg tags: - lxc-host - lxc-host-network include_tasks: networkd.yml -- tags: lxc-host - with_dict: "{{ lxc_host_containers }}" +- name: List containers + tags: + - lxc-host + - lxc-host-containers + become: yes + block: + - name: Listing all containers + shell: lxc-ls -1 -f -F NAME,STATE + register: lxc_ls + changed_when: False + - set_fact: + existing_containers_yaml: | + {% for line in lxc_ls.stdout_lines[1:] %} + {% set parts = line.split(" ") %} + "{{ parts[0] }}": + state: "{{ parts[1] }}" + {% endfor %} +#" + - set_fact: + existing_containers: "{{ existing_containers_yaml | from_yaml }}" + - set_fact: + new_containers: "{{ lxc_host__containers | difference(existing_containers) }}" + +- tags: + - lxc-host + - lxc-host-containers + become: yes + loop: "{{ lxc_host__containers | dict2items }}" + loop_control: + loop_var: item + when: item.value.state == 'started' or item.value.state == 'stopped' vars: - i: "{{ item }}" - host: "{{ host_database[item.key] }}" - lan: "{{ host_database | json_query(item.key + '.interfaces | * | [?role==`lan`]') | first }}" + name: "{{ item.key }}" + container: "{{ item.value }}" + host: "{{ host_database[container.host_database if container.host_database is defined else name] }}" + lan_if: "{{ container.interface if container.interface is defined else lxc_host__default_container_if_name }}" + lan: "{{ host.interfaces[lan_if] }}" + new: "{{ name in new_containers }}" +# debug: +# msg: "name={{name}}\nhost={{host}}\nlan={{lan}}\nnew={{new}}" +# debug: msg=PRESENT include_tasks: per-host.yml + +- name: Removing containers + tags: + - lxc-host + - lxc-host-containers + become: yes + loop: "{{ lxc_host__containers | dict2items }}" + loop_control: + loop_var: item + when: item.value.state == 'absent' + lxc_container: + name: "{{ item.key }}" + state: absent diff --git a/ansible/roles/lxc-host/tasks/networkd.yml b/ansible/roles/lxc-host/tasks/networkd.yml index 41ddb3f..f7ae410 100644 --- a/ansible/roles/lxc-host/tasks/networkd.yml +++ b/ansible/roles/lxc-host/tasks/networkd.yml @@ -3,59 +3,20 @@ - lxc-host-network become: yes vars: - hardware_if: "{{ host_database | json_query(ansible_hostname + '.interfaces.' + lxc_host__hardware_if) }}" + file_prefix: "/etc/systemd/network/{{ lxc_host__networkd_number }}-lxc-host" br_if: "{{ lxc_host__br_if }}" - internal_if: "{{ host_database | json_query(ansible_hostname + '.interfaces.' + lxc_host__internal_if) }}" + internal_if: "{{ host_database[ansible_hostname].interfaces[lxc_host__internal_if] }}" block: - - debug: var=hardware_if - debug: var=br_if - debug: var=internal_if - name: Configure sysctl, enable ipv4 and ipv6 forwarding - become: yes - copy: - dest: /etc/sysctl.d/99-lxc-host.conf - content: | - net.ipv4.ip_forward=1 - net.ipv6.conf.all.forwarding=1 - notify: restart sysctl - - - name: Enable UFW - become: yes - ufw: - state: enabled - - - become: yes - ufw: - policy: allow - direction: outgoing - - - become: yes - ufw: - policy: allow - direction: routed - - - become: yes - ufw: - policy: deny - direction: incoming - - - name: Enable NAT configuration through UFW - become: yes - notify: reload ufw - blockinfile: - path: /etc/ufw/before.rules - insertbefore: "# Don't delete these required lines, otherwise there will be errors" - block: | - # NAT table rules - *nat - :POSTROUTING ACCEPT [0:0] - - # Forward traffic through eth0 - Change to match you out-interface - -A POSTROUTING -s {{ internal_if.ipv4.address }}/{{ internal_if.ipv4.netmask }} -o {{ lxc_host__hardware_if }} -j MASQUERADE - - # don't delete the 'COMMIT' line or these nat table rules won't be processed - COMMIT + sysctl: + name: "{{ item }}" + value: 1 + with_items: + - net.ipv4.ip_forward + - net.ipv6.conf.all.forwarding - name: enable systemd-networkd service: @@ -63,31 +24,31 @@ enabled: yes state: started - - name: "/etc/systemd/network/50-0-lxc-host-{{ lxc_host__hardware_if }}.network" +# - name: "/etc/systemd/network/50-0-lxc-host-{{ lxc_host__hardware_if }}.network" +# notify: systemctl restart systemd-networkd +# copy: +# dest: "/etc/systemd/network/50-0-lxc-host-{{ lxc_host__hardware_if }}.network" +# content: | +# [Match] +# Name={{ lxc_host__hardware_if }} +# +# [Network] +# Address={{ hardware_if.ipv4.address }}/{{ hardware_if.ipv4.netmask }} +# Gateway={{ hardware_if.ipv4.gateway }} + + - name: "{{ file_prefix }}-1-{{ lxc_host__internal_if }}.netdev" notify: systemctl restart systemd-networkd copy: - dest: "/etc/systemd/network/50-0-lxc-host-{{ lxc_host__hardware_if }}.network" - content: | - [Match] - Name={{ lxc_host__hardware_if }} - - [Network] - Address={{ hardware_if.ipv4.address }}/{{ hardware_if.ipv4.netmask }} - Gateway={{ hardware_if.ipv4.gateway }} - - - name: "/etc/systemd/network/50-1-lxc-host-{{ lxc_host__internal_if }}.netdev" - notify: systemctl restart systemd-networkd - copy: - dest: "/etc/systemd/network/50-1-lxc-host-{{ lxc_host__internal_if }}.netdev" + dest: "{{ file_prefix }}-1-{{ lxc_host__internal_if }}.netdev" content: | [NetDev] Name={{ lxc_host__internal_if }} Kind=dummy - - name: "/etc/systemd/network/50-2-lxc-host-{{ lxc_host__internal_if }}.network" + - name: "{{ file_prefix }}-2-{{ lxc_host__internal_if }}.network" notify: systemctl restart systemd-networkd copy: - dest: "/etc/systemd/network/50-2-lxc-host-{{ lxc_host__internal_if }}.network" + dest: "{{ file_prefix }}-2-{{ lxc_host__internal_if }}.network" content: | [Match] Name={{ lxc_host__internal_if }} @@ -95,25 +56,27 @@ [Network] Bridge={{ br_if }} - - name: "/etc/systemd/network/50-3-lxc-host-{{ br_if }}.netdev" + - name: "{{ file_prefix }}-3-{{ br_if }}.netdev" notify: systemctl restart systemd-networkd copy: - dest: "/etc/systemd/network/50-3-lxc-host-{{ br_if }}.netdev" + dest: "{{ file_prefix }}-3-{{ br_if }}.netdev" content: | [NetDev] Name={{ br_if }} Kind=bridge - - name: "/etc/systemd/network/50-4-lxc-host-{{ br_if }}.network" + - name: "{{ file_prefix }}-4-{{ br_if }}.network" notify: systemctl restart systemd-networkd copy: - dest: "/etc/systemd/network/50-4-lxc-host-{{ br_if }}.network" + dest: "{{ file_prefix }}-4-{{ br_if }}.network" content: | [Match] Name={{ br_if }} [Network] + {% if internal_if.ipv4 is defined %} Address={{ internal_if.ipv4.address }}/{{ internal_if.ipv4.netmask }} + {% endif %} {% if internal_if.ipv6 is defined %} Address={{ internal_if.ipv6.address }}/{{ internal_if.ipv6.netmask }} {% endif %} diff --git a/ansible/roles/lxc-host/tasks/per-host.yml b/ansible/roles/lxc-host/tasks/per-host.yml index 817497b..3bc9d24 100644 --- a/ansible/roles/lxc-host/tasks/per-host.yml +++ b/ansible/roles/lxc-host/tasks/per-host.yml @@ -1,115 +1,117 @@ - debug: - msg: "LXC HOST: {{ i.key }}" + msg: "LXC HOST: {{ name }}" tags: lxc-host -- name: Create container +- when: new tags: lxc-host become: yes - lxc_container: - name: "{{ i.key }}" - state: "{{ i.value.state }}" - template: debian - template_options: -r stretch --packages git,etckeeper,python,sudo - backing_store: "{{ lxc_host__backing_store }}" - zfs_root: "{{ lxc_host__zfs_root|default('') }}" - register: lxc + block: + - name: Create container + lxc_container: + name: "{{ name }}" + state: "{{ container.state }}" + template: debian + template_options: -r stretch --packages git,etckeeper,python,sudo + backing_store: "{{ lxc_host__backing_store }}" + zfs_root: "{{ lxc_host__zfs_root|default('') }}" -- name: Connection info - tags: lxc-host - become: yes - when: lxc.changed - debug: - msg: "Container created! All keys for superusers are installed for - root user, so remember to add 'ansible_user=root' when running the - play for the host the first time." + - name: Important message! + debug: + msg: "Container created! All keys for superusers are installed for + root user, so remember to add 'ansible_user=root' when running the + play for the host the first time." -- name: Create /root/.ssh - tags: lxc-host - become: yes - when: lxc.changed - file: - path: "/var/lib/lxc/{{ i.key }}/rootfs/root/.ssh" - state: directory - mode: 0600 - owner: root - group: root + - name: Create /root/.ssh + file: + path: "/var/lib/lxc/{{ name }}/rootfs/root/.ssh" + state: directory + mode: 0600 + owner: root + group: root -- name: Fill authorized_keys - tags: lxc-host - become: yes - when: lxc.changed - copy: - dest: "/var/lib/lxc/{{ i.key }}/rootfs/root/.ssh/authorized_keys" - content: | - {% for user in superusers %} - {% if users[user].authorized_keys is not none %} - {{ users[user].authorized_keys }} - {% endif %} - {% endfor %} + - name: Fill authorized_keys + copy: + dest: "/var/lib/lxc/{{ name }}/rootfs/root/.ssh/authorized_keys" + content: | + {% for user in superusers %} + {% if users[user].authorized_keys is not none %} + {{ users[user].authorized_keys }} + {% endif %} + {% endfor %} -- name: config-lxc-host - tags: lxc-host +- tags: lxc-host become: yes - register: config_lxc_host - copy: - dest: "/var/lib/lxc/{{ i.key }}/config-lxc-host" - content: | - lxc.network.type = veth - lxc.network.link = br0 - lxc.network.flags = up - lxc.network.hwaddr = {{ lan.hwaddr }} - {% if lan.ipv4 is defined %} - lxc.network.ipv4 = {{ lan.ipv4.address }}/{{ lan.ipv4.netmask }} - lxc.network.ipv4.gateway = {{ lan.ipv4.gateway }} - {% endif %} - # 0 = trace, 1 = debug, 2 = info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 = alert, and 8 = fatal. - lxc.loglevel = 1 - lxc.logfile = /var/lib/lxc/{{ i.key }}/{{ i.key }}.log + block: + - name: config-lxc-host + copy: + dest: "/var/lib/lxc/{{ name }}/config-lxc-host" + content: | + lxc.net.0.type = veth + lxc.net.0.link = {{ lxc_host__br_if }} + lxc.net.0.flags = up + lxc.net.0.name = {{ lan_if }} + lxc.net.0.hwaddr = {{ lan.hwaddr }} + {% if lan.ipv4 is defined %} + lxc.net.0.ipv4.address = {{ lan.ipv4.address }}/{{ lan.ipv4.netmask }} + {% if lan.ipv4.gateway is defined %} + lxc.net.0.ipv4.gateway = {{ lan.ipv4.gateway }} + {% endif %} + {% endif %} + {% if lan.ipv6 is defined %} + lxc.net.0.ipv6.address = {{ lan.ipv6.address }}/{{ lan.ipv6.netmask }} + {% endif %} -- name: "include file: config-lxc-host" - tags: lxc-host - become: yes - register: include_lxc_host - lineinfile: - path: "/var/lib/lxc/{{ i.key }}/config" - regexp: "^lxc.include *=.*/config-lxc-host$" - line: "lxc.include = /var/lib/lxc/{{ i.key }}/config-lxc-host" + # 0 = trace, 1 = debug, 2 = info, 3 = notice, 4 = warn, 5 = error, 6 = critical, 7 = alert, and 8 = fatal. + lxc.log.level = 1 + lxc.log.file = /var/lib/lxc/{{ name }}/{{ name }}.log + register: restart_1 -- name: "include file: config.d" - tags: lxc-host - become: yes - register: include_config_d - lineinfile: - path: "/var/lib/lxc/{{ i.key }}/config" - regexp: "^lxc.include *=.*/conf.d/$" - line: "lxc.include = /var/lib/lxc/{{ i.key }}/conf.d/" + - name: "include file: config-lxc-host" + lineinfile: + path: "/var/lib/lxc/{{ name }}/config" + regexp: "^lxc.include *=.*/config-lxc-host$" + line: "lxc.include = /var/lib/lxc/{{ name }}/config-lxc-host" + register: restart_2 -- name: "mkdir conf.d" - tags: lxc-host - become: yes - file: - path: "/var/lib/lxc/{{ i.key }}/conf.d" - state: "directory" + - name: "include file: config.d" + lineinfile: + path: "/var/lib/lxc/{{ name }}/config" + regexp: "^lxc.include *=.*/conf.d/$" + line: "lxc.include = /var/lib/lxc/{{ name }}/conf.d/" + register: restart_3 -- name: "fill conf.d" - tags: lxc-host - become: yes - register: fill_config_d - with_fileglob: "lxc-host/{{ i.key }}/*" - loop_control: - loop_var: file - copy: - dest: "/var/lib/lxc/{{ i.key }}/conf.d" - src: "{{ file }}" + - name: "mkdir conf.d" + file: + path: "/var/lib/lxc/{{ name }}/conf.d" + state: "directory" -- name: "restart lxc container {{ i.key }}" - tags: lxc-host - become: yes - when: i.value.state == 'started' and ( - lxc.changed or - config_lxc_host.changed or - include_config_d.changed or - fill_config_d.changed) - lxc_container: - name: "{{ i.key }}" - state: restarted + - name: Find files to copy + local_action: + module: find + paths: "files/lxc-host/{{ name }}" + patterns: "*" + register: find + + - name: "fill conf.d" + with_items: "{{ find.files | map(attribute='path') | list }}" + loop_control: + loop_var: path + copy: + dest: "/var/lib/lxc/{{ name }}/conf.d" + src: "{{ path }}" + register: restart_4 + + - set_fact: + restart: "{{ restart_1.changed or restart_2.changed or restart_3.changed or restart_4.changed }}" + + - name: Restart LXC container + lxc_container: + name: "{{ name }}" + state: restarted + when: restart and container.state == "started" + + - name: Stop LXC container + lxc_container: + name: "{{ name }}" + state: stopped + when: container.state == "stopped" diff --git a/ansible/roles/lxc-host/tasks/radvd.yml b/ansible/roles/lxc-host/tasks/radvd.yml new file mode 100644 index 0000000..4283a4b --- /dev/null +++ b/ansible/roles/lxc-host/tasks/radvd.yml @@ -0,0 +1,44 @@ +- name: Install packages + tags: + - lxc-host + - packages + become: yes + apt: + name: "{{ items }}" + install_recommends: no + vars: + items: + - radvd + +- name: Configure radvd + become: yes + tags: + - lxc-host + - lxc-host-radvd + vars: + ipv6: "{{ host_database[ansible_hostname].interfaces[lxc_host__internal_if].ipv6 }}" + notify: restart radvd + copy: + dest: /etc/radvd.conf + content: | + interface {{ lxc_host__br_if }} + { + AdvSendAdvert on; + MinRtrAdvInterval 5; + MaxRtrAdvInterval 10; + MinDelayBetweenRAs 1; + + AdvDefaultPreference medium; + AdvLinkMTU 1500; + + prefix {{ ipv6.address }}/{{ ipv6.netmask }} + { + AdvOnLink on; + AdvAutonomous on; + + AdvValidLifetime 14400; + AdvPreferredLifetime 3600; + AdvRouterAddr on; + }; + }; + diff --git a/ansible/roles/lxc-host/tasks/ufw-nat.yml b/ansible/roles/lxc-host/tasks/ufw-nat.yml new file mode 100644 index 0000000..219b70b --- /dev/null +++ b/ansible/roles/lxc-host/tasks/ufw-nat.yml @@ -0,0 +1,21 @@ +- name: + tags: + - lxc-host + - lxc-host-network + block: + - name: Enable NAT configuration through UFW + become: yes + notify: reload ufw + blockinfile: + path: /etc/ufw/before.rules + insertbefore: "# Don't delete these required lines, otherwise there will be errors" + block: | + # NAT table rules + *nat + :POSTROUTING ACCEPT [0:0] + + # Forward traffic through eth0 - Change to match you out-interface + -A POSTROUTING -s {{ internal_if.ipv4.address }}/{{ internal_if.ipv4.netmask }} -o {{ lxc_host__hardware_if }} -j MASQUERADE + + # don't delete the 'COMMIT' line or these nat table rules won't be processed + COMMIT diff --git a/ansible/roles/lxc-host/tasks/ufw.yml b/ansible/roles/lxc-host/tasks/ufw.yml new file mode 100644 index 0000000..1cfb50b --- /dev/null +++ b/ansible/roles/lxc-host/tasks/ufw.yml @@ -0,0 +1,25 @@ +- name: + tags: + - lxc-host + - lxc-host-network + block: + - name: Enable UFW + become: yes + ufw: + state: enabled + + - become: yes + ufw: + policy: allow + direction: outgoing + + - become: yes + ufw: + policy: allow + direction: routed + + - become: yes + ufw: + policy: deny + direction: incoming + -- cgit v1.2.3