From fa856141cf875e56c4a5ce7d28d4574db6c8a60f Mon Sep 17 00:00:00 2001 From: "Ketelsen, Sven" Date: Fri, 16 Jun 2023 09:53:26 +0000 Subject: [PATCH] DEV-1008 added wireguard vpn --- .gitlab-ci.yml | 66 ++++++++++++++++++ group_vars/all/firewall.yml | 19 ++++++ group_vars/all/plain.yml | 3 +- group_vars/all/versions.yml | 2 + group_vars/all/vpn.yml | 8 +++ hcloud_firewall.yml | 21 +++++- host_vars/dev-vpn-01.yml | 5 ++ roles/wireguard/defaults/main.yaml | 3 + roles/wireguard/tasks/main.yaml | 67 +++++++++++++++++++ roles/wireguard/vars/main.yml | 25 +++++++ stage-dev | 4 ++ stage-prodnso | 4 ++ stage-qa | 4 ++ templates/_docker/docker-compose.yml.j2 | 33 +++++++++ .../wireguard/config/templates/server.conf.j2 | 13 ++++ users/hp.wissenbach/wireguard.yml | 3 + users/michael.haehnel/wireguard.yml | 3 + users/sven.ketelsen/wireguard.yml | 3 + vpn.yml | 28 ++++++++ 19 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 group_vars/all/vpn.yml create mode 100644 roles/wireguard/defaults/main.yaml create mode 100644 roles/wireguard/tasks/main.yaml create mode 100644 roles/wireguard/vars/main.yml create mode 100644 templates/wireguard/config/templates/server.conf.j2 create mode 100644 users/hp.wissenbach/wireguard.yml create mode 100644 users/michael.haehnel/wireguard.yml create mode 100644 users/sven.ketelsen/wireguard.yml create mode 100644 vpn.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 74744fa..5080226 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,7 @@ services: stages: - lint - ansible-builder + - run-vpn-config-update - run-setup - run-setup-digitalocean - run-management-update @@ -116,6 +117,71 @@ builder-job-prodnso-manual: - dind - harbor # 05.02.22 TODO some runners run into timeouts +################################################################################## +### http://patorjk.com/software/taag/#p=display&f=Doom&t=vpn.yml +### _ +### | | +### __ ___ __ _ __ _ _ _ __ ___ | | +### \ \ / / '_ \| '_ \ | | | | '_ ` _ \| | +### \ V /| |_) | | | || |_| | | | | | | | +### \_/ | .__/|_| |_(_)__, |_| |_| |_|_| +### | | __/ | +### |_| |___/ +### + +.vpn-config-update: + extends: .run-ansible + # A resource group ensures a job is mutually exclusive across different pipelines for the same project. + stage: run-vpn-config-update + script: + - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )' + - eval $(ssh-agent -s) + - 'echo "$GITLAB_SSH_KEY" | tr -d "\r" | ssh-add -' + - mkdir -p ~/.ssh + - chmod 0700 ~/.ssh + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config' + - ssh-add -L + - export HETZNER_LABEL_SELECTOR="stage=${STAGE}" + - ansible-playbook -i stage-${STAGE}-netgo-hcloud.yml vpn.yml --vault-password-file /tmp/vault-pass -u gitlabci + only: + changes: + - usser/**/wireguard.yml + except: + - schedules + tags: + - dind + - harbor # 05.02.22 TODO some runners run into timeouts + +vpn-config-update-dev: + extends: .vpn-config-update + # A resource group ensures a job is mutually exclusive across different pipelines for the same project. + resource_group: dev + before_script: + - export STAGE=dev + - echo "${ANSIBLE_VAULT_PASS_DEV}" > /tmp/vault-pass + only: + - main + +vpn-config-update-qa: + extends: .vpn-config-update + # A resource group ensures a job is mutually exclusive across different pipelines for the same project. + resource_group: qa + before_script: + - export STAGE=qa + - echo "${ANSIBLE_VAULT_PASS_QA}" > /tmp/vault-pass + only: + - qa + +vpn-config-update-prodnso: + extends: .vpn-config-update + # A resource group ensures a job is mutually exclusive across different pipelines for the same project. + resource_group: prodnso + before_script: + - export STAGE=prodnso + - echo "${ANSIBLE_VAULT_PASS_PRODNSO}" > /tmp/vault-pass + only: + - prodnso + ######## ### http://patorjk.com/software/taag/#p=display&f=Doom&t=setup.yml ### diff --git a/group_vars/all/firewall.yml b/group_vars/all/firewall.yml index 6179cfb..92de91f 100644 --- a/group_vars/all/firewall.yml +++ b/group_vars/all/firewall.yml @@ -123,6 +123,25 @@ hcloud_firewall_objects_awx: label_selector: selector: 'stage={{ stage }},service' +hcloud_firewall_objects_vpn: + - + name: "{{ stage }}-vpn-access" + state: present + rules: + - + direction: in + protocol: udp + port: "{{ service_port_wireguard }}" + source_ips: + - "0.0.0.0/0" + destination_ips: [] + description: "Allow access for vpn" + apply_to: + - + type: label_selector + label_selector: + selector: 'stage={{ stage }},service=vpn' + hcloud_firewall_objects_backup: - name: "{{ stage }}-backup-ssh-access" diff --git a/group_vars/all/plain.yml b/group_vars/all/plain.yml index c1c6d23..531a73b 100644 --- a/group_vars/all/plain.yml +++ b/group_vars/all/plain.yml @@ -131,7 +131,7 @@ ip_whitelist_netgo: - "46.245.219.98/32" # netgo borken - "164.138.195.162/32" # netgo Aachen -ip_whitelist: "{{ ip_whitelist_netgo + [shared_service_network] }}" +ip_whitelist: "{{ ip_whitelist_netgo + [shared_service_network] + [(shared_service_vpn_ip+'/32') | default('')] | select() }}" offsite_storage_server_ip: 142.132.155.83/32 @@ -173,6 +173,7 @@ service_port_pgadmin: "9001" service_port_phpmyadmin: "9002" service_port_node_exporter: "9100" service_port_elasticsearch: "9200" +service_port_wireguard: "51820" monitor_port_system: "9082" monitor_port_docker: "9083" diff --git a/group_vars/all/versions.yml b/group_vars/all/versions.yml index 346bca0..0339c77 100644 --- a/group_vars/all/versions.yml +++ b/group_vars/all/versions.yml @@ -28,3 +28,5 @@ connect_version: "10.5" iam_version: "10.5" ansible_minimal_version: "2.12.0" + +wireguard_version: latest diff --git a/group_vars/all/vpn.yml b/group_vars/all/vpn.yml new file mode 100644 index 0000000..b881e39 --- /dev/null +++ b/group_vars/all/vpn.yml @@ -0,0 +1,8 @@ +--- +shared_service_vpn: "{{ stage }}-vpn-01" +shared_service_vpn_ip: "{{ stage_server_infos + | selectattr('name', 'match', shared_service_vpn ) + | map(attribute='public_ip') + | list + | first + | default('-') }}" diff --git a/hcloud_firewall.yml b/hcloud_firewall.yml index 39bd507..68db9b3 100644 --- a/hcloud_firewall.yml +++ b/hcloud_firewall.yml @@ -37,7 +37,18 @@ gather_facts: false connection: local + pre_tasks: + - name: "Import autodiscover pre-tasks" + import_tasks: tasks/autodiscover_pre_tasks.yml + become: false + tags: + - always + tasks: + - name: "Print IP Whitelist" + ansible.builtin.debug: + msg: "Whitelisted IPs <{{ ip_whitelist | join(',') }}>" + - name: "Setup base hcloud firewall rules" include_role: name: hetzner-ansible-hcloud @@ -45,7 +56,7 @@ loop: "{{ hcloud_firewall_objects }}" loop_control: loop_var: firewall_object -# + - name: "Generate awx-related hcloud firewall rules" block: - name: "Lookup hetzner servers - smaradigo k8s worker nodes" @@ -72,6 +83,14 @@ loop_control: loop_var: firewall_object + - name: "Setup hcloud firewalls for vpn stuff..." + include_role: + name: hetzner-ansible-hcloud + tasks_from: configure-firewall2 + loop: "{{ hcloud_firewall_objects_vpn }}" + loop_control: + loop_var: firewall_object + - name: "Setup hcloud firewalls for database backup..." include_role: name: hetzner-ansible-hcloud diff --git a/host_vars/dev-vpn-01.yml b/host_vars/dev-vpn-01.yml index 3d9ef37..436f615 100644 --- a/host_vars/dev-vpn-01.yml +++ b/host_vars/dev-vpn-01.yml @@ -1,2 +1,7 @@ --- +# small server for vpn sufficient 1vCPU, 2GB RAM, 20 GB Disk +hetzner_server_type: cx11 +hetzner_server_labels: "stage={{ stage }} service=vpn" + +# disable traefik traefik_enabled: false \ No newline at end of file diff --git a/roles/wireguard/defaults/main.yaml b/roles/wireguard/defaults/main.yaml new file mode 100644 index 0000000..d8ea465 --- /dev/null +++ b/roles/wireguard/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +wireguard_image_name: "lscr.io/linuxserver/wireguard" +wireguard_network: 10.200.1.1 diff --git a/roles/wireguard/tasks/main.yaml b/roles/wireguard/tasks/main.yaml new file mode 100644 index 0000000..128ff79 --- /dev/null +++ b/roles/wireguard/tasks/main.yaml @@ -0,0 +1,67 @@ +--- + +### tags: +### update_config +### update_deployment + +- name: "Register wireguard peers" + set_fact: + wireguard_peers: "{{ wireguard_peers | default([]) + [ lookup('file', 'users/' + item + '/wireguard.yml') | from_yaml ] }}" + loop: '{{ smardigo_plattform_users }}' + when: "('users/' ~ item ~ '/wireguard.yml') is file" + +- name: "Print wireguard peers" + debug: var=wireguard_peers + +- name: "Register source IPs" + set_fact: + source_ips: "{{ (wireguard_peers | selectattr('source_ip', 'defined') | map(attribute='source_ip') | list) }}" + +- name: "Assert no duplicate source IPs" + assert: + that: "{{ source_ips|length == source_ips|unique|length }}" + fail_msg: "Detected duplicate source IPs {{ source_ips }}" + +- name: "Check if {{ wireguard_id }}/docker-compose.yml exists" + stat: + path: '{{ service_base_path }}/{{ wireguard_id }}/docker-compose.yml' + register: check_docker_compose_file + tags: + - update_config + - update_deployment + +- name: "Stop {{ wireguard_id }}" + community.docker.docker_compose: + project_src: '{{ service_base_path }}/{{ wireguard_id }}' + state: absent + when: check_docker_compose_file.stat.exists + tags: + - update_config + - update_deployment + +- name: "Deploy docker templates for {{ wireguard_id }}" + include_role: + name: hetzner-ansible-sma-deploy + tasks_from: templates + vars: + current_config: "_docker" + current_base_path: "{{ service_base_path }}" + current_destination: "{{ wireguard_id }}" + current_owner: "{{ docker_owner }}" + current_group: "{{ docker_group }}" + current_docker: "{{ wireguard_docker }}" + tags: + - update_config + +- name: "Deploy service templates for {{ wireguard_id }}" + include_role: + name: hetzner-ansible-sma-deploy + tasks_from: templates + vars: + current_config: "wireguard" + current_base_path: "{{ service_base_path }}" + current_destination: "{{ wireguard_id }}" + current_owner: "{{ docker_owner }}" + current_group: "{{ docker_group }}" + tags: + - update_config diff --git a/roles/wireguard/vars/main.yml b/roles/wireguard/vars/main.yml new file mode 100644 index 0000000..98238a7 --- /dev/null +++ b/roles/wireguard/vars/main.yml @@ -0,0 +1,25 @@ +--- +wireguard_id: "{{ inventory_hostname }}-wireguard" + +wireguard_docker: + services: + - name: "{{ wireguard_id }}" + image_name: "{{ wireguard_image_name }}" + image_version: "{{ wireguard_version }}" + environment: + - "PUID: \"1000\"" + - "PGID: \"1000\"" + - "TZ: \"Etc/UTC\"" + - "PEERS: 0" + - "INTERNAL_SUBNET: \"{{ wireguard_network }}\"" + volumes: + - '"./config/templates/server.conf:/config/templates/server.conf:rw"' + ports: + - external: "{{ service_port_wireguard }}" + internal: "{{ service_port_wireguard }}/udp" + restart: "unless-stopped" + cap_add: + - "NET_ADMIN" + - "SYS_MODULE" + sysctls: + - "\"net.ipv4.conf.all.src_valid_mark=1\"" diff --git a/stage-dev b/stage-dev index b185352..eb9a228 100644 --- a/stage-dev +++ b/stage-dev @@ -61,6 +61,9 @@ dev-prometheus-01 [ubuntu_docker] dev-devops-iaas-01 +[vpn] +dev-vpn-01 + [kube_control_plane] devnso-kube-cpl-01 devnso-kube-cpl-02 @@ -101,6 +104,7 @@ postfix postgres prometheus ubuntu_docker +vpn [all:children] stage_dev diff --git a/stage-prodnso b/stage-prodnso index f454bf2..47cd912 100644 --- a/stage-prodnso +++ b/stage-prodnso @@ -61,6 +61,9 @@ prodnso-prometheus-01 prodnso-platform-iaas-01 prodnso-hocr-iaas-01 +[vpn] +prodnso-vpn-01 + [kube_control_plane] prodnso-kube-cpl-01 prodnso-kube-cpl-02 @@ -101,6 +104,7 @@ postfix postgres prometheus ubuntu_docker +vpn [all:children] stage_prodnso diff --git a/stage-qa b/stage-qa index 7022dd8..0462166 100644 --- a/stage-qa +++ b/stage-qa @@ -59,6 +59,9 @@ qa-prometheus-01 [ubuntu_docker] +[vpn] +qa-vpn-01 + [kube_control_plane] qanso-kube-cpl-01 qanso-kube-cpl-02 @@ -99,6 +102,7 @@ postfix postgres prometheus ubuntu_docker +vpn [all:children] stage_qa diff --git a/templates/_docker/docker-compose.yml.j2 b/templates/_docker/docker-compose.yml.j2 index 28f02ed..447c3f3 100644 --- a/templates/_docker/docker-compose.yml.j2 +++ b/templates/_docker/docker-compose.yml.j2 @@ -74,6 +74,39 @@ services: {% endfor %} {% endif %} {# ###################################### labels #} +{# ###################################### depends_on #} +{% if + service.depends_on is defined + and (service.depends_on|length>0) +%} + depends_on: +{% for item in service.depends_on %} + - {{ item }} +{% endfor %} +{% endif %} +{# ###################################### depends_on #} +{# ###################################### cap-add #} +{% if + service.cap_add is defined + and (service.cap_add|length>0) +%} + cap_add: +{% for item in service.cap_add %} + - {{ item }} +{% endfor %} +{% endif %} +{# ###################################### cap-add #} +{# ###################################### sysctls #} +{% if + service.sysctls is defined + and (service.sysctls|length>0) +%} + sysctls: +{% for item in service.sysctls %} + - {{ item }} +{% endfor %} +{% endif %} +{# ###################################### sysctls #} {# ###################################### environment #} {% if service.environment is defined diff --git a/templates/wireguard/config/templates/server.conf.j2 b/templates/wireguard/config/templates/server.conf.j2 new file mode 100644 index 0000000..3665444 --- /dev/null +++ b/templates/wireguard/config/templates/server.conf.j2 @@ -0,0 +1,13 @@ +[Interface] +Address = ${INTERFACE}.1 +ListenPort = {{ service_port_wireguard }} +PrivateKey = $(cat /config/server/privatekey-server) +PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE +PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE +{% for item in wireguard_peers %} + +[Peer] +# Name = {{ item.name }} +PublicKey = {{ item.public_key }} +AllowedIPs = {{ item.source_ip }} +{% endfor %} \ No newline at end of file diff --git a/users/hp.wissenbach/wireguard.yml b/users/hp.wissenbach/wireguard.yml new file mode 100644 index 0000000..de5414f --- /dev/null +++ b/users/hp.wissenbach/wireguard.yml @@ -0,0 +1,3 @@ +name: "hp.wissenbach" +public_key: "t35U0S9W80EH6PuE85zvFBr5FJkC2idMCVnd6mawjAc=" +source_ip: "10.200.1.2/32" \ No newline at end of file diff --git a/users/michael.haehnel/wireguard.yml b/users/michael.haehnel/wireguard.yml new file mode 100644 index 0000000..3dca776 --- /dev/null +++ b/users/michael.haehnel/wireguard.yml @@ -0,0 +1,3 @@ +name: "mha" +public_key: "wuBO3LHyC/DOOaPuks5o313SYGdReJbRB7mCkH5hVG4=" +source_ip: "10.200.1.3/32" \ No newline at end of file diff --git a/users/sven.ketelsen/wireguard.yml b/users/sven.ketelsen/wireguard.yml new file mode 100644 index 0000000..593aef8 --- /dev/null +++ b/users/sven.ketelsen/wireguard.yml @@ -0,0 +1,3 @@ +name: "sven.ketelsen" +public_key: "mT6edinYWI9jdIIhwem8KaqQwOATO6yOdeYD6tDTdBI=" +source_ip: "10.200.1.4/32" \ No newline at end of file diff --git a/vpn.yml b/vpn.yml new file mode 100644 index 0000000..c2d19e3 --- /dev/null +++ b/vpn.yml @@ -0,0 +1,28 @@ +--- +- name: 'apply setup to {{ host | default("vpn") }}' + hosts: '{{ host | default("vpn") }}' + serial: "{{ serial_number | default(5) }}" + strategy: free + vars: + ansible_ssh_host: "{{ stage_server_domain }}" + become: yes + + pre_tasks: + - name: "Check if ansible version is at least {{ ansible_minimal_version }}" + assert: + that: + - ansible_version.string is version(ansible_minimal_version, ">=") + msg: "The ansible version has to be at least {{ ansible_minimal_version }}" + tags: + - always + + - name: "Import autodiscover pre-tasks" + import_tasks: tasks/autodiscover_pre_tasks.yml + become: false + tags: + - always + + roles: + - role: wireguard + when: + - "'vpn' in group_names"