diff --git a/roles/access/tasks/main.yml b/roles/access/tasks/main.yml index b5cb43350..8df9e2c32 100644 --- a/roles/access/tasks/main.yml +++ b/roles/access/tasks/main.yml @@ -18,10 +18,6 @@ - serverapplication.yml - mockapplication.yml -- name: Create the access container network - community.docker.docker_network: - name: "access" - - name: Create the server container community.docker.docker_container: name: openconextaccessserver @@ -29,7 +25,7 @@ pull: true restart_policy: "always" networks: - - name: "access" + - name: "loadbalancer" mounts: - source: /opt/openconext/access/serverapplication.yml target: /application.yml @@ -39,17 +35,18 @@ etc_hosts: host.docker.internal: host-gateway - - name: Create the client container community.docker.docker_container: name: accessclient image: ghcr.io/openconext/openconext-access/accessclient:{{ access_client_version }} pull: true restart_policy: "always" - published_ports: - - 81:80 networks: - - name: "access" + - name: "loadbalancer" + labels: + traefik.http.routers.accessclient.rule: "Host(`access.{{ base_domain }}`)" + traefik.http.routers.accessclient.tls: "true" + traefik.enable: "true" - name: Create the welcome container community.docker.docker_container: @@ -57,10 +54,12 @@ image: ghcr.io/openconext/openconext-access/accessswelcome:{{ access_welcome_version }} pull: true restart_policy: "always" - published_ports: - - 82:80 networks: - - name: "access" + - name: "loadbalancer" + labels: + traefik.http.routers.accesswelcome.rule: "Host(`welcome.{{ base_domain }}`)" + traefik.http.routers.accesswelcome.tls: "true" + traefik.enable: "true" - name: Create the mock provisioning container community.docker.docker_container: @@ -74,18 +73,21 @@ target: /application.yml type: bind networks: - - name: "access" - published_ports: - - 83:8081 + - name: "loadbalancer" + labels: + traefik.http.routers.accessmock.rule: "Host(`mock.{{ base_domain }}`)" + traefik.http.routers.accessmock.tls: "true" + traefik.http.services.accessmock.loadbalancer.server.port: "8081" + traefik.enable: "true" - name: Include the role manage_provision_entities to provision access client to Manage - include_role: + ansible.builtin.include_role: name: manage_provision_entities vars: entity_type: oidc10_rp - name: Include the role manage_provision_entities to provision access client to Manage - include_role: + ansible.builtin.include_role: name: manage_provision_entities vars: entity_type: oauth20_rs diff --git a/roles/docker/files/iptablesdocker.service b/roles/docker/files/iptablesdocker.service new file mode 100644 index 000000000..56b820484 --- /dev/null +++ b/roles/docker/files/iptablesdocker.service @@ -0,0 +1,11 @@ +[Unit] +Description=Restore iptables firewall rules +Before=network-pre.target + +[Service] +Type=oneshot +ExecStart=/usr/local/sbin/ip4tables.sh + +[Install] +WantedBy=multi-user.target + diff --git a/roles/docker/files/router.yaml b/roles/docker/files/router.yaml new file mode 100644 index 000000000..bac8d9951 --- /dev/null +++ b/roles/docker/files/router.yaml @@ -0,0 +1,7 @@ +tls: + stores: + default: + defaultCertificate: + certFile: /config/certs/backend.crt + keyFile: /config/certs/backend.key + diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml new file mode 100644 index 000000000..0dbe4f835 --- /dev/null +++ b/roles/docker/tasks/main.yml @@ -0,0 +1,102 @@ +--- +- name: Add Docker GPG key. + ansible.builtin.rpm_key: + key: "https://download.docker.com/linux/centos/gpg" + state: present + +- name: Add Docker repository. + ansible.builtin.get_url: + url: https://download.docker.com/linux/centos/docker-ce.repo + dest: '/etc/yum.repos.d/docker-ce.repo' + owner: root + group: root + mode: "0644" + +- name: Install docker + ansible.builtin.package: + name: docker-ce + state: present + +- name: Start and enable the docker daemon + ansible.builtin.systemd: + name: docker + state: started + enabled: true + +- name: Create the traefik configuration file directory + ansible.builtin.file: + state: directory + path: "/opt/openconext/traefik/{{ item }}" + owner: root + mode: "0755" + with_items: + - config + - certs + +- name: Place the dynamic configuration + ansible.builtin.copy: + src: router.yaml + dest: /opt/openconext/traefik/config/router.yaml + owner: root + mode: "0640" + +- name: Create Traefik backend key + ansible.builtin.copy: + content: "{{ backend_tls_key }}" + dest: "/opt/openconext/traefik/certs/backend.key" + mode: "0600" + owner: root + +- name: Create SSL certificate + ansible.builtin.copy: + src: "{{ inventory_dir }}/files/certs/backend.{{ base_domain }}.pem" + dest: "/opt/openconext/traefik/certs/backend.crt" + owner: root + mode: "0644" + +- name: Create the Traefik loadbalancer network + community.docker.docker_network: + name: loadbalancer + +- name: Create the Traefik loadbalancer + community.docker.docker_container: + name: loadbalancer + image: traefik:latest + published_ports: + - "0.0.0.0:443:443" + pull: true + restart_policy: "always" + networks: + - name: "loadbalancer" + command: "--providers.docker --providers.docker.network=loadbalancer --entrypoints.websecure.address=:443 --providers.file.directory=/config/config/ --providers.docker.exposedbydefault=false" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /opt/openconext/traefik/:/config/ + comparisons: + published_ports: strict + networks: strict + +- name: Place the iptables file + ansible.builtin.template: + src: ip4tables.sh.j2 + dest: /usr/local/sbin/ip4tables.sh + mode: "0750" + owner: root + +- name: Disable the default iptables service + ansible.builtin.systemd: + service: iptables + enabled: false + +- name: Place the new systemd service file + ansible.builtin.copy: + src: iptablesdocker.service + dest: /etc/systemd/system/ + owner: root + mode: "0755" + +- name: Enable and start the new firewall service + ansible.builtin.systemd: + service: iptablesdocker.service + enabled: true + state: started diff --git a/roles/docker/templates/ip4tables.sh.j2 b/roles/docker/templates/ip4tables.sh.j2 new file mode 100644 index 000000000..a7460fe21 --- /dev/null +++ b/roles/docker/templates/ip4tables.sh.j2 @@ -0,0 +1,92 @@ +#!/bin/sh +## SEE https://medium.com/@ebuschini/iptables-and-docker-95e2496f0b45 + +## You need to add rules in DOCKER-BLOCK AND INPUT for traffic that does not go to a container. +## You only need to add one rule if the traffic goes to the container + +set -e + +install_docker_block() { + ## One time install rules for the DOCKER-BLOCK chain + /sbin/iptables -t nat -N DOCKER-BLOCK && + ## Deploy the new rules. After this, everything goes to DOCKER-BLOCK then to RETURN + /sbin/iptables -t nat -I PREROUTING -m addrtype --dst-type LOCAL -g DOCKER-BLOCK || + true +} + +## install the PREROUTING rules for the DOCKER chain in case docker starts after +/sbin/iptables -t nat -N DOCKER || true + +## Block new connections while we restore the first PREROUTING RULES +/sbin/iptables -t nat -I PREROUTING -m addrtype --dst-type LOCAL -m state --state NEW -j RETURN + +## One time install rules for the DOCKER-BLOCK chain +#/sbin/iptables -t nat -N DOCKER-BLOCK && { + ## Deploy the new rules. After this, everything goes to DOCKER-BLOCK then to RETURN +# deploy_docker_block +#} || true +install_docker_block +## Delete installed rules, we need to ensure they always are at the top +## If rules were already installed, it would mean that the second and third rule +## are going to be deleted. We still have the RETURN on top. +while true; do + /sbin/iptables -t nat -D PREROUTING -m addrtype --dst-type LOCAL -j RETURN || break +done +while true; do + /sbin/iptables -t nat -D PREROUTING -m addrtype --dst-type LOCAL -j DOCKER-BLOCK || break +done + +## Re-deploy the right rules on the top. After this, the flow is restored to DOCKER-BLOCK +#deploy_docker_block +/sbin/iptables -t nat -I PREROUTING -m addrtype --dst-type LOCAL -g DOCKER-BLOCK + + +## Remove the blocking rule, which should be unreachable after deploy_docker_block anyway +while true; do + /sbin/iptables -t nat -D PREROUTING -m addrtype --dst-type LOCAL -m state --state NEW -j RETURN || break +done + +## Only let established connections go through while we flush the rules +/sbin/iptables -t nat -I PREROUTING -m addrtype --dst-type LOCAL -m state --state ESTABLISHED -j DOCKER + +## Flush the rules of DOCKER-BLOCK, at this point new connections will be blocked +/sbin/iptables -t nat -F DOCKER-BLOCK + +## Add your new rules below, allowing new connections +## Don't forget the NEW and ESTABLISHED states +{% if iptables_incoming_docker is defined %} +{% for service in iptables_incoming_docker %} +{{'##'|e }} {{ service.name }} +{{'##'|e }} {{'=' * service.name|length }} +/sbin/iptables -t nat -A DOCKER-BLOCK -p {{ service.protocol | default('tcp') }} {{ '-s '+service.source if service.source is defined else '' }} -m multiport --dports {{ service.port }} -m state --state NEW,ESTABLISHED -j DOCKER +{% endfor %} +{% endif %} + + +## Restore the flow +## Loop trying to delete the rule in case the script failed above, we don't want to add more than one rule +while true; do + /sbin/iptables -t nat -D PREROUTING -m addrtype --dst-type LOCAL -m state --state ESTABLISHED -j DOCKER || break +done + +## The INPUT chain is set to drop, then we flush it and reinstall the rules. +## Finally we restore the policy on the chain +## Remember that those rules don't apply to docker +/sbin/iptables -t filter -P INPUT DROP +/sbin/iptables -t filter -F INPUT +/sbin/iptables -t filter -A INPUT -i lo -j ACCEPT +# Add your non docker rules here + +/sbin/iptables -t filter -A INPUT -p icmp -j ACCEPT + +{% if iptables_incoming is defined %} +{% for service in iptables_incoming %} +{{'##'|e }} {{ service.name }} +{{'##'|e }} {{'=' * service.name|length }} +/sbin/iptables -t filter -A INPUT -p {{ service.protocol | default('tcp') }} {{ '-s '+service.source if service.source is defined else '' }} -m multiport --dports {{ service.port }} -j ACCEPT +{% endfor %} +{% endif %} + +/sbin/iptables -t filter -A INPUT -m state --state ESTABLISHED -j ACCEPT +/sbin/iptables -t filter -A INPUT -j DROP +/sbin/iptables -t filter -P INPUT ACCEPT diff --git a/roles/spdashboard/tasks/main.yml b/roles/spdashboard/tasks/main.yml index 5691767c9..184dd3152 100644 --- a/roles/spdashboard/tasks/main.yml +++ b/roles/spdashboard/tasks/main.yml @@ -23,11 +23,16 @@ docker_container: name: spdashboard_web image: ghcr.io/surfnet/sp-dashboard/spdashboard_web:{{ spd_docker_web_version }} - published_ports: 0.0.0.0:80:80 pull: true restart_policy: "always" networks: - name: "spdashboard" + - name: "loadbalancer" + labels: + traefik.http.routers.spdashboard.rule: "Host(`{{ spdashboard_domain }}`)" + traefik.http.routers.spdashboard.tls: "true" + traefik.enable: "true" + - name: Create the php-fpm container docker_container: