Forward Proxy

Proprietà di un Forward Proxy

Gestisce le richieste cliente di accedere a risorse in internet. E' posizionato tra i client e l'internet, e inoltra le richieste a server esterni.

Il server di destinazione vede arrivare la richiesta dal forward proxy e non sa del vero client che l'ha originata.

Può includere filtraggio di contenuto, controlli di accesso e anonimizzazione delle richieste, nascondendo l'indirizzo IP del client.

Posizionato al confine della rete intranet del client.

Esercizio con Versione Debian e Ubuntu

Fwproxy

Creare la directory di esercizio:

mkdir 01net2-ccli-cproxy-cweb
cd 01net2-ccli-cproxy-cweb

NOTA

L'esercizio è scaricabile come file tar 01net2-ccli-cproxy-cweb.tar

Preparazione dello scaffolding:

mkdir ccli cproxy cweb
touch ccli/Dockerfile cproxy/Dockerfile docker-compose.yml
tree
.
├── ccli
│   └── Dockerfile
├── cproxy
│   └── Dockerfile
├── cweb
└── docker-compose.yml

Client

Il client ccli è un'immagine Alpine abbastanza semplice.

vim ccli/Dockerfile
FROM alpine:3.7
MAINTAINER John Smith <john@stormforce.ac>

RUN apk --update add --no-cache openssh tcpdump curl

CMD ["/bin/sleep","1000000"]

Proxy

Il proxy cproxy è un'immagine Ubuntu con la versione Debian/Ubuntu di Apache installata, più qualche altra utility.

vim cproxy/Dockerfile
FROM ubuntu

RUN apt update
RUN apt install -y apache2
RUN apt install -y vim curl wget iproute2 iputils-ping tcpdump

EXPOSE 80 443
CMD ["/bin/sleep","1000000"]

L'immagine Ubuntu di base è così scarna che non ha il comando ping e nemmeno il comando ip. Così, a scopo di debugging, vengono aggiunti i pacchetti iproute2, iputils-ping e tcpdump.

La configurazione del proxy viene mappata in un volume esterno, per la persistenza dei dati.

E' necessario creare a mano tale volume:

docker volume create conf

Web Server

Il web server cweb è un'immagine Alpine con la versione Unix di Apache, disponibile su Docker Hub.

docker-compose.yml

Il docker-compose.yml è:

vim docker-compose.yml
version: '3.6'

services:
  one:
    build: ccli
    image: ccli
    container_name: one
    hostname: one
    cap_add:
      - ALL
    networks:
      net1:
        ipv4_address: 192.168.101.11
  two:
    build: cproxy
    image: cproxy
    container_name: two
    hostname: two
    cap_add:
      - ALL
    volumes:
      - conf:/etc/apache2
    networks:
      net1:
        ipv4_address: 192.168.101.10
      net2:
        ipv4_address: 192.168.102.10
  three:
    image: httpd:2.4-alpine
    container_name: three
    hostname: three
    cap_add:
      - ALL
    networks:
      net2:
        ipv4_address: 192.168.102.12
networks:
  net1:
    name: net1
    ipam:
      driver: default
      config:
        - subnet: 192.168.101.0/24
  net2:
    name: net2
    ipam:
      driver: default
      config:
        - subnet: 192.168.102.0/24
volumes:
  conf:
    external: true

Lancio del progetto:

docker compose up -d

Controllo dei contenitori generati:

docker ps

Verifica Iniziale

Vogliamo verificare che il contenitore one (client) non riesce a connettersi col contenitore three (web server). Tra l'altro sono su due reti diverse e non è configurato il routing.

Connettersi a one:

docker exec -ti one sh

Provare la connessione:

curl http://192.168.102.12

Il comando si blocca: non è raggiungibile. Interrompere con Control-C

Uscire:

exit

Configurazione del Proxy

In una finestra di terminale collegarsi al contenitore two:

docker exec -ti two bash

Lanciare Apache:

apache2ctl -k start

Controllare che i processi siano attivi:

ps wax

Abilitare i moduli proxy, proxy_http, e proxy_connect:

a2enmod proxy proxy_http proxy_connect

Editare il file del modulo di proxy abilitato, scommentando le linee del proxy:

vim /etc/apache2/mods-enabled/proxy.conf
.....
        ProxyRequests On
        <Proxy *>
           AddDefaultCharset off
           Require all denied
           Require local
        </Proxy>
.....

Creare un nuovo Virtual Hosts:

vim /etc/apache2/sites-available/forward-proxy.conf
<VirtualHost *:8080>
  ProxyRequests On
  ProxyVia On
  <Proxy "*">
  Require ip 192.168
  </Proxy>
  ErrorLog ${APACHE_LOG_DIR}/error_forward_proxy.log
  CustomLog ${APACHE_LOG_DIR}/access_forward_proxy.log combined
</VirtualHost>

Modificare il file di configurazione delle porte, per aggiungere l'ascolto alla porta 8080:

vim /etc/apache2/ports.conf
Listen 80
Listen 8080

<IfModule ssl_module>
        Listen 443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
</IfModule>

Abilitare il sito virtuale:

a2ensite forward-proxy.conf

Restartare il server:

apache2ctl -k restart

Uscire dal container:

exit

Test del Proxy

Connettersi a one:

docker exec -ti one sh

Occorre configurare la variabile d'ambiente che setta il proxy:

export http_proxy=http://192.168.101.10:8080

Provare la connessione:

curl http://192.168.102.12
<html><body><h1>It works!</h1></body></html>

Prova di Persistenza Dati

Fermare e ristartare il progetto:

docker compose down
docker compose up -d

La configurazione precedente è rimasta perchè mantenuta nel volume conf.

Attivare il server proxy:

docker exec two apache2ctl -k start

Attenzione a non dare l'opzione -ti. Questa crea un terminale di collegamento, fa partire il server, poi il comando termina, il terminale muore e il processo apache2 rimane senza terminale di controllo e si trasforma in un processo zombie. L'unico modo di uscirne è di ristartare il progetto.

Il client ha lo stesso comportamento di prima.

Connettersi a one:

docker exec -ti one sh

Provare la connessione:

export http_proxy=http://192.168.101.10:8080
curl http://192.168.102.12

Esercizio con Versione Unix su Alpine Docker

Progetto

Nella stessa locazione dell'esercizio precedente, creare una nuova directory:

mkdir cproxyalp

Il Dockerfile è:

vim cproxyalp/Dockerfile
FROM alpine

RUN apk add apache2 apache2-proxy apache2-proxy-html curl

EXPOSE 80 443
CMD ["/bin/sleep","1000000"]

Il docker-compose.yml è:

vim docker-compose.yml
version: '3.6'

services:
  one:
    build: ccli
    image: ccli
    container_name: one
    hostname: one
    cap_add:
      - ALL
    networks:
      net1:
        ipv4_address: 192.168.101.11
  two:
    build: cproxyalp
    image: cproxyalp
    container_name: two
    hostname: two
    cap_add:
      - ALL
    networks:
      net1:
        ipv4_address: 192.168.101.10
      net2:
        ipv4_address: 192.168.102.10
  three:
    image: httpd:2.4-alpine
    container_name: three
    hostname: three
    cap_add:
      - ALL
    networks:
      net2:
        ipv4_address: 192.168.102.12
networks:
  net1:
    name: net1
    ipam:
      driver: default
      config:
        - subnet: 192.168.101.0/24
  net2:
    name: net2
    ipam:
      driver: default
      config:
        - subnet: 192.168.102.0/24

Partenza del progetto:

docker compose up -d

Configurazione

Connessione al proxy:

docker exec -ti two sh

Configurazione:

cd /etc/apache2
vi conf.d/forward-proxy.conf
<VirtualHost *:8080>
  ProxyRequests On
  ProxyVia On
  <Proxy "*">
  Require ip 192.168
  </Proxy>
  ErrorLog logs/error_forward_proxy.log
  CustomLog logs/access_forward_proxy.log combined
</VirtualHost>

Modificare il file di configurazione principale:

vi httpd.conf

Nella sezione Listen, aggiungere la linea:

Listen 8080

Far partire il server:

httpd -k start

Uscire:

exit

Test

Connettersi a one:

docker exec -ti one sh

Configurare il client proxy:

export http_proxy=http://192.168.101.10:8080

Provare la connessione:

curl http://192.168.102.12
<html><body><h1>It works!</h1></body></html>

Naturalmente questa configurazione non resiste ad un docker compose down. Se desideriamo la persistenza, allora dobbiamo creare un apposito volume docker e mapparlo alla directory di configurazione.