Virtualizace 2 - Projekt 1

Zadání projektu

V rámci virtuálního serveru vytvořte vždy 2 kontejnery propojené vlastní vnitřní síti. Jeden (první) kontejner bude nabízet služby do "veřejné sítě". Konfigurace přes Docker compose.

Kontejner 1 - Firewall a monitorování a logování provozu. Kontejner 2 OpenVPN server

Krok 1: Docker Compose

Vytvoříme si Docker compose s 2 sítěma, jedna pro vnitřní komunikaci mezi kontejnery, bez přístupu k "internetu". Druhá pro přístup FW kontejneru do "internetu".


name: virt_project_1
services:
  firewall:
    build: ./firewall
    container_name: firewall
    cap_add:
      - NET_ADMIN
      - NET_RAW
    ports:
      - "1194:1194/udp"  # veřejný port pro VPN
    networks:
      external-net:
      internal-net:
        ipv4_address: 10.0.0.3
    sysctls:
      - net.ipv4.ip_forward=1
    volumes:
      - ./logs:/var/log/firewall
    restart: unless-stopped

  openvpn:
    image: kylemanna/openvpn
    container_name: openvpn
    cap_add:
      - NET_ADMIN
    networks:
      internal-net:
        ipv4_address: 10.0.0.2
    depends_on:
      - firewall
    volumes:
      - ./openvpn-data/conf:/etc/openvpn
    expose:
      - "1194/udp"
    command: >
       sh -c "ip route del default || true && ip route add default via 10.0.0.3 && ovpn_run"

networks:
  internal-net:
    driver: bridge
    internal: true
    ipam:
      config:
        - subnet: 10.0.0.0/24
  external-net:
    driver: bridge
                

Krok 2: Firewall kontejner

Pro Firewall kontejner si vytvoříme Dockerfile společně s entrypoint.sh skriptem. Tento skript nám nastaví pravidla firewallu pomocí IPtables a zapne monitoring sítě společně s logováním.

Dockerfile


FROM debian:bullseye

RUN apt-get update && apt-get install -y \
    iptables \
    tcpdump \
    iputils-ping \
    net-tools \
    curl \
    iproute2 \
    ulogd2 \
    && rm -rf /var/lib/apt/lists/*

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
                

entrypoint.sh


#!/bin/bash
set -e

# Najít správná rozhraní
INTERNAL_IF=$(ip -o -4 addr show | grep "10.0.0" | awk '{print $2}')
EXTERNAL_IF=$(ip -o -4 addr show | grep -v "10.0.0" | grep -v "127.0.0" | awk '{print $2}' | head -n1)

echo "Internal: $INTERNAL_IF, External: $EXTERNAL_IF"

if [ -z "$INTERNAL_IF" ] || [ -z "$EXTERNAL_IF" ]; then
    echo "CHYBA: Nelze detekovat rozhraní!"
    exit 1
fi

# Vyčistit pravidla
iptables -F
iptables -t nat -F
iptables -X

# Výchozí politiky
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Povolit loopback a navázaná spojení
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# === PING na firewall z internal sítě ===
iptables -A INPUT -i $INTERNAL_IF -p icmp --icmp-type echo-request -j ACCEPT

# === VPN PROVOZ (příchozí z venku) ===
# Logovat příchozí VPN provoz
iptables -A INPUT -i $EXTERNAL_IF -p udp --dport 1194 -j LOG --log-prefix "VPN-IN: "
iptables -A INPUT -i $EXTERNAL_IF -p udp --dport 1194 -j ACCEPT

# DNAT s logováním
iptables -t nat -A PREROUTING -i $EXTERNAL_IF -p udp --dport 1194 -j LOG --log-prefix "DNAT: "
iptables -t nat -A PREROUTING -i $EXTERNAL_IF -p udp --dport 1194 -j DNAT --to-destination 10.0.0.2:1194

# MASQUERADE pro příchozí VPN (KLÍČOVÉ!)
iptables -t nat -A POSTROUTING -o $INTERNAL_IF -d 10.0.0.2 -p udp --dport 1194 -j MASQUERADE

# Forward VPN provozu
iptables -A FORWARD -i $EXTERNAL_IF -o $INTERNAL_IF -d 10.0.0.2 -p udp --dport 1194 -j LOG --log-prefix "FWD-TO-VPN: "
iptables -A FORWARD -i $EXTERNAL_IF -o $INTERNAL_IF -d 10.0.0.2 -p udp --dport 1194 -j ACCEPT

# === ODCHOZÍ PROVOZ z internal sítě (OpenVPN kontejner) ===
# Povolit VEŠKERÝ odchozí provoz z OpenVPN kontejneru
iptables -A FORWARD -i $INTERNAL_IF -o $EXTERNAL_IF -s 10.0.0.0/24 -j LOG --log-prefix "FWD-OUT: "
iptables -A FORWARD -i $INTERNAL_IF -o $EXTERNAL_IF -s 10.0.0.0/24 -j ACCEPT

# MASQUERADE pro VEŠKERÝ odchozí provoz z internal net
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o $EXTERNAL_IF -j MASQUERADE

# Logovat zamítnuté pakety
iptables -A INPUT -j LOG --log-prefix "DROP-IN: " --log-level 4
iptables -A INPUT -j DROP
iptables -A FORWARD -j LOG --log-prefix "DROP-FWD: " --log-level 4
iptables -A FORWARD -j DROP

echo "Firewall pravidla nastavena s monitoringem"
iptables -L -n -v
iptables -t nat -L -n -v

echo "Přesměrovávám kernel logy..."
dmesg -w | tee -a /var/log/firewall/kernel.log &

# === MONITORING ===
mkdir -p /var/log/firewall

# Zachytávání VPN provozu do pcap souboru
echo "Spouštím tcpdump pro monitoring VPN provozu..."
tcpdump -i any -n udp port 1194 -w /var/log/firewall/vpn_traffic.pcap &

# Jednoduchý monitoring loop
echo "Spouštím monitoring loop..."
while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$TIMESTAMP] === Firewall Statistics ===" >> /var/log/firewall/stats.log
    iptables -L -n -v -x >> /var/log/firewall/stats.log
    echo "" >> /var/log/firewall/stats.log
    iptables -t nat -L -n -v -x >> /var/log/firewall/stats.log
    echo "======================================" >> /var/log/firewall/stats.log
    sleep 60
done
                

Krok 3: První spuštění

Před prvním spuštěním aplikace je potřeba provést pár kroků spojených s inicializací OpenVPN serveru a jeho konfigurace.

Vytvoření konfigurace OVPN serveru + Inicializace PKI

                    
docker compose run --rm openvpn ovpn_genconfig -u udp://IP_ADRESA_VIRTUALU:1194
docker compose run --rm openvpn ovpn_initpki
                

Vytvoření klientského certifikátu

                    
export CLIENTNAME="pks_virtual"
# with a passphrase (recommended)
docker compose run --rm openvpn easyrsa build-client-full $CLIENTNAME
# without a passphrase (not recommended)
docker compose run --rm openvpn easyrsa build-client-full $CLIENTNAME nopass
                

Získání klientské konfigurace pro připojení

                    
docker compose run --rm openvpn ovpn_getclient $CLIENTNAME > $CLIENTNAME.ovpn
                

Spuštění aplikace

                    
docker compose up -d --build
                

Krok 4: Úprava konfigurace OpenVPN serveru

Změna rozsahu odkud jsou přiřazovány adresy aby se nepřekrývaly s docker sítěma, nebo sítí v učebně. float aby prijimal klienty z jakehokoliv portu.

                    
server 172.30.0.0 255.255.255.0 #změna
float #přidat
                

Krok 5: Připojení k VPN

Vytvořený konfigurační soubor klienta zkopírujeme a přeneseme na vybrané zařízení. Pro testování jsem jako klienta zvolil PKS virtuál, kde jsem konfiguraci přenesl přes SCP.

                    
openvpn --config pks_virtual.ovpn &
                

Krok 5: Monitoring a logování

                    
tshark -r vpn_traffic.pcap

 1   0.000000 192.168.0.29 → 172.18.0.2   OpenVPN 90 MessageType: P_CONTROL_HARD_RESET_CLIENT_V2
 2   0.000068     10.0.0.3 → 10.0.0.2     OpenVPN 90 MessageType: P_CONTROL_HARD_RESET_CLIENT_V2
 3   0.000518     10.0.0.2 → 10.0.0.3     OpenVPN 102 MessageType: P_CONTROL_HARD_RESET_SERVER_V2
 4   0.000531   172.18.0.2 → 192.168.0.29 OpenVPN 102 MessageType: P_CONTROL_HARD_RESET_SERVER_V2
 5   0.000827 192.168.0.29 → 172.18.0.2   TLSv1 379 Client Hello
 6   0.000835     10.0.0.3 → 10.0.0.2     TLSv1 379 Client Hello
 7   0.003523     10.0.0.2 → 10.0.0.3     OpenVPN 98 MessageType: P_ACK_V1
 8   0.003533   172.18.0.2 → 192.168.0.29 OpenVPN 98 MessageType: P_ACK_V1
 9   0.003614     10.0.0.2 → 10.0.0.3     TLSv1.3 1208 Server Hello, Change Cipher Spec, Application Data, Application Data
10   0.003620   172.18.0.2 → 192.168.0.29 TLSv1.3 1208 Server Hello, Change Cipher Spec, Application Data, Application Data
11   0.003663     10.0.0.2 → 10.0.0.3     TLSv1.3 1208 Continuation Data
12   0.003683   172.18.0.2 → 192.168.0.29 TLSv1.3 1208 Continuation Data
13   0.003739     10.0.0.2 → 10.0.0.3     TLSv1.3 221 Continuation Data
14   0.003743   172.18.0.2 → 192.168.0.29 TLSv1.3 221 Continuation Data
15   0.004219 192.168.0.29 → 172.18.0.2   OpenVPN 102 MessageType: P_ACK_V1
16   0.004227     10.0.0.3 → 10.0.0.2     OpenVPN 102 MessageType: P_ACK_V1
17   0.005135 192.168.0.29 → 172.18.0.2   OpenVPN 106 MessageType: P_ACK_V1
18   0.005139     10.0.0.3 → 10.0.0.2     OpenVPN 106 MessageType: P_ACK_V1
19   0.007547 192.168.0.29 → 172.18.0.2   TLSv1.3 1270 Change Cipher Spec
20   0.007552     10.0.0.3 → 10.0.0.2     TLSv1.3 1270 Change Cipher Spec
21   0.007568 192.168.0.29 → 172.18.0.2   TLSv1.3 1270 Continuation Data
22   0.007572     10.0.0.3 → 10.0.0.2     TLSv1.3 1270 Continuation Data
23   0.007570 192.168.0.29 → 172.18.0.2   TLSv1.3 336 Continuation Data
24   0.007575     10.0.0.3 → 10.0.0.2     TLSv1.3 336 Continuation Data
25   0.007638     10.0.0.2 → 10.0.0.3     OpenVPN 98 MessageType: P_ACK_V1
26   0.007646   172.18.0.2 → 192.168.0.29 OpenVPN 98 MessageType: P_ACK_V1
27   0.008507     10.0.0.2 → 10.0.0.3     TLSv1.3 260 Application Data, Application Data
28   0.008516   172.18.0.2 → 192.168.0.29 TLSv1.3 260 Application Data, Application Data
29   0.008762 192.168.0.29 → 172.18.0.2   OpenVPN 114 MessageType: P_ACK_V1
30   0.008768     10.0.0.3 → 10.0.0.2     OpenVPN 114 MessageType: P_ACK_V1
31   0.008922     10.0.0.2 → 10.0.0.3     TLSv1.3 343 Application Data
32   0.008930   172.18.0.2 → 192.168.0.29 TLSv1.3 343 Application Data
33   0.009260 192.168.0.29 → 172.18.0.2   OpenVPN 118 MessageType: P_ACK_V1
34   0.009266     10.0.0.3 → 10.0.0.2     OpenVPN 118 MessageType: P_ACK_V1
35   1.135729 192.168.0.29 → 172.18.0.2   TLSv1.3 149 Application Data
36   1.135745     10.0.0.3 → 10.0.0.2     TLSv1.3 149 Application Data
37   1.136230     10.0.0.2 → 10.0.0.3     OpenVPN 98 MessageType: P_ACK_V1
38   1.136246   172.18.0.2 → 192.168.0.29 OpenVPN 98 MessageType: P_ACK_V1
39   1.136320     10.0.0.2 → 10.0.0.3     TLSv1.3 317 Application Data
40   1.136325   172.18.0.2 → 192.168.0.29 TLSv1.3 317 Application Data
41   1.137945 192.168.0.29 → 172.18.0.2   OpenVPN 122 MessageType: P_ACK_V1
42   1.137954     10.0.0.3 → 10.0.0.2     OpenVPN 122 MessageType: P_ACK_V1
43   1.137981 192.168.0.29 → 172.18.0.2   OpenVPN 121 MessageType: P_DATA_V2
44   1.137984     10.0.0.3 → 10.0.0.2     OpenVPN 121 MessageType: P_DATA_V2
45   5.199670 192.168.0.29 → 172.18.0.2   OpenVPN 121 MessageType: P_DATA_V2
            
                    
[2025-10-28 19:59:21] === Firewall Statistics ===
Chain INPUT (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination
      12     1128 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
       1       84 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
       1       84 ACCEPT     icmp --  eth1   *       0.0.0.0/0            0.0.0.0/0            icmptype 8
       0        0 LOG        udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:1194 LOG flags 0 level 4 prefix "VPN-IN: "
       0        0 ACCEPT     udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:1194
       0        0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4 prefix "DROP-IN: "
       0        0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain FORWARD (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination
     112    14795 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
       1       70 LOG        udp  --  eth0   eth1    0.0.0.0/0            10.0.0.2             udp dpt:1194 LOG flags 0 level 4 prefix "FWD-TO-VPN: "
       1       70 ACCEPT     udp  --  eth0   eth1    0.0.0.0/0            10.0.0.2             udp dpt:1194
       0        0 LOG        all  --  eth1   eth0    10.0.0.0/24          0.0.0.0/0            LOG flags 0 level 4 prefix "FWD-OUT: "
       0        0 ACCEPT     all  --  eth1   eth0    10.0.0.0/24          0.0.0.0/0
       0        0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4 prefix "DROP-FWD: "
       0        0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 14 packets, 1296 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination
       1       70 LOG        udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:1194 LOG flags 0 level 4 prefix "DNAT: "
       1       70 DNAT       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp dpt:1194 to:10.0.0.2:1194

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 6 packets, 480 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 6 packets, 480 bytes)
    pkts      bytes target     prot opt in     out     source               destination
       1       70 MASQUERADE  udp  --  *      eth1    0.0.0.0/0            10.0.0.2             udp dpt:1194
       0        0 MASQUERADE  all  --  *      eth0    10.0.0.0/24          0.0.0.0/0

Chain DOCKER_OUTPUT (0 references)
    pkts      bytes target     prot opt in     out     source               destination

Chain DOCKER_POSTROUTING (0 references)
    pkts      bytes target     prot opt in     out     source               destination
======================================

            

Zdroje

https://hub.docker.com/r/kylemanna/openvpn

https://github.com/kylemanna/docker-openvpn/blob/master/docs/docker-compose.md

https://docs.docker.com/reference/compose-file/networks/