Kurumsal Network Kurulumu

Switch Yapılandırma Yedeği: Elle ve Otomatik Yedekleme

Switch yapılandırma yedeği nasıl alınır: SFTP ile elle yedek, yalnız değişince kaydeden git deposu ve GitHub'a git-crypt ile şifreli giden gece yedeği.

İlker Pehlivan

Switch yapılandırma yedeği, switch’in çalışan ayarlarının cihazın dışında duran, tarihli bir kopyasıdır. Switch bozulduğunda ya da biri bir ayarı yanlış değiştirdiğinde, cihazı son sağlam hâline döndürmenin yolu budur. Bu yazıda lab switch’imin yedeğini önce elle SFTP ile alıyorum. Sonra her gece kendiliğinden alınacak, yalnız değiştiğinde kaydedilecek ve şifreli bir kopyası GitHub’daki özel bir depoya gidecek biçimde kuruyorum.

Bir süpermarket şubesinde gün sonu kasa defterinin bir kopyası tutulur. Kopya şubenin çekmecesinde durursa şube su bastığında defterle birlikte gider; bu yüzden kopya her akşam merkeze gönderilir ve tarihiyle arşivlenir. Switch’in yedeği de böyledir: kopya cihazın dışında, tarihli ve yalnız yetkilinin açabildiği bir arşivde durmalıdır.

Switch yapılandırma yedeği benzetmesi: şube müdürü günün kasa defterinin kopyasını merkeze gidecek kutuya koyuyor, açık çekmecede eski bir kopya, arkada tarihli klasörlerin durduğu arşiv dolabı
Çekmecedeki kopya şubeyle birlikte kaybolur; her akşam merkeze giden ve tarihiyle arşivlenen kopya yedektir. Switch yedeği de cihazın dışında, tarihli durur.

Bu yazı Kurumsal Network Kurulumu hizmetimizin switch tarafına aittir ve switch yapılandırma rehberimizdeki 18. adımın ayrıntısıdır. Aynı işi müşterilerimizin ağında nasıl yürüttüğümüzü switch kurulumu ve VLAN yapılandırma hizmeti sayfamızda anlattık.

Yedeğin taşındığı protokolü, yani TFTP’nin ağda nasıl göründüğünü ve neden kimlik sormadığını TFTP makalemizde ayrıntısıyla anlattık. Bu yazı yedeğin kendisine odaklanıyor: nereye, nasıl ve ne sıklıkla alındığına. Doğrudan kuruluma geçmek isterseniz otomatik yedek bölümüne, yedeği buluta göndermek için şifreli uzak depo bölümüne atlayabilirsiniz.

Switch Yedeklemede İlk Tuzak: Cihazın İçindeki Kopya

Switch’in belleğinde üç yapılandırma dosyası durur. Çalışan yapılandırma (running-config) o an geçerli olan ayarlardır. Başlangıç yapılandırması (startup-config) switch yeniden açıldığında yüklenen kayıtlı hâldir; ikisinin farkını yönetilebilir switch ayarları yazımızda anlattık. Üçüncüsü backup-config adını taşır ve adı onu yedek gibi gösterir.

Lab switch’imin belleğine baktım:

Switch Konsol Çıktısı
gmsw01#dir
Attr  Size(bytes)          Creation Time        Name
...
  -rw                 3600 Sep 23 2026 14:20:32 startup-config
  -rw                 2065 Aug 20 2026 02:50:49 backup-config
...

backup-config bir ay önce yazılmış. İki dosyanın içeriğini karşılaştırdım. Başlangıç yapılandırması 255 satır, backup-config ise 132 satır. backup-config’te switch’in adı hâlâ eski adı olan sistemkusu-sw01; bugün kurulan yedi VLAN’dan ve saat senkronizasyonundan hiçbiri yok. Switch bu dosyayı kendiliğinden güncellemiyor.

Bu kopyanın iki kusuru var. Birincisi bayatlamasıdır; kimse güncellemediği sürece geride kalır. İkincisi daha ağırdır: dosya switch’in kendi belleğindedir. Switch bozulduğunda, yandığında ya da çalındığında yedeği de onunla gider. Çekmecedeki defter kopyası su baskınında defterle birlikte ıslanır.

Switch Yapılandırma Yedeği Hangi Protokolle Alınır?

Yedeğin cihazın dışına çıkması gerekiyor. Lab switch’imin bu iş için sunduğu yolları yardım ekranından okudum:

Switch Konsol Çıktısı
gmsw01#copy running-config ?
<url>                    Uploads Code using
                         tftp://<ipaddress|hostname>/<filepath>/<filename> |
                         ftp://<user>@<ipaddr|hostname>/<path>/<filename> |
                         scp://<user>@<ipaddr|hostname>/<path>/<filename> |
                         sftp://<user>@<ipaddr|hostname>/<path>/<filename>|
                         flash://<filename> | usb://<filepath>/<filename>}.
backup-config            Copies system config file.
startup-config           Copies system config file.

Dört ağ protokolü var: TFTP, FTP, SCP ve SFTP. İlk ikisi yapılandırmayı şifrelemeden taşır ve TFTP kimlik bile sormaz. SCP ve SFTP ise SSH’ın içinden geçer, yani hem şifreli taşır hem de sunucuda bir hesapla oturum açar. İki grubun ağda nasıl göründüğünü TFTP ile SFTP’yi aynı dosyayla yakaladığımız bölümde gösterdik.

Protokol seçimi bir kolaylık meselesi değil, çünkü yedeğin içinde ne olduğunu bilmek gerekiyor. Lab switch’imin yapılandırmasında iki gizli satır var. Biri SNMP community string’idir ve düz metin durur; bunu TFTP makalemizde paket dökümünden okumuştuk. Öbürü yönetici hesaplarının parola özetidir:

Çıktı
username "yedekci" password 3ce569af...b5c4 privilege 1 encrypted

Bu hesabı ve parolasını ben açtım, yani parolayı biliyorum. Parolanın MD5 hash’ini kendim hesapladım ve sonuç satırdaki değerle birebir aynı çıktı (değerin ortasını burada kısalttım). Bu switch parolaları salt eklenmemiş MD5 olarak saklıyor, yani hash’e her parolaya özgü rastgele bir değer katılmıyor. Böyle bir hash, bilinen parola listeleriyle çevrimdışı denenebilir. Yedek dosyasını ele geçiren biri, switch’e hiç dokunmadan yönetici parolasını bulmaya çalışabilir.

Kural bu yüzden tek cümledir: switch yedeği şifreli bir yoldan, yalnız yedek için açılmış bir hesaba gönderilir ve gizli belge gibi saklanır.

Elle Yedek: Switch’ten SFTP Sunucusuna

İlk yedeği elle alıyorum. Yedeğin gideceği sunucu, lab’da merkezi log için kurduğumuz sistemkusu-syslog adlı Ubuntu sunucusu. Bu bölüm o sunucunun zaten ayakta olduğunu varsayar; Ubuntu kurulumunu Ubuntu Server kurulum rehberimizde anlattık.

Sunucuda önce yedek için ayrı bir hesap açıyorum. Bu hesap oturum açıp komut çalıştıramayacak, yalnız SFTP konuşacak ve tek bir dizinin dışına çıkamayacak:

Bash
sudo useradd -M -d /srv/switch-yedek -s /usr/sbin/nologin swyedek
sudo passwd swyedek
sudo mkdir -p /srv/switch-yedek/gelen
sudo chown root:root /srv/switch-yedek
sudo chown swyedek:swyedek /srv/switch-yedek/gelen
sudo chmod 750 /srv/switch-yedek/gelen

SSH sunucusuna da bu hesabın yalnız SFTP konuşacağını ve /srv/switch-yedek’e hapsolacağını söylüyorum. Dosya /etc/ssh/sshd_config.d/50-swyedek.conf:

Yapılandırma
Match User swyedek
    ChrootDirectory /srv/switch-yedek
    ForceCommand internal-sftp
    PasswordAuthentication yes
    AllowTcpForwarding no
    X11Forwarding no

ChrootDirectory hesabı o dizine hapseder ve dizinin sahibi root olmak zorundadır; hesabın yazabildiği yer bu yüzden alt dizin gelen’dir. ForceCommand internal-sftp hesabın kabuk açmasını engeller. Ayarı sudo sshd -t ile sınayıp sudo systemctl reload ssh ile yüklüyorum.

Switch tarafında yedek tek komuttur:

Switch Konsolu
copy running-config sftp://swyedek@192.168.1.46/gelen/gmsw01-running.cfg

Switch parolayı ve onayı soruyor, sonra aktarımı yapıyor:

Switch Konsol Çıktısı
Remote Password:*********
Transfer Mode.................................. SFTP
Server IP Address.............................. 192.168.1.46
Destination File Path.......................... gelen/
Destination Filename........................... gmsw01-running.cfg
Data Type...................................... Config Script
Source Filename................................ running-config
Management access will be blocked for the duration of the transfer
Are you sure you want to start? (y/n) y
3507 bytes transferred
File transfer operation completed successfully.

Bu çıktıda bakılacak üç satır var:

  1. 3507 bytes transferred, sunucudaki dosyanın boyutuyla karşılaştırılır. Sunucuda ls -l aynı sayıyı, 3.507 baytı gösterdi. Boyutu sıfır ya da çok küçük bir yedek, “başarılı” dense bile boştur; bu tuzağı TFTP makalemizde ölçtük.
  2. Management access will be blocked for the duration of the transfer, aktarım bitene kadar switch’e yeni bir yönetim oturumu açılamayacağını söyler. Trafik etkilenmez, yalnız yönetim erişimi kısa bir süre kapanır.
  3. Sunucunun kaydı, yedeğin gerçekten beklenen hesapla geldiğini doğrular: sshd günlüğünde Accepted password for swyedek from 192.168.1.2 satırı var.

Otomatik Switch Yedeği: Her Gece, Yalnız Değiştiyse

Elle yedek, onu almayı hatırlayan birine bağlıdır. Unutulan tek bir değişiklik, bir sonraki arızada eksik yedek demektir. Otomatik yedeği bu yüzden tersinden kuruyorum: sunucu her gece switch’e bağlanıp yapılandırmayı kendisi çekiyor ve yalnız bir şey değiştiyse yeni bir sürüm kaydediyor.

Sürümleri git deposunda tutuyorum, çünkü git iki sürüm arasındaki farkı satır satır gösterir. Aynı depo, kopyayı binanın dışına taşımanın da yolu; bunu yazının sonunda GitHub’a göndererek yapıyorum.

Switch Tarafı: Yedek Kullanıcısı ve Anahtar

Sunucu switch’e parolayla değil, SSH anahtarıyla bağlanacak; böylece bir betiğin içinde parola durmaz. Anahtarla girişin nasıl çalıştığını SSH makalemizde anlattık. Sunucuda bir anahtar çifti üretip açık anahtarı switch’e yedek kullanıcısıyla birlikte tanıtıyorum:

Switch Konsolu
configure
username yedekci password <parola> privilege 15
crypto key pubkey-chain ssh user-key yedekci rsa
key-string "ssh-rsa AAAA... gmsw01-yedek@sistemkusu-syslog"
exit
exit
ip ssh pubkey-auth
exit

Son satır önemli, çünkü lab switch’imde açık anahtarla giriş varsayılan olarak kapalıydı (SSH Public Key Authentication is disabled). Bu ayar erişimi kesebilir mi diye düşünerek, değişikliği yaparken ayrı bir SSH oturumunu açık tuttum. Ayar parolayla girişi etkilemedi; yeni parola oturumu sorunsuz açıldı.

Kullanıcıyı önce en düşük yetkiyle, 1. seviyeyle açmıştım. Burada bir bulgu çıktı: lab switch’imde enable parolası tanımlı değildi ve 1. seviyedeki yedekci, enable komutuyla parola sorulmadan en yüksek yetkiye çıkabildi. Yetki seviyeleri enable parolası olmadan bir şey ayırmıyordu.

Bu açığı switch sıkılaştırma yazımızda kapattım: enable parolası tanımlandı ve yedekci açıkça 15. seviyeye alındı. Yapılandırmanın tamamını okumak bu switch’te 15. seviye istiyor. Bu yetkiyi parolasız bir enable’ın arkasına saklamak yerine açıkça vermek, hangi hesabın neyi okuyabildiğini yapılandırmada görünür kılıyor. Hesabın yalnız anahtarla ve yalnız yedek sunucusundan girebilmesi de bu yetkinin karşılığıdır.

Eski Switch, Yeni SSH İstemcisi

İlk bağlantı denemesi hata verdi:

Bash
$ ssh -tt -i ~/.ssh/gmsw01_yedek -o BatchMode=yes yedekci@192.168.1.2
Unable to negotiate with 192.168.1.2 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

Switch’in SSH sunucusu yalnız ssh-rsa ve ssh-dss türünde host anahtarı sunuyor. Ubuntu 24.04’teki OpenSSH 9.6 ikisini de varsayılan olarak kabul etmiyor, çünkü ikisi de SHA-1 imzasına dayanıyor. Eski algoritmayı sistemin tamamında açmak yerine yalnız bu switch için açıyorum. Dosya ~/.ssh/config:

Yapılandırma
Host gmsw01
    HostName 192.168.1.2
    User yedekci
    IdentityFile ~/.ssh/gmsw01_yedek
    IdentitiesOnly yes
    HostKeyAlgorithms +ssh-rsa
    PubkeyAcceptedAlgorithms +ssh-rsa

Asıl çözüm switch’in yazılımını güncellemektir. O yapılana kadar gevşetmenin yalnız bir host’la sınırlı kalması, sunucunun öbür bağlantılarını korur.

Sunucu Tarafı: Git Deposunu Hazırlamak

Yedeklerin duracağı depoyu betikten önce kuruyorum. Ubuntu Server’da git kurulu gelir; lab sunucusunda git --version komutu git version 2.43.0 döndürdü. Sizde dönmüyorsa sudo apt install git ile kurabilirsiniz. Yedeği buluta şifreli göndermek için bir paket daha gerekiyor, git-crypt:

Bash
sudo apt install git-crypt
sudo install -d -m 700 -o sistemkusu -g sistemkusu /srv/switch-yedek/depo
cd /srv/switch-yedek/depo
git init -b main
git config user.name "switch-yedek"
git config user.email "switch-yedek@sistemkusu-syslog"
git-crypt init
echo "*.cfg filter=git-crypt diff=git-crypt" > .gitattributes
git add .gitattributes
git commit -m "cfg dosyalari sifreli"

Üç yer açıklama ister:

  1. install -d -m 700 dizini yalnız sahibinin açabileceği biçimde kurar. Git’in geçmişi ayrı dosyalarda durduğu için dosyayı değil dizini kapatmak gerekir; nedenini deponun korunmasını anlattığım bölümde ölçtüm.
  2. user.name ve user.email her kaydın altına yazılacak adı belirler. Kayıtları yedek betiği açtığı için bu ad betiğin adıdır. Git bu yüzden neyin ne zaman değiştiğini söyler; kimin değiştirdiğini switch’in kendi günlüğü söyler.
  3. git-crypt init ve .gitattributes satırı, adı .cfg ile biten her dosyanın depoya şifreli girmesini sağlar. Sunucudaki dosya okunur kalır. Yedeği buluta göndermeyecekseniz git-crypt satırlarını atlayabilirsiniz. Gönderecekseniz şifrelemeyi şimdi, ilk yedekten önce açın; sonradan açmanın eski sürümleri korumadığını aşağıda ölçtüm.

Sunucu Tarafı: Betik ve Zamanlama

Betik yapılandırmayı çekiyor, boş ya da yarım geldiyse yazmayı reddediyor, yalnız değiştiyse yeni bir sürüm kaydediyor ve bekleyen sürümleri uzak depoya gönderiyor. Dosya /usr/local/bin/switch-yedek.sh:

Bash
#!/bin/bash
# Switch yapilandirmasini SSH ile ceker, git deposuna yalniz degistiyse kaydeder
# ve bekleyen kayitlari uzak depoya gonderir.
set -euo pipefail
DEPO=/srv/switch-yedek/depo
CIHAZ=gmsw01
GECICI=$(mktemp)
trap 'rm -f "$GECICI"' EXIT

printf 'terminal length 0\nshow running-config\nexit\n' \
  | timeout 60 ssh -tt -o BatchMode=yes "$CIHAZ" 2>/dev/null \
  | tr -d '\r' \
  | awk '/^!Current Configuration:/{f=1} f && /^'"$CIHAZ"'[#>]/{exit} f' > "$GECICI" || true

# Bos ya da yarim bir ciktiyi yedek diye kaydetme: basi, sayfalamayi ve sonu denetle
SON=$(grep -v '^[[:space:]]*$' "$GECICI" | tail -n 1 || true)
if ! grep -q '^hostname "'"$CIHAZ"'"' "$GECICI" \
   || grep -q -- '--More--' "$GECICI" \
   || [ "$SON" != "exit" ]; then
  logger -t switch-yedek "$CIHAZ: yapilandirma eksik ya da alinamadi, onceki yedek korunuyor"
  exit 1
fi

cp "$GECICI" "$DEPO/$CIHAZ.cfg"
cd "$DEPO"
git add "$CIHAZ.cfg"
if git diff --cached --quiet; then
  logger -t switch-yedek "$CIHAZ: degisiklik yok"
else
  git commit -q -m "$CIHAZ $(date -u '+%Y-%m-%d %H:%M UTC')"
  logger -t switch-yedek "$CIHAZ: yeni surum kaydedildi"
fi

# Degisiklik olmasa da gonder: onceki gecelerden bekleyen kayitlar da gider
if timeout 120 git push -q origin main 2>/dev/null; then
  logger -t switch-yedek "$CIHAZ: uzak depo guncel"
else
  logger -t switch-yedek "$CIHAZ: uzak depoya gonderilemedi, kayitlar yerelde bekliyor"
fi

Betiği güvenilir yapan iki denetim var:

  1. İçerik denetimi yarım yedeği reddeder. Çıktıda switch’in hostname satırı olmalı, içinde sayfalama işareti --More-- bulunmamalı ve son satırı yapılandırmanın kapanışı olan exit olmalıdır. Böylece switch’e ulaşılamadığında ya da çıktı yarım kaldığında eksik bir dosya iyi yedeğin üstüne yazılmaz. Denetimin ilk hâli yalnız hostname satırına bakıyordu; bunun yetmediğini aşağıda ölçtüm.
  2. git diff --cached --quiet boş kaydı önler. Yapılandırma değişmediyse yeni kayıt açılmaz.

Her sonuç logger ile sistem günlüğüne düşüyor; günlüğü merkezi log sunucusuna gönderiyorsanız başarısız bir gece orada görünür.

Son blok sürümleri uzak depoya gönderiyor. Uzak depoyu yazının sonunda bağlıyorum. Bağlanana kadar bu blok günlüğe yalnız uzak depoya gonderilemedi yazar ve yerel yedeğe dokunmaz.

Betiği her gece 02.15’te çalıştırmak için tek bir cron satırı yeterli:

15 2 * * * /usr/local/bin/switch-yedek.sh

Saat UTC’dir, çünkü sunucu UTC’de çalışıyor. Saat diliminin log ve zamanlama üzerindeki etkisini switch NTP server ayarı yazımızda ölçtük.

Otomatik Yedeği Sınamak: Değişiklik, Değişmeme ve Ulaşılamayan Cihaz

Bir yedek betiği, yalnız her şey yolundayken çalıştığı görülerek sınanmış sayılmaz. Üç durumu tek tek denedim.

Birincisi, hiçbir şey değişmediğinde. Betiği ilk çalıştırmanın hemen ardından ikinci kez çalıştırdım. Depoda yeni kayıt açılmadı ve günlüğe gmsw01: degisiklik yok yazıldı.

İkincisi, bir ayar değiştiğinde. Boş bir porta, Gi1/0/48’e bir açıklama yazdım ve betiği çalıştırdım. Yeni bir sürüm kaydedildi ve git farkı tam o satırı gösterdi:

Çıktı
@@ -248,4 +248,5 @@ exit
 !
 interface Gi1/0/48
+description "YEDEK-DENEMESI"
 switchport access vlan 999
 exit

Açıklamayı geri aldığımda bu da ayrı bir sürüm oldu. Deponun geçmişi artık neyin ne zaman değiştiğini sorduğunuz yer. Bir arızada “dün ne değişti?” sorusunun cevabı git log ile iki sürüm arasındaki farktır.

Üçüncüsü, switch’e ulaşılamadığında. Betiği var olmayan bir cihaz adıyla çalıştırdım:

Bash
$ bash /tmp/deneme-yedek.sh; echo "cikis $?"
cikis 1
$ journalctl -q -t switch-yedek --no-pager | tail -1
Sep 27 02:48:24 sistemkusu-syslog switch-yedek[3129]: gmsw99: yapilandirma eksik ya da alinamadi, onceki yedek korunuyor

Betik hata koduyla çıktı, günlüğe nedenini yazdı ve depodaki son iyi yedeğe dokunmadı. Kasa defterinin gelmediği bir akşam, merkez dünkü kopyanın üstüne boş bir sayfa koymaz.

Dördüncüsü, switch sıkılaştırıldıktan sonra. Bu senaryoyu ben kurmadım, kendiliğinden çıktı. Switch’e enable parolası tanımladıktan ve yedekci’yi 15. seviyeye aldıktan sonra betik yine başarıyla bitti ve yeni bir sürüm kaydetti. Ama sürüm yarımdı: dosya 209 satırdı, yapılandırmanın sonu yoktu ve içinde 11 kez --More-- geçiyordu.

Nedeni betiğin o zamanki ilk satırıydı. 15. seviyedeki hesap enable yazınca switch artık parola sordu ve betiğin sonraki satırı olan terminal length 0 parola diye yutuldu. Sayfalama açık kaldı ve çıktı ilk sayfadan sonra kesildi. Denetim yalnız hostname satırına bakıyordu ve o satır ilk sayfadaydı; yarım yedek iyi yedek diye kaydedildi.

Betikten enable satırını çıkardım ve denetime sayfalama ile son satır koşullarını ekledim. Aynı hatayı betiğin son hâliyle yeniden üretmek için enable satırını geri koydum. Switch yine parola sordu, terminal length 0 yine parola diye yutuldu ve yeni denetim yedeği reddetti:

Bash
$ journalctl -q -t switch-yedek --no-pager | tail -1
Sep 27 02:48:26 sistemkusu-syslog switch-yedek[3145]: gmsw01: yapilandirma eksik ya da alinamadi, onceki yedek korunuyor

Düzeltilmiş betiğin aldığı yedek 279 satırdı ve hiç --More-- içermiyordu. Bir yedeğin tam olduğunu anlamak için başına değil sonuna bakmak gerekir.

Yedek Deposunu Korumak: Dosya Kapalı, Geçmiş Açık

Kurulumda depo dizinini baştan 700 izniyle açtım. Nedeni ilk kurulumdaki bir denetimdi. Yedek dosyasının parola hash’leri taşıdığını yukarıda gördük ve depoyu bu gözle denetledim. Yapılandırma dosyasının izni -rw------- idi, yani yalnız sahibi okuyabiliyordu; betik dosyayı sıkı izinle açılan geçici bir dosyadan kopyaladığı için böyle olmuştu. Ama deponun dizini varsayılan izinle, drwxr-xr-x açılmıştı ve git’in geçmişi ayrı dosyalarda tutuluyordu:

Bash
$ ls -l .git/objects/2c/9425e9fca1339a0611dbef6a1717af8743d51c
-r--r--r-- 1 sistemkusu sistemkusu 144 Sep 23 15:11 .git/objects/2c/9425e9fca1339a0611dbef6a1717af8743d51c
$ sudo -u nobody cat /srv/switch-yedek/depo/.git/objects/2c/9425e9fca1339a0611dbef6a1717af8743d51c >/dev/null 2>&1 && echo "nobody git nesnesini OKUYABİLİYOR" || echo "nobody git nesnesini okuyamıyor"
nobody git nesnesini OKUYABİLİYOR

Sunucudaki yetkisiz bir kullanıcı, yapılandırma dosyasını okuyamasa da geçmişteki her sürümü okuyabiliyordu. Dizini chmod 700 ile kapattıktan sonra aynı deneme başarısız oldu. Yedeği korumak dosyayı korumak değil, deponun tamamını korumaktır.

git-crypt bu korumanın yerini tutmaz. Şifreleme anahtarı da sunucuda, .git dizininin içinde durur; dizini okuyabilen biri anahtarı da okur. Şifreleme yalnız sunucudan çıkan kopyayı korur.

Switch Yedeğini Buluta Göndermek: Şifreli Uzak Depo

Yedek artık cihazın dışında, tarihli ve kapalı bir dizinde duruyor. Ama bu sunucu switch’le aynı binada. Şubenin arka ofisindeki arşiv dolabı tarihli kopyaları düzenli tutar; şube su basarsa dolap da gider. Kopyanın merkeze gitmesi gerekir. 3-2-1 kuralının bir kopyayı başka bir yerde tutma şartı da budur. Lab’da bunun için GitHub’da özel bir depo açtım ve sunucudaki depoyu ona bağladım.

Yalnız Bu Depoya Yazabilen Anahtar: Deploy Key

Sunucuya GitHub hesabımın anahtarını vermedim. Hesabın anahtarı, sunucuyu ele geçiren birine hesaptaki bütün depoları açar. Onun yerine yalnız bu depoya yazabilen bir deploy key ürettim. GitHub’ın host anahtarını da ilk bağlantıda körü körüne kabul etmedim:

Bash
ssh-keygen -t ed25519 -N "" -C "switch-yedek@sistemkusu-syslog" -f ~/.ssh/github_switch_yedek
ssh-keyscan -t ed25519 github.com > /tmp/gh.kh
ssh-keygen -l -f /tmp/gh.kh
Çıktı
256 SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU github.com (ED25519)

Bu parmak izini GitHub’ın SSH anahtarı parmak izleri sayfasında yayımladığı değerle karşılaştırdım. Eşleştiğini gördükten sonra /tmp/gh.kh dosyasını ~/.ssh/known_hosts’a ekledim. Sunucunun SSH ayarına da bu depo için ayrı bir blok yazdım:

Yapılandırma
Host github-switch-yedek
    HostName github.com
    User git
    IdentityFile ~/.ssh/github_switch_yedek
    IdentitiesOnly yes
    ConnectTimeout 15

ConnectTimeout 15, internet kesildiğinde gönderme denemesinin geceyi bekletmemesi içindir. Açık anahtarı depoya deploy key olarak ekledim ve yazma iznini açtım. GitHub’da bu iş deponun Settings → Deploy keys sayfasında, Allow write access kutusu işaretlenerek yapılır; ben aynı işi gh repo deploy-key add komutuyla yaptım. Sonra depoyu uzak depo olarak tanıttım ve ilk gönderimi yaptım:

Bash
cd /srv/switch-yedek/depo
git remote add origin git@github-switch-yedek:ilkerserce/switch-yedek-lab.git
git push -u origin main

Anahtarın sınırını iki denemeyle ölçtüm. Önce hesabımdaki başka bir özel depoyu okumayı denedim, sonra GitHub’a kimin bağlandığını sordum:

Bash
$ git ls-remote git@github-switch-yedek:ilkerserce/sistemkusu.com.git
ERROR: Repository not found.
fatal: Could not read from remote repository.
$ ssh -T github-switch-yedek
Hi ilkerserce/switch-yedek-lab! You've successfully authenticated, but GitHub does not provide shell access.

GitHub bu anahtarla bağlananı bir kullanıcı olarak değil, depo olarak tanıyor. Aynı hesaptaki öbür özel depoyu ise hiç görmüyor. Sunucu ele geçirilirse kaybedilecek şey yalnız bu depodur.

Buluta Giden Dosya Şifreli Gider: git-crypt

Kurulumda açtığım git-crypt, adı .cfg ile biten dosyayı depoya şifreli koyuyor. GitHub’a giden de bu şifreli kopya. Betiğin ilk gönderiminden sonra dosyayı GitHub’dan indirip ilk baytlarına baktım:

Bash
$ gh api repos/ilkerserce/switch-yedek-lab/contents/gmsw01.cfg --jq .content | base64 -d | head -c 32 | od -An -c
  \0   G   I   T   C   R   Y   P   T  \0   \ 264  \r 030 243 025
   t   \   j 032 364 371   h   9   F 027  \0 251   G 361  \r 264

Dosya git-crypt’in \0GITCRYPT\0 başlığıyla başlıyor. İçinde hostname sözcüğünü aradım, bir kez bile geçmiyor. Sunucudaki çalışma kopyası ise düz metin:

Bash
$ head -1 gmsw01.cfg
!Current Configuration:
$ git-crypt status
not encrypted: .gitattributes
    encrypted: gmsw01.cfg

Şifreleme betiğin değişiklik denetimini bozmadı. git-crypt aynı dosyayı her seferinde aynı biçimde şifreliyor; değişmeyen gecede betik yine degisiklik yok yazdı ve yeni kayıt açmadı. Sunucuda iki sürüm arasındaki fark da düz metin okunuyor, aşağıdaki kesinti ölçümünde görünüyor.

Şifrelemeyi Sonradan Açmak Geçmişi Korumaz

İlk kurulumda depoyu şifresiz açmıştım ve içinde 23 Eylül’den kalma beş sürüm vardı. O deponun bir kopyasında şifrelemeyi sonradan açtım. .gitattributes satırını eklemek tek başına yetmedi; var olan dosya ancak yeniden eklenince şifrelendi ve git-crypt bir uyarı yazdı:

Bash
$ git-crypt status -f
Staged 1 encrypted file.
Warning: if these files were previously committed, unencrypted versions still exist in the repository's history.

Sonra her sürümün ilk baytlarına baktım:

Çıktı
2b062b8 yeniden sifrele   \0 G I T C R Y P T \0
e1388b0 gmsw01 2026-09-23 16:09 UTC   ! C u r r e n t C
5600db1 gmsw01 2026-09-23 16:07 UTC   ! C u r r e n t C
931d11e gmsw01 2026-09-23 15:12 UTC   ! C u r r e n t C
5c26b95 gmsw01 2026-09-23 15:11 UTC   ! C u r r e n t C
2c9425e gmsw01 2026-09-23 15:11 UTC   ! C u r r e n t C

Yalnız şifrelemeden sonraki sürüm şifreli. Bu depoyu GitHub’a göndermek, düz metin beş sürümü de göndermek olurdu. Bu yüzden eski depoyu sunucuda arşive aldım ve buluta giden depoyu şifreleme açık olarak baştan kurdum. Yedeği bir gün başka bir yere göndermeyi düşünüyorsanız şifrelemeyi ilk yedekten önce açın.

Şifreleme Anahtarı Sunucunun Dışında Durur

Şifreli kopyanın bir bedeli var: anahtarı olmayan, yedeği de açamaz. Sunucu yanarsa içindeki anahtar da onunla gider. Bu yüzden anahtarı dışa aktardım:

Bash
git-crypt export-key /home/sistemkusu/switch-yedek.key

Dosya 148 bayt. Onu bir parola yöneticisine ya da çevrimdışı bir yere koyun, sunucuda bırakmayın. Lab’da iş istasyonuma aldım ve sunucudaki kopyayı shred -u ile sildim.

Anahtarın işe yaradığını görmek için depoyu GitHub’dan boş bir dizine klonladım. Yeni klon sunucunun anahtarını taşımaz, yani başka bir makinedeki klonla aynı durumdadır:

Bash
$ git clone -q git@github-switch-yedek:ilkerserce/switch-yedek-lab.git /tmp/geri
$ cd /tmp/geri
$ head -c 10 gmsw01.cfg | od -An -c
  \0   G   I   T   C   R   Y   P   T  \0
$ git-crypt unlock /tmp/switch-yedek.key
$ head -1 gmsw01.cfg
!Current Configuration:
$ cmp gmsw01.cfg /srv/switch-yedek/depo/gmsw01.cfg && echo "sunucudaki yedekle BIREBIR AYNI"
sunucudaki yedekle BIREBIR AYNI

Anahtarsız klon şifreliydi. Anahtarla açılan dosya, sunucudaki yedekle bayt bayt aynı çıktı.

İnternet Kesikken: Bekleyen Kayıt Ertesi Gece Gider

Gönderme bloğu betiğin sonunda, değişiklik denetiminin dışında duruyor. Nedeni bir kesinti senaryosu. Gönderme yalnız yeni sürüm olan gece çalışsaydı, gönderilemeyen bir sürüm switch’teki bir sonraki değişikliğe kadar yerelde beklerdi. Bunu ölçmek için sunucunun internete giden SSH trafiğini kestim; switch’e giden yerel yol açık kaldı. Sonra switch’te boş bir porta açıklama yazdım ve betiği çalıştırdım:

Bash
$ sudo iptables -I OUTPUT -p tcp --dport 22 ! -d 192.168.0.0/16 -j DROP
$ /usr/local/bin/switch-yedek.sh
$ journalctl -q -t switch-yedek --no-pager | tail -2
Sep 27 02:49:15 sistemkusu-syslog switch-yedek[3354]: gmsw01: yeni surum kaydedildi
Sep 27 02:49:30 sistemkusu-syslog switch-yedek[3380]: gmsw01: uzak depoya gonderilemedi, kayitlar yerelde bekliyor
$ git -C /srv/switch-yedek/depo status -sb | head -1
## main...origin/main [ahead 1]

Sürüm yerelde kaydedildi. Gönderme, SSH ayarındaki 15 saniyelik bağlantı süresinin sonunda düştü ve depo GitHub’dakinin bir kayıt önünde kaldı. Ardından ertesi geceyi taklit ettim: kuralı kaldırdım, switch’te hiçbir şey değiştirmedim ve betiği yeniden çalıştırdım:

Bash
$ sudo iptables -D OUTPUT -p tcp --dport 22 ! -d 192.168.0.0/16 -j DROP
$ /usr/local/bin/switch-yedek.sh
$ journalctl -q -t switch-yedek --no-pager | tail -2
Sep 27 02:49:40 sistemkusu-syslog switch-yedek[3577]: gmsw01: degisiklik yok
Sep 27 02:49:43 sistemkusu-syslog switch-yedek[3584]: gmsw01: uzak depo guncel

Switch değişmediği hâlde bekleyen sürüm gitti. Sunucunun ve GitHub’ın son kaydını yan yana yazdırdım:

Çıktı
yerel HEAD: c151d1f
GitHub main: c151d1f

Gönderilen sürümün farkı sunucuda düz metin okunuyor; GitHub’da aynı sürüm şifreli duruyor:

Çıktı
c151d1f gmsw01 2026-09-27 02:49 UTC
@@ -251,6 +251,7 @@ exit
 !
 interface Gi1/0/48
 shutdown
+description "YEDEK-DENEMESI"
 switchport access vlan 999
 exit
 !

Açıklamayı switch’ten geri aldım. Betik bunu da yeni bir sürüm olarak kaydetti ve gönderdi.

Zorla Göndermeye Karşı Koruma GitHub Pro İstiyor

Uzak depo bir yedek gibi davranmalı, bir senkronizasyon gibi değil. Yani sunucudaki bir hata ya da sunucuyu ele geçiren biri buluttaki geçmişi silememeli. Git’te geçmişi silmenin yolu zorla göndermedir (git push --force). GitHub bunu dal korumasıyla ya da kural setiyle (ruleset) kapatır. İkisini de lab deposunda açmayı denedim ve iki denemede de aynı cevabı aldım:

Çıktı
{"message":"Upgrade to GitHub Pro or make this repository public to enable this feature.","documentation_url":"https://docs.github.com/rest/branches/branch-protection#update-branch-protection","status":"403"}
{"message":"Upgrade to GitHub Pro or make this repository public to enable this feature.","documentation_url":"https://docs.github.com/rest/repos/rules#create-a-repository-ruleset","status":"403"}

Ücretsiz hesapta özel depo bu korumayı alamıyor. GitHub iki yol gösteriyor: GitHub Pro ya da depoyu herkese açmak. Yedek deposunu herkese açmak bir seçenek değil. Korumasız depoda neyin mümkün olduğunu da ölçtüm. Depoyu sunucuda ayrı bir dizine klonladım, son üç kaydı sildim ve sunucunun deploy key’iyle zorla gönderdim:

Bash
$ git reset -q --hard HEAD~3
$ git push --force origin main
...
 + 674ca88...7bdc332 main -> main (forced update)

GitHub’daki dört kayıttan üçü silindi. Bir sonraki çalıştırmada geri geldiler, çünkü sunucudaki depo sağlamdı ve betik eksik kayıtları yeniden gönderdi. Yani korumasız uzak depo, sunucu ayakta kaldığı sürece yedektir. Sunucuyu ele geçiren biri önce buluttaki geçmişi silip sonra sunucuyu bozarsa iki kopya birden gider.

Bu korumayı GitHub’da açmak için GitHub Pro gerekiyor. Kendi git sunucunuzda aynı koruma git’in receive.denyNonFastForwards ayarıyla açılır; bunu bu lab’da ölçmedim.

Switch Yedeğinde Sık Yapılan Hatalar

  • Cihazdaki kopyayı yedek saymak. backup-config switch’le birlikte bozulur ve kendiliğinden güncellenmez; lab’dakinin bir aylık olduğunu gördük.
  • Yedeği TFTP ile almak. Dosya kimlik sorulmadan ve şifresiz taşınır, içinde parola hash’leri ve SNMP community string’i vardır.
  • Yönetici hesabını yedek için kullanmak. Betikte yönetici parolası durur. Ayrı bir kullanıcı ve SSH anahtarı bu riski kaldırır.
  • Merkezi kimliğe geçerken yedek hesabını unutmak. Switch girişi TACACS+‘a bağlanınca yedek hesabı da o sunucuya sorulur; lab’da tanımlı olmadığı için yedek durdu. Bunu switch TACACS+ yapılandırması yazımızda ölçtük.
  • Boş ya da yarım yedeği iyi yedeğin üstüne yazmak. Çıktının yalnız başı değil sonu da denetlenmeli; lab’da ilk sayfası tam, sonu kesik bir yedek “başarılı” diye kaydedildi.
  • Switch’i değiştirip yedeği sınamamak. Sıkılaştırma, yetki ya da kimlik değişikliğinden sonra yedek betiği elle bir kez çalıştırılmalı; lab’da enable parolası betiği sessizce bozdu.
  • Yönetim adresini değiştirip yedek hedefini unutmak. Lab switch’imin adresi yönetim VLAN’ına taşınınca yedek betiği eski adrese gitti ve No route to host aldı. HostName düzelince bu kez Host key verification failed geldi, çünkü sunucu switch’in anahtarını eski adresle tanıyordu. İki adresin sunduğu parmak izi aynıydı; bunu gördükten sonra yeni adresi tanıttım.
  • Depoyu herkese açık bırakmak. Dosya korumalı olsa da git geçmişi ayrı dosyalarda durur; dizinin tamamı kapatılmalı.
  • Şifrelemeyi sonradan açmak. Eski sürümler düz metin kalır ve uzak depoya onlar da gider.
  • Şifreleme anahtarını yalnız sunucuda tutmak. Sunucu kaybolursa buluttaki şifreli yedek açılamaz.
  • Eski algoritmayı her yerde açmak. Eski bir switch için SSH ayarı gevşetilecekse bu yalnız o cihaza özgü bir blokta yapılmalı.
  • Geri yüklemeyi hiç denememek. Bir yedeğin işe yaradığını ancak geri yükleme gösterir. Bu yazıda dosyanın buluttan anahtarla geri alınmasını denedim. Dosyayı boş bir switch’e yükleyip sonucu karşılaştırmak ise düzenli yapılması gereken ayrı bir sınamadır.

Sonuç: Yedek Cihazın Dışında, Tarihli ve Korumalı Durur

Switch yapılandırma yedeği üç şartı birlikte sağladığında işe yarar. Cihazın dışında durmalı, çünkü cihazla birlikte giden kopya yedek değildir. Tarihli olmalı, çünkü bir arızada asıl soru “dün ne değişti?” sorusudur. Korumalı olmalı, çünkü lab switch’imde yapılandırma dosyası yönetici parolalarının salt eklenmemiş MD5 hash’ini taşıyordu.

Kasa defterinin kopyası da her akşam merkeze gider, tarihiyle arşivlenir ve yalnız yetkili personelin erişebildiği bir yerde durur. Bu yazıdaki betik aynı işi her gece kendiliğinden yapıyor. Yalnız bir şey değiştiğinde yeni bir sayfa açıyor ve kopyayı şifreli olarak binanın dışına gönderiyor.

Yedeğin bir switch’i canlıya alma sırasındaki yerini switch yapılandırma rehberimizde gösterdik. Yedeğin kurumsal ağ projesindeki yerini Kurumsal Network Kurulumu sayfamızda anlattık.

Switch Yapılandırma Yedeği Hakkında Sık Sorulan Sorular

Her yapılandırma değişikliğinden sonra bir yedek alınmalı; bunun yanında her gece otomatik bir yedek, unutulan değişikliği yakalar. Otomatik yedeği yalnız yapılandırma değiştiğinde yeni sürüm kaydedecek biçimde kurmak, gece yüzlerce aynı dosyanın birikmesini önler. Lab'daki betik değişiklik olmayan gece yeni kayıt açmadı.
Güvenli değildir. TFTP kimlik sormaz ve dosyayı şifrelemeden taşır. Switch yapılandırması ise SNMP community string'ini ve yönetici parolalarının hash'ini taşır; lab switch'imde bu hash'ler salt eklenmemiş MD5'ti. Yedek SFTP ya da SCP gibi şifreli bir yoldan, yalnız yedek için açılmış bir hesaba gönderilmelidir.
Sayılmaz. O dosya switch'in kendi belleğinde durur; switch bozulursa ya da çalınırsa onunla birlikte gider. Ayrıca kendiliğinden güncellenmez. Lab switch'imdeki backup-config bir ay önceki hâlde kalmıştı ve switch'in bugünkü adını bile taşımıyordu.
Özel bir depo ve şifrelemeyle makul bir yoldur, tek bir eksiği var. Lab'da dosyayı git-crypt ile şifreledim; GitHub'daki kopyada hostname satırı bile okunmuyor. Sunucuya yalnız o depoya yazabilen bir deploy key verdim. Eksik olan zorla gönderme koruması: ücretsiz hesapta özel depoda bu koruma açılamıyor, GitHub bunun için Pro istedi.
Trafikte kesinti yaratmaz; portlar ve VLAN'lar yedek sırasında çalışmaya devam eder. Lab switch'im ise aktarım süresince yönetim erişimini kapattığını söyledi: aktarım bitene kadar switch'e yeni bir oturum açılamaz. Yapılandırma birkaç kilobayt olduğu için aktarım saniyeler sürer.
İlker Pehlivan
Yazan

BT Danışmanı | Ağ, Sistem ve Güvenlik Yönetimi

İlker Pehlivan, karmaşık BT altyapılarını ölçeklenebilir ve güvenli sistemlere dönüştürür. Buradaki rehberleri kendi laboratuvarında kurup ölçerek yazar.

LinkedIn

Benzer Makaleler

Kurumsal Network Kurulumu altındaki diğer 114 makale