Ansible Vault ile Şifreli Değişken Yönetimi

Production ortamında Ansible kullanıyorsanız, er ya da geç şu soruyla yüzleşmek zorundasınız: “Bu şifreleri, API anahtarlarını ve hassas verileri playbook’larımda nasıl saklayacağım?” Git reposuna düz metin olarak commit etmek en kötü seçenek, her seferinde elle girmek ise sürdürülebilir değil. İşte tam bu noktada Ansible Vault devreye giriyor.

Ansible Vault, hassas verileri AES256 şifrelemeyle koruyarak hem güvenli hem de otomasyon dostu bir çözüm sunuyor. Bu yazıda sadece temel komutları değil, gerçek dünya senaryolarında nasıl kullanacağınızı, CI/CD pipeline’larıyla nasıl entegre edeceğinizi ve ekip ortamında nasıl yöneteceğinizi ele alacağız.

Ansible Vault Nedir ve Neden Gerekli?

Ansible Vault, Ansible’ın yerleşik şifreleme aracıdır. Dosyaları veya tek tek değişkenleri AES256-CBC algoritmasıyla şifreler. Şifreli içerik, normal YAML dosyaları gibi playbook’larınızda kullanılabilir; Ansible çalışma zamanında otomatik olarak çözer.

Şifrelenebilecek veriler şunlardır:

  • Veritabanı şifreleri: MySQL, PostgreSQL, MongoDB bağlantı bilgileri
  • API anahtarları: AWS, Stripe, Twilio, SendGrid token’ları
  • SSL sertifika private key’leri: Web sunucusu yapılandırmaları için
  • SSH private key’leri: Uzak sunuculara erişim için kullanılan anahtarlar
  • LDAP/AD bind şifreleri: Dizin servisi entegrasyonları
  • Uygulama secret key’leri: Django SECRET_KEY, Laravel APP_KEY gibi değerler

Bir production senaryosu düşünün: 50 sunucuya deploy yapan bir ekibiniz var. Her geliştiricinin her sunucunun şifresini bilmesi hem güvenlik açığı hem de operasyonel kabus. Ansible Vault ile şifreli bir değişken dosyası oluşturuyor, bu dosyayı Git’e gönderiyorsunuz ve sadece vault şifresini (veya anahtar dosyasını) yetkili kişilerle paylaşıyorsunuz.

Vault Kurulumu ve İlk Adımlar

Ansible Vault, Ansible kurulumunun bir parçasıdır, ayrıca bir şey yüklemenize gerek yoktur.

# Ansible versiyonunu kontrol et
ansible --version

# Vault komutlarını listele
ansible-vault --help

İlk Şifreli Dosyanızı Oluşturmak

En basit kullanım, tüm bir dosyayı şifrelemektir:

# Yeni şifreli dosya oluştur
ansible-vault create group_vars/production/vault.yml

# Mevcut dosyayı şifrele
ansible-vault encrypt group_vars/production/secrets.yml

# Şifreli dosyayı görüntüle (şifre ister)
ansible-vault view group_vars/production/vault.yml

# Şifreli dosyayı düzenle
ansible-vault edit group_vars/production/vault.yml

# Şifreyi çöz (dikkatli kullanın!)
ansible-vault decrypt group_vars/production/vault.yml

create komutu çalıştırdığınızda vault şifrenizi girmenizi ister, ardından tercih ettiğiniz editörü açar (genellikle vi, EDITOR ortam değişkeniyle değiştirebilirsiniz).

Değişken Yapısını Doğru Organize Etmek

Vault kullanımında en yaygın hata, her şeyi tek bir dosyaya doldurmaktır. Bunun yerine vault değişkenlerini normal değişkenlerden ayıran bir yapı kurmak çok daha yönetilebilir.

Önerilen dizin yapısı:

inventory/
  production/
    group_vars/
      all/
        vars.yml          # Şifresiz genel değişkenler
        vault.yml         # Şifreli değişkenler
      webservers/
        vars.yml          # Webserver'a özel şifresiz değişkenler
        vault.yml         # Webserver'a özel şifreli değişkenler
      databases/
        vars.yml
        vault.yml
    host_vars/
      db-master-01/
        vars.yml
        vault.yml

Şimdi bu yapıyı nasıl dolduracağımıza bakalım. Önce şifresiz vars.yml dosyası:

# group_vars/all/vars.yml
---
app_name: myapp
app_port: 8080
db_host: "db-master-01.internal"
db_port: 5432
db_name: "{{ vault_db_name }}"
db_user: "{{ vault_db_user }}"
db_password: "{{ vault_db_password }}"

# API entegrasyonları
stripe_api_base: "https://api.stripe.com/v1"
stripe_api_key: "{{ vault_stripe_api_key }}"

Ardından şifreli vault.yml dosyası (vault prefix kullanımına dikkat edin):

# group_vars/all/vault.yml (ansible-vault create ile oluşturulmuş)
---
vault_db_name: "production_db"
vault_db_user: "app_user"
vault_db_password: "S3cur3P@ssw0rd!2024"
vault_stripe_api_key: "sk_live_AbCdEfGhIjKlMnOpQrStUv"
vault_app_secret_key: "django-insecure-but-now-secure-random-string-here"

Bu vault_ prefix geleneği çok önemlidir. Playbook’larınızda db_password kullandığınızda, bunun şifreli bir kaynaktan geldiğini hemen anlarsınız. Yeni ekip üyeleri de hangi değişkenlerin hassas olduğunu kolayca görebilir.

Inline (Satır İçi) Şifreleme

Bazen tüm bir dosyayı şifrelemek yerine, sadece belirli bir değeri şifrelemek daha mantıklıdır. ansible-vault encrypt_string tam olarak bunu yapar:

# Tek bir değeri şifrele
ansible-vault encrypt_string 'S3cur3P@ssw0rd!2024' --name 'db_password'

# Stdin'den oku (şifreyi terminal history'sine yazmamak için)
ansible-vault encrypt_string --name 'api_key' --stdin-name 'api_key'
# Komutu çalıştır, değeri yaz, Ctrl+D'ye bas

# Farklı vault ID ile
ansible-vault encrypt_string --vault-id production@prompt 'mypassword' --name 'db_pass'

Komutun çıktısı şu şekilde görünür:

db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          33316635623639323434373831343439623234633466313537613366623132643961363636333866
          6234663664313763376437393535393737626630623934340a333762323930306233666537613232
          38363961316437613765616436303865663935316539373532366130656635383430363434363630
          6339616564306463360a643337313564333661636433326131333264363636363636323662303562
          3435

Bu çıktıyı direkt olarak vars dosyanıza kopyalayabilirsiniz. Dosyanın geri kalanı şifresiz kalırken sadece bu değer korunur.

Vault Password Dosyaları ve Otomasyon

Etkileşimli olmayan ortamlarda (CI/CD, cron job’lar) her seferinde şifre girmeniz mümkün değil. Bunun için vault password dosyaları kullanılır:

# Vault şifresini bir dosyaya yaz
echo "VaultSuperSecretPassword2024!" > ~/.vault_pass
chmod 600 ~/.vault_pass

# Bu dosyayı .gitignore'a ekle!
echo "~/.vault_pass" >> ~/.gitignore
echo ".vault_pass" >> .gitignore

# Playbook çalıştırırken vault password dosyasını belirt
ansible-playbook -i inventory/production site.yml --vault-password-file ~/.vault_pass

# Alternatif: Ortam değişkeni ile
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
ansible-playbook -i inventory/production site.yml

ansible.cfg dosyanıza da ekleyebilirsiniz:

# ansible.cfg
[defaults]
inventory = ./inventory
vault_password_file = ~/.vault_pass

Uyarı: Vault şifre dosyasını Git reposuna asla commit etmeyin. .gitignore kontrolünüzü titizlikle yapın.

Vault ID’ler ile Çoklu Ortam Yönetimi

Gerçek dünyada birden fazla ortamınız var: development, staging, production. Her ortamın farklı vault şifresi olması gerekir. Vault ID özelliği tam burada işe yarıyor:

# Development ortamı için şifreli dosya oluştur
ansible-vault create --vault-id dev@prompt group_vars/dev/vault.yml

# Staging için
ansible-vault create --vault-id staging@~/.vault_pass_staging group_vars/staging/vault.yml

# Production için (farklı şifre)
ansible-vault create --vault-id production@~/.vault_pass_prod group_vars/production/vault.yml

# Birden fazla vault ID ile playbook çalıştır
ansible-playbook site.yml 
  --vault-id dev@~/.vault_pass_dev 
  --vault-id production@~/.vault_pass_prod

Şifreli dosyanın başındaki header, hangi vault ID ile şifrelendiğini gösterir:

$ANSIBLE_VAULT;1.2;AES256;production

Bu sayede Ansible hangi şifreyi kullanması gerektiğini bilir. Production sunucularına deploy yaparken development vault şifresine ihtiyaç duymadan çalışabilirsiniz.

CI/CD Pipeline Entegrasyonu

GitLab CI örneği üzerinden gerçek bir senaryo gösterelim:

# .gitlab-ci.yml
stages:
  - test
  - deploy

variables:
  ANSIBLE_HOST_KEY_CHECKING: "False"

deploy_production:
  stage: deploy
  image: python:3.11-slim
  before_script:
    - pip install ansible
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    # Vault şifresini CI değişkeninden al
    - echo "$ANSIBLE_VAULT_PASSWORD" > ~/.vault_pass
    - chmod 600 ~/.vault_pass
  script:
    - ansible-playbook -i inventory/production site.yml
      --vault-password-file ~/.vault_pass
      --extra-vars "deploy_env=production"
  after_script:
    - rm -f ~/.vault_pass
    - rm -f ~/.ssh/id_rsa
  only:
    - main
  environment:
    name: production

GitLab’da Settings > CI/CD > Variables bölümünde ANSIBLE_VAULT_PASSWORD değişkenini Masked ve Protected olarak tanımlarsınız. Bu sayede şifre pipeline loglarında görünmez.

GitHub Actions için benzer yaklaşım:

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Ansible
        run: pip install ansible

      - name: Setup Vault Password
        run: |
          echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/.vault_pass
          chmod 600 /tmp/.vault_pass

      - name: Run Ansible Playbook
        run: |
          ansible-playbook -i inventory/production site.yml 
            --vault-password-file /tmp/.vault_pass
        env:
          ANSIBLE_HOST_KEY_CHECKING: false

      - name: Cleanup
        if: always()
        run: rm -f /tmp/.vault_pass

Vault Şifresi Script ile Dışarıdan Almak

Vault şifresini HashiCorp Vault, AWS Secrets Manager veya başka bir secret store’dan dinamik olarak almak isteyebilirsiniz. Vault password dosyası yerine çalıştırılabilir bir script kullanabilirsiniz:

#!/bin/bash
# scripts/get_vault_password.sh
# AWS Secrets Manager'dan vault şifresini al

SECRET_NAME="ansible/vault-password"
REGION="eu-west-1"

aws secretsmanager get-secret-value 
  --secret-id "$SECRET_NAME" 
  --region "$REGION" 
  --query 'SecretString' 
  --output text
# Script'i çalıştırılabilir yap
chmod +x scripts/get_vault_password.sh

# Kullanımı
ansible-playbook site.yml --vault-password-file scripts/get_vault_password.sh

HashiCorp Vault entegrasyonu için:

#!/bin/bash
# scripts/vault_password_from_hcvault.sh

VAULT_ADDR="https://vault.company.internal:8200"
SECRET_PATH="secret/ansible/vault-password"

# Vault token environment'tan okunuyor (VAULT_TOKEN)
vault kv get -field=password "$SECRET_PATH"

Bu yaklaşım, vault şifresinin hiçbir zaman disk üzerinde kalmamasını sağlar. CI/CD ortamında script’e VAULT_TOKEN veya AWS credentials environment değişkenleriyle verilir.

Vault Şifresini Yeniden Şifrelemek

Bir ekip üyesi ayrıldığında veya güvenlik ihlali şüphesi olduğunda vault şifresini değiştirmeniz gerekir:

# Vault şifresini değiştir (rekey)
ansible-vault rekey group_vars/production/vault.yml

# Birden fazla dosyayı aynı anda yeniden şifrele
ansible-vault rekey group_vars/production/vault.yml 
  group_vars/all/vault.yml 
  host_vars/db-master-01/vault.yml

# Yeni şifre dosyası ile rekey
ansible-vault rekey --new-vault-password-file ~/.new_vault_pass 
  group_vars/production/vault.yml

# Tüm vault dosyalarını bul ve rekey et
find . -name "vault.yml" -exec ansible-vault rekey {} ;

Rekey işlemi şifreli içeriği değiştirmez, sadece şifreleme anahtarını değiştirir. Eski şifreyi bilmeden bu işlemi yapamazsınız.

Pratik Bir Senaryo: Web Uygulama Deployment’ı

Hepsini bir araya getirelim. Django uygulaması deploy eden gerçek bir örnek:

# group_vars/webservers/vars.yml
---
django_debug: false
django_allowed_hosts:
  - "myapp.com"
  - "www.myapp.com"
django_static_root: "/var/www/myapp/static"
django_media_root: "/var/www/myapp/media"

# Vault'tan gelen değişkenleri referans al
django_secret_key: "{{ vault_django_secret_key }}"
django_db_password: "{{ vault_django_db_password }}"
django_email_password: "{{ vault_django_email_password }}"
aws_s3_access_key: "{{ vault_aws_s3_access_key }}"
aws_s3_secret_key: "{{ vault_aws_s3_secret_key }}"
# group_vars/webservers/vault.yml (şifreli)
---
vault_django_secret_key: "50-character-random-string-goes-here-keep-it-safe"
vault_django_db_password: "Pr0duct!onDBPass2024"
vault_django_email_password: "EmailSMTPPassword"
vault_aws_s3_access_key: "AKIAIOSFODNN7EXAMPLE"
vault_aws_s3_secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
# playbooks/deploy_webapp.yml
---
- name: Deploy Django Web Application
  hosts: webservers
  become: yes

  tasks:
    - name: Uygulama konfigürasyon dosyasını oluştur
      template:
        src: templates/django_settings.env.j2
        dest: /var/www/myapp/.env
        owner: www-data
        group: www-data
        mode: '0640'
      notify: restart gunicorn

    - name: Veritabanı migrasyonlarını çalıştır
      django_manage:
        command: migrate
        app_path: /var/www/myapp
        virtualenv: /var/www/myapp/venv
      environment:
        DATABASE_URL: "postgresql://{{ django_db_user }}:{{ django_db_password }}@{{ db_host }}/{{ db_name }}"

  handlers:
    - name: restart gunicorn
      systemd:
        name: gunicorn
        state: restarted
{# templates/django_settings.env.j2 #}
SECRET_KEY={{ django_secret_key }}
DEBUG={{ django_debug | lower }}
ALLOWED_HOSTS={{ django_allowed_hosts | join(',') }}
DATABASE_URL=postgresql://{{ django_db_user }}:{{ django_db_password }}@{{ db_host }}/{{ db_name }}
EMAIL_HOST_PASSWORD={{ django_email_password }}
AWS_ACCESS_KEY_ID={{ aws_s3_access_key }}
AWS_SECRET_ACCESS_KEY={{ aws_s3_secret_key }}

Yaygın Hatalar ve Çözümleri

Hata 1: Vault şifreli dosyayı Git’e commit etmek ama şifre dosyasını da eklemek

Vault dosyalarını Git’e commit etmek tamamen normaldir, hatta beklenen budur. Şifreli haldedir. Asla commit etmemeniz gereken şey vault şifresini içeren .vault_pass dosyasıdır.

# .gitignore'unuzda bunlar olmalı
.vault_pass
.vault_pass*
*.vault_password

Hata 2: Şifrelenmemiş dosyayı yanlışlıkla commit etmek

Git pre-commit hook ile bunu önleyebilirsiniz:

#!/bin/bash
# .git/hooks/pre-commit

# vault.yml dosyalarının şifrelenip şifrelenmediğini kontrol et
for file in $(git diff --cached --name-only | grep "vault.yml"); do
  if ! grep -q '^$ANSIBLE_VAULT' "$file"; then
    echo "HATA: $file dosyası şifrelenmemiş! ansible-vault encrypt ile şifreleyin."
    exit 1
  fi
done

exit 0
chmod +x .git/hooks/pre-commit

Hata 3: Tüm değişkenleri vault’a koymak

Sadece hassas değerleri vault’a koyun. Port numaraları, hostname’ler, uygulama ayarları gibi şeyler şifrelenmesine gerek yoktur. Aşırı şifreleme, playbook’larınızın debug edilmesini zorlaştırır.

Hata 4: Vault şifresini unutmak

Vault şifreniz kaybolursa şifreli verilerinize erişim imkansızdır. Vault şifresini mutlaka başka bir güvenli yerde (şirket şifre yöneticisi, HR kasası vb.) saklayın.

Vault ile Güvenlik En İyi Uygulamaları

Vault kullanımınızı daha güvenli hale getirecek pratik öneriler:

  • Ortam başına farklı vault şifresi: Dev, staging ve production için ayrı vault şifreleri kullanın. Bu şekilde bir şifrenin sızdırılması tüm ortamları etkilemez.
  • Vault şifresini döndürün: 90 günde bir veya ekip değişikliklerinde vault şifrelerini ansible-vault rekey ile güncelleyin.
  • Audit trail oluşturun: Vault dosyalarına kim, ne zaman erişti bilgisini tutun. Git commit history bu konuda yardımcı olur.
  • Minimal kapsam: Her rol ve grup için ayrı vault dosyası oluşturun. Database takımı, web sunucusu vault değişkenlerine erişememelidir.
  • Test etmeyi unutmayın: ansible-vault view ile şifreli dosyaların içeriğini periyodik olarak doğrulayın. Bozuk vault dosyası keşfedilmesi en kötü deployment sırasında olur.
  • Backup: Vault şifreli dosyalarınızı ve vault şifrelerinizi ayrı backup’larında saklayın.

Sonuç

Ansible Vault, karmaşık görünen ama aslında son derece pratik bir araçtır. Temel prensibi basit: hassas veriler şifreli dosyalarda yaşar, Ansible çalışma zamanında bunları çözer, siz de bu değerleri normal değişkenler gibi kullanırsınız.

Başlangıç noktası olarak şu adımları öneririm: Önce mevcut playbook’larınızı tarayın ve içinde düz metin şifre olan tüm yerleri tespit edin. Ardından vault_ prefix geleneğini benimseyerek vars ve vault dosyalarını ayırın. Son olarak CI/CD sisteminize vault şifresini güvenli bir secret olarak tanımlayın ve otomasyon pipeline’ınızı tamamlayın.

Vault sadece bir güvenlik önlemi değil, aynı zamanda operasyonel olgunluğun göstergesidir. Production’da kimsenin elle şifre yazmaması, her şeyin kod olarak yönetilmesi ve bu kodun güvenli şekilde saklanması; işte gerçek anlamda Infrastructure as Code bu demek.

Yorum yapın