# 03 - Test Ansible Bootstrap Bu aşamanın amacı Terraform ile oluşturulan test makinelerini Linux, hardening, Docker ve Swarm açısından hazır hale getirmektir. DB yazılımı kurulumu bu aşamanın dışındadır. ## Ansible Kurulumu Ansible, kontrol makinesinde (kendi bilgisayarınızda) yüklü olmalıdır. Hedef sunuculara herhangi bir ajan kurulmaz, sadece SSH erişimi yeterlidir. ### İşletim Sistemine Göre Kurulum - **Ubuntu / Debian:** ```bash sudo apt update sudo apt install -y pipx python3-venv pipx ensurepath export PATH="$HOME/.local/bin:$PATH" pipx install --include-deps ansible ``` > Not: `sudo apt install ansible` komutu bazı Ubuntu/Debian sürümlerinde eski Ansible paketlerini kurabilir. Bu nedenle güncel Ansible kullanımı için `pipx` yöntemi tercih edilmelidir. - **Fedora / Rocky Linux / RHEL:** ```bash sudo dnf install -y pipx python3-virtualenv pipx ensurepath export PATH="$HOME/.local/bin:$PATH" pipx install --include-deps ansible ``` - **macOS (Homebrew):** ```bash brew install ansible ``` - **Python Pip ile (Her platformda):** ```bash pipx install --include-deps ansible ``` ### Ek Python Bağımlılıkları `password_hash` filtresi için `passlib` kontrol makinesinde gereklidir: ```bash pipx inject ansible passlib ``` > `pip` ile kurduysanız: `pip install passlib` ### Kurulumun Doğrulanması Hangi yöntemle kurarsanız kurun, kurulumun başarılı olduğunu doğrulamak için aşağıdaki komutları kullanın: ```bash # Ansible versiyonunu ve yapılandırma yollarını kontrol edin ansible --version # Ansible binary’sinin hangi konumdan çalıştığını kontrol edin which -a ansible ``` ## Ansible Komutlarını Çalıştırma Tüm komutlar `ansible/test/` dizininden çalıştırılmalıdır. `ansible.cfg` inventory ve roles_path'i otomatik olarak tanımlar. ### 0. Gerekli Collection'ları Kur (İlk kurulumda bir kez) ```bash ansible-galaxy collection install -r ../requirements.yml ``` ### 1. Bağlantı Testi (Ping) ```bash ansible all -m ping ``` ### 2. Bootstrap Playbook'unu Çalıştırma ```bash ansible-playbook test-bootstrap.yml --ask-vault-pass ``` *Not: `--ask-vault-pass` parametresi Ansible Vault parolasını sorar; StorageBox şifresi bu şekilde çözülür.* ### 3. Sadece Belirli Bir Rolü Çalıştırma (Tags) ```bash ansible-playbook test-bootstrap.yml --tags "hardening" --ask-vault-pass ``` ## Hedef Makineler | Host | Rol | | --- | --- | | `iklim-app-01` | Swarm manager + app worker | | `iklim-db-01` | Manuel DB kurulumu için OS-hardening uygulanmış DB node | ## Önerilen Dosya Yapısı ```text ansible/ test/ ansible.cfg inventory/ generated/ test.yml group_vars/ all/ vars.yml vault.yml test-bootstrap.yml roles/ base/ hardening/ docker/ swarm/ node_dirs/ storagebox/ storagebox_ssh_key/ ``` ## Base Role Tüm test node'larına uygulanır: - `dnf update` - `epel-release` — ayrı task olarak önce kurulur; `fail2ban`, `davfs2`, `htop`, `btop` bu repoya bağımlı - temel paketler (`epel-release` aktif olduktan sonra): - `curl` - `wget` - `git` - `jq` - `tar` - `unzip` - `bash-completion` - `gettext` — envsubst için; CI/CD deploy pipeline'larında gerekli - `tree` - `ca-certificates` - `fail2ban` - `chrony` - `python3` - `python3-pip` - `python3-passlib` — `password_hash` filtresi için (EPEL) - `htop` — interaktif proses izleme (EPEL) - `btop` — kaynak monitörü, grafik arayüz (EPEL) - timezone: `Europe/Istanbul` - hostname ayarı - klavye düzeni: `trq` (Türkçe Q) - sistem reboot gerekiyorsa kontrollü reboot ## Security Hardening Role Tüm test node'larına uygulanır: - SSH password login kapatılır. - Root SSH login kapatılır. - Sadece SSH key ile login kalır. - `PermitEmptyPasswords no` - `MaxAuthTries 3` - `fail2ban` SSH jail aktif edilir. - `dnf-automatic` ile otomatik güvenlik güncelleştirmeleri aktif edilir. - `iklim` sistem kullanıcısı oluşturulur; `wheel` grubuna eklenir (şifre vault'tan alınır). - `firewalld` default: - incoming: deny (drop zone) - outgoing: allow - SSH kuralı önce `drop` zone'a rich rule olarak yazılır, ardından default zone `drop` yapılır — kilitleme riski ortadan kalkar. - Public SSH sadece admin CIDR'dan açılır. ### SELinux Kararı Rocky Linux 10 SELinux enforcing modda gelir. Karar: **disabled**. Gerekçe: - Hetzner Cloud firewall (dış perimeter) + firewalld (host) iki katman ağ güvenliğini sağlar. - Docker + davfs2 + firewalld kombinasyonu SELinux enforcing modda ek policy ve volume label yönetimi gerektirir. - Utils VPS'te de disabled yapılmış; tutarlılık sağlanır. ```bash # /etc/selinux/config içinde: SELINUX=disabled # Değişiklik reboot sonrası aktif olur reboot ``` Ansible'da: ```yaml - name: Disable SELinux ansible.posix.selinux: state: disabled register: selinux_change - name: Reboot if SELinux state changed ansible.builtin.reboot: when: selinux_change.changed ``` ### fail2ban Konfigürasyonu `/etc/fail2ban/jail.local` içeriği: ```ini [DEFAULT] ignoreip = 127.0.0.1/8 {{ admin_allowed_cidrs }} bantime = 21600 findtime = 300 maxretry = 5 banaction = iptables-multiport backend = systemd [sshd] enabled = true ``` - `bantime`: 6 saat ban - `findtime`: 5 dakika içinde - `maxretry`: 5 başarısız giriş → ban - `ignoreip`: admin CIDR'ları ban'dan muaf tutar Ansible'da `admin_allowed_cidrs` listesi space-separated stringe dönüştürülüp template'e basılır. Not: Docker iptables kuralları firewalld ile etkileşebilir. Hetzner Cloud firewall asıl dış perimeter kabul edilir; firewalld host içinde ikinci katman olarak kullanılır. ## Docker Role Her iki node (`iklim-app-01` ve `iklim-db-01`) üzerinde de zorunludur. DB node'u Swarm Worker olarak ağa dahil olacağı için Docker Engine her iki makinede de kurulu olmalıdır. Docker kurulumu resmi Docker dnf repository üzerinden yapılır: - Docker GPG key + dnf repository (`https://download.docker.com/linux/rhel/docker-ce.repo`) - paketler: - `docker-ce` - `docker-ce-cli` - `containerd.io` - `docker-buildx-plugin` - `docker-compose-plugin` - Docker servisi enabled + started Docker convenience script kullanılmayacak. Production benzeri test ortamı için paket repository yolu tercih edilir. ## Swarm Role - `iklim-app-01` üzerinde Swarm Manager olarak init edilir. - `iklim-db-01` üzerinde Swarm Worker olarak join edilir (Overlay network erişimi için). - advertise addr: `10.10.10.11` (manager için) - overlay network: - `iklimco-net` - driver: `overlay` - attachable: `true` - Node etiketleri: - `iklim-app-01` -> `type=service` - `iklim-db-01` -> `role=db` - `iklim-app-01` üzerinde hem manager hem worker (Active) görevini sürdürür. ## Node Directory Role `iklim-app-01` üzerinde deploy ön koşulları: ```text /opt/iklimco /opt/iklimco/ssl /opt/iklimco/init /opt/iklimco/init/postgresql /opt/iklimco/init/mongodb /opt/iklimco/stacks ``` DB node üzerinde manuel DB kurulumu için minimum: ```text /opt/iklimco /opt/iklimco/db /opt/iklimco/backup ``` ## StorageBox DAVFS Mount Role Her iki node'a uygulanır (`iklim-app-01` ve `iklim-db-01`). ### Amaç Hetzner StorageBox'u WebDAV (DAVFS) protokolü üzerinden `/mnt/storagebox` olarak mount eder. Docker volume'ları bu dizine bağlanarak veri kalıcılığını ve yedeklemeyi sağlar. ### Test Ortamı Sub-Account | Parametre | Değişken | Değer | | --- | --- | --- | | Ana hesap | `storagebox_account` | `u469968` | | Sub-account | `storagebox_user` | `u469968-sub4` | | WebDAV URL | `storagebox_url` | `https://u469968-sub4.your-storagebox.de/` | | Mount point | `storagebox_mount_point` | `/mnt/storagebox` | ### Role Değişkenleri Tüm değişkenler `group_vars/all/vars.yml` içinde tanımlanır: ```yaml storagebox_account: "u469968" storagebox_user: "{{ storagebox_account }}-sub4" storagebox_url: "https://{{ storagebox_user }}.your-storagebox.de/" storagebox_password: "{{ vault_storagebox_password }}" storagebox_mount_point: "/mnt/storagebox" ``` Prod ortamında suffix `sub4` → `sub5` olarak değişir. Şifreler Ansible Vault ile şifreli `group_vars/all/vault.yml` içinde tutulur: ```bash ansible-vault edit group_vars/all/vault.yml ``` `vault.yml` içeriği: ```yaml vault_storagebox_password: "SUB_ACCOUNT_PAROLASI" vault_iklim_password: "IKLIM_KULLANICI_PAROLASI" ``` ### Adımlar 1. **davfs2 kurulumu** ```yaml - name: Install davfs2 ansible.builtin.dnf: name: davfs2 state: present ``` 2. **Kimlik bilgileri dosyası** (`/etc/davfs2/secrets`) ```yaml - name: Configure davfs2 secrets ansible.builtin.lineinfile: path: /etc/davfs2/secrets line: "{{ storagebox_url }} {{ storagebox_user }} {{ storagebox_password }}" create: yes mode: "0600" owner: root group: root ``` 3. **Mount point oluştur** ```yaml - name: Create mount point ansible.builtin.file: path: "{{ storagebox_mount_point }}" state: directory mode: "0755" ``` 4. **fstab kaydı** ```yaml - name: Add fstab entry ansible.builtin.lineinfile: path: /etc/fstab line: >- {{ storagebox_url }} {{ storagebox_mount_point }} davfs _netdev,auto,user,rw,uid=root,gid=root 0 0 state: present ``` 5. **Mount et** ```yaml - name: Mount StorageBox ansible.builtin.command: mount {{ storagebox_mount_point }} args: creates: "{{ storagebox_mount_point }}/.mounted_marker" ``` Mount başarısı için dizine bir marker dosyası yazılabilir: ```yaml - name: Write mount marker ansible.builtin.copy: content: "mounted by ansible" dest: "{{ storagebox_mount_point }}/.mounted_marker" ``` ### Notlar - `davfs2` paketi EPEL repository'sinde bulunur; base role `epel-release`'i zaten kurar. - StorageBox şifreleri asla plaintext olarak repository'e eklenmez; Ansible Vault zorunludur. - Mount noktası reboot'ta `_netdev` flag'ı sayesinde network hazır olduktan sonra otomatik mount edilir. - Docker Swarm servisleri `/mnt/storagebox///` altındaki dizinleri bind mount olarak kullanır. ## StorageBox SSH Key Role Her iki node'a uygulanır (`iklim-app-01` ve `iklim-db-01`). ### Amaç Sunucu üzerinde ed25519 SSH anahtar çifti üretilir ve StorageBox ana hesabına yüklenir. Bu sayede CI/CD pipeline'ları `STORAGEBOX_SSH_PRIV` Gitea secret'ini kullanarak şifresiz erişim sağlayabilir. ### Adımlar 1. **SSH Key üretimi** ```yaml - name: Generate SSH key for StorageBox ansible.builtin.user: name: root generate_ssh_key: yes ssh_key_type: ed25519 ssh_key_file: .ssh/id_ed25519_storagebox ssh_key_comment: "{{ inventory_hostname }}-storagebox" ``` 2. **Public key'i StorageBox'a yükle** Bu adım manuel yapılır (ilk kez şifre gerektirir): ```bash cat /root/.ssh/id_ed25519_storagebox.pub | ssh -p23 u469968-sub4@u469968-sub4.your-storagebox.de install-ssh-key ``` Sonraki erişimler şifresiz çalışır: ```bash sftp -P23 u469968-sub4@u469968-sub4.your-storagebox.de ``` 3. **Private ve public key'leri Gitea'ya ekle** Gitea → Organization Settings → Actions → Secrets: | Secret Adı | Değer | | --- | --- | | `STORAGEBOX_SSH_PRIV` | `/root/.ssh/id_ed25519_storagebox` içeriği | | `STORAGEBOX_SSH_PUB` | `/root/.ssh/id_ed25519_storagebox.pub` içeriği | Key içeriğini almak için: ```bash cat /root/.ssh/id_ed25519_storagebox cat /root/.ssh/id_ed25519_storagebox.pub ``` ### Notlar - Her sunucu için ayrı key üretilir; tüm public key'ler StorageBox ana hesabına yüklenir. - Private key asla repo'ya commit edilmez; yalnızca Gitea secret olarak saklanır. ## Kabul Kriterleri