Uzak sunucularınızda çalışan Docker konteynerlerine güvenli bir şekilde erişmek, özellikle production ortamlarında oldukça kritik bir konu. Doğrudan port açmak hem güvensiz hem de yönetimi zor bir yol. Bunun yerine OpenVPN tüneli üzerinden Docker ağına erişmek, hem güvenliği hem de esnekliği bir arada sunuyor. Bu yazıda gerçek dünyada sıkça karşılaşılan bu senaryoyu adım adım ele alacağız.
Senaryo: Neden Böyle Bir Yapıya İhtiyaç Duyarsınız?
Diyelim ki bir mikroservis mimariniz var. Onlarca konteyner çalışıyor, bazıları yalnızca iç iletişim için portlar açıyor, bazıları veritabanı barındırıyor. Bu konteynerlere geliştirici ekibinizin erişmesi gerekiyor ancak her servisi internete açmak istemiyorsunuz. Klasik çözüm bastion host kullanmak, ama bu da yönetimsel yük getiriyor. OpenVPN ile Docker bridge ağını doğrudan VPN üzerinden erişilebilir hale getirdiğinizde, geliştiriciler sanki aynı iç ağdaymış gibi konteynerlere ulaşabiliyor.
Tipik kullanım senaryoları şunlardır:
- Staging ortamı erişimi: Geliştiricilerin sadece VPN bağlantısı üzerinden staging’e bağlanabilmesi
- Veritabanı erişimi: MySQL, PostgreSQL gibi servislerin internete kapalı, VPN’e açık tutulması
- İç servis monitöring: Grafana, Kibana gibi araçlara sadece VPN’den erişim
- CI/CD pipeline’ları: Deployment araçlarının konteynerlerle güvenli iletişimi
Altyapı Planlaması
Başlamadan önce ağ adreslemesini doğru planlamak şart. Çakışan subnet’ler en çok karşılaşılan sorundur.
Örnek planımız şu şekilde olsun:
- Sunucu IP’si: 203.0.113.10 (public)
- OpenVPN tünel ağı: 10.8.0.0/24
- Docker bridge ağı: 172.20.0.0/16 (özel tanımlı)
- VPN istemcileri: 10.8.0.2 ve üzeri
Docker’ın varsayılan bridge ağı olan 172.17.0.0/16 yerine özel bir ağ tanımlamak, hem çakışmaları önler hem de yönetimi kolaylaştırır.
Sunucu Hazırlığı
İlk adım olarak sunucunuzda IP forwarding’i etkinleştirmeniz gerekiyor. Bu olmadan paketler VPN tünelinden Docker ağına geçemez.
# Geçici olarak etkinleştir
echo 1 > /proc/sys/net/ipv4/ip_forward
# Kalıcı hale getir
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
# Doğrula
sysctl net.ipv4.ip_forward
Ardından OpenVPN ve gerekli araçları kurun:
# Ubuntu/Debian için
apt update && apt install -y openvpn easy-rsa
# CentOS/RHEL için
yum install -y epel-release
yum install -y openvpn easy-rsa
# OpenVPN versiyonunu kontrol et
openvpn --version
PKI Altyapısı ve Sertifika Oluşturma
Easy-RSA 3 ile PKI altyapısını kuruyoruz. Bu adımı bir kez yapıyorsunuz, sonrasında sadece istemci sertifikası ekliyorsunuz.
# Easy-RSA dizinini oluştur
make-cadir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
# vars dosyasını düzenle
cat > vars << 'EOF'
set_var EASYRSA_REQ_COUNTRY "TR"
set_var EASYRSA_REQ_PROVINCE "Istanbul"
set_var EASYRSA_REQ_CITY "Istanbul"
set_var EASYRSA_REQ_ORG "Sirket Adi"
set_var EASYRSA_REQ_EMAIL "[email protected]"
set_var EASYRSA_REQ_OU "DevOps"
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 3650
set_var EASYRSA_CERT_EXPIRE 825
EOF
# PKI'yi başlat
./easyrsa init-pki
# CA oluştur (passphrase girmek istiyorsanız --batch kaldırın)
./easyrsa build-ca nopass
# Sunucu sertifikası oluştur
./easyrsa build-server-full server nopass
# Diffie-Hellman parametreleri (biraz zaman alır)
./easyrsa gen-dh
# TLS Auth key oluştur
openvpn --genkey --secret /etc/openvpn/ta.key
# İlk istemci sertifikasını oluştur
./easyrsa build-client-full developer1 nopass
Docker Ağı Yapılandırması
Konteynerlerimizin bağlanacağı özel Docker ağını oluşturuyoruz. Bu ağ, VPN üzerinden yönlendirilecek.
# Özel Docker ağı oluştur
docker network create
--driver bridge
--subnet 172.20.0.0/16
--gateway 172.20.0.1
--opt "com.docker.network.bridge.name"="docker_vpn"
vpn_network
# Ağı doğrula
docker network inspect vpn_network
# Test konteynerleri ayağa kaldır
docker run -d
--name postgres_db
--network vpn_network
--ip 172.20.0.10
-e POSTGRES_PASSWORD=gizliparola
postgres:15
docker run -d
--name redis_cache
--network vpn_network
--ip 172.20.0.11
redis:7-alpine
# Konteyner IP'lerini kontrol et
docker inspect postgres_db | grep IPAddress
docker inspect redis_cache | grep IPAddress
OpenVPN Sunucu Konfigürasyonu
Asıl kritik nokta burada. Sunucu konfigürasyonunda Docker subnet’ini push route olarak ekliyoruz:
cat > /etc/openvpn/server.conf << 'EOF'
# Temel ayarlar
port 1194
proto udp
dev tun
# Sertifikalar
ca /etc/openvpn/easy-rsa/pki/ca.crt
cert /etc/openvpn/easy-rsa/pki/issued/server.crt
key /etc/openvpn/easy-rsa/pki/private/server.key
dh /etc/openvpn/easy-rsa/pki/dh.pem
tls-auth /etc/openvpn/ta.key 0
# VPN ağ ayarları
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt
# Docker subnet'ini istemcilere duyur
push "route 172.20.0.0 255.255.0.0"
# DNS (opsiyonel, iç DNS kullanıyorsanız ekleyin)
# push "dhcp-option DNS 172.20.0.53"
# Bağlantı ayarları
keepalive 10 120
cipher AES-256-CBC
auth SHA256
tls-version-min 1.2
comp-lzo
# Güvenlik
user nobody
group nogroup
persist-key
persist-tun
# Loglama
status /var/log/openvpn/openvpn-status.log
log-append /var/log/openvpn/openvpn.log
verb 3
# İstemciler arası iletişim (ihtiyaca göre açın)
# client-to-client
EOF
# Log dizinini oluştur
mkdir -p /var/log/openvpn
# OpenVPN'i başlat
systemctl enable openvpn@server
systemctl start openvpn@server
systemctl status openvpn@server
Firewall ve NAT Kuralları
Bu adım çoğu zaman atlanan ve “neden çalışmıyor?” sorusuna yol açan kısım. iptables kurallarını doğru yapılandırmazsanız paketler Docker ağına ulaşamaz.
# Önce mevcut durumu kontrol et
iptables -L -n -v
iptables -t nat -L -n -v
# VPN tünelinden gelen trafiğe izin ver
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A FORWARD -o tun0 -j ACCEPT
# Docker ağına forwarding
iptables -A FORWARD -i tun0 -o docker_vpn -j ACCEPT
iptables -A FORWARD -i docker_vpn -o tun0 -j ACCEPT
# NAT masquerade (VPN istemcilerinin Docker ağına erişimi için)
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -d 172.20.0.0/16 -j MASQUERADE
# OpenVPN portundan gelen bağlantılara izin ver
iptables -A INPUT -p udp --dport 1194 -j ACCEPT
# Kuralları kalıcı hale getir
apt install -y iptables-persistent
netfilter-persistent save
# Doğrulama
iptables -t nat -L POSTROUTING -n -v
Eğer sunucunuzda ufw kullanıyorsanız, ek olarak şunu yapmanız gerekir:
# ufw ile OpenVPN portu aç
ufw allow 1194/udp
ufw allow OpenSSH
# /etc/ufw/before.rules dosyasına NAT kuralları ekle
# *nat bölümünü COMMIT'ten önce ekleyin:
# *nat
# :POSTROUTING ACCEPT [0:0]
# -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
# COMMIT
ufw reload
İstemci Konfigürasyonu Oluşturma
Her geliştirici için ayrı bir .ovpn dosyası oluşturmak en temiz yöntem. Aşağıdaki script bunu otomatikleştirir:
#!/bin/bash
# Kullanım: ./create_client.sh developer2
CLIENT_NAME=$1
EASY_RSA_DIR="/etc/openvpn/easy-rsa"
OUTPUT_DIR="/etc/openvpn/clients"
SERVER_IP="203.0.113.10"
if [ -z "$CLIENT_NAME" ]; then
echo "Kullanim: $0 <istemci-adi>"
exit 1
fi
mkdir -p $OUTPUT_DIR
# Sertifika oluştur
cd $EASY_RSA_DIR
./easyrsa build-client-full $CLIENT_NAME nopass
# .ovpn dosyasını birleştir
cat > $OUTPUT_DIR/$CLIENT_NAME.ovpn << OVPN_EOF
client
dev tun
proto udp
remote $SERVER_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
auth SHA256
tls-version-min 1.2
comp-lzo
verb 3
key-direction 1
<ca>
$(cat $EASY_RSA_DIR/pki/ca.crt)
</ca>
<cert>
$(cat $EASY_RSA_DIR/pki/issued/$CLIENT_NAME.crt)
</cert>
<key>
$(cat $EASY_RSA_DIR/pki/private/$CLIENT_NAME.key)
</key>
<tls-auth>
$(cat /etc/openvpn/ta.key)
</tls-auth>
OVPN_EOF
chmod 600 $OUTPUT_DIR/$CLIENT_NAME.ovpn
echo "Istemci dosyasi olusturuldu: $OUTPUT_DIR/$CLIENT_NAME.ovpn"
Script’i çalıştırılabilir yapın ve kullanın:
chmod +x /etc/openvpn/create_client.sh
/etc/openvpn/create_client.sh developer1
/etc/openvpn/create_client.sh developer2
# Dosyayı geliştiriciye güvenli şekilde ilet
scp /etc/openvpn/clients/developer1.ovpn developer1@workstation:/home/developer1/
Bağlantı Testi ve Doğrulama
VPN bağlantısı kurulduktan sonra Docker konteynerlerine erişimi test etmek için şu adımları izleyin:
# İstemci tarafında VPN'e bağlan (Linux)
sudo openvpn --config developer1.ovpn --daemon
# Tünel arayüzünü kontrol et
ip addr show tun0
# Route tablosunu kontrol et
ip route | grep 172.20
# Docker konteynerlere ping at
ping 172.20.0.10 # postgres
ping 172.20.0.11 # redis
# PostgreSQL'e VPN üzerinden bağlan
psql -h 172.20.0.10 -U postgres -d postgres
# Redis'e bağlan
redis-cli -h 172.20.0.11 ping
# Sunucu tarafında aktif bağlantıları görüntüle
cat /var/log/openvpn/openvpn-status.log
Sık Karşılaşılan Sorunlar ve Çözümleri
Sorun: Ping çalışıyor ama servis portu erişilemiyor
Bu genellikle Docker konteynerinin port binding’i yanlış yapılmış olmasından kaynaklanır. Konteyner IP’sine direk bağlantı yapıyorsanız port publish etmenize gerek yok, ama konteyner --network parametresiyle doğru ağa bağlanmış olmalı.
# Konteynerin doğru ağda olup olmadığını kontrol et
docker network inspect vpn_network | grep -A 5 "Containers"
# Konteyneri vpn_network'e sonradan bağlama
docker network connect vpn_network mevcut_konteyner
# tcpdump ile paketi izle (sorun gidermek için)
tcpdump -i tun0 host 172.20.0.10 -n
tcpdump -i docker_vpn host 10.8.0.2 -n
Sorun: Route ekleniyor ama Docker ağına ulaşılamıyor
# Forwarding kurallarını kontrol et
iptables -L FORWARD -n -v | grep -E "tun|docker"
# Conntrack modülünün yüklü olduğunu doğrula
lsmod | grep conntrack
modprobe nf_conntrack
# Docker'ın kendi iptables kurallarını kontrol et
iptables -L DOCKER-USER -n -v
Sorun: VPN bağlantısı kuruluyor ama route push edilmiyor
Sunucu loglarını ve istemci loglarını karşılaştırın:
# Sunucu logunda push mesajlarını ara
grep "PUSH" /var/log/openvpn/openvpn.log
# İstemci tarafında
sudo openvpn --config developer1.ovpn --verb 5 2>&1 | grep -i route
Docker Compose ile Entegrasyon
Gerçek dünyada konteynerlerinizi büyük ihtimalle Docker Compose ile yönetiyorsunuzdur. VPN erişimi için Compose dosyanıza ağ tanımını ekleyin:
cat > docker-compose.yml << 'EOF'
version: '3.8'
networks:
vpn_network:
external: true
name: vpn_network
services:
postgres:
image: postgres:15
container_name: postgres_db
networks:
vpn_network:
ipv4_address: 172.20.0.10
environment:
POSTGRES_PASSWORD: gizliparola
POSTGRES_DB: uygulama_db
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: redis_cache
networks:
vpn_network:
ipv4_address: 172.20.0.11
restart: unless-stopped
api:
image: myapp:latest
container_name: api_server
networks:
vpn_network:
ipv4_address: 172.20.0.20
environment:
DB_HOST: 172.20.0.10
REDIS_HOST: 172.20.0.11
depends_on:
- postgres
- redis
restart: unless-stopped
volumes:
postgres_data:
EOF
# Compose ile başlat
docker compose up -d
# Servislerin ayakta olduğunu doğrula
docker compose ps
Güvenlik Sertleştirme Önerileri
Temel kurulumu tamamladıktan sonra güvenliği artırmak için şu adımları uygulayın:
- Sertifika iptal listesi (CRL): Ayrılan bir geliştirici olduğunda sertifikasını iptal etmek için CRL kullanın.
./easyrsa revoke developer2ve ardından./easyrsa gen-crlkomutlarıyla CRL oluşturupcrl-verifydirektifiyle sunucuya ekleyin. - İstemci bazlı erişim kısıtlaması:
client-config-dirdirektifiyle her istemci için ayrı konfigürasyon dosyası oluşturabilir, belirli bir geliştiriciyi sadece belirli Docker subnet’lerine yönlendirebilirsiniz. - Zaman aşımı ve oturum sınırları:
--tls-timeout,--reneg-secgibi direktiflerle oturum yenileme sürelerini kısaltın. - Two-factor authentication:
openvpn-otpeklentisiyle TOTP tabanlı 2FA eklenebilir, özellikle production erişimi için şiddetle tavsiye edilir. - Bant genişliği ve bağlantı limitleri:
--shaperile istemci bant genişliğini sınırlayın,--max-clientsile aynı anda bağlanabilecek istemci sayısını kontrol altında tutun. - Log izleme:
/var/log/openvpn/openvpn-status.logdosyasını düzenli izleyin, fail2ban ile başarısız bağlantı girişimlerini engelleyin.
İzleme ve Bakım
Uzun vadede bu altyapıyı sağlıklı tutmak için otomatize bir izleme süreci kurun:
#!/bin/bash
# /etc/cron.d/vpn_monitor - Her 5 dakikada çalışır
# OpenVPN servis durumu
if ! systemctl is-active --quiet openvpn@server; then
systemctl restart openvpn@server
echo "OpenVPN yeniden baslatildi: $(date)" >> /var/log/vpn_monitor.log
fi
# Aktif bağlantı sayısı
CONNECTIONS=$(grep -c "CLIENT_LIST" /var/log/openvpn/openvpn-status.log 2>/dev/null || echo 0)
echo "$(date): Aktif VPN baglantisi: $CONNECTIONS" >> /var/log/vpn_monitor.log
# Docker ağ durumu
if ! docker network inspect vpn_network &>/dev/null; then
docker network create --driver bridge --subnet 172.20.0.0/16 vpn_network
echo "Docker agi yeniden olusturuldu: $(date)" >> /var/log/vpn_monitor.log
fi
Sertifikaların sona erme tarihlerini de takip edin:
# Sunucu sertifikasının kalan süresini kontrol et
openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/server.crt
-noout -enddate
# Tüm istemci sertifikalarını kontrol et
for cert in /etc/openvpn/easy-rsa/pki/issued/*.crt; do
echo "$cert: $(openssl x509 -in $cert -noout -enddate)"
done
Sonuç
OpenVPN ile Docker konteyner erişimini birleştirmek, özellikle ekipsel geliştirme ortamlarında güvenlik ile kullanılabilirliği dengelemenin en pratik yollarından biri. Kurulumu biraz zaman alsa da bir kez yapılandırdıktan sonra yeni geliştirici eklemek yalnızca yeni bir sertifika oluşturup .ovpn dosyasını göndermek kadar basit bir işleme dönüşüyor.
Bu yazıda anlattığım yapının temel avantajları şunlar: Docker servislerinizi internete kapalı tutuyorsunuz, her erişim kayıt altına alınıyor, sertifika iptal mekanizmasıyla anlık erişim kesme imkanınız var ve ağ segmentasyonu sayesinde bir istemcinin ele geçirilmesi tüm altyapıyı riske atmıyor.
Bir sonraki adım olarak bu altyapıyı Ansible ile otomatize etmeyi veya WireGuard ile daha modern bir alternatif kurmayı değerlendirebilirsiniz. WireGuard, OpenVPN’e kıyasla çok daha düşük overhead ile benzer güvenlik seviyesi sunuyor, ancak PKI yönetimi açısından farklı bir yaklaşım gerektiriyor. Bu da ayrı bir yazının konusu.