Endereço do visitante
Toda requisição que chega ao seu app passa antes pelo ingress do GoShip. Por isso o endereço da conexão que o app vê
(o RemoteAddr do Go, o REMOTE_ADDR do PHP, o req.socket.remoteAddress do Node) é o do ingress, não o do
visitante. O endereço do visitante vem nos cabeçalhos.
O que o GoShip garante
Em toda requisição, o GoShip define:
| Cabeçalho | Valor |
|---|---|
X-Real-IP | o endereço que abriu a conexão com o GoShip |
X-Forwarded-For | o mesmo endereço, sozinho |
X-Forwarded-Proto | https ou http, como o visitante chegou |
X-Forwarded-Host | o domínio pedido |
Se o cliente mandar algum desses cabeçalhos, o valor dele é descartado e substituído. X-Forwarded-For não acumula
o que veio antes: ele traz um endereço só. Assim, um visitante não consegue se passar por outro endereço só
mandando um cabeçalho.
Vale no cluster GoShip e nos clusters que o GoShip monta nos seus servidores (Conectar servidor). Num Kubernetes que você conectou (Conectar Kubernetes), quem define esses cabeçalhos é o ingress do seu cluster.
Use X-Real-IP. Outros cabeçalhos que o cliente mandar, como True-Client-IP ou CF-Connecting-IP, chegam ao app
como vieram. Não confie neles sem a verificação abaixo.
Com uma CDN na frente do seu domínio
Se o seu domínio próprio passa por uma CDN, como o proxy laranja da Cloudflare, quem abre a conexão com o GoShip é a CDN.
Então X-Real-IP traz o endereço da CDN. O do visitante vem no cabeçalho da CDN: CF-Connecting-IP, no caso da
Cloudflare.
Leia esse cabeçalho só quando X-Real-IP estiver nas faixas publicadas pela CDN. O endereço *.apps.goship.sh
do app não passa pela CDN. Quem chamar esse endereço direto pode mandar o CF-Connecting-IP que quiser. A Cloudflare
publica as faixas dela em https://www.cloudflare.com/ips/. Elas mudam pouco, mas mudam: atualize a lista de tempos
em tempos.
Exemplo em Go:
package clientip
import (
"net/http"
"net/netip"
)
// Faixas de https://www.cloudflare.com/ips-v4 e https://www.cloudflare.com/ips-v6.
// Copie a lista completa e atualize de tempos em tempos.
var cloudflare = []netip.Prefix{
netip.MustParsePrefix("173.245.48.0/20"),
netip.MustParsePrefix("103.21.244.0/22"),
// ...
netip.MustParsePrefix("2606:4700::/32"),
}
// From devolve o endereço do visitante.
func From(r *http.Request) string {
real := r.Header.Get("X-Real-IP") // definido pelo GoShip
addr, err := netip.ParseAddr(real)
if err != nil {
return real
}
for _, p := range cloudflare {
if p.Contains(addr.Unmap()) {
if cf, err := netip.ParseAddr(r.Header.Get("CF-Connecting-IP")); err == nil {
return cf.String()
}
break
}
}
return real
}O mesmo vale em qualquer linguagem: primeiro confira de onde veio a conexão (X-Real-IP), depois decida se o
cabeçalho da CDN merece confiança.
Não adicione as faixas da CDN como “proxies confiáveis” num middleware que lê X-Forwarded-For de trás para frente.
O GoShip já entrega um endereço só, então não há cadeia para percorrer.