00 WireGuard nedir?
WireGuard, Jason Donenfeld tarafından tasarlanan ve Linux 5.6 kernel'ine dahil edilen modern bir VPN protokolüdür. OpenVPN ve IPsec'e kıyasla 4000 satır altında C koduyla yazılmış olması, güvenlik analizini ve denetimini radikal biçimde kolaylaştırır.
Kriptografi seçimleri
| Amaç | Algoritma | Neden? |
|---|---|---|
| Anahtar değişimi | Curve25519 (ECDH) | Hız, küçük anahtar boyu, side-channel direnci |
| Simetrik şifreleme | ChaCha20-Poly1305 | AES donanım hızlandırması olmayan ARM/MIPS için ideal |
| Hash / MAC | BLAKE2s | SHA-256'dan daha hızlı, sabit zamanlı uygulama |
| Anahtar türetme | HKDF | ChaCha20 oturum anahtarlarını Curve25519 çıktısından türetir |
| Kimlik doğrulama | Noise Protocol (IKpsk2) | Formal doğrulanmış el sıkışma çerçevesi |
Geleneksel VPN ile karşılaştırma
OpenVPN: TLS handshake → RSA/DH → sertifika doğrulama → şifrelenmiş tünel
~600 KB kod, TLS stack, PKI altyapısı gerekli
IPsec: IKEv2 → çok sayıda cipher suite → SA müzakeresi → ESP/AH
Karmaşık yapılandırma, firewall bypass sorunları
WireGuard: Noise_IKpsk2 → Curve25519 → ChaCha20-Poly1305 → UDP tüneli
~4000 satır kod, yapılandırma = public key + AllowedIPs
Roaming ve kimlik
WireGuard'da her peer, public key ile tanımlanır — IP adresi değil. Bu, IP değişikliklerinde (mobil ağ geçişi, DHCP yenileme) tunnel'ın kesintisiz devam etmesini sağlar. Paket geldiğinde WireGuard geçerli kaynak IP'yi peer ile ilişkilendirir ve AllowedIPs tablosuna göre yönlendirir.
Linux 5.6+ kernel'de WireGuard modülü (wireguard.ko) doğrudan dahildir. Daha eski kerneller için wireguard-dkms veya backport paketi gereklidir. Embedded sistemlerde Buildroot/Yocto ile kernel konfigürasyonuna CONFIG_WIREGUARD=y eklenmesi yeterlidir.
Bu bölümde
- WireGuard = ~4000 satır C; kernel 5.6'dan itibaren built-in
- Peer kimliği = public key; IP değişikliklerinde roaming sorunsuz
- ChaCha20/Poly1305: donanım AES yoksa OpenVPN'den 3-5x hızlı
01 Kurulum ve anahtar üretimi
WireGuard'ın çekirdek araçları wg ve wg-quick'tir. Anahtar çifti üretimi, preshared key oluşturma ve temel doğrulama adımları.
Kurulum
# Debian / Ubuntu
apt install wireguard wireguard-tools
# Arch Linux
pacman -S wireguard-tools
# Alpine (gömülü sistemler için yaygın)
apk add wireguard-tools
# Buildroot (defconfig veya menuconfig)
# BR2_PACKAGE_WIREGUARD_TOOLS=y
# CONFIG_WIREGUARD=y (kernel config)
# Kernel modülünü yükle (5.6 öncesi veya modüler build)
modprobe wireguard
lsmod | grep wireguard
Anahtar çifti üretimi
# Özel anahtar üret (256-bit rastgele, base64)
wg genkey | tee privatekey | wg pubkey > publickey
cat privatekey # → base64 private key (ASLA paylaşma)
cat publickey # → base64 public key (peer'lara ver)
# Preshared key (PSK) — ek simetrik güvenlik katmanı
# Quantum-safe ek koruma; isteğe bağlı ama önerilir
wg genpsk > presharedkey
# Güvenli izinler
chmod 600 privatekey presharedkey
chmod 644 publickey
# Sunucu için toplu anahtar üretimi:
SERVER_PRIVKEY=$(wg genkey)
SERVER_PUBKEY=$(echo "$SERVER_PRIVKEY" | wg pubkey)
echo "Server private: $SERVER_PRIVKEY"
echo "Server public: $SERVER_PUBKEY"
wg komutu ile interface yönetimi
# Manuel interface oluşturma (wg-quick olmadan)
ip link add wg0 type wireguard
ip address add 10.0.0.1/24 dev wg0
wg set wg0 listen-port 51820 private-key /etc/wireguard/server_private.key
ip link set wg0 up
# Peer ekleme
wg set wg0 peer <CLIENT_PUBLIC_KEY> \
preshared-key /etc/wireguard/preshared.key \
allowed-ips 10.0.0.2/32
# Mevcut durumu göster
wg show wg0
wg showconf wg0 # mevcut config dosyası formatında göster
Bu bölümde
- wg genkey | wg pubkey → private/public key çifti üretimi
- wg genpsk → preshared key; quantum-resistant ek katman
- wg set ile dinamik peer ekleme/çıkarma; wg show ile durum
02 Peer yapılandırması
/etc/wireguard/wg0.conf dosyası, WireGuard interface ve peer'larını tanımlar. Sözdizimi INI formatına benzer; [Interface] ve [Peer] bölümlerinden oluşur.
Sunucu yapılandırması
# /etc/wireguard/wg0.conf — Sunucu
[Interface]
# Sunucunun VPN IP adresi
Address = 10.10.0.1/24
# Dinlenecek UDP portu
ListenPort = 51820
# Özel anahtar (doğrudan veya dosya yolu)
PrivateKey = <SERVER_PRIVATE_KEY>
# Bağlantı geldiğinde IP forwarding + NAT aç
PostUp = iptables -A FORWARD -i %i -j ACCEPT; \
iptables -A FORWARD -o %i -j ACCEPT; \
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; \
iptables -D FORWARD -o %i -j ACCEPT; \
iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# İstemci 1
[Peer]
PublicKey = <CLIENT1_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
AllowedIPs = 10.10.0.2/32 # Bu istemciden yalnızca bu IP kabul et
# İstemci 2
[Peer]
PublicKey = <CLIENT2_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY_2>
AllowedIPs = 10.10.0.3/32
İstemci yapılandırması
# /etc/wireguard/wg0.conf — İstemci (gömülü cihaz)
[Interface]
Address = 10.10.0.2/32
PrivateKey = <CLIENT_PRIVATE_KEY>
# DNS (isteğe bağlı — systemd-resolved veya resolvconf ile)
DNS = 10.10.0.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
# Sunucunun gerçek IP ve portu
Endpoint = vpn.example.com:51820
# 0.0.0.0/0 → tüm trafiği VPN'den geçir (full tunnel)
# Sadece VPN ağı için: 10.10.0.0/24
AllowedIPs = 0.0.0.0/0, ::/0
# NAT arkasındaysa keepalive açık tut
PersistentKeepalive = 25
AllowedIPs mantığı
Bu bölümde
- [Interface] = yerel ayarlar; [Peer] = karşı taraf tanımı
- AllowedIPs çift yönlü çalışır: hem routing hem kaynak doğrulama
- PostUp/PostDown: iptables NAT kuralları wg-quick ile otomatik yönetilir
03 wg-quick ile bağlantı yönetimi
wg-quick, WireGuard interface'ini yapılandırma dosyasından otomatik olarak oluşturan, routing tablolarını güncelleyen ve PostUp/PostDown hook'larını çalıştıran yardımcı araçtır.
Temel komutlar
# Interface'i başlat (/etc/wireguard/wg0.conf kullanılır)
wg-quick up wg0
# Interface'i durdur
wg-quick down wg0
# Yapılandırmayı yeniden uygula (down + up)
wg-quick strip wg0 # wg-quick ek direktifleri çıkarıp saf wg config göster
# Belirli bir conf dosyası ile
wg-quick up /etc/wireguard/wg0.conf
# Mevcut durum
wg show
wg show wg0
wg show wg0 peers
wg show wg0 latest-handshakes
wg-quick ek direktifleri
| Direktif | Yer | Açıklama |
|---|---|---|
Address | [Interface] | Interface'e atanacak IP/prefix; birden fazla yazılabilir |
DNS | [Interface] | resolvconf veya systemd-resolved üzerinden DNS ayarla |
MTU | [Interface] | Varsayılan 1420; bazı ISP'lerde azaltılması gerekebilir |
Table | [Interface] | Routing tablosu numarası; off = otomatik routing eklenmesin |
PreUp/PostUp | [Interface] | Interface açılmadan önce/sonra çalıştırılacak komut |
PreDown/PostDown | [Interface] | Interface kapatılmadan önce/sonra çalıştırılacak komut |
nftables ile PostUp
# nftables kullanan sistemlerde PostUp (iptables yerine)
[Interface]
Address = 10.10.0.1/24
PrivateKey = <SERVER_PRIVATE_KEY>
ListenPort = 51820
PostUp = nft add rule inet filter forward iifname %i accept; \
nft add rule inet filter forward oifname %i accept; \
nft add rule ip nat postrouting oifname eth0 masquerade
PostDown = nft flush table inet filter; \
nft flush table ip nat
systemd-networkd entegrasyonu
# /etc/systemd/network/wg0.netdev — WireGuard netdev
[NetDev]
Name = wg0
Kind = wireguard
[WireGuard]
PrivateKey = <PRIVATE_KEY>
ListenPort = 51820
[WireGuardPeer]
PublicKey = <CLIENT1_PUBLIC_KEY>
PresharedKey = <PSK>
AllowedIPs = 10.10.0.2/32
---
# /etc/systemd/network/wg0.network — IP ve routing
[Match]
Name = wg0
[Network]
Address = 10.10.0.1/24
[Route]
Destination = 10.10.0.0/24
Bu bölümde
- wg-quick up/down: routing + PostUp/PostDown otomatik yönetimi
- systemd-networkd: .netdev + .network dosyaları ile kalıcı yapılandırma
- wg show latest-handshakes: peer bağlantı durumunu izle
04 NAT traversal
Gömülü IoT cihazları genellikle NAT arkasında bulunur — sabit IP'leri yoktur, doğrudan ulaşılamazlar. WireGuard, UDP hole punching ve PersistentKeepalive mekanizmasıyla bu sorunu çözer.
UDP hole punching nasıl çalışır?
[Cihaz A] [NAT-A] [Sunucu] [NAT-B] [Cihaz B]
│ │ │ │ │
│──── UDP ─────►│ │ │ │
│ NAT-A açık: A:port1 ─────► │ │
│ │◄──── UDP ─────│ │ │
│ │ │◄──── UDP ──────────────────│
│ │ │ NAT-B açık: B:port2 │
│ │ │ │
│ Handshake: WireGuard Noise IKpsk2 (encrypted) │
│◄═══════════════════════════════════════════════════════════►│
PersistentKeepalive
NAT tabloları belirli süre sonra UDP akışlarını siler. PersistentKeepalive bu süreyi doldurmadan düzenli aralıklarla boş paket göndererek NAT oturumunu canlı tutar.
# İstemci peer tanımında
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.10.0.0/24
PersistentKeepalive = 25 # 25 saniyede bir boş paket gönder
# 25s: çoğu NAT için yeterli
# Aggressive NAT: 15s önerilir
Symmetric NAT kısıtlamaları
# NAT tipini tespit et (stun-client veya nmap ile)
apt install stun-client
stun stun.l.google.com 19302 -v 2>&1 | grep "Mapped Address"
# Bağlantı sorunlarını debug et
wg show wg0 latest-handshakes # son handshake zamanı
tcpdump -i eth0 udp port 51820 -n
# Firewall'da UDP portunu açmayı unutma (sunucu tarafı)
ufw allow 51820/udp
# veya nftables:
nft add rule inet filter input udp dport 51820 accept
Bu bölümde
- WireGuard UDP üzerinde çalışır — hole punching ile NAT'ı aşar
- PersistentKeepalive = 25: NAT oturumunu canlı tutar
- Symmetric NAT durumunda relay/sunucu tarafı sabit IP gerekebilir
05 Hub-and-spoke IoT topolojisi
N adet gömülü cihazın merkezi bir sunucu üzerinden birbirine bağlandığı hub-and-spoke modeli, IoT fleet yönetiminde en yaygın WireGuard topolojisidir.
Topoloji diyagramı
┌─────────────────────┐
│ VPN Sunucu │
│ 10.10.0.1/24 │
│ eth0: 203.0.113.5 │
└──────┬──────────────┘
│ wg0 (51820/UDP)
┌────────────┼────────────┐
│ │ │
┌────▼───┐ ┌─────▼──┐ ┌─────▼──┐
│ Cihaz1 │ │ Cihaz2 │ │Cihaz10 │
│10.10.0.2│ │10.10.0.3│ │10.10.0.11│
│ (NAT) │ │ (NAT) │ │ (NAT) │
└────────┘ └────────┘ └────────┘
Sunucu yapılandırması — IP forwarding
# /etc/sysctl.d/99-wireguard.conf
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
sysctl -p /etc/sysctl.d/99-wireguard.conf
# /etc/wireguard/wg0.conf — Sunucu (10 cihaz için)
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; \
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; \
iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer] # Cihaz 1
PublicKey = <DEVICE1_PUBKEY>
AllowedIPs = 10.10.0.2/32
[Peer] # Cihaz 2
PublicKey = <DEVICE2_PUBKEY>
AllowedIPs = 10.10.0.3/32
# ... 10 cihaza kadar devam eder
Cihazlar arası routing
# Cihaz 1'den Cihaz 2'ye erişim için:
# Cihaz 1 konfig → AllowedIPs = 10.10.0.0/24 (tüm VPN ağı)
# Sunucu FORWARD kuralı ile paketi Cihaz 2'ye yönlendirir
# Cihaz 1: /etc/wireguard/wg0.conf
[Interface]
Address = 10.10.0.2/32
PrivateKey = <DEVICE1_PRIVATE_KEY>
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = 203.0.113.5:51820
AllowedIPs = 10.10.0.0/24 # tüm VPN ağına routing
PersistentKeepalive = 25
# Cihaz 1'den Cihaz 3'e ping testi:
# ping 10.10.0.4 → sunucu üzerinden yönlendirilir
Bu bölümde
- Hub-and-spoke: tüm cihazlar sunucuya bağlı; peer-to-peer geçiş sunucu üzerinden
- ip_forward + MASQUERADE: cihazların internete çıkışı için gerekli
- Cihazlarda AllowedIPs = 10.10.0.0/24 → VPN ağına doğrudan routing
06 systemd entegrasyonu
WireGuard bağlantısını sistem başlangıcında otomatik kurmak ve yönetmek için wg-quick@.service systemd birimi kullanılır. DNS sızıntısı engellemesi ve NetworkManager entegrasyonu da bu bölümde ele alınıyor.
wg-quick systemd servisi
# Servisi etkinleştir ve başlat
systemctl enable wg-quick@wg0.service
systemctl start wg-quick@wg0.service
systemctl status wg-quick@wg0.service
# Yapılandırma değişikliği sonrası yenile
systemctl restart wg-quick@wg0.service
# Logları izle
journalctl -u wg-quick@wg0 -f
# wg-quick@.service unit dosyasını incele
systemctl cat wg-quick@.service
systemd-resolved ve DNS sızıntısı
# /etc/wireguard/wg0.conf — DNS direktifi ile
[Interface]
Address = 10.10.0.2/32
PrivateKey = <PRIVATE_KEY>
DNS = 10.10.0.1 # VPN DNS sunucusu
# systemd-resolved ile DNS sızıntısı engeli
# wg-quick, DNS ayarını resolvconf veya systemd-resolved üzerinden uygular
# DNS sızıntısını test et:
curl https://dnsleaktest.com/test # veya
dig +short myip.opendns.com @resolver1.opendns.com
nslookup example.com # hangi DNS sunucusu cevap veriyor?
# systemd-resolved durumunu kontrol et
resolvectl status wg0
resolvectl dns wg0
NetworkManager entegrasyonu
# NetworkManager WireGuard bağlantısı oluştur
nmcli connection add type wireguard \
ifname wg0 \
con-name "IoT-VPN"
# Bağlantı ayarlarını düzenle
nmcli connection modify "IoT-VPN" \
wireguard.private-key "$(cat /etc/wireguard/private.key)" \
wireguard.listen-port 51820
# Peer ekle (nmcli ile)
nmcli connection modify "IoT-VPN" \
"+wireguard.peers" \
"public-key=<SERVER_PUBKEY>,endpoint=vpn.example.com:51820,allowed-ips=10.10.0.0/24,persistent-keepalive=25"
# Bağlantıyı aktif et
nmcli connection up "IoT-VPN"
Gömülü sistemlerde NetworkManager genellikle kullanılmaz; wg-quick@.service veya doğrudan systemd-networkd tercih edilir. DNS direktifi yalnızca resolvconf veya systemd-resolved yüklüyse çalışır; yoksa görmezden gelinir.
Bu bölümde
- systemctl enable wg-quick@wg0 → boot'ta otomatik bağlantı
- DNS direktifi + systemd-resolved ile DNS sızıntısı engellenir
- Gömülü: systemd-networkd .netdev/.network en hafif çözüm
07 Pratik: 10 gömülü cihaz için fleet VPN
Fabrikadan çıkan gömülü cihazlara otomatik WireGuard yapılandırması oluşturan provisioning scripti ve fleet izleme araçları.
Otomatik provisioning scripti
#!/bin/bash
# provision_fleet.sh — 10 cihaz için WireGuard konfig üretici
set -euo pipefail
SERVER_IP="203.0.113.5"
SERVER_PORT="51820"
VPN_SUBNET="10.10.0"
SERVER_VPN_IP="${VPN_SUBNET}.1"
OUTPUT_DIR="./wg-fleet-configs"
NUM_DEVICES=10
mkdir -p "$OUTPUT_DIR/server"
# Sunucu anahtar çifti
SERVER_PRIVKEY=$(wg genkey)
SERVER_PUBKEY=$(echo "$SERVER_PRIVKEY" | wg pubkey)
# Sunucu conf başlangıcı
cat > "$OUTPUT_DIR/server/wg0.conf" <<EOF
[Interface]
Address = ${SERVER_VPN_IP}/24
ListenPort = ${SERVER_PORT}
PrivateKey = ${SERVER_PRIVKEY}
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
EOF
# Her cihaz için
for i in $(seq 1 $NUM_DEVICES); do
DEVICE_IP="${VPN_SUBNET}.$((i + 1))"
DEVICE_DIR="$OUTPUT_DIR/device_${i}"
mkdir -p "$DEVICE_DIR"
# Cihaz anahtar çifti
DEV_PRIVKEY=$(wg genkey)
DEV_PUBKEY=$(echo "$DEV_PRIVKEY" | wg pubkey)
PSK=$(wg genpsk)
# Cihaz conf dosyası
cat > "$DEVICE_DIR/wg0.conf" <<EOF
[Interface]
Address = ${DEVICE_IP}/32
PrivateKey = ${DEV_PRIVKEY}
[Peer]
PublicKey = ${SERVER_PUBKEY}
PresharedKey = ${PSK}
Endpoint = ${SERVER_IP}:${SERVER_PORT}
AllowedIPs = ${VPN_SUBNET}.0/24
PersistentKeepalive = 25
EOF
chmod 600 "$DEVICE_DIR/wg0.conf"
# Sunucu conf'a peer ekle
cat >> "$OUTPUT_DIR/server/wg0.conf" <<EOF
[Peer] # Device ${i}
PublicKey = ${DEV_PUBKEY}
PresharedKey = ${PSK}
AllowedIPs = ${DEVICE_IP}/32
EOF
echo "Cihaz $i: IP=${DEVICE_IP}, pubkey=${DEV_PUBKEY:0:10}..."
done
chmod 600 "$OUTPUT_DIR/server/wg0.conf"
echo "Yapılandırmalar oluşturuldu: $OUTPUT_DIR"
Fleet izleme scripti
#!/bin/bash
# monitor_fleet.sh — WireGuard peer durumunu izle
echo "=== WireGuard Fleet Durumu $(date) ==="
echo ""
wg show wg0 peers | while read -r PUBKEY; do
ENDPOINT=$(wg show wg0 endpoints | grep "^$PUBKEY" | awk '{print $2}')
HANDSHAKE=$(wg show wg0 latest-handshakes | grep "^$PUBKEY" | awk '{print $2}')
TRANSFER=$(wg show wg0 transfer | grep "^$PUBKEY" | awk '{printf "rx=%s tx=%s", $2, $3}')
# Handshake zamanını değerlendir
NOW=$(date +%s)
AGE=$(( NOW - HANDSHAKE ))
if [ "$AGE" -lt 180 ]; then
STATUS="ONLINE"
else
STATUS="OFFLINE"
fi
printf "%-20s %-10s %-30s %s\n" \
"${PUBKEY:0:16}..." "$STATUS" "$ENDPOINT" "$TRANSFER"
done
Cihaza konfig gönderme ve uygulama
# cihaza SSH ile konfig gönder ve uygula
DEVICE_IP="192.168.1.100" # cihazın fabrika IP'si
scp wg-fleet-configs/device_1/wg0.conf root@${DEVICE_IP}:/etc/wireguard/
ssh root@${DEVICE_IP} "chmod 600 /etc/wireguard/wg0.conf && \
systemctl enable wg-quick@wg0 && \
systemctl start wg-quick@wg0 && \
wg show wg0"
# Bağlantıyı doğrula (VPN IP üzerinden)
ping -c3 10.10.0.2 # cihaz 1 VPN IP'si
Üretilen yapılandırma dosyaları özel anahtarlar içerir. chmod 600 ile korunmalı, git'e eklenmemeli ve şifreli bir vault (HashiCorp Vault, SOPS) üzerinden yönetilmelidir. Her cihazın benzersiz anahtar çifti olmalı — anahtarlar paylaşılmamalıdır.
Bu bölümde
- provision_fleet.sh: N cihaz için otomatik anahtar üretimi + conf dosyası
- monitor_fleet.sh: latest-handshakes ile online/offline tespiti
- PSK her peer için benzersiz; anahtarlar şifreli vault'ta saklanmalı