diff --git a/.gitignore b/.gitignore index f678ff8..4562321 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ .yamllint drafts/* hosts +.vscode/settings.json diff --git a/README.md b/README.md index 5b006c0..0840134 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ docker_compose: false docker_compose_release: 2.26.0 docker_compose_release_shasum: 59c6b262bedc4a02f46c8400e830e660935684899c770c3f5e804a2b7079fc16 docker_daemon_json_template: daemon.json.j2 +docker_expose_docker_api_via_tcp: false docker_release: 26.1.0 docker_release_rootless_shasum: c40ce28994ae8c481eac796f25da587a4cdf1711c279abc9b9472ffca01d5d9e docker_release_shasum: ab46df00fbf4d218a8694da06f9c171760b6cad875924ed251a3a9d57a7180bf @@ -133,6 +134,10 @@ The most important template is most likely `docker_daemon_json_template: daemon.json.j2`, which is the location of the Docker `daemon.json` configuration file template. +If `docker_expose_docker_api_via_tcp: true` then the docker daemon will expose its API via tcp. This is insecure, please check the [official docs](https://docs.docker.com/config/daemon/remote-access/) and ensure you understand the implications before activating this. + +Exposing the Docker API securely by using TLS is currently not supported via Ansible variable. You will need to edit the [template/docker_rootless.service.j2](https://github.com/konstruktoid/ansible-role-docker-rootless/blob/main/templates/docker_rootless.service.j2) file yourself or provide your own template using the `docker_rootless_service_template` variable. In general you'll need to change the `DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS` and `tcp_connection_str` within the template to use port `:2376` and include the necessary `--tlsverify`, `--tlscacert`, `--tlscert` and `--tlskey` parameters. Check the [official Docker docs](https://docs.docker.com/engine/security/rootless/#expose-docker-api-socket-through-tcp) for more info about that. + ## Container management ### Standalone container diff --git a/defaults/main.yml b/defaults/main.yml index 0947644..aed5768 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -8,6 +8,7 @@ docker_compose: false docker_compose_release: 2.26.0 docker_compose_release_shasum: 59c6b262bedc4a02f46c8400e830e660935684899c770c3f5e804a2b7079fc16 docker_daemon_json_template: daemon.json.j2 +docker_expose_docker_api_via_tcp: false docker_release: 26.1.0 docker_release_rootless_shasum: c40ce28994ae8c481eac796f25da587a4cdf1711c279abc9b9472ffca01d5d9e docker_release_shasum: ab46df00fbf4d218a8694da06f9c171760b6cad875924ed251a3a9d57a7180bf diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index af42f95..96ef157 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -29,6 +29,7 @@ provisioner: docker_user: bookwormuser docker_user_bashrc: false docker_compose: false + docker_expose_docker_api_via_tcp: true almalinux8: docker_add_alias: false docker_allow_ping: false @@ -65,6 +66,7 @@ provisioner: docker_user: dockeruser docker_user_bashrc: false docker_compose: false + docker_expose_docker_api_via_tcp: true jammy: docker_add_alias: false docker_allow_ping: false diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index d5241a1..7d10b7a 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -88,6 +88,8 @@ register: ps_dockerd changed_when: docker_user[:7] not in ps_dockerd.stdout failed_when: docker_user[:7] not in ps_dockerd.stdout + when: + - not docker_expose_docker_api_via_tcp - name: Verify docker_rootless.sh ansible.builtin.stat: @@ -178,6 +180,20 @@ delay: 10 timeout: 120 + - name: Verify tcp exposure + become: true + ansible.builtin.shell: + cmd: | + set -o pipefail + ss -ltnp | grep '\:2375.*rootlesskit' + args: + executable: /bin/bash + register: tcp_exposure + changed_when: false + failed_when: tcp_exposure.rc != 0 + when: + - docker_expose_docker_api_via_tcp + - name: Ensure no docker-compose.yml exists become: true become_user: "{{ docker_user }}" diff --git a/templates/docker_rootful.service.j2 b/templates/docker_rootful.service.j2 index 8bbebe2..71f32ca 100644 --- a/templates/docker_rootful.service.j2 +++ b/templates/docker_rootful.service.j2 @@ -1,6 +1,12 @@ # {{ ansible_managed }} # Generated by Ansible role {{ ansible_role_name }} +{# Set the external connection str if docker_expose_docker_api_via_tcp is wanted #} +{% set tcp_connection_str = '' %} +{% if docker_expose_docker_api_via_tcp %} +{% set tcp_connection_str = '-H tcp://0.0.0.0:2375' %} +{% endif %} + [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com @@ -10,7 +16,7 @@ Requires=docker.socket [Service] Type=notify -ExecStart=/usr/bin/dockerd {{ docker_rootful_opts if docker_rootful_opts else '-H fd:// --containerd=/run/containerd/containerd.sock' }} +ExecStart=/usr/bin/dockerd {{ tcp_connection_str }} {{ docker_rootful_opts if docker_rootful_opts else '-H fd:// --containerd=/run/containerd/containerd.sock' }} ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 diff --git a/templates/docker_rootless.service.j2 b/templates/docker_rootless.service.j2 index a6276cf..5f7cfb4 100644 --- a/templates/docker_rootless.service.j2 +++ b/templates/docker_rootless.service.j2 @@ -1,6 +1,12 @@ # {{ ansible_managed }} # Generated by Ansible role {{ ansible_role_name }} +{# Set the external connection str if docker_expose_docker_api_via_tcp is wanted #} +{% set tcp_connection_str = '' %} +{% if docker_expose_docker_api_via_tcp %} +{% set tcp_connection_str = '-H tcp://0.0.0.0:2375 -H unix://${XDG_RUNTIME_DIR}/docker.sock' %} +{% endif %} + [Unit] Description=Docker Application Container Engine (Rootless) Documentation=https://docs.docker.com/engine/security/rootless/ @@ -9,18 +15,21 @@ Documentation=https://docs.docker.com/engine/security/rootless/ Environment="DOCKER_HOST=unix:///run/user/{{ docker_user_info.uid }}/docker.sock" Environment="PATH={{ docker_user_info.home }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" Environment="XDG_RUNTIME_DIR=/run/user/{{ docker_user_info.uid }}" +{% if docker_expose_docker_api_via_tcp %} +Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=-p 0.0.0.0:2375:2375/tcp" +{% endif %} {% if not docker_rootful %} {% if ansible_distribution == "Debian" and ansible_kernel >= "4.18" and ansible_kernel <= "5.11" %} -ExecStart={{ docker_user_info.home }}/bin/dockerd-rootless.sh -s fuse-overlayfs +ExecStart={{ docker_user_info.home }}/bin/dockerd-rootless.sh {{ tcp_connection_str }} -s fuse-overlayfs {% else %} -ExecStart={{ docker_user_info.home }}/bin/dockerd-rootless.sh +ExecStart={{ docker_user_info.home }}/bin/dockerd-rootless.sh {{ tcp_connection_str }} {% endif %} {% endif %} {% if docker_rootful %} {% if ansible_distribution == "Debian" and ansible_kernel >= "4.18" and ansible_kernel <= "5.11" %} -ExecStart=/usr/bin/dockerd-rootless.sh -s fuse-overlayfs +ExecStart=/usr/bin/dockerd-rootless.sh {{ tcp_connection_str }} -s fuse-overlayfs {% else %} -ExecStart=/usr/bin/dockerd-rootless.sh +ExecStart=/usr/bin/dockerd-rootless.sh {{ tcp_connection_str }} {% endif %} {% endif %} ExecReload=/bin/kill -s HUP $MAINPID