diff --git a/ansible/roles/act_runner/defaults/main.yml b/ansible/roles/act_runner/defaults/main.yml index cb85188..2117994 100644 --- a/ansible/roles/act_runner/defaults/main.yml +++ b/ansible/roles/act_runner/defaults/main.yml @@ -2,7 +2,8 @@ act_runner_version: "0.2.12" act_runner_arch: "linux-amd64" act_runner_gitea_url: "https://git.tarla.io" +# -> bunu değişkene ata ve test ve prod için farklı isimler oluştur! act_runner_name: "iklim-test-app" -act_runner_labels: "ubuntu-latest,ubuntu-22.04,ubuntu-20.04,test-runner:docker://ubuntu:22.04" +act_runner_labels: "ubuntu-latest,ubuntu-22.04,ubuntu-20.04,test-runner:docker://catthehacker/ubuntu:act-22.04" # Gitea'dan alınan tek seferlik registration token; kayıt olmadıysa boş bırakılır. act_runner_registration_token: "{{ vault_gitea_runner_token | default('') }}" diff --git a/ansible/roles/act_runner/templates/config.yaml.j2 b/ansible/roles/act_runner/templates/config.yaml.j2 index bd96204..2e62880 100644 --- a/ansible/roles/act_runner/templates/config.yaml.j2 +++ b/ansible/roles/act_runner/templates/config.yaml.j2 @@ -26,12 +26,14 @@ container: network: "iklimco-net" enable_ipv6: false privileged: false - # Docker socket mount: docker build/push/stack komutlarının çalışması için gerekli. - options: "-v /var/run/docker.sock:/var/run/docker.sock" + options: "" workdir_parent: "" valid_volumes: - "/var/run/docker.sock" - docker_host: "" + # docker_host set edilince act_runner socket'i tek seferlik mount eder ve + # DOCKER_HOST env'ini job container'a iletir; options'daki manuel mount ile + # çakışıp "Duplicate mount point" hatasına yol açmaz. + docker_host: "unix:///var/run/docker.sock" force_pull: false force_rebuild: false diff --git a/ansible/roles/db_stack/templates/db.stack.yml.j2 b/ansible/roles/db_stack/templates/db.stack.yml.j2 index 2b3ebfa..6565d7f 100644 --- a/ansible/roles/db_stack/templates/db.stack.yml.j2 +++ b/ansible/roles/db_stack/templates/db.stack.yml.j2 @@ -40,3 +40,41 @@ services: placement: constraints: - node.labels.role == db + + # WireGuard üzerinden DB manager erişimi için köprü servisler. + # Host portları firewalld ile sadece WireGuard subnet'ine (10.8.0.0/24) açılır. + pg-proxy: + image: alpine/socat:latest + command: TCP-LISTEN:5432,fork,reuseaddr TCP:postgresql:5432 + ports: + - target: 5432 + published: 15432 + protocol: tcp + mode: host + networks: + - iklimco-net + deploy: + placement: + constraints: + - node.labels.role == db + restart_policy: + condition: on-failure + delay: 5s + + mongo-proxy: + image: alpine/socat:latest + command: TCP-LISTEN:27017,fork,reuseaddr TCP:mongodb:27017 + ports: + - target: 27017 + published: 17017 + protocol: tcp + mode: host + networks: + - iklimco-net + deploy: + placement: + constraints: + - node.labels.role == db + restart_policy: + condition: on-failure + delay: 5s diff --git a/ansible/roles/wireguard/defaults/main.yml b/ansible/roles/wireguard/defaults/main.yml new file mode 100644 index 0000000..eb379c4 --- /dev/null +++ b/ansible/roles/wireguard/defaults/main.yml @@ -0,0 +1,13 @@ +--- +wireguard_interface: wg0 +wireguard_address: "10.8.0.1/24" +wireguard_port: 51820 +wireguard_subnet: "10.8.0.0/24" + +# DB proxy portları — host ağında dinlenecek, sadece wireguard_subnet'ten erişilebilir +wireguard_db_pg_proxy_port: 15432 +wireguard_db_mongo_proxy_port: 17017 + +# Her client için: name, public_key, allowed_ips +# group_vars/all/vars.yml içinde tanımlanır +wireguard_clients: [] diff --git a/ansible/roles/wireguard/handlers/main.yml b/ansible/roles/wireguard/handlers/main.yml new file mode 100644 index 0000000..39fa9f7 --- /dev/null +++ b/ansible/roles/wireguard/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart wireguard + ansible.builtin.systemd: + name: "wg-quick@{{ wireguard_interface }}" + state: restarted diff --git a/ansible/roles/wireguard/tasks/main.yml b/ansible/roles/wireguard/tasks/main.yml new file mode 100644 index 0000000..c1cf13f --- /dev/null +++ b/ansible/roles/wireguard/tasks/main.yml @@ -0,0 +1,84 @@ +--- +- name: Install WireGuard + ansible.builtin.dnf: + name: wireguard-tools + state: present + +- name: Ensure /etc/wireguard directory exists + ansible.builtin.file: + path: /etc/wireguard + state: directory + mode: "0700" + owner: root + group: root + +- name: Check if WireGuard private key exists + ansible.builtin.stat: + path: /etc/wireguard/private.key + register: wg_key_stat + +- name: Generate WireGuard keypair + ansible.builtin.shell: | + wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key + chmod 600 /etc/wireguard/private.key + chmod 644 /etc/wireguard/public.key + when: not wg_key_stat.stat.exists + +- name: Read WireGuard private key + ansible.builtin.slurp: + src: /etc/wireguard/private.key + register: wg_private_key_raw + +- name: Read WireGuard public key + ansible.builtin.slurp: + src: /etc/wireguard/public.key + register: wg_public_key_raw + +- name: Set WireGuard key facts + ansible.builtin.set_fact: + wg_server_private_key: "{{ wg_private_key_raw.content | b64decode | trim }}" + wg_server_public_key: "{{ wg_public_key_raw.content | b64decode | trim }}" + +- name: Deploy wg0.conf + ansible.builtin.template: + src: wg0.conf.j2 + dest: "/etc/wireguard/{{ wireguard_interface }}.conf" + mode: "0600" + owner: root + group: root + notify: restart wireguard + +- name: Enable and start WireGuard + ansible.builtin.systemd: + name: "wg-quick@{{ wireguard_interface }}" + enabled: true + state: started + daemon_reload: true + +- name: Allow WireGuard UDP port from admin CIDRs + ansible.posix.firewalld: + rich_rule: >- + rule family="ipv4" source address="{{ item }}" + port port="{{ wireguard_port }}" protocol="udp" accept + zone: drop + state: enabled + permanent: true + immediate: true + loop: "{{ admin_allowed_cidrs.split(' ') }}" + +- name: Allow DB proxy ports from WireGuard subnet only + ansible.posix.firewalld: + rich_rule: >- + rule family="ipv4" source address="{{ wireguard_subnet }}" + port port="{{ item }}" protocol="tcp" accept + zone: drop + state: enabled + permanent: true + immediate: true + loop: + - "{{ wireguard_db_pg_proxy_port }}" + - "{{ wireguard_db_mongo_proxy_port }}" + +- name: Print server public key (client config için gerekli) + ansible.builtin.debug: + msg: "WireGuard server public key: {{ wg_server_public_key }}" diff --git a/ansible/roles/wireguard/templates/wg0.conf.j2 b/ansible/roles/wireguard/templates/wg0.conf.j2 new file mode 100644 index 0000000..bd7ec70 --- /dev/null +++ b/ansible/roles/wireguard/templates/wg0.conf.j2 @@ -0,0 +1,12 @@ +[Interface] +PrivateKey = {{ wg_server_private_key }} +Address = {{ wireguard_address }} +ListenPort = {{ wireguard_port }} + +{% for client in wireguard_clients %} +[Peer] +# {{ client.name }} +PublicKey = {{ client.public_key }} +AllowedIPs = {{ client.allowed_ips }} + +{% endfor %} diff --git a/ansible/test/group_vars/all/vars.yml b/ansible/test/group_vars/all/vars.yml index 7d7b8c7..2ba43fb 100644 --- a/ansible/test/group_vars/all/vars.yml +++ b/ansible/test/group_vars/all/vars.yml @@ -9,6 +9,14 @@ admin_allowed_cidrs: "78.187.87.109/32 95.70.151.248/32" admin_ssh_public_key_path: "~/.ssh/id_rsa.pub" timezone: "Europe/Istanbul" +# WireGuard +# Her client için: name, public_key, allowed_ips +# public_key: client makinasında `wg genkey | tee client.key | wg pubkey` ile üretilir +wireguard_clients: + - name: murat-inspiron-15-3525 + public_key: "8nYHZvSwxCr2uwOYohLG3DlC85NbVNhKnPxYtOEKvE0=" + allowed_ips: 10.8.0.2/32 + # DB Stack db_postgres_image: "postgis/postgis:17-3.5" db_mongo_image: "mongo:8" diff --git a/ansible/test/test-app-post-stack.yml b/ansible/test/test-app-post-stack.yml index 9e5e747..01775a4 100644 --- a/ansible/test/test-app-post-stack.yml +++ b/ansible/test/test-app-post-stack.yml @@ -10,7 +10,7 @@ # Token tanımlı değilse kurulum tamamlanır ancak kayıt adımı atlanır. # Sonraki çalıştırmada .runner dosyası varsa kayıt tekrar yapılmaz (idempotent). -- name: "App Node -Gitea runner ve deploy ön koşulları" +- name: "App Node - Gitea runner ve deploy ön koşulları" hosts: app become: true diff --git a/ansible/test/test-db-post-stack.yml b/ansible/test/test-db-post-stack.yml index 759e347..876f301 100644 --- a/ansible/test/test-db-post-stack.yml +++ b/ansible/test/test-db-post-stack.yml @@ -1,10 +1,18 @@ --- -- name: DB Node - StorageBox Dizinleri ve MongoDB Konfigürasyonu +# WireGuard client eklemek için group_vars/all/vars.yml içindeki +# wireguard_clients listesine client public key'ini ekleyin. +# +# Sadece WireGuard güncellemek için: +# ansible-playbook test-db-post-stack.yml --vault-password-file=.vault_pass --tags wireguard + +- name: DB Node - StorageBox Dizinleri, MongoDB Konfigürasyonu ve WireGuard hosts: db become: yes roles: - role: db_stack tags: [db_stack] + - role: wireguard + tags: [wireguard] - name: App Node - DB Stack Deploy hosts: app diff --git a/roadmap/test-env/07-deploy-pipeline-update.md b/roadmap/test-env/07-deploy-pipeline-update.md index c1fd602..e44ffec 100644 --- a/roadmap/test-env/07-deploy-pipeline-update.md +++ b/roadmap/test-env/07-deploy-pipeline-update.md @@ -133,9 +133,10 @@ Final step order in the pipeline: 13. Docker Login to Harbor 14. **Prepare SWAG Directories** ← NEW 15. Deploy Swarm Stack -16. **Bootstrap SWAG Certificate** ← NEW -17. **Run Database Init Scripts** ← NEW (önceki oturumda eklendi) -18. Review Environment +16. **Run APISIX Init** ← NEW (Swarm etcd volume'süz başlar; idempotent PUT) +17. **Bootstrap SWAG Certificate** ← NEW +18. **Run Database Init Scripts** ← NEW (önceki oturumda eklendi) +19. Review Environment > Steps 8 (Provision Vault) runs before SWAG because it creates Docker secrets and > AppRole IDs — Vault must be reachable for this. On re-deploys, Vault is already diff --git a/terraform/hetzner/test/firewall.tf b/terraform/hetzner/test/firewall.tf index a3fb1b8..3526cea 100644 --- a/terraform/hetzner/test/firewall.tf +++ b/terraform/hetzner/test/firewall.tf @@ -186,6 +186,14 @@ resource "hcloud_firewall" "db" { description = "SSH — admin CIDRs only" } + rule { + direction = "in" + protocol = "udp" + port = "51820" + source_ips = ["0.0.0.0/0", "::/0"] + description = "WireGuard VPN — public (auth kriptografik anahtar ile yapılır)" + } + rule { direction = "in" protocol = "tcp"