2014-08-28 21 views
9

Il flusso di richiesta è il seguente;Vernice aggiungendo automaticamente il bilanciamento del carico IP all'intestazione X-Forwarded-For

HAProxy --> Varnish (4.0.1) --> Apache web backends 

Quando una nuova richiesta arriva a HAProxy, viene aggiunto l'indirizzo IP del client al X-Forwarded-For intestazione (che è buono!). Tuttavia, sembra che Varnish stia aggiungendo anche l'IP HAProxy. Quando la richiesta arriva al mio vcl_recv di routine, l'intestazione X-Forwarded-For è:

X-Forwarded-For: end-user-ip, haproxy-ip 

Si può vedere che nel varnishlog uscita:

* <<Request>> 8 
- Begin   req 7 rxreq 
- Timestamp  Start: 1409262358.542659 0.000000 0.000000 
- Timestamp  Req: 1409262358.542659 0.000000 0.000000 
- ReqStart  192.168.1.103 48193 
- ReqMethod  PURGE 
- ReqURL   /some/path 
- ReqProtocol HTTP/1.1 
- ReqHeader  Authorization: Basic xxx 
- ReqHeader  User-Agent: curl/7.30.0 
- ReqHeader  Host: example.com 
- ReqHeader  Accept: */* 
- ReqHeader  X-Forwarded-For: 1.2.3.4 
- ReqHeader  Connection: close 
- ReqUnset  X-Forwarded-For: 1.2.3.4 
- ReqHeader  X-Forwarded-For: 1.2.3.4, 192.168.1.101 
- VCL_call  RECV 
- ReqUnset  X-Forwarded-For: 1.2.3.4, 192.168.1.101 
- VCL_acl  NO_MATCH purge_acl 
- Debug   "VCL_error(403, Not allowed.)" 
- VCL_return  synth 

La ragione per cui ho bisogno l'indirizzo IP del client accurata è così posso controllarlo in base alle regole ACL per PURGE/BAN. Poiché l'ultimo IP nell'intestazione X-Forwarded-For è quello di HAProxy, il controllo ACL non riesce per tutti gli IP. Ecco la relativa sezione del mio config:

acl purge_acl { 
    "1.2.3.4"; 
} 

sub vcl_recv { 

    set req.backend_hint = load_balancer.backend(); 

    if (req.method == "PURGE") { 
     if (!std.ip(req.http.X-forwarded-for, "0.0.0.0") ~ purge_acl) { 
      return(synth(403, "Not allowed.")); 
     } 
     ban("obj.http.x-url ~ " + req.url); 
     return(synth(200, "Ban added")); 
    } 

} 

Tutte le idee come posso contare unicamente sulla X-Forwarded-For colpo di testa da HAProxy, senza smalto manomissione con esso?

Una nota a margine, sembra che Varnish sta facendo esattamente questo (anche se questo non è in mv config VCL):

if (req.restarts == 0) { 
    if (req.http.X-Forwarded-For) { 
     set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; 
    } else { 
     set req.http.X-Forwarded-For = client.ip; 
    } 
} 

risposta

8

Ho anche imbattuto in questo problema oggi.

Il default.vcl in vernice 4.0 è stato rinominato in builtin.vcl e non contiene la parte set req.http.X-Forwarded-For che lei ha menzionato - link. Ciononostante, aggiunge ad un elenco separato da virgole l'indirizzo IP del proxy intermedio secondo le specifiche del protocollo - Wikipedia link.

Una soluzione sarebbe utilizzare l'intestazione X-Real-IP invece, sovrascrivendo questa intestazione tutto il tempo in HAProxy con l'ip del client reale e utilizzando questo per ACL vcl.

Un'altra soluzione come (erroneamente) menzionata in the varnish forum, è regsub(req.http.X-Forwarded-For, "[, ].*$", "") che prende l'indirizzo IP più a sinistra. Tuttavia, questo metodo è NOT SECURE, poiché questa intestazione può essere facilmente falsificata.

Il mio suggerimento sarebbe quello di estrarre la parte conosciuto, IP vernice dalla testata in questo modo:

if (!std.ip(regsub(req.http.X-Forwarded-For, ", 192\.168\.1\.101$", ""), "0.0.0.0") ~ purge_acl) { 
    return(synth(403, "Not allowed.")); 
} 

L'unico problema di questo è che se ci sono più di 2 luppolo nella connessione, ad esempio. si utilizza anche un proxy per connettersi a Internet. Una buona soluzione per questo è fornita da nginx poiché è possibile definire hop fidati e vengono ignorati in modo ricorsivo fino all'ip reale del client.

set_real_ip_from 192.168.1.101; 
real_ip_header X-Forwarded-For; 
real_ip_recursive on; 

si possono vedere più dettagli su questo in questo serverfault thread answer

Si potrebbe anche voler controllare il motivo per cui nel vostro VCL_call RECV si fa un ReqUnset X-Forwarded-For prima della partita ACL.

+0

Eccellente grazie per essere tornato in questo post –

6

Varnish accoda la sua logica di default per tutte le funzioni si definisce come vcl_recv piuttosto piuttosto che ignorarlo. La logica di default vcl_recv contiene:

if (req.http.x-forwarded-for) { 
    set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; 
} else { 
    set req.http.X-Forwarded-For = client.ip; 
} 

come avete notato. Ciò che mi sembra strano è che sembra che la logica di default di Varnish in vcl_recv sia in esecuzione prima della logica vcl_recv. Che valore vedi per X-Forwarded-For entro vcl_deliver se definisci il tuo?

Una cosa che potreste fare è analizzare il primo indirizzo IP in questo modo, se necessario,: ​​

set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, "^([^,]+),?.*$", "\1"); 
+0

Questa risposta mi ha aiutato di più. – Josh

+0

Questa risposta non è valida per Varnish 4.xe versioni successive. Vedi https://stackoverflow.com/a/40840890/11303 – cosimo

2

Il codice sorgente Vanish è trasferita in GitHub così, per riferimento, poiché versione 4.0 logica X-Forwarded-For è stato spostato dalla builtin.vcl, (ex default.vcl), e la logica sorgente può essere trovato in bin/varnishd/cache/cache_req_fsm.c.