1. はじめに
https://github.com/nin2yasu/samplephp
にあるようなHTTPヘッダ情報を出力するようなPHPアプリを用意して、アプリ側でのHTTPヘッダの中身をチェックしてみた。
2. 事前準備
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ oc new-app php~https://github.com/nin2yasu/samplephp
$ oc expose svc samplephp
$ oc get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
samplephp-1-build 0/1 Completed 0 117m 172.17.37.110 10.0.0.19 <none> <none>
samplephp-55c9fb7f6d-nngnz 1/1 Running 0 116m 172.17.37.122 10.0.0.19 <none> <none>
$ oc get routes
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
samplephp samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud samplephp 8080-tcp None
対象にcurlでアクセスしてみると、
$ curl http://samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
User-Agent: curl/7.29.0 <br>
Accept: */* <br>
Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud <br>
X-Forwarded-Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud <br>
X-Forwarded-Port: 80 <br>
X-Forwarded-Proto: http <br>
Forwarded: for=10.0.0.19;host=samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud;proto=http <br>
X-Forwarded-For: 10.0.0.19 <br>
のようにX-Forwarded-For
がHAProxyによって追加されていることも確認できる。
3. haproxy.configの内容
上記アプリはhaproxy.configで以下のように構成されている。
$ oc exec -it router-default-68b7c6f6c8-9cdpf -n openshift-ingress -- cat /var/lib/haproxy/conf/haproxy.config
(途中略)
# Plain http backend or backend with TLS terminated at the edge or a
# secure backend with re-encryption.
backend be_http:syasuda1:samplephp
mode http
option redispatch
option forwardfor
balance leastconn
timeout check 5000ms
http-request add-header X-Forwarded-Host %[req.hdr(host)]
http-request add-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto http if !{ ssl_fc }
http-request add-header X-Forwarded-Proto https if { ssl_fc }
http-request add-header X-Forwarded-Proto-Version h2 if { ssl_fc_alpn -i h2 }
http-request add-header Forwarded for=%[src];host=%[req.hdr(host)];proto=%[req.hdr(X-Forwarded-Proto)]
cookie 5444480f934221e15be9da82d28a3823 insert indirect nocache httponly
server pod:samplephp-55c9fb7f6d-nngnz:samplephp:8080-tcp:172.17.37.122:8080 172.17.37.122:8080 cookie c367f61b069035b158a420307b996c7f weight 256 check inter 5000ms
-
set-header
ではなくadd-header
が使われている。よって、上記で指定したヘッダは置換ではなく追記されている。 -
HAProxyのdocsによると、
option forwardfor
という設定でX-Forwarded-For
ヘッダが追加されている。実際、このdocsには以下のように記載されてもいる。
Since this header is always appended at the end of the existing header list
4. tcpdumpを実行して実際のHTTPヘッダを覗いてみる。
IBM Cloud: nsenterを使ったコンテナ上でのデバッグ方法(Red Hat OpenShift on IBM Cloudでの例)および80番ポートのHTTP GET requestの抽出方法を参照してtcpdumpを取得してみる。
4.1 通常アクセスの時
# curl http://samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
User-Agent: curl/7.29.0 <br>
Accept: */* <br>
Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud <br>
X-Forwarded-Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud <br>
X-Forwarded-Port: 80 <br>
X-Forwarded-Proto: http <br>
Forwarded: for=10.0.0.19;host=samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud;proto=http <br>
X-Forwarded-For: 10.0.0.19 <br>
tcpdumpによるHTTPリクエストヘッダ(GET)の情報
sh-4.4# nsenter -n -t ${pid} -- tcpdump -i any -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
03:52:45.082552 IP 172.17.37.45.39452 > kube-c3j463dt0o165mnm7be0-privonlysya-default-000005f4.webcache: Flags [P.], seq 2341353716:2341354263, ack 3432626976, win 57, options [nop,nop,TS val 371268340 ecr 371268340], length 547: HTTP: GET / HTTP/1.1
E..W" @.?.t...%-..%z......8.... ...9.......
.!...!..GET / HTTP/1.1
User-Agent: curl/7.29.0
Accept: */*
Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
X-Forwarded-Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Forwarded: for=10.0.0.19;host=samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud;proto=http
X-Forwarded-For: 10.0.0.19
4.1 X-Forwarded-For
をリクエストヘッダに含めた時(ROKSの前段にReverse Proxyが存在していることを想定)
$ curl http://samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud -H "X-Forwarded-For: 192.168.100.100"
User-Agent: curl/7.29.0 <br>
Accept: */* <br>
X-Forwarded-For: 192.168.100.100, 10.0.0.19 <br>
Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud <br>
X-Forwarded-Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud <br>
X-Forwarded-Port: 80 <br>
X-Forwarded-Proto: http <br>
Forwarded: for=10.0.0.19;host=samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud;proto=http <br>
tcpdumpによるHTTPリクエストヘッダ(GET)の情報
sh-4.4# nsenter -n -t ${pid} -- tcpdump -i any -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
04:24:56.570989 IP 172.17.37.45.58842 > kube-c3j463dt0o165mnm7be0-privonlysya-default-000005f4.webcache: Flags [P.], seq 3632158659:3632159240, ack 4114263037, win 57, options [nop,nop,TS val 373199828 ecr 373199828], length 581: HTTP: GET / HTTP/1.1
E..y..@.?.....%-..%z.....~W..:.....9.5.....
.>...>..GET / HTTP/1.1
User-Agent: curl/7.29.0
Accept: */*
X-Forwarded-For: 192.168.100.100
Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
X-Forwarded-Host: samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Forwarded: for=10.0.0.19;host=samplephp-syasuda1.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud;proto=http
X-Forwarded-For: 10.0.0.19
つまり、
X-Forwarded-For: xxx.xxx.xxx.xxx(リクエスト時の情報)
その他の Header
X-Forwarded-For: yyy.yyy.yyy.yyy(HAProxyが追加した情報)
```
という形式で実際はヘッダは付与されている。この2つの`X-Forwarded-For`をどのように取り扱うのかはアプリ側やサーバー側での処理に依存するということなのであろう。PHP+Apacheだと上記の結果のようにマージされて表示されている。