From 5ae19f834b5dc7bc411cc9a6f647d6e5ff5df011 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 09:58:19 +0200 Subject: [PATCH 01/16] [debops.netbase] Skip hostname conf. in containers --- CHANGELOG.rst | 4 ++++ ansible/roles/debops.netbase/defaults/main.yml | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b39d2e43e9..24db1ec42e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -76,6 +76,10 @@ Changed preparation of adding a role that will provide client functionality like network and container management. +- [debops.netbase] Do not try to manage the hostname in LXC, Docker or OpenVZ + containers by default. We assume that these containers are unprivileged and + their hostname cannot be changed from the inside of the container. + `debops v1.0.0`_ - 2019-05-22 ----------------------------- diff --git a/ansible/roles/debops.netbase/defaults/main.yml b/ansible/roles/debops.netbase/defaults/main.yml index 75204986f0..801abfe0f5 100644 --- a/ansible/roles/debops.netbase/defaults/main.yml +++ b/ansible/roles/debops.netbase/defaults/main.yml @@ -40,12 +40,16 @@ netbase__packages: [] # .. envvar:: netbase__hostname_config_enabled [[[ # # Enable or disable configuration of the hostname based on presence of the -# ``cap_sys_admin`` POSIX capability. Hostname will still be defined in +# ``cap_sys_admin`` POSIX capability. The role will also avoid configuring the +# hostname in containers, which usually cannot change their own hostname +# directory due to host restrictions. Hostname will still be defined in # :file:`/etc/hosts` if the local domain configuration is enabled. netbase__hostname_config_enabled: '{{ True - if (((ansible_system_capabilities_enforced|d())|bool and + if ((((ansible_system_capabilities_enforced|d())|bool and "cap_sys_admin" in ansible_system_capabilities) or - not (ansible_system_capabilities_enforced|d(True))|bool) + not (ansible_system_capabilities_enforced|d(True))|bool) and + (ansible_virtualization_type is undefined or + ansible_virtualization_type not in [ "lxc", "docker", "openvz" ])) else False }}' # ]]] From c72b2096548a72ae8dcb33987490fa37e4ebb881 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 10:12:44 +0200 Subject: [PATCH 02/16] [debops.sudo] Allow dpkg to remove 'sudo' package The 'SUDO_FORCE_REMOVE=yes' variable tells dpkg(1) that it can safely remove the 'sudo' package, which can happen when we try to switch to the 'sudo-ldap' package. Normally 'dpkg' checks if the 'root' account has a password and will stop the upgrade process because access to the 'root' account could be lost when the password is not set; but we assume that users can still access root via SSH public keys and loss of access is unlikely to happen in this case. --- ansible/roles/debops.sudo/tasks/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ansible/roles/debops.sudo/tasks/main.yml b/ansible/roles/debops.sudo/tasks/main.yml index 3b56c7b1c7..3e2b2967cb 100644 --- a/ansible/roles/debops.sudo/tasks/main.yml +++ b/ansible/roles/debops.sudo/tasks/main.yml @@ -1,6 +1,8 @@ --- - name: Install required packages + environment: + SUDO_FORCE_REMOVE: 'yes' package: name: '{{ item }}' state: 'present' From a70d6ea009adb5c7435a2d3e75ea33e4c1e23a92 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 10:53:07 +0200 Subject: [PATCH 03/16] [debops.sudo] Reorder LDAP configuration task This change should ensure that the 'sudo' LDAP configuration is present on a host before the 'sudo-ldap' APT package is installed. This will hopefully prevent losing access via sudo from non-local accounts. --- ansible/roles/debops.sudo/tasks/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ansible/roles/debops.sudo/tasks/main.yml b/ansible/roles/debops.sudo/tasks/main.yml index 3e2b2967cb..e8078b1dd6 100644 --- a/ansible/roles/debops.sudo/tasks/main.yml +++ b/ansible/roles/debops.sudo/tasks/main.yml @@ -1,5 +1,12 @@ --- +- name: Configure access to LDAP directory + template: + src: 'etc/sudo-ldap.conf.j2' + dest: '/etc/sudo-ldap.conf' + mode: '0440' + when: sudo__enabled|bool and sudo__ldap_enabled|bool + - name: Install required packages environment: SUDO_FORCE_REMOVE: 'yes' @@ -54,13 +61,6 @@ mode: '0644' when: sudo__enabled|bool and sudo__logind_session|bool -- name: Configure access to LDAP directory - template: - src: 'etc/sudo-ldap.conf.j2' - dest: '/etc/sudo-ldap.conf' - mode: '0440' - when: sudo__enabled|bool and sudo__ldap_enabled|bool - - name: Make sure that Ansible local facts directory exists file: path: '/etc/ansible/facts.d' From f213b7bb43718f90f4536b7161ef0c35e1ab0946 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 10:56:38 +0200 Subject: [PATCH 04/16] [debops.sysctl] Add support for diverting configs This patch implements the 'item.divert' parameter in the 'debops.sysctl' role which allows diverting/reverting configuration files located in the '/etc/sysctl.d/' directory that are provided by APT packages. --- ansible/roles/debops.sysctl/tasks/main.yml | 32 +++++++++++++++++++ .../roles/debops.sysctl/defaults-detailed.rst | 5 +++ 2 files changed, 37 insertions(+) diff --git a/ansible/roles/debops.sysctl/tasks/main.yml b/ansible/roles/debops.sysctl/tasks/main.yml index 9e6fb80300..d75ea8acc3 100644 --- a/ansible/roles/debops.sysctl/tasks/main.yml +++ b/ansible/roles/debops.sysctl/tasks/main.yml @@ -30,6 +30,28 @@ action: setup when: sysctl__register_facts is changed +- name: Check current sysctl diversions + environment: + LC_ALL: 'C' + shell: set -o nounset -o pipefail -o errexit && + dpkg-divert --list '/etc/sysctl.d/*.dpkg-divert' | awk '{print $NF}' || true + args: + executable: 'bash' + register: sysctl__register_diversions + check_mode: False + changed_when: False + +- name: Divert the custom sysctl configuration + command: dpkg-divert --quiet --local + --divert /etc/sysctl.d/{{ item.filename | d(item.weight|string + "-" + item.name + ".conf") }}.dpkg-divert + --rename /etc/sysctl.d/{{ item.filename | d(item.weight|string + "-" + item.name + ".conf") }} + with_items: '{{ sysctl__combined_parameters | parse_kv_items }}' + when: (item.name|d() and item.options|d() and + item.state|d('present') not in [ 'absent', 'ignore', 'init' ] and + (item.divert|d())|bool and + ('/etc/sysctl.d/' + (item.filename | d(item.weight|string + "-" + item.name + ".conf")) + + '.dpkg-divert') not in sysctl__register_diversions.stdout_lines) + - name: Remove sysctl configuration files if requested file: path: '/etc/sysctl.d/{{ item.filename | d(item.weight|string + "-" + item.name + ".conf") }}' @@ -49,6 +71,16 @@ register: sysctl__register_config_created when: item.name|d() and item.options|d() and item.state|d('present') not in [ 'absent', 'ignore', 'init' ] +- name: Revert original sysctl configuration + shell: rm -f /etc/sysctl.d/{{ item.filename | d(item.weight|string + "-" + item.name + ".conf") }} + ; dpkg-divert --quiet --local --rename --remove /etc/sysctl.d/{{ item.filename | d(item.weight|string + "-" + item.name + ".conf") }} + args: + warn: False + with_items: '{{ sysctl__combined_parameters | parse_kv_items }}' + when: (item.name|d() and item.state|d('present') == 'absent' and (item.divert|d())|bool and + ('/etc/sysctl.d/' + item.filename | d(item.weight|string + "-" + item.name + ".conf") + + '.dpkg-divert') in sysctl__register_diversions.stdout_lines) + - name: Check sysctl command capabilities shell: set -o nounset -o pipefail -o errexit && sysctl --help | grep -E '^\s+\-\-system\s+' || true diff --git a/docs/ansible/roles/debops.sysctl/defaults-detailed.rst b/docs/ansible/roles/debops.sysctl/defaults-detailed.rst index f231269941..a1b1d00f2b 100644 --- a/docs/ansible/roles/debops.sysctl/defaults-detailed.rst +++ b/docs/ansible/roles/debops.sysctl/defaults-detailed.rst @@ -74,6 +74,11 @@ specific parameters: /etc/sysctl.d/{{ weight }}-{{ name }}.conf +``divert`` + Boolean, optional. When specified and ``True``, the original configuration + file will be diverted using :man:`dpkg-divert(8)`. If a configuration file is + due to be removed, the original file will be reverted back into place. + ``comment`` Optional. A string or YAML text block with a comment added at the top of the generated configuration file. From 3a142ff55a56e3251a9518a367d98e958ad8ed94 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 11:03:54 +0200 Subject: [PATCH 05/16] [debops.sysctl] Protect hardlinks and symlinks --- CHANGELOG.rst | 3 +++ ansible/roles/debops.sysctl/defaults/main.yml | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 24db1ec42e..ec64a3050d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,6 +42,9 @@ Added able to access SSH service from any host. Existing installations might need to be updated manually to fix UID/GID or LDAP DN conflicts. +- [debops.sysctl] The kernel protection for symlinks and hardlinks will be + enabled by default on Debian/Ubuntu hosts. + Changed ~~~~~~~ diff --git a/ansible/roles/debops.sysctl/defaults/main.yml b/ansible/roles/debops.sysctl/defaults/main.yml index 8eaae5e303..1bf9091c90 100644 --- a/ansible/roles/debops.sysctl/defaults/main.yml +++ b/ansible/roles/debops.sysctl/defaults/main.yml @@ -229,6 +229,29 @@ sysctl__default_parameters: ansible_virtualization_type == "openvz")) | ternary("present", "absent") }}' + # The '/proc/sys/fs/' namespace is usually read-only in unprivileged LXC + # containers. The default 'protect-links.conf' file that comes with the + # 'procps' APT package has the 'fs.*' parameters uncommented, which breaks + # the 'sysctl' configuration via the role. Therefore, let's divert the + # original file and regenerate it; the read-only parameters will be + # automatically commented out in unprivileged LXC containers. + - name: 'protect-links' + filename: 'protect-links.conf' + divert: True + comment: | + Protected links + + Protects against creating or following links under certain conditions + Debian kernels have both set to 1 (restricted) + See https://www.kernel.org/doc/Documentation/sysctl/fs.txt + options: + + - name: 'fs.protected_hardlinks' + value: 1 + + - name: 'fs.protected_symlinks' + value: 1 + # ]]] # .. envvar:: sysctl__parameters [[[ # From ea0adb1ac77e2f340edf631579b2bd64c52ae63c Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 11:13:05 +0200 Subject: [PATCH 06/16] [debops.rsnapshot] Exclude '/libx32' from backups --- ansible/roles/debops.rsnapshot/defaults/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ansible/roles/debops.rsnapshot/defaults/main.yml b/ansible/roles/debops.rsnapshot/defaults/main.yml index 303ce42d99..1a0dbbc30c 100644 --- a/ansible/roles/debops.rsnapshot/defaults/main.yml +++ b/ansible/roles/debops.rsnapshot/defaults/main.yml @@ -282,6 +282,8 @@ rsnapshot__default_excludes: - '/lib64' + - '/libx32' + - '/media' - '/mnt' From 38cf03ccc68d454fddc5d97c8318f2febc01f9d7 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 11:16:08 +0200 Subject: [PATCH 07/16] [debops.lxc] Install AppArmor on newer OS releases The LXC containers on newer OS releases (starting from Debian Buster) require AppArmor userspace support when AppArmor is enabled in the kernel. The role will ensure that the 'apparmor' APT package is present on the host, otherwise the LXC containers will not start properly. --- ansible/roles/debops.lxc/defaults/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index 09d103e2a9..8baf22b95a 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -19,6 +19,11 @@ lxc__base_packages: - [ 'lxc', 'lxcfs', 'debootstrap', 'xz-utils' ] - '{{ [ "dnsmasq-base", "resolvconf" ] if (lxc__net_deploy_state == "present") else [] }}' + - '{{ [] + if (ansible_distribution_release in + [ "wheezy", "jessie", "stretch", + "precise", "trusty", "xenial" ]) + else [ "apparmor" ] }}' # ]]] # .. envvar:: lxc__packages [[[ From 5852e31820eb89ded906bd6106294174a929370e Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 11:20:53 +0200 Subject: [PATCH 08/16] [debops.lxc] Expose LXC version in Ansible facts --- ansible/roles/debops.lxc/defaults/main.yml | 10 +++++ ansible/roles/debops.lxc/tasks/main.yml | 42 +++++++++---------- .../templates/etc/ansible/facts.d/lxc.fact.j2 | 3 +- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index 8baf22b95a..c7a99ad912 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -30,6 +30,16 @@ lxc__base_packages: # # List of additional APT packages to install with LXC. lxc__packages: [] + + # ]]] +# .. envvar:: lxc__version [[[ +# +# The variable that exposes the version of the LXC service installed on +# a host. It will be set automatically using the Ansible local facts. +lxc__version: '{{ ansible_local.lxc.version + if (ansible_local|d() and ansible_local.lxc|d() and + ansible_local.lxc.version|d()) + else "0.0.0" }}' # ]]] # ]]] # Unprivileged LXC containers [[[ diff --git a/ansible/roles/debops.lxc/tasks/main.yml b/ansible/roles/debops.lxc/tasks/main.yml index e9e7495d98..8c5208d7e8 100644 --- a/ansible/roles/debops.lxc/tasks/main.yml +++ b/ansible/roles/debops.lxc/tasks/main.yml @@ -13,6 +13,27 @@ register: lxc__register_packages until: lxc__register_packages is succeeded +- name: Make sure that Ansible local facts directory exists + file: + path: '/etc/ansible/facts.d' + state: 'directory' + owner: 'root' + group: 'root' + mode: '0755' + +- name: Save LXC local facts + template: + src: 'etc/ansible/facts.d/lxc.fact.j2' + dest: '/etc/ansible/facts.d/lxc.fact' + owner: 'root' + group: 'root' + mode: '0755' + register: lxc__register_facts + +- name: Update Ansible facts if they were modified + action: setup + when: lxc__register_facts is changed + - name: Create required directories file: path: '{{ item }}' @@ -175,27 +196,6 @@ with_items: '{{ lxc__common_combined_conf | parse_kv_items }}' when: item.name|d() and item.state|d('present') not in [ 'absent', 'ignore', 'init' ] -- name: Make sure that Ansible local facts directory exists - file: - path: '/etc/ansible/facts.d' - state: 'directory' - owner: 'root' - group: 'root' - mode: '0755' - -- name: Save LXC local facts - template: - src: 'etc/ansible/facts.d/lxc.fact.j2' - dest: '/etc/ansible/facts.d/lxc.fact' - owner: 'root' - group: 'root' - mode: '0755' - register: lxc__register_facts - -- name: Update Ansible facts if they were modified - action: setup - when: lxc__register_facts is changed - - name: Stop LXC containers if requested systemd: name: 'lxc@{{ item.name | d(item) }}.service' diff --git a/ansible/roles/debops.lxc/templates/etc/ansible/facts.d/lxc.fact.j2 b/ansible/roles/debops.lxc/templates/etc/ansible/facts.d/lxc.fact.j2 index d9f0b0a5ac..8b4d6bee52 100644 --- a/ansible/roles/debops.lxc/templates/etc/ansible/facts.d/lxc.fact.j2 +++ b/ansible/roles/debops.lxc/templates/etc/ansible/facts.d/lxc.fact.j2 @@ -18,7 +18,8 @@ def cmd_exists(cmd): lxc_net_conf = '/etc/default/lxc-net' output = {'installed': cmd_exists('/usr/bin/lxc-create'), - 'containers': list(lxc.list_containers())} + 'containers': list(lxc.list_containers()), + 'version': lxc.version} if os.path.exists(lxc_net_conf) and os.path.isfile(lxc_net_conf): try: From ec16980d7f9b6db8ace9153f499cace61a0c1a4d Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 12:42:29 +0200 Subject: [PATCH 09/16] [debops.lxc] Don't use '@all' cgroup on LXC 2.1.0+ The use of cgroupv1 '@all' hierarchy is not needed on hosts with LXC 2.1.0+ since this version supports cgroupv2 unified hierarchy. Without this change, LXC containers don't want to start on Debian Buster, so I think this is correct thing to do. --- ansible/roles/debops.lxc/defaults/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index c7a99ad912..f63550d8fb 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -209,6 +209,9 @@ lxc__default_configuration: - name: 'lxc.cgroup.use' value: '@all' + state: '{{ "present" + if (lxc__version is version("2.1.0", "<")) + else "absent" }}' - name: 'lxc.default_config' comment: | From c3da9656d39833070b7972bc063ddd7442bdd32a Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 14:29:27 +0200 Subject: [PATCH 10/16] [debops.lxc] Support new LXC 2.1 config options --- CHANGELOG.rst | 7 ++ ansible/roles/debops.lxc/defaults/main.yml | 60 +++++++++--- .../files/usr/local/bin/lxc-hwaddr-static | 94 ++++++++++++++----- .../files/usr/local/bin/lxc-new-unprivileged | 6 +- docs/news/upgrades.rst | 11 +++ 5 files changed, 137 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ec64a3050d..1055dd9538 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -83,6 +83,13 @@ Changed containers by default. We assume that these containers are unprivileged and their hostname cannot be changed from the inside of the container. +- [debops.lxc] The role now checks the version of the installed LXC support and + uses the old or new configuration keys accordingly. You can review the + `changed configuration keys`__ between the old and new LXC version for + comparsion. + + .. __: https://discuss.linuxcontainers.org/t/lxc-2-1-has-been-released/487 + `debops v1.0.0`_ - 2019-05-22 ----------------------------- diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index f63550d8fb..35bc08c511 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -229,10 +229,14 @@ lxc__default_configuration: - name: 'unprivileged' options: - - name: 'lxc.network.type' + - name: '{{ "lxc.network.type" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.type" }}' value: 'veth' - - name: 'lxc.network.link' + - name: '{{ "lxc.network.link" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.link" }}' value: '{{ "br0" if (ansible_local|d() and ansible_local.ifupdown|d() and (ansible_local.ifupdown.configured|d())|bool) @@ -240,7 +244,9 @@ lxc__default_configuration: if (lxc__net_deploy_state == "present") else "br0") }}' - - name: 'lxc.network.flags' + - name: '{{ "lxc.network.flags" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.flags" }}' value: 'up' - name: 'lxc.id_map_user' @@ -282,10 +288,14 @@ lxc__default_configuration: - name: 'privileged' options: - - name: 'lxc.network.type' + - name: '{{ "lxc.network.type" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.type" }}' value: 'veth' - - name: 'lxc.network.link' + - name: '{{ "lxc.network.link" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.link" }}' value: '{{ "br0" if (ansible_local|d() and ansible_local.ifupdown|d() and (ansible_local.ifupdown.configured|d())|bool) @@ -293,7 +303,9 @@ lxc__default_configuration: if (lxc__net_deploy_state == "present") else "br0") }}' - - name: 'lxc.network.flags' + - name: '{{ "lxc.network.flags" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.flags" }}' value: 'up' - name: 'lxc.start.auto' @@ -310,13 +322,19 @@ lxc__default_configuration: state: '{{ "present" if (lxc__net_deploy_state == "present") else "absent" }}' options: - - name: 'lxc.network.type' + - name: '{{ "lxc.network.type" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.type" }}' value: 'veth' - - name: 'lxc.network.link' + - name: '{{ "lxc.network.link" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.link" }}' value: '{{ lxc__net_bridge }}' - - name: 'lxc.network.flags' + - name: '{{ "lxc.network.flags" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.flags" }}' value: 'up' - name: 'lxc.id_map_user' @@ -360,11 +378,15 @@ lxc__default_configuration: options: - name: 'lxc.network.type_net0' - alias: 'lxc.network.type' + alias: '{{ "lxc.network.type" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.type" }}' value: 'veth' - name: 'lxc.network.link_net0' - alias: 'lxc.network.link' + alias: '{{ "lxc.network.link" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.link" }}' value: '{{ "br0" if (ansible_local|d() and ansible_local.ifupdown|d() and (ansible_local.ifupdown.configured|d())|bool) @@ -373,20 +395,28 @@ lxc__default_configuration: else "br0") }}' - name: 'lxc.network.flags_net0' - alias: 'lxc.network.flags' + alias: '{{ "lxc.network.flags" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.0.flags" }}' value: 'up' - name: 'lxc.network.type_net1' - alias: 'lxc.network.type' + alias: '{{ "lxc.network.type" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.1.type" }}' value: 'veth' separator: True - name: 'lxc.network.link_net1' - alias: 'lxc.network.link' + alias: '{{ "lxc.network.link" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.1.link" }}' value: 'br1' - name: 'lxc.network.flags_net1' - alias: 'lxc.network.flags' + alias: '{{ "lxc.network.flags" + if (lxc__version is version("2.1.0", "<")) + else "lxc.net.1.flags" }}' value: 'up' - name: 'lxc.start.auto' diff --git a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-hwaddr-static b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-hwaddr-static index 4ed8e0a8eb..70dc38ab5b 100755 --- a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-hwaddr-static +++ b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-hwaddr-static @@ -30,39 +30,83 @@ readonly MAC_LAA2=( 2 6 a e ) if [ -n "${CONTAINER}" ] ; then if [ -r "${CONFIG}" ] ; then - # Don't modify configuration files that already contain hardware addresses - if ! grep -qE '^lxc\.network\.hwaddr\s+=' "${CONFIG}" \ - && ! grep -qE '^# no-static-hwaddr' "${CONFIG}" \ - && ! grep -qE '^# no-hwaddr-static' "${CONFIG}" ; then + # Detect the new LXC configuration, 2.1.x+ + if grep -qE '^lxc\.uts\.name\s+=' "${CONFIG}" ; then - # Count number of network interfaces defined for a container - iface_count="$(grep -cE '^lxc\.network\.type\s+=' "${CONFIG}")" + # Don't modify configuration files that already contain hardware addresses + if ! grep -qE '^lxc\.net\.[0-9]+\.hwaddr\s+=' "${CONFIG}" \ + && ! grep -qE '^# no-static-hwaddr' "${CONFIG}" \ + && ! grep -qE '^# no-hwaddr-static' "${CONFIG}" ; then - # Convert the container name into a number usable by RANDOM - container_seed="$(printf "%s" "${CONTAINER}" | od -An -vtu1 | tr -d '[:blank:]')" + # Count number of network interfaces defined for a container + iface_count="$(grep -cE '^lxc\.net\.[0-9]+\.type\s+=' "${CONFIG}")" - for (( i=1 ; i<=iface_count ; i++ )) ; do + # Convert the container name into a number usable by RANDOM + container_seed="$(printf "%s" "${CONTAINER}" | od -An -vtu1 | tr -d '[:blank:]')" - # Seed the randomizer with a predictable string based on container - # name and the network interface number - RANDOM="${container_seed}${i}" - interface_seed="${CONTAINER}${i}" + for (( i=0 ; i "${CONFIG}.tmp" - mv "${CONFIG}.tmp" "${CONFIG}" + # Generate random MAC address based on predictable seed + static_prefix="${MAC_LAA1[ $RANDOM % ${#MAC_LAA1[@]} ]}${MAC_LAA2[ $RANDOM % ${#MAC_LAA2[@]} ]}" + static_hwaddr="$(printf "%s" "${interface_seed}" | md5sum | sed "s/^\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\).*$/${static_prefix}:\\1:\\2:\\3:\\4:\\5/")" - done + # Configure the generated MAC address for each network interface + # found in the container configuration file + printf "Setting a static MAC address for interface %s: %s\\n" "${i}" "${static_hwaddr}" + awk "/^lxc.net.${i}.type/ {sub(/lxc.net.${i}.type.*$/,\"&\\nlxc.net.${i}.hwaddr = ${static_hwaddr}\")}1" "${CONFIG}" > "${CONFIG}.tmp" + mv "${CONFIG}.tmp" "${CONFIG}" + + done + + else + printf "Configuration file '%s' already contains MAC addresses, skipping\\n" "${CONFIG}" + exit 0 + fi + + + # Detect the old LXC configuration, pre 2.1.x + elif grep -qE '^lxc\.utsname\s+=' "${CONFIG}" ; then + + # Don't modify configuration files that already contain hardware addresses + if ! grep -qE '^lxc\.network\.hwaddr\s+=' "${CONFIG}" \ + && ! grep -qE '^# no-static-hwaddr' "${CONFIG}" \ + && ! grep -qE '^# no-hwaddr-static' "${CONFIG}" ; then + + # Count number of network interfaces defined for a container + iface_count="$(grep -cE '^lxc\.network\.type\s+=' "${CONFIG}")" + + # Convert the container name into a number usable by RANDOM + container_seed="$(printf "%s" "${CONTAINER}" | od -An -vtu1 | tr -d '[:blank:]')" + + for (( i=1 ; i<=iface_count ; i++ )) ; do + + # Seed the randomizer with a predictable string based on container + # name and the network interface number + RANDOM="${container_seed}${i}" + interface_seed="${CONTAINER}${i}" + + # Generate random MAC address based on predictable seed + static_prefix="${MAC_LAA1[ $RANDOM % ${#MAC_LAA1[@]} ]}${MAC_LAA2[ $RANDOM % ${#MAC_LAA2[@]} ]}" + static_hwaddr="$(printf "%s" "${interface_seed}" | md5sum | sed "s/^\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\).*$/${static_prefix}:\\1:\\2:\\3:\\4:\\5/")" + + # Configure the generated MAC address for each network interface + # found in the container configuration file + printf "Setting a static MAC address for interface %s: %s\\n" "${i}" "${static_hwaddr}" + awk "/^lxc.network.type/{x++} x==${i}{sub(/lxc.network.type.*$/,\"&\\nlxc.network.hwaddr = ${static_hwaddr}\")}1" "${CONFIG}" > "${CONFIG}.tmp" + mv "${CONFIG}.tmp" "${CONFIG}" + + done + + else + printf "Configuration file '%s' already contains MAC addresses, skipping\\n" "${CONFIG}" + exit 0 + fi - else - printf "Configuration file '%s' already contains MAC addresses, skipping\\n" "${CONFIG}" - exit 0 fi else diff --git a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-new-unprivileged b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-new-unprivileged index f403a31187..2248a8ccdb 100755 --- a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-new-unprivileged +++ b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-new-unprivileged @@ -69,7 +69,11 @@ main () { --release "${release}" \ --arch "${architecture}" - iface_count="$(grep -cE '^lxc\.network\.type\s+=' "${config_file}")" + if grep -qE '^lxc\.uts\.name\s+=' "/var/lib/lxc/${container}/config" ; then + iface_count="$(grep -cE '^lxc\.net\.[0-9]+\.type\s+=' "/var/lib/lxc/${container}/config")" + elif grep -qE '^lxc\.utsname\s+=' "/var/lib/lxc/${container}/config" ; then + iface_count="$(grep -cE '^lxc\.network\.type\s+=' "/var/lib/lxc/${container}/config")" + fi iface_count="$(( iface_count - 1 ))" if [ -f "/var/lib/lxc/${container}/rootfs/etc/network/interfaces" ] ; then diff --git a/docs/news/upgrades.rst b/docs/news/upgrades.rst index 2e49c5930c..5cc7121ce8 100644 --- a/docs/news/upgrades.rst +++ b/docs/news/upgrades.rst @@ -31,6 +31,17 @@ Inventory variable changes inventory group ``[debops_service_docker_server]`` to continue using this role. +- The :ref:`debops.lxc` role uses different names of the container + configuration options depending on the LXC version used on the host. The + ``name`` parameters used in the configuration might change unexpectedly + between LXC versions, which might lead to wrong configuration entries being + merged and broken LXC configuration. + + If you have configured :ref:`lxc__ref_configuration` variables in the Ansible + inventory, review them before applying the role configuration on LXC hosts. + You can check the :envvar:`lxc__default_configuration` variable to see which + ``name`` parameters can change. + v1.0.0 (2019-05-22) ------------------- From 4ee7913054507a98fab98680e5dbcfa7b8c60bbc Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 19:31:54 +0200 Subject: [PATCH 11/16] [debops.lxc] Support old and new idmap config keys --- ansible/roles/debops.lxc/defaults/main.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index 35bc08c511..28833d8186 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -250,12 +250,16 @@ lxc__default_configuration: value: 'up' - name: 'lxc.id_map_user' - alias: 'lxc.id_map' + alias: '{{ "lxc.id_map" + if (lxc__version is version("2.1.0", "<")) + else "lxc.idmap" }}' value: 'u 0 {{ lxc__root_subuid_start }} {{ lxc__root_subuid_count }}' separator: True - name: 'lxc.id_map_group' - alias: 'lxc.id_map' + alias: '{{ "lxc.id_map" + if (lxc__version is version("2.1.0", "<")) + else "lxc.idmap" }}' value: 'g 0 {{ lxc__root_subgid_start }} {{ lxc__root_subgid_count }}' - name: 'lxc.start.auto' @@ -338,12 +342,16 @@ lxc__default_configuration: value: 'up' - name: 'lxc.id_map_user' - alias: 'lxc.id_map' + alias: '{{ "lxc.id_map" + if (lxc__version is version("2.1.0", "<")) + else "lxc.idmap" }}' value: 'u 0 {{ lxc__root_subuid_start }} {{ lxc__root_subuid_count }}' separator: True - name: 'lxc.id_map_group' - alias: 'lxc.id_map' + alias: '{{ "lxc.id_map" + if (lxc__version is version("2.1.0", "<")) + else "lxc.idmap" }}' value: 'g 0 {{ lxc__root_subgid_start }} {{ lxc__root_subgid_count }}' - name: 'lxc.start.auto' From 146ef846bb814cad5b8f537ea5526d224f235587 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 19:40:26 +0200 Subject: [PATCH 12/16] [debops.lxc] Drop SYS_TIME, SYS_ADMIN capabilities --- CHANGELOG.rst | 8 ++++++++ ansible/roles/debops.lxc/defaults/main.yml | 12 ++++++++---- .../debops.lxc/templates/etc/lxc/template.conf.j2 | 2 +- docs/ansible/roles/debops.lxc/defaults-detailed.rst | 3 ++- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1055dd9538..308d7d39e2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -90,6 +90,14 @@ Changed .. __: https://discuss.linuxcontainers.org/t/lxc-2-1-has-been-released/487 +- [debops.lxc] New LXC containers will have the ``CAP_SYS_TIME`` POSIX + capability dropped by default to ensure that time configuration is disabled + inside of the container. This should fix an issue on Debian Buster where an + unprivileged LXC containers still have this capability enabled. + + On Debian Buster LXC hosts, the ``CAP_SYS_ADMIN`` POSIX capbility will be + dropped in new LXC containers by default. + `debops v1.0.0`_ - 2019-05-22 ----------------------------- diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index 28833d8186..683f9ee211 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -268,7 +268,8 @@ lxc__default_configuration: - name: 'lxc.cap.drop_secure' alias: 'lxc.cap.drop' - value: 'mknod sys_rawio syslog wake_alarm' + value: '{{ [ "mknod", "sys_rawio", "syslog", "wake_alarm", "sys_time" ] + + ([] if (lxc__version is version("3.0.0", "<")) else [ "sys_admin" ]) }}' # Select how many CPUs are available inside of the container - name: 'lxc.cgroup.cpuset.cpus' @@ -318,7 +319,8 @@ lxc__default_configuration: - name: 'lxc.cap.drop_secure' alias: 'lxc.cap.drop' - value: 'mknod sys_rawio syslog wake_alarm' + value: '{{ [ "mknod", "sys_rawio", "syslog", "wake_alarm", "sys_time" ] + + ([] if (lxc__version is version("3.0.0", "<")) else [ "sys_admin" ]) }}' # Configuration for unprivileged LXC containers that uses only the internal # bridge managed by the 'lxc-net' service @@ -360,7 +362,8 @@ lxc__default_configuration: - name: 'lxc.cap.drop_secure' alias: 'lxc.cap.drop' - value: 'mknod sys_rawio syslog wake_alarm' + value: '{{ [ "mknod", "sys_rawio", "syslog", "wake_alarm", "sys_time" ] + + ([] if (lxc__version is version("3.0.0", "<")) else [ "sys_admin" ]) }}' # Select how many CPUs are available inside of the container - name: 'lxc.cgroup.cpuset.cpus' @@ -433,7 +436,8 @@ lxc__default_configuration: - name: 'lxc.cap.drop_secure' alias: 'lxc.cap.drop' - value: 'mknod sys_rawio syslog wake_alarm' + value: '{{ [ "mknod", "sys_rawio", "syslog", "wake_alarm", "sys_time" ] + + ([] if (lxc__version is version("3.0.0", "<")) else [ "sys_admin" ]) }}' # ]]] # .. envvar:: lxc__configuration [[[ diff --git a/ansible/roles/debops.lxc/templates/etc/lxc/template.conf.j2 b/ansible/roles/debops.lxc/templates/etc/lxc/template.conf.j2 index 3c2855d216..2ac2d54e89 100644 --- a/ansible/roles/debops.lxc/templates/etc/lxc/template.conf.j2 +++ b/ansible/roles/debops.lxc/templates/etc/lxc/template.conf.j2 @@ -10,7 +10,7 @@ {% endif %} {{ element.comment | regex_replace('\n$','') | comment(prefix='', postfix='') -}} {% endif %} -{{ '{} = {}'.format(('\n' if (element.separator|d())|bool else '') + ('#' if (element.state == 'comment') else '') + element.alias | d(element.name), element.value) }} +{{ '{} = {}'.format(('\n' if (element.separator|d())|bool else '') + ('#' if (element.state == 'comment') else '') + element.alias | d(element.name), (element.value if (element.value is string) else (element.value | selectattr('state', 'equalto', 'present') | map(attribute='name') | list | join(' ')))) }} {% endif %} {% endfor %} {% endif %} diff --git a/docs/ansible/roles/debops.lxc/defaults-detailed.rst b/docs/ansible/roles/debops.lxc/defaults-detailed.rst index b2b9e34057..9be32dd1d4 100644 --- a/docs/ansible/roles/debops.lxc/defaults-detailed.rst +++ b/docs/ansible/roles/debops.lxc/defaults-detailed.rst @@ -115,7 +115,8 @@ specific parameters: same name. ``value`` - The value of an LXC configuration option, a string. + The value of an LXC configuration option, a string or a YAML list of + strings which will joined with spaces. ``comment`` Option. a string or a YAML text block with a comment added to a given LXC From b1d89a84b75a0b756a2ad4ed7d07aaea5829cc3f Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 20:10:31 +0200 Subject: [PATCH 13/16] [debops.lxc] Relax AppArmor LXC profiles on Buster --- CHANGELOG.rst | 10 +++++ ansible/roles/debops.lxc/defaults/main.yml | 44 ++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 308d7d39e2..b9d086b635 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -98,6 +98,16 @@ Changed On Debian Buster LXC hosts, the ``CAP_SYS_ADMIN`` POSIX capbility will be dropped in new LXC containers by default. +- [debops.lxc] On Debian Buster (specifically on LXC versions below 3.1.0) the + AppArmor restrictions on unprivileged LXC containers will be relaxed to allow + correct operation of the :command:`systemd` service manager inside of + a container. Check the Debian Bugs `#916644`__, `#918839`__ and `#911806`__ + for reasoning behind this modification. + + .. __: https://bugs.debian.org/916644 + .. __: https://bugs.debian.org/918839 + .. __: https://bugs.debian.org/911806 + `debops v1.0.0`_ - 2019-05-22 ----------------------------- diff --git a/ansible/roles/debops.lxc/defaults/main.yml b/ansible/roles/debops.lxc/defaults/main.yml index 683f9ee211..61f7b1b6f0 100644 --- a/ansible/roles/debops.lxc/defaults/main.yml +++ b/ansible/roles/debops.lxc/defaults/main.yml @@ -289,6 +289,28 @@ lxc__default_configuration: value: '{{ ((ansible_memtotal_mb|int + ansible_swaptotal_mb|int) / 1024) | round | int }}G' state: 'comment' + # Required in AppArmor environment to allow systemd services to start + # inside of the LXC unprivileged containers. + # See also: https://bugs.debian.org/916644, + # https://bugs.debian.org/918839, https://bugs.debian.org/911806 + - name: 'lxc.apparmor.profile' + value: 'generated' + state: '{{ "absent" + if (lxc__version is version("3.0.0", "<") or + lxc__version is version("3.1.0", ">=")) + else "present" }}' + + # Required in AppArmor environment to allow systemd services to start + # inside of the LXC unprivileged containers. + # See also: https://bugs.debian.org/916644, + # https://bugs.debian.org/918839, https://bugs.debian.org/911806 + - name: 'lxc.apparmor.allow_nesting' + value: '1' + state: '{{ "absent" + if (lxc__version is version("3.0.0", "<") or + lxc__version is version("3.1.0", ">=")) + else "present" }}' + # Default configuration for privileged LXC containers - name: 'privileged' options: @@ -383,6 +405,28 @@ lxc__default_configuration: value: '{{ ((ansible_memtotal_mb|int + ansible_swaptotal_mb|int) / 1024) | round | int }}G' state: 'comment' + # Required in AppArmor environment to allow systemd services to start + # inside of the LXC unprivileged containers. + # See also: https://bugs.debian.org/916644, + # https://bugs.debian.org/918839, https://bugs.debian.org/911806 + - name: 'lxc.apparmor.profile' + value: 'generated' + state: '{{ "absent" + if (lxc__version is version("3.0.0", "<") or + lxc__version is version("3.1.0", ">=")) + else "present" }}' + + # Required in AppArmor environment to allow systemd services to start + # inside of the LXC unprivileged containers. + # See also: https://bugs.debian.org/916644, + # https://bugs.debian.org/918839, https://bugs.debian.org/911806 + - name: 'lxc.apparmor.allow_nesting' + value: '1' + state: '{{ "absent" + if (lxc__version is version("3.0.0", "<") or + lxc__version is version("3.1.0", ">=")) + else "present" }}' + # Default configuration for privileged LXC containers with multiple network # interfaces - name: 'external-internal' From 27efbcbdf299139da80a72a5ee2a6bbd2f691e34 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 20:34:20 +0200 Subject: [PATCH 14/16] [debops.lxc] Support SSH key lookup in LDAP --- CHANGELOG.rst | 4 ++++ .../files/usr/local/bin/lxc-prepare-ssh | 23 +++++++++++++++++-- .../roles/debops.lxc/getting-started.rst | 6 +++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b9d086b635..0f2e7d8528 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -45,6 +45,10 @@ Added - [debops.sysctl] The kernel protection for symlinks and hardlinks will be enabled by default on Debian/Ubuntu hosts. +- [debops.lxc] The :command:`lxc-prepare-ssh` script can now look up the SSH + keys of the current user in LDAP if support for it is enabled on the LXC + host. + Changed ~~~~~~~ diff --git a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh index e1a74d90bd..4a573a6368 100755 --- a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh +++ b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh @@ -12,6 +12,11 @@ readonly CONTAINER="${1:-}" if [ -n "${SUDO_USER:-}" ] ; then readonly SUDO_USER_HOME="$(getent passwd "${SUDO_USER}" | cut -d: -f6)" readonly SUDO_AUTHORIZED_KEYS="${SUDO_USER_HOME}/.ssh/authorized_keys" + + # Support for SSH keys from LDAP directory + if [ -x "/etc/ssh/authorized_keys_lookup" ] ; then + readonly LDAP_AUTHORIZED_KEYS="$(/etc/ssh/authorized_keys_lookup "${SUDO_USER}")" + fi else readonly SUDO_AUTHORIZED_KEYS="" fi @@ -61,14 +66,22 @@ prepare_authorized_keys () { authorized_keys="${2}" local -a authorized_keys_content - readarray -t authorized_keys_content <<< "$(< "${authorized_keys}")" + if [ -f "${authorized_keys}" ] ; then + readarray -t authorized_keys_content <<< "$(< "${authorized_keys}")" + else + readarray -t authorized_keys_content <<< "${authorized_keys}" + fi if ! lxc-attach -n "${container}" -- test -d /root/.ssh ; then lxc-attach -n "${container}" -- mkdir -p -m 0700 /root/.ssh lxc-attach -n "${container}" -- touch /root/.ssh/authorized_keys lxc-attach -n "${container}" -- chmod 0600 /root/.ssh/authorized_keys fi - printf "Adding authorized SSH keys from '%s'...\\n" "${authorized_keys}" + if [ -f "${authorized_keys}" ] ; then + printf "Adding authorized SSH keys from '%s'...\\n" "${authorized_keys}" + else + printf "Adding authorized SSH key...\\n" + fi for key_line in "${authorized_keys_content[@]}" ; do if ssh-keygen -l -f - <<< "${key_line}" > /dev/null ; then if ! lxc-attach -n "${container}" -- grep -Fxq "${key_line}" /root/.ssh/authorized_keys ; then @@ -88,6 +101,7 @@ Usage: ${SCRIPT} The keys will be taken from files: /root/.ssh/authorized_keys \${SUDO_USER}/.ssh/authorized_keys +If enabled, LDAP directory will be checked for SSH authorized_keys EOF } @@ -100,6 +114,8 @@ main () { container="${CONTAINER}" local -a authorized_keys authorized_keys=( "${AUTHORIZED_KEYS}" "${SUDO_AUTHORIZED_KEYS}" ) + local ldap_authorized_keys + ldap_authorized_keys="${LDAP_AUTHORIZED_KEYS:-}" if [ -n "${container}" ] ; then if container_exists "${container}" ; then @@ -120,6 +136,9 @@ main () { prepare_authorized_keys "${container}" "${key_file}" fi done + if [ -n "${ldap_authorized_keys}" ] ; then + prepare_authorized_keys "${container}" "${ldap_authorized_keys}" + fi else error_msg "Error: container '${container}' doesn't exist" return 1 diff --git a/docs/ansible/roles/debops.lxc/getting-started.rst b/docs/ansible/roles/debops.lxc/getting-started.rst index 36055dcd39..e5e5a744cf 100644 --- a/docs/ansible/roles/debops.lxc/getting-started.rst +++ b/docs/ansible/roles/debops.lxc/getting-started.rst @@ -176,6 +176,12 @@ source of SSH public keys. Alternatively, you can specify a custom file with authorized SSH keys to add in the container's :file:`/root/.ssh/authorized_keys` file. +If :ref:`the LDAP support ` is configured on a host and SSH key +lookup in LDAP is enabled by the :ref:`debops.sshd` role, the script will look +up the current user keys in LDAP directory as well - this ensures that the SSH +access is configured even when the SSH public keys are not explicitly defined +in the current user's :file:`~/.ssh/authorized_keys` file. + After that, the LXC container should be ready to be used remotely, at which point you can use normal DebOps ``bootstrap`` playbook and other playbooks to configure it. From 6dd088e413ef4c5dac23d94bb338ae19398985e2 Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 20:54:08 +0200 Subject: [PATCH 15/16] [debops.lxc] Don't copy SSH keys from 'root' to CT --- CHANGELOG.rst | 10 ++++++++++ .../debops.lxc/files/usr/local/bin/lxc-prepare-ssh | 6 +----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0f2e7d8528..23c09e358d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -112,6 +112,16 @@ Changed .. __: https://bugs.debian.org/918839 .. __: https://bugs.debian.org/911806 +Removed +~~~~~~~ + +- [debops.lxc] The :command:`lxc-prepare-ssh` script will no longer install SSH + keys from the LXC host ``root`` account on the LXC container ``root`` + account. This can cause confusion and unintended security breach when other + services (for example backup scripts or remote command execution tools) + install their own SSH keys on the LXC host and they are subsequently + copied inside of the LXC containers created on that host. + `debops v1.0.0`_ - 2019-05-22 ----------------------------- diff --git a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh index 4a573a6368..2c2859faae 100755 --- a/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh +++ b/ansible/roles/debops.lxc/files/usr/local/bin/lxc-prepare-ssh @@ -21,9 +21,6 @@ else readonly SUDO_AUTHORIZED_KEYS="" fi -readonly USER_HOME="${HOME}" -readonly AUTHORIZED_KEYS="${USER_HOME}/.ssh/authorized_keys" - container_exists () { local container container="${1}" @@ -99,7 +96,6 @@ ${SCRIPT}: add authorized SSH keys to an LXC container Usage: ${SCRIPT} The keys will be taken from files: - /root/.ssh/authorized_keys \${SUDO_USER}/.ssh/authorized_keys If enabled, LDAP directory will be checked for SSH authorized_keys EOF @@ -113,7 +109,7 @@ main () { local container container="${CONTAINER}" local -a authorized_keys - authorized_keys=( "${AUTHORIZED_KEYS}" "${SUDO_AUTHORIZED_KEYS}" ) + authorized_keys=( "${SUDO_AUTHORIZED_KEYS}" ) local ldap_authorized_keys ldap_authorized_keys="${LDAP_AUTHORIZED_KEYS:-}" From 6bb860130918add7e08de6f6d91c8405cf621c5b Mon Sep 17 00:00:00 2001 From: Maciej Delmanowski Date: Wed, 26 Jun 2019 20:54:57 +0200 Subject: [PATCH 16/16] [debops.lxc] Add 'auth-server' option in dnsmasq The 'dnsmasq' version in Debian Buster does not start without the 'auth-server' option set in its configuration file, which breaks the 'lxc-net' service. --- .../roles/debops.lxc/templates/etc/lxc/lxc-net-dnsmasq.conf.j2 | 1 + 1 file changed, 1 insertion(+) diff --git a/ansible/roles/debops.lxc/templates/etc/lxc/lxc-net-dnsmasq.conf.j2 b/ansible/roles/debops.lxc/templates/etc/lxc/lxc-net-dnsmasq.conf.j2 index 39b0770ee9..bc5c977b23 100644 --- a/ansible/roles/debops.lxc/templates/etc/lxc/lxc-net-dnsmasq.conf.j2 +++ b/ansible/roles/debops.lxc/templates/etc/lxc/lxc-net-dnsmasq.conf.j2 @@ -11,6 +11,7 @@ domain = {{ lxc__net_domain + ',' + (lxc__net_address | ipaddr('subnet')) + (',l # Mark the lxc-net dnsmasq instance as an authoritative DNS server for the LXC domain auth-zone = {{ lxc__net_domain }},{{ lxc__net_address | ipaddr('subnet') }} +auth-server = {{ lxc__net_domain }},{{ lxc__net_bridge }} # Set the FQDN name of the bridge interface in the DNS interface-name = {{ lxc__net_interface_fqdn }},{{ lxc__net_bridge }}