Reverse Proxy

Proprietà di un Reverse Proxy

Gestisce le richieste di un cliente esterno che accede a risorse nella intranet di un'organizzazione. Compie il forward delle richieste del client all'appropriato backend server.

Usato per load balancing, terminazione di SSL, cache e controlli di sicurezza.

I backend servers vedono la richiesta provenire dal reverse proxy come se questo fosse il client.

Posizionato al confine di ingresso dell'intranet di un'organizzazione, gestisce e controlla le richieste in ingresso.

Casi d'Uso di un Reverse Proxy

Con moduli del proxy server stesso:

  • Load Balancing: bilanciamento del carico dei backend server.
  • SSL Termination: possono gestire la crittografazione e decrittografazione con SSL/TLS per conto dei backend server.
  • Caching: accelerazione dei tempi di responso al client e diminuzione del carico dei backend server.

Con software aggiuntivo installato a bordo del proxy:

  • Sicurezza: possono filtrare il contenuto in provenienza dall'internet, e bloccare attacchi DDoS.
  • Web Application Firewall (WAF): possono proteggere la sicurezza dell'applicativo dei backend server, impedendo p.es. SQL Injection e Cross Site Scripting (XSS).
  • Conversione di Protocollo: possono tradurre richieste da un protocollo ad un altro.
  • Compressione ed Ottimizzazione: possono effettuare compressione ed ottimizzazionne dei responsi verso il client, riducendo i tempi di trasferimento.

Moduli Requisiti

  • mod_proxy: modulo primario, requisito
  • mod_proxy_http: gestisce i protocolli HTTP&HTTPS
  • mod_ssl: supporta i protocolli SSL v3 e TLS v1.x

Esercizio su Debian e Ubuntu

Revproxy

Preparazione

Creare la directory di esercizio:

mkdir -p 02net1-ccli-net2-cproxy-2cweb
cd 02net1-ccli-net2-cproxy-2cweb

Preparare lo scaffolding:

mkdir ccli cproxy cweb
touch ccli/Dockerfile cproxy/Dockerfile docker-compose.yml

Verificare l'albero:

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

Preparare volumi per la persistenza dati:

docker volume create confrev
docker volume create three-html
docker volume create four-html
docker volume ls

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"]

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:
      - confrev:/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
    volumes:
      - three-html:/usr/local/apache2/htdocs/
    networks:
      net2:
        ipv4_address: 192.168.102.12
  four:
    image: httpd:2.4-alpine
    container_name: four
    hostname: four
    cap_add:
      - ALL
    volumes:
      - four-html:/usr/local/apache2/htdocs/
    networks:
      net2:
        ipv4_address: 192.168.102.13
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:
  confrev:
    external: true
  three-html:
    external: true
  four-html:
    external: true

Lancio del progetto:

docker compose up -d

Controllo dei contenitori generati:

docker ps

Configurazione

Collegarsi a two ed abilitare il servizio web se non lo è già:

docker exec -ti two bash
apache2ctl -k start
ps wax

Moduli

Abilitare i moduli requisiti:

a2enmod proxy 
a2enmod proxy_http
a2enmod ssl

Verificare:

apache2ctl -M

Disabilitare il sito di default

a2dissite 000-default.conf

Creare un nuovo sito virtuale

cd /etc/apache2/sites-available
vim example.com.conf
<VirtualHost *:80>
    ServerName site1.com
    ServerAlias www.site1.com 
    ServerAdmin postmaster@site1.com
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    ProxyPass / http://192.168.102.12:80/
    ProxyPassReverse / http://192.168.102.12:80/
    ProxyRequests Off
</VirtualHost>
  • ServerName: nome ufficiale del server
  • ServerAlias: nomi aggiuntivi accettati dal server
  • ServerAdmin: posta elettronica dell'amministratore
  • ErrorLog: file degli errori
  • CustomLog: log delle richieste dei client al server
  • ProxyPass: mappa i server remoti nello spazio locale e definisce gli indirizzi target per la redirezione del traffico. E' il parametro che definisce il server corrente come reverse proxy.
  • ProxyPassReverse: gestisce i responsi dei backend servers, compiendo una riscrittura dei campi e headers del responso con le proprie informazioni. Questo impedisce che i backend server vengano esposti all'internet.
  • ProxyRequests: impedisce cge il server venga usato come forward proxy. Dovrebbe tipicamente essere settato ad off quando si usa ProxyPass.

Abilitare il Virtual Host

a2ensite example.com.conf

Restart

Restartare il server.

apachectl -k restart
ps wax

Uscire:

exit

Verifica

Vogliamo creare pagine web distintive per i downstream servers.

Collegarsi a three:

docker exec -ti three sh

Modificare il file principale di DocumentRoot:

vi /usr/local/apache2/htdocs/index.html
<html><body><h1>It works! I am three</h1></body></html>
exit

Simili cambiamenti su four:

docker exec -ti four sh

Modificare il file principale di DocumentRoot:

vi /usr/local/apache2/htdocs/index.html
<html><body><h1>It works! I am four</h1></body></html>
exit

Collegarsi a one:

docker exec -ti one sh

Collegamento a two:

curl 192.168.101.10
<html><body><h1>It works! I am three</h1></body></html>

Configurazione su Docker Alpine

Progetto 2

Aggiungere al progetto la directory cproxyalp:

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 è:

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
    volumes:
      - three-html:/usr/local/apache2/htdocs/
    networks:
      net2:
        ipv4_address: 192.168.102.12
  four:
    image: httpd:2.4-alpine
    container_name: four
    hostname: four
    cap_add:
      - ALL
    volumes:
      - four-html:/usr/local/apache2/htdocs/
    networks:
      net2:
        ipv4_address: 192.168.102.13
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:
  three-html:
    external: true
  four-html:
    external: true

Partenza del progetto:

docker compose up -d

Configurazione 2

Connessione al proxy:

docker exec -ti two sh

Configurazione:

cd /etc/apache2
vi conf.d/reverse-proxy.conf
<VirtualHost *:80>
    ServerName site1.com
    ServerAlias www.site1.com 
    ServerAdmin postmaster@site1.com
    ErrorLog logs/error.log
    CustomLog logs/access.log combined
    ProxyPass / http://192.168.102.12:80/
    ProxyPassReverse / http://192.168.102.12:80/
    ProxyRequests Off
</VirtualHost>

Disabilitare il forward proxy se esiste:

cd /etc/apache2/conf.d
mv forward-proxy.conf forward-proxy.conf.old 2> /dev/null

Verificare la configurazione:

httpd -t

Startare il server:

httpd -k start