From b920bdf52b48a783150b05e703c97cc7914ba135 Mon Sep 17 00:00:00 2001 From: "Andreas B. Mundt" Date: Wed, 10 Nov 2021 17:01:56 +0100 Subject: [PATCH] Provide playbook and role to deploy containers. The containers are deployed for educational purposes with user 'ansible' in the sudo group and an empty password. SSH login is available via ports 10000 upwards on the host. Port 80 is forwarded as well (ssh port + 100). The container's rootfs is read only with an overlay: After restart of the container, modifications are lost. --- edubox.yml | 16 +++ roles/educontainer/tasks/main.yml | 114 ++++++++++++++++++ .../educontainer/templates/contcfg.nspawn.j2 | 11 ++ roles/educontainer/templates/hostname.j2 | 1 + 4 files changed, 142 insertions(+) create mode 100644 edubox.yml create mode 100644 roles/educontainer/tasks/main.yml create mode 100644 roles/educontainer/templates/contcfg.nspawn.j2 create mode 100644 roles/educontainer/templates/hostname.j2 diff --git a/edubox.yml b/edubox.yml new file mode 100644 index 0000000..f952c29 --- /dev/null +++ b/edubox.yml @@ -0,0 +1,16 @@ +--- +# ansible-playbook edubox.yml -i , --ask-become-pass + +- name: apply configuration to the edubox + hosts: all # eduboxes + remote_user: ansible + become: yes + vars: + contname: cont + containers: "{{ range(0, 9 + 1) | list }}" + extra_pkgs: [apt-cacher-ng] + + roles: + - up2date-debian + - educontainer + diff --git a/roles/educontainer/tasks/main.yml b/roles/educontainer/tasks/main.yml new file mode 100644 index 0000000..1f503b2 --- /dev/null +++ b/roles/educontainer/tasks/main.yml @@ -0,0 +1,114 @@ +## Prepare minimal systemd-nspawn containers for educational use. +## +## Port mapping to the host: +## +## container 0: ssh → host port 10000, HTTP → 10100 +## container 1: ssh → host port 10001, HTTP → 10101 +## ... ... ... +## +## User 'ansible' in the sudo group. Password is empty. +## + +- name: start all containers + command: machinectl start {{ contname }}{{ "%02d" | format(item|int) }} + loop: "{{ containers }}" + tags: + - never + - start + +- name: stop all containers + command: machinectl stop {{ contname }}{{ "%02d" | format(item|int) }} + loop: "{{ containers }}" + tags: + - never + - stop + +- name: purge all containers + command: machinectl remove {{ contname }}{{ "%02d" | format(item|int) }} + loop: "{{ containers }}" + tags: + - never + - purge + +- name: debootstrap minimal system + command: + cmd: > + debootstrap + --include=systemd-{{ contname }}ainer,openssh-server,sudo + --components=main,{{ contname }}rib,non-free stable + {{ contname }}00 http://deb.debian.org/debian + args: + chdir: /var/lib/machines/ + creates: /var/lib/machines/{{ contname }}00 + environment: + http_proxy: http://localhost:3142 + +- name: provide ansible user account + command: + cmd: > + chroot . sh -c '/usr/sbin/useradd -m -s /bin/bash + -c "Ansible User,,," -G sudo ansible' + args: + chdir: /var/lib/machines/{{ contname }}00 + creates: /var/lib/machines/{{ contname }}00/home/ansible + register: user_account + +- name: provide empty password for ansible user + command: + cmd: chroot . sh -c "passwd -d ansible" + args: + chdir: /var/lib/machines/{{ contname }}00 + when: user_account.changed | default(false) + +- name: allow empty passwords in ssh + lineinfile: + path: /var/lib/machines/{{ contname }}00/etc/ssh/sshd_config + insertafter: '#PermitEmptyPasswords no' + line: 'PermitEmptyPasswords yes' + # when: user_account.changed | default(false) + +- name: prepare directories + file: + path: /var/lib/machines/{{ contname }}00/etc/systemd/system/{{ item }} + state: directory + loop: + - multi-user.target.wants + - sockets.target.wants + - network-online.target.wants + +- name: enable systemd-networkd service + file: + src: /lib/systemd/system/{{ item.src }} + dest: /var/lib/machines/{{ contname }}00/etc/systemd/system/{{ item.dest }} + state: link + force: yes + loop: + - { src: systemd-networkd.service, dest: dbus-org.freedesktop.network1.service } + - { src: systemd-networkd.service, dest: multi-user.target.wants/systemd-networkd.service } + - { src: systemd-networkd.socket, dest: sockets.target.wants/systemd-networkd.socket } + - { src: systemd-networkd-wait-online.service, dest: network-online.target.wants/systemd-networkd-wait-online.service } + +- name: clone the initial container + command: machinectl clone {{ contname }}00 {{ contname }}{{ "%02d" | format(item|int) }} + args: + creates: /var/lib/machines/{{ contname }}{{ "%02d" | format(item|int) }} + loop: "{{ containers[1:] }}" + +- name: provide container configuration + template: + src: contcfg.nspawn.j2 + dest: /etc/systemd/nspawn/{{ contname}}{{ "%02d" | format(item|int) }}.nspawn + loop: "{{ containers }}" + +- name: provide container hostname + template: + src: hostname.j2 + dest: /var/lib/machines/{{ contname }}{{ "%02d" | format(item|int) }}/etc/hostname + loop: "{{ containers }}" + +- name: start all containers on boot + systemd: + name: systemd-nspawn@{{ contname }}{{ "%02d" | format(item|int) }}.service + state: started + enabled: yes + loop: "{{ containers }}" diff --git a/roles/educontainer/templates/contcfg.nspawn.j2 b/roles/educontainer/templates/contcfg.nspawn.j2 new file mode 100644 index 0000000..c436224 --- /dev/null +++ b/roles/educontainer/templates/contcfg.nspawn.j2 @@ -0,0 +1,11 @@ +[Exec] +Capability=CAP_NET_ADMIN +ResolvConf=copy-host + +[Network] +Port=10{{ "%03d" | format(item|int) }}:22 +Port=10{{ "%03d" | format(item|int + 100) }}:80 + +[Files] +Volatile=overlay +PrivateUsersChown=false diff --git a/roles/educontainer/templates/hostname.j2 b/roles/educontainer/templates/hostname.j2 new file mode 100644 index 0000000..3c3ac55 --- /dev/null +++ b/roles/educontainer/templates/hostname.j2 @@ -0,0 +1 @@ +{{ contname }}{{ "%02d" | format(item|int) }}