Controllare il proxy proxy Nginx usando un cookie?


11

Sto cercando di convertire un proxy inverso utilizzando un'interessante configurazione mod_rewrite di Apache per utilizzare Nginx (a causa di preoccupazioni esterne ci stiamo spostando da Apache a Nginx e quasi tutto funziona bene tranne questa parte).

La mia configurazione originale era quella di leggere un cookie HTTP (impostato da alcune applicazioni) e, a seconda del suo valore, indirizzare il proxy inverso a diversi backend. È andata più o meno così:

RewriteCond %{HTTP_COOKIE}  proxy-target-A
RewriteRule ^/original-request/ http://backend-a/some-application [P,QSA]

RewriteCond %{HTTP_COOKIE}  proxy-target-B
RewriteRule ^/original-request http://backend-b/another-application [P,QSA]

RewriteRule ^/original-request http://primary-backend/original-application [P,QSA]

Sto cercando di ottenere lo stesso utilizzando Nginx e la mia configurazione iniziale era qualcosa del genere (dove "proxy_override" è il nome del cookie):

location /original-request {
    if ($cookie_proxy_override = "proxy-target-A") {
        rewrite . http://backend-a/some-application;
        break;
    }
    if ($cookie_proxy_override = "proxy-target-B") {
        rewrite . http://backend-b/another-application;
        break;
    }
    proxy_pass http://primary-backend/original-application;
}

Ma non lo fece. Ho provato a vedere se Nginx è in grado di leggere il mio cookie scrivendo il proxy principale per reindirizzare a qualcosa in base ${cookie_proxy_override}e posso vedere che legge bene il contenuto, ma ifsembra che non riescano sempre.

Il mio prossimo tentativo, secondo la risposta di Rikih, è stato questo:

location /original-request {
    if ($http_cookie ~ "proxy-target-A") {
        rewrite . http://backend-a/some-application;
        break;
    }
    if ($http_cookie ~ "proxy-target-B") {
        rewrite . http://backend-b/another-application;
        break;
    }
    proxy_pass http://primary-backend/original-application;
}

E ora posso vedere che il ifblocco viene attivato, ma invece di inoltrare la richiesta (come pensavo che avrebbe fatto) restituisce un reindirizzamento 302 all'URL specificato - che non è quello che sto cercando di fare: ho bisogno del server per inoltrare in modo trasparente la richiesta ai backend e inoltrare la risposta al client originale.

Che cosa sto facendo di sbagliato?

Risposte:


16

Simile a questa risposta . L'approccio idiomatico di Nginx a questo tipo di problemi è via map.

Fondamentalmente, si definisce un mapnella httpsezione

map $cookie_proxy_override $my_upstream {
  default default-server-or-upstream;
  ~^(?P<name>[\w-]+) $name;
}

Quindi usi semplicemente $my_upstreamnelle locationsezioni:

location /original-request {
  proxy_pass http://$my_upstream$uri;
}

Nginx valuta pigramente le variabili della mappa, solo una volta (per richiesta) e quando le stai usando.


3
Grazie, questo è un approccio migliore del mio, in particolare perché posso usare direttamente la variabile cookie denominata (non sono sicuro del perché non riesco a ifentrare) e l'ho implementata. C'è un problema però: a Nginx (almeno la mia versione 1.0.0) non piacciono le acquisizioni numerate map, quindi ho dovuto usare ~^(?P<name>[\w-]+) $name;invece. Ho modificato la tua risposta di conseguenza.
Guss,

3

Alla fine la mia soluzione si riduce a questo:

server {
    ...
    set $upstream "default-server-or-upstream";
    if ($http_cookie ~ "proxy_override=([\w-]+)") {
        set $upstream $1;                                   
    }

    location /original-request {
        proxy_pass http://$upstream/original-application
    }
}

Il test viene eseguito servernell'ambito di ciascuna richiesta (prima che venga risolto il reindirizzamento effettivo) e viene appena utilizzato per impostare una variabile - questo è apparentemente un utilizzo supportato del modulo "riscrivi" di Nginx. $http_cookieVerifica anche l'intero come suggerito da @Rikih, ma include il nome del cookie per assicurarsi che non corrisponda a cose casuali che le persone potrebbero lanciarmi.

Quindi locationnell'ambito in cui desidero eseguire il reindirizzamento, utilizzo il nome della variabile che contiene la configurazione upstream predefinita o è stato sovrascritto dal cookie.


0

hai provato $ http_cookie? http://wiki.nginx.org/HttpRewriteModule

if ($ http_cookie ~ * "proxy-target-A") {pippo; }


Questo ha funzionato davvero per il test, anche se non sono sicuro del motivo per cui non posso semplicemente testare con il nome specifico del cookie. Quello che non mi è piaciuto è che in rewriterealtà non esegue una riscrittura del proxy ma restituisce un reindirizzamento al client e non riesco a utilizzare proxy_pass nel ifblocco. Ho aggiornato la domanda di conseguenza.
Guss,

0

ho un campione che uso per rilevare l'intestazione della richiesta basata su udid e funziona, potrebbe darti un'idea.

   location / {
      proxy_set_header Host $http_host;
  if ($request_uri ~ ^/(.*)udid=xxxxxxxxxxxxxx(.*)$) {
    proxy_pass   http://1.1.1.1$request_uri;
    break;
  }
  if ($request_uri ~ ^/(.*)udid=yyyyyyyyyyyyyy(.*)$) {
    proxy_pass   http://3.3.3.3$request_uri;
    break;
  }
       proxy_pass http://2.2.2.2$request_uri;
    }

Quale versione di Nginx stai usando? Sto usando 1.0 e quando uso proxy_pass come hai specificato qui, ricevo questo messaggio di errore:nginx: [emerg] "proxy_pass" may not have URI part in location given by regular expression, or inside named location, or inside the "if" statement, or inside the "limit_except" block in /etc/nginx/conf.d/proxy.conf:47
Guss

uso nginx-0.8.53-1.el5
chocripple

potresti voler dare un'occhiata forum.nginx.org/read.php?2,13955,15981
chocripple

La soluzione nel forum è non modificare l'URI della richiesta quando si esegue il proxy su un altro server, ma è esattamente quello che devo fare: riscrivere l'URI della richiesta per indirizzare un'applicazione diversa da quella inclusa nell'URL originale. Inoltre, il tuo esempio sembra utilizzare anche l'URI di richiesta nel proxy_passcomando, quindi non sono sicuro di come possa funzionare per te, dato la discussione del forum sopra.
Guss,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.