OpenVPN ile Docker Konteynerlerine Güvenli Erişim Sağlama

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 developer2 ve ardından ./easyrsa gen-crl komutlarıyla CRL oluşturup crl-verify direktifiyle sunucuya ekleyin.
  • İstemci bazlı erişim kısıtlaması: client-config-dir direktifiyle 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-sec gibi direktiflerle oturum yenileme sürelerini kısaltın.
  • Two-factor authentication: openvpn-otp eklentisiyle TOTP tabanlı 2FA eklenebilir, özellikle production erişimi için şiddetle tavsiye edilir.
  • Bant genişliği ve bağlantı limitleri: --shaper ile istemci bant genişliğini sınırlayın, --max-clients ile aynı anda bağlanabilecek istemci sayısını kontrol altında tutun.
  • Log izleme: /var/log/openvpn/openvpn-status.log dosyası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.

Yorum yapın