Arşivleme İşlemlerinde Parola Yönetimi: gpg-agent ve pass ile Otomatik Şifre Girişi
Üretim ortamında çalışan bir sistem yöneticisinin en can sıkıcı anlarından biri şudur: bir cron job gece yarısı çalışıyor, şifreli bir arşiv oluşturmaya çalışıyor ve süreç parola beklediği için askıda kalıyor. Sabah geliyorsunuz, yedekleme başarısız, log’da “passphrase required but no tty” hatası. Bu yazıda bu problemi kökten çözecek bir yaklaşımdan bahsedeceğim: gpg-agent ve pass kullanarak arşivleme işlemlerinde otomatik şifre yönetimi.
Neden Parola Yönetimi Arşivlemenin Parçası Olmalı
Çoğu sysadmin arşivleme ve şifrelemeyi birbirinden bağımsız düşünür. tar ile sıkıştırırsın, gpg ile şifrelersin, işin biter. Ama otomasyona girdiğinizde bu iki adım arasındaki köprüyü kim kuruyor? Kimse. Ve bu boşluk güvenlik açıklarına zemin hazırlıyor.
Klasik çözümler şunlardır: şifreyi bir dosyaya yazıp --passphrase-file ile vermek, ya da environment variable’a gömmek. Her ikisi de berbat. Dosyaya yazılan parola düz metin olarak oturuyor, environment variable’lar ise ps aux ile görülebiliyor. Üretimde bu kabul edilemez.
gpg-agent + pass kombinasyonu bu problemi temiz bir şekilde çözüyor. pass, parolaları GPG ile şifrelenmiş olarak saklıyor. gpg-agent ise GPG işlemleri için parolayı önbelleğe alıyor ve belirli bir süre boyunca tekrar sormadan kullanıyor. Birlikte çalıştıklarında, scriptleriniz parola dosyası veya plain text içermeden şifreli arşivler oluşturabiliyor.
Temel Kurulum
Önce gerekli paketleri kuralım. Debian/Ubuntu tabanlı sistemler için:
sudo apt update
sudo apt install gnupg2 pass pinentry-curses -y
RHEL/CentOS/Rocky Linux için:
sudo dnf install gnupg2 pass pinentry -y
Kurulum sonrası GPG sürümünü kontrol edin:
gpg --version | head -3
GPG 2.1 ve üzeri olması önemli. Eski 1.x sürümlerinde gpg-agent entegrasyonu farklı çalışıyor ve burada anlattıklarım tam olarak uygulanamıyor.
GPG Anahtar Çifti Oluşturma
pass kullanabilmek için bir GPG anahtar çiftine ihtiyacınız var. Eğer halihazırda bir anahtarınız varsa bu adımı atlayabilirsiniz.
gpg --full-generate-key
Bu komut sizi interaktif bir sürece götürür. Anahtar tipi olarak RSA and RSA seçin, bit uzunluğu olarak 4096 tercih edin. Kullanım süresi için üretim ortamlarında sonsuz yerine 2 yıl gibi makul bir değer öneriyorum; anahtar rotasyonu güvenliğin parçası.
Oluşturduğunuz anahtarın ID’sini almak için:
gpg --list-secret-keys --keyid-format=long
Çıktı şöyle görünür:
sec rsa4096/A1B2C3D4E5F6G7H8 2024-01-15 [SC]
FINGERPRINT_BURAYA_GELIR
uid [ultimate] Ahmet Yılmaz <[email protected]>
ssb rsa4096/1234567890ABCDEF 2024-01-15 [E]
Burada A1B2C3D4E5F6G7H8 kısmı sizin anahtar ID’niz.
gpg-agent Konfigürasyonu
gpg-agent kurulumla birlikte geliyor ama varsayılan ayarları production senaryoları için optimize edilmiş değil. Konfigürasyon dosyasını düzenleyelim:
mkdir -p ~/.gnupg
cat > ~/.gnupg/gpg-agent.conf << 'EOF'
default-cache-ttl 3600
max-cache-ttl 86400
pinentry-program /usr/bin/pinentry-curses
allow-loopback-pinentry
EOF
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/gpg-agent.conf
Bu ayarları açıklayayım:
- default-cache-ttl 3600: Son kullanımdan itibaren 1 saat parola önbellekte kalır
- max-cache-ttl 86400: Parola maksimum 24 saat önbellekte kalır, kullanılmasa bile
- pinentry-program: Headless sunucularda curses tabanlı pinentry kullanın
- allow-loopback-pinentry: Scriptlerden parola göndermek için gerekli
Konfigürasyonu uygulamak için agent’ı yeniden başlatın:
gpgconf --kill gpg-agent
gpg-agent --daemon
pass Deposunu Başlatma
pass bir parola deposu (password store) yöneticisidir. Parolaları GPG anahtarınızla şifrelenmiş dosyalar olarak ~/.password-store/ altında saklar.
pass init A1B2C3D4E5F6G7H8
Buradaki ID’yi kendi anahtar ID’nizle değiştirin. Başarılı olursa şu mesajı görürsünüz:
Password store initialized for A1B2C3D4E5F6G7H8
Arşivleme işlemlerimiz için bir parola ekleyelim:
pass insert backup/arsiv-parolasi
Sistem iki kez parola isteyecek. Bu parola, şifreli arşivlerinizi koruyacak olan parola. Güçlü ve rastgele bir şey kullanın:
# Rastgele güçlü parola üretip doğrudan pass'e ekleyebilirsiniz
pass generate backup/arsiv-parolasi 32
Bu komut 32 karakterlik rastgele bir parola oluşturup backup/arsiv-parolasi yoluna kaydeder.
Arşivleme Scriptleri ile Entegrasyon
Şimdi asıl konuya gelelim. Aşağıdaki script, pass üzerinden parolayı alıp tar + gpg kombinasyonuyla şifreli arşiv oluşturuyor:
#!/bin/bash
# /usr/local/bin/sifreli-arsivle.sh
set -euo pipefail
KAYNAK_DIZIN="${1:?Kaynak dizin belirtilmeli}"
HEDEF_DOSYA="${2:?Hedef dosya yolu belirtilmeli}"
PASS_YOLU="backup/arsiv-parolasi"
# GPG agent socket'ini bul
export GPG_TTY=$(tty 2>/dev/null || echo "not-a-tty")
export GNUPGHOME="${GNUPGHOME:-$HOME/.gnupg}"
# Parolayı pass'den al
PAROLA=$(pass show "$PASS_YOLU")
if [ -z "$PAROLA" ]; then
echo "HATA: Parola alınamadı" >&2
exit 1
fi
# Sıkıştır ve şifrele
tar -czf - "$KAYNAK_DIZIN" |
gpg --batch
--yes
--passphrase "$PAROLA"
--symmetric
--cipher-algo AES256
--compress-algo none
-o "$HEDEF_DOSYA"
unset PAROLA
echo "Arşiv oluşturuldu: $HEDEF_DOSYA"
Scripti çalıştırılabilir yapın:
chmod 750 /usr/local/bin/sifreli-arsivle.sh
Test edelim:
sifreli-arsivle.sh /etc/nginx /tmp/nginx-yedek-$(date +%Y%m%d).tar.gz.gpg
Asimetrik Şifreleme ile Daha Güvenli Yaklaşım
Simetrik şifreleme (--symmetric) kolay ama daha güvenli bir yaklaşım asimetrik şifredir. Bu durumda parola yerine GPG anahtarınızı kullanırsınız:
#!/bin/bash
# /usr/local/bin/gpg-arsivle.sh
set -euo pipefail
KAYNAK="${1:?Kaynak belirtilmeli}"
HEDEF="${2:?Hedef belirtilmeli}"
ALICI_KEY="${3:-A1B2C3D4E5F6G7H8}"
tar -czf - "$KAYNAK" |
gpg --batch
--yes
--trust-model always
--encrypt
--recipient "$ALICI_KEY"
-o "$HEDEF"
echo "Şifreli arşiv hazır: $HEDEF"
Asimetrik şifrelemede gpg-agent parolayı önbelleğe aldığı sürece herhangi bir pin girişi gerekmez. Bu yaklaşımda pass‘e ihtiyacınız olmadığını fark edeceksiniz; gpg-agent‘ın önbelleği tek başına yeterli.
Şifreyi çözmek için:
gpg --batch --yes --decrypt /tmp/nginx-yedek-20240115.tar.gz.gpg | tar -xzf - -C /tmp/restore/
Cron Job Entegrasyonu
Cron’da çalışacak bir arşivleme görevi için birkaç şeyi düzgün ayarlamak gerekiyor. Cron ortamında GPG_AGENT_INFO veya socket bilgisi olmayabilir:
#!/bin/bash
# /usr/local/bin/gece-yedek.sh
set -euo pipefail
LOG_DOSYA="/var/log/yedekleme.log"
TARIH=$(date +%Y%m%d-%H%M%S)
# Log fonksiyonu
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_DOSYA"
}
# GPG agent socket'ini bul veya başlat
if ! pgrep -u "$USER" gpg-agent > /dev/null 2>&1; then
eval $(gpg-agent --daemon --options ~/.gnupg/gpg-agent.conf 2>/dev/null)
log "GPG agent başlatıldı"
fi
# Agent socket'ini ortam değişkenine bağla
GPG_AGENT_SOCK=$(gpgconf --list-dirs agent-socket 2>/dev/null)
export GPG_AGENT_INFO="${GPG_AGENT_SOCK}:0:1"
# Yedekleme dizinleri
YEDEK_DIZINLER=(
"/etc"
"/var/www/html"
"/home"
)
HEDEF_KLASS="/backup/gunluk"
mkdir -p "$HEDEF_KLASS"
for DIZIN in "${YEDEK_DIZINLER[@]}"; do
DIZIN_ADI=$(basename "$DIZIN")
HEDEF_DOSYA="${HEDEF_KLASS}/${DIZIN_ADI}-${TARIH}.tar.gz.gpg"
log "Yedekleniyor: $DIZIN"
if tar -czf - "$DIZIN" 2>/dev/null |
gpg --batch
--yes
--passphrase "$(pass show backup/arsiv-parolasi)"
--symmetric
--cipher-algo AES256
--compress-algo none
-o "$HEDEF_DOSYA"; then
log "Başarılı: $HEDEF_DOSYA"
else
log "HATA: $DIZIN yedeklenemedi"
fi
done
# 30 günden eski yedekleri temizle
find "$HEDEF_KLASS" -name "*.tar.gz.gpg" -mtime +30 -delete
log "Eski yedekler temizlendi"
Crontab’a ekleyin:
crontab -e
0 2 * * * /usr/local/bin/gece-yedek.sh
Preseed Yaklaşımı ile gpg-agent Önbelleğini Doldurma
Bazı senaryolarda, özellikle uzun süre çalışacak otomasyonlarda, agent’ın önbelleğinin dolu olduğundan emin olmak isteyebilirsiniz. Bunun için bir preseed scripti yazabilirsiniz:
#!/bin/bash
# /usr/local/bin/gpg-preseed.sh
# Bu script agent önbelleğini önceden doldurur
PASS_YOLU="backup/arsiv-parolasi"
# Agent'ın çalıştığından emin ol
gpgconf --launch gpg-agent
# Küçük bir test şifrelemesi yaparak önbelleği aktifleştir
echo "test" |
gpg --batch
--yes
--passphrase "$(pass show $PASS_YOLU)"
--symmetric
--cipher-algo AES256
-o /dev/null 2>/dev/null
echo "GPG agent önbelleği hazır"
Bu scripti büyük yedekleme işleminden önce çalıştırarak agent’ın uyanık olduğundan emin olabilirsiniz.
Systemd ile Entegrasyon
Modern Linux sistemlerinde cron yerine systemd timer kullanmak daha iyi bir yaklaşım. Log yönetimi, bağımlılıklar ve başarısızlık yönetimi çok daha temiz:
# /etc/systemd/system/gece-yedek.service
cat > /etc/systemd/system/gece-yedek.service << 'EOF'
[Unit]
Description=Gece Şifreli Yedekleme
After=network.target
Wants=gpg-agent.service
[Service]
Type=oneshot
User=backup-user
Environment="GNUPGHOME=/home/backup-user/.gnupg"
ExecStartPre=/usr/local/bin/gpg-preseed.sh
ExecStart=/usr/local/bin/gece-yedek.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=gece-yedek
[Install]
WantedBy=multi-user.target
EOF
# /etc/systemd/system/gece-yedek.timer
cat > /etc/systemd/system/gece-yedek.timer << 'EOF'
[Unit]
Description=Gece Şifreli Yedekleme Zamanlayıcısı
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable --now gece-yedek.timer
Sorun Giderme
Gerçek hayatta en sık karşılaşılan sorunlar ve çözümleri:
“gpg: cannot open tty” hatası: Headless ortamlarda --batch flag’ini ekleyin ve GPG_TTY değişkenini ayarlayın.
export GPG_TTY=/dev/null
gpg --batch --passphrase-fd 0 ...
Agent bulunamıyor: Socket’i manuel olarak kontrol edin.
gpgconf --list-dirs agent-socket
ls -la $(gpgconf --list-dirs agent-socket)
pass komutu “No such file” diyor: pass deposunun başlatıldığından ve doğru anahtarla şifrelendiğinden emin olun.
pass ls
# Depo listesini gösterir, boşsa init atmışsınızdır ama parola eklememiş olabilirsiniz
Cron’da “no pinentry” hatası: gpg-agent.conf dosyasında allow-loopback-pinentry ve pinentry-program /usr/bin/pinentry-curses satırlarının olduğundan emin olun.
Güvenlik Notları
Bu kurulumu production’a alırken dikkat etmeniz gereken birkaç nokta:
passdeposunu yedekleyin:~/.password-store/dizinini GPG anahtarınızla birlikte güvenli bir yerde saklayın. Anahtar giderse parolalar gider.- Anahtar parola kalitesi: GPG anahtarınızın kendisini koruyan parolayı güçlü tutun.
gpg-agentbu parolayı önbelleğe alıyor ama fiziksel anahtar güvende olmalı. chmodkontrolü: Script dosyalarınız ve.gnupgdizininiz düzgün izinlere sahip olsun.700dizin,600konfigürasyon dosyaları.- Anahtar rotasyonu: GPG anahtarlarınız için bir rotasyon planı yapın. Eski anahtarla şifrelenmiş arşivleri yeni anahtarla yeniden şifrelemeyi unutmayın.
- Log’larda parola bırakmayın: Scriptlerinizde
set -xdebug modunu prod’da kapalı tutun; parola değişkenlerini terminale yazdırmayın.
Sonuç
gpg-agent ve pass kombinasyonu, arşivleme iş akışlarınıza temiz ve güvenli bir parola yönetimi katmanı ekliyor. Plain text parola dosyalarından, environment variable’lara gömülü sırlardan kurtuluyorsunuz. Otomasyon güvenli oluyor, log’larda hassas veri kalmıyor.
Bu yaklaşımın en büyük avantajı ölçeklenebilirlik. Tek bir sunucuda çalışan bir script için overengineering gibi görünebilir ama 20 sunucuda çalışan bir yedekleme altyapısı kurduğunuzda, her makinede tek bir GPG anahtar çiftiyle tüm süreci kontrol edebilmek büyük rahatlık sağlıyor. Vault veya başka gizli yönetim araçlarına geçmeden önce bu kombinas yon çoğu orta ölçekli yapı için fazlasıyla yeterli.
Bir sonraki adım olarak pass deposunu Git ile versiyonlamayı inceleyebilirsiniz; pass git init ile başlayan bu süreç, parola geçmişi ve ekip paylaşımı konularında da kapılar açıyor.
