Skip to content

Connect to a FortiGate VPN through docker

Notifications You must be signed in to change notification settings

cemtopkaya/docker-forticlient-vpn

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

forticlient

Kısaca Kullanımı

docker-compose up -d ile konteyner ayaklandırılır ancak çift yollu doğrulamada gelen eposta token değerini girmek için stdin_open: true, tty: true parametreleri daha sonra konteynere attach yapmak istediğimizde (docker attach forti) konsola TOKEN değerini yazabilmemizi sağlayacak.

version: "3.7"

services:
  forticlient:
    container_name: forti
    build:
      context: .
      dockerfile: Dockerfile
    image: cemt/docker-forticlient-vpn
    stdin_open: true # docker run -i
    tty: true        # docker run -t
    environment:
      - VPNADDR=host-ip:port
      - VPNUSER=kullanici-adi
      - VPNPASS=kullanici-sifresi
      - VPNTIMEOUT=${VPNTIMEOUT:-60}
    network_mode: "host"
    privileged: true

Özetle:

image

VPN Konteynerini kullanması için cgrafana isimli bir konteyner daha ayaklandırıyorum. VPN'nin arkasındaki bir IP adresine cgrafana makinasından gitmek istediğimizde (ping 172.19.0.85 -c 1) hata alacağız:

image

Çünkü bu adrese gitmek için bir yönlendirme tanımlı değil (route -n) :

image

VPN yapan konteyner kendisine gelen istekleri yönlendirmek için iptables -t nat -A POSTROUTING -s "$iface" -j MASQUERADE komutunu çalıştırmış, gelen isteği -> SSL bağlantısına yönlendirip SSL bağlantısından gelen cevabı -> isteği yapana doğru yönlendiriyor:

image

Şimdi cgrafana konteynerinde şunu yapacağız:

VPN'nin arkasındaki IP adresine bir istek olduğunda VPN konteynerinin IP adresine yönlendirme

ip route add 172.19.0.0/16 via 172.30.1.2

image


Kullanılan yansı auchandirect/forticlient eğer bulunamazsa ubuntu yansısına aşağıdaki forticlient-sslvpn paketini kurarak istediğiniz yansıyı oluşturabilirsiniz.

Örneğin:

FROM ubuntu:xenial
RUN echo "deb [arch=amd64] https://repo.fortinet.com/repo/6.4/ubuntu/ xenial multiverse" > /etc/apt/sources.list.d/forti.list
RUN apt-get update
RUN apt-get install -y forticlient

Farklı linux sürümlerine kurulum için:

Konteyner içinde forticlient-sslvpn_amd64.deb paketinin kurulmuş ve start.sh betiğinin çalışmasıyla bağlantı kurar. start.sh İçinde:

  • Ortam değişkenlerinde şunların boş olmamasını ister: $VPNADDR, $VPNUSER, $VPNPASS"
  • Linux üstünde NAT yaparak: image
$ for iface in $(ip a | grep eth | grep inet | awk '{print $2}'); do iptables -t nat -A POSTROUTING -s "$iface" -j MASQUERADE; done
$ iptables -t nat -L

NAT ve IPTables'a Dair

Linux 2.2 öncesinde firewall rule editorü ipfwadm idi, sonra yerini ipchains'e ve daha da sonra iptables'a bıraktı. iptables sanılanın aksine uygulama katmanında değil, network ve transport katmanlarında çalışan kernel seviyesindeki yazılımdır. Belirli bir süre geçerli olacak kurallar tanımlamaya izin veren libipt_time.so adında bir time modülü vardır.

Örnekler

  1. Hafta içi mesai saatleri arasında sozluk.sourtimes.org adresine erişimi engelleyen kural:
$ iptables -i output -m time --timestart 09:00 --timestop 17:00 --days mon,tue,wed,thu,fri -d sozluk.sourtimes.org -j reject
  1. server.php adresine giden trafiği engeller (düşürür). ekşi-iptables
$ iptables -i input -m string --algo bm --string 'server.php' -j drop

Peki NAT nedir ve iptables ile ilişkisini nasıl kurabiliriz?

nat (network address translation) ileride(ipv6 düşünülmeden önce) oluşabilecek potansiyel ip sıkıntısı düşünülerek geliştirilmiştir. bir network içerisinde bilinen bir ip adresinin başka bir network tarafından erişilebilmesine yarar. biri içeride, biri dışarıda iki network ü bağlamak amaçlanmıştır. tipik ofis, internet cafe internet bağlantılarında kullanılır. dışarı veya içeri yönde her request tanımlanmış, önceden bekleniyor, bir öncekine cevap yada tekrar niteliğinde olması beklenir. ip sıkıntısı yada maliyet nedeni ile tercih edilir.ekşi-nat

temel olarak, bir public ip adresi ile, birden çok private ip adresinin internete erişimini sağlar. çünkü yerel ağlarda* kullanılan private ip adresleri, internette kullanılamaz.

nat ve port-forwarding kavramını anlamak için telefon santralini örnek alalım. Şirketlerde kurulu olan, aradığınızda "lütfen dahili numarayı çeviriniz veya operatöre bağlanmak için bekleyiniz" karşılamasının sorumlusu olan sistemleri düşünelim. Karel'in MS26 santralinin şirketinizde kullanılıyor olduğunu düşünün.

2 dış hat ve 6 dahili kullanıcıya ek olarak 4 IP dış hat ve 24 IP abone kapasitesine ulaşabilen telefon santralları 1 Dış hattın (PSTN) bağlı ve telefon numarasını 0212 216 12 16 olsun. Santralinize bağlı 6 dahili hattınız takılı olduğunda gelen arama dahili hatlardan birini tuşlayarak içerideki dahiliye ulaşsın. ekşi-nat


Devam edelim... Sadece kullanıcı adı ve şifresiyle doğrulama yapıyorsanız ortam değişkenleriyle bilgileri verebilir. Konteyner başlar başlamaz otomatik olarak bağlantı kurulacaktır.

Eğer iki etkili doğrulama (kullanıcı adı ve şifresinden sonra bir de ileti veya SMS ile gelen kodu) kullanıyorsanız bu kez bağlantı kuramayacağınız için konteynere konsolunuzu bağlayarak aşağıdaki komutu elle çalıştırarak bağlantı kurabilirsiniz.

$ cd /usr/share/forticlient/opt/forticlient-sslvpn/64bit/
$ ./forticlientsslvpn_cli --server 176.236.170.162:443 --vpnuser cem.topkaya
.... şifrenizi soracaktır,
.... sonrasında gelecek kodunuzu gireceğiniz satırda bekleyecek,
.... kodu girdikten sonra bağlantınız kurulacaktır.

Önce bridge türünde bir ağ oluşturacağız (sanal ağ türleri için ip-link kılavuzuna bkz).

image

Bu ağda; hem VPN bağlantısını kuracağınız konteyner hem de bu konteyner üstünden VPN ağına erişmek istediğiniz konteynerler olacaktır.

# bir ağ yaratalım ki buradaki konteynerler VPN bağlantılı konteyneri GATEWAY olarak alıp VPN ağına çıkabilsinler
$ docker network create    \
  --driver=bridge          \
  --subnet=172.30.1.0/16   \ # 255.255.0.0 olacak şekilde alt ağ maskesi ayarlıyoruz 
  --ip-range=172.30.1.0/24 \ # 172.30.1.1-254 arasında IP dağıtacağız
  --gateway=172.30.1.254   \ # Kapımız ...254 IP adresinden olacak
  fortinet                   # Ağın adı fortinet olsun

Alt ağı 16 olarak ayarladığımızda 192.168.0.0/16 nasıl bir ağa erişebildiğimizi görebiliriz. image

Şimdi oluşturduğumuz fortinet ağına bir bakalım:

C:\>docker inspect fortinet
[
    {
        "Name": "fortinet",
        "Id": "2b48262c094a045012372af63d3008ba8c409d839af9754c587e0accad30f857",
        "Created": "2021-12-11T20:20:41.7355242Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.30.1.0/24",
                    "IPRange": "172.30.1.0/24",
                    "Gateway": "172.30.1.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

C:\>

Şimdi VPN bağlantısı kurmak istediğimiz docker konteynerini başlatalım:

$ docker run                         \
     -it                             \ # şifre veya bir cevap vermemiz için interactive terminal yapıyoruz
     --rm                            \ # konteynerden çıkıldığında otomatik silinsin
     --privileged                    \ # root yetkisinde konteyner başlatılsın
     --net fortinet                  \ # az önce oluşturduğumuz network'e bağlansın ki, diğer konteynerleri buraya bağlayıp üstünden çıksınlar
     --ip 172.30.1.2                 \ # konteynerin IP'sini sabitleyelim ki routingi bu IP üstünden yapalım
     -e VPNADDR=176.236.170.162:443  \ # VPN sunucusunun IP adresi ve port bilgisi
     -e VPNUSER=cem.topkaya          \ # VPN kullanıcı adı
     -e VPNPASS=kullaniciSifresi     \
     --mac-address=E8-6A-64-BE-F8-47 \ # konteyner MAC adresini bilgisayarın MAC'i ile aynı yapalım ki doğrulansın
     auchandirect/forticlient

Windows konsolda tek satırda çalıştırmak için:

$ docker run --name=vpn -it --rm --privileged --net=fortinet --ip=172.30.0.2 -e VPNADDR=176.236.170.162:443 -e VPNUSER=cem.topkaya -e VPNPASS=sifre --mac-address=22-11-FF-CC-BB-AA  auchandirect/forticlient
$ docker exec -it --user root vpn bash 
$ echo 1 > /proc/sys/net/ipv4/ip_forward
$ iptables -A FORWARD -i eth0 -o ppp0 -j ACCEPT
$ iptables -A FORWARD -i ppp0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
$ iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

Kontrol etmek için:

$ iptables -L
$ iptables -S

Oluşan IP tablosunu ihraç ve ithal etmek için:

$ iptables-save > ~/ruleset-v4
$ iptables-restore < ~/ruleset-v4

Şimdi Grafana'yı konteyner içinde çalıştırıp VPN ağındaki bir sunucuya erişmek isteyelim. Önce Grafana konteynerinin docker-compose dosyası:

# docker-compose -f "docker-compose.yaml" up -d --build grafana 
# docker-compose -f "docker-compose.yaml" down
version: '3'

# Bu dosyanın dışında oluşturulduğu için 'external: true' olarak işaretleniyor.
networks:
  fortinet:
    external: true
    name: fortinet

services:
  grafana:
    # fortinet ağına dahil olacak ki VPN ağına erişebilsin
    networks:
      - fortinet
    container_name: cgrafana
    image: grafana/grafana
    privileged: true 
    environment:
      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
    volumes:
      - "./grafana/datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml"
    ports:
    - 3000:3000

datasources.yml

apiVersion: 1
datasources:
  - name: prometheus-ulak
    type: prometheus
    access: proxy
    orgId: 1
    url: http://172.19.0.85:31355
    isDefault:
    version: 1
    editable: true

Grafana'yı ayaklandırıp VPN ağındaki 172.19.0.85 makinaya erişebilmesi için ip routing ayarını yapacağız:

$ docker-compose  -f "docker-compose.yaml" up -d --build grafana 
docker exec -it --user root cgrafana route add -net 172.19.0.85/32 gw 172.30.1.2

Usage

The container uses the forticlientsslvpn_cli linux binary to manage ppp interface

All of the container traffic is routed through the VPN, so you can in turn route host traffic through the container to access remote subnets.

Linux

# Create a docker network, to be able to control addresses
$ docker network create --subnet=172.20.0.0/16 fortinet

# Start the priviledged docker container with a static ip
$ docker run -it --rm \
  --privileged \
  --net fortinet --ip 172.20.0.2 \
  -e VPNADDR=host:port \
  -e VPNUSER=me@domain \
  -e VPNPASS=secret \
  auchandirect/forticlient

# Add route for you remote subnet (ex. 10.201.0.0/16)
$ ip route add 10.201.0.0/16 via 172.20.0.2

# Access remote host from the subnet
$ ssh 10.201.8.1

OSX

UPDATE: 2017/06/10
Docker's microkernel still lacks ppp interface support, so you'll need to use a docker-machine VM.
# Create a docker-machine and configure shell to use it
docker-machine create fortinet --driver virtualbox
eval $(docker-machine env fortinet)

# Start the priviledged docker container on its host network
docker run -it --rm \
  --privileged --net host \
  -e VPNADDR=host:port \
  -e VPNUSER=me@domain \
  -e VPNPASS=secret \
  auchandirect/forticlient

# Add route for you remote subnet (ex. 10.201.0.0/16)
sudo route add -net 10.201.0.0/16 $(docker-machine ip fortinet)

# Access remote host from the subnet
ssh 10.201.8.1

Misc

If you don't want to use a docker network, you can find out the container ip once it is started with:

# Find out the container IP
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container>

Precompiled binaries

Thanks to https://hadler.me for hosting up to date precompiled binaries which are used in this Dockerfile.

About

Connect to a FortiGate VPN through docker

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • Dockerfile 59.6%
  • Shell 40.4%