为什么 docker 主机上的 Jenkins 响应来自容器内部的 HTTP 请求?
Why is Jenkins on the docker host responding to HTTP requests from inside containers?
我在一台同时安装了 Jenkins 和 Docker 的机器上遇到了一些相当奇怪的行为。为清楚起见,Jenkins 不是 运行 作为 Docker 容器,而是在 jenkins
用户下运行。
当 运行 curl
在一个容器中时,我得到一个 403:
root@ada71c8116bf:/# curl -I www.google.co.uk
HTTP/1.1 403 Forbidden
Date: Tue, 30 May 2017 13:41:07 GMT
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID.f1223778=36hjq9sozhveoe1bfsss1dnq;Path=/;HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=UTF-8
X-Hudson: 1.395
X-Jenkins: 2.46.3
X-Jenkins-Session: 2836b130
X-You-Are-Authenticated-As: anonymous
X-You-Are-In-Group-Disabled: JENKINS-39402: use -Dhudson.security.AccessDeniedException2.REPORT_GROUP_HEADERS=true or use /whoAmI to diagnose
X-Required-Permission: hudson.model.Hudson.Read
X-Permission-Implied-By: hudson.security.Permission.GenericRead
X-Permission-Implied-By: hudson.model.Hudson.Administer
Content-Length: 793
Server: Jetty(9.2.z-SNAPSHOT)
在主机上的容器外,我得到了预期的响应:
$ curl -I www.google.co.uk
HTTP/1.1 200 OK
Date: Tue, 30 May 2017 13:40:17 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=104=mMKjBy002X3N_SkhkD_8xuAwpFuw03CFi0iOJjNX81FUHfMT6qTq95LcgRwdhrV_GZoUF9LQ1B9qAQPriN9Er3Bu2JWoqPgvt16TduuVj5QsNs9GiJTQBtaSXWic7G9E; expires=Wed, 29-Nov-2017 13:40:17 GMT; path=/; domain=.google.co.uk; HttpOnly
Transfer-Encoding: chunked
Accept-Ranges: none
Vary: Accept-Encoding
Jenkins 显然是罪魁祸首,但我不知道为什么它会拦截离开容器的 HTTP 流量。 Pinging Google 工作正常,发送 HTTPS 请求也是如此。没有其他机器拥有这个问题(大概是因为他们没有安装 Jenkins)。那么,这是怎么回事?如何让 Jenkins 停止拦截来自 Docker 容器的 HTTP?
更新
关闭 Jenkins 的 "Prevent Cross Site Request Forgery exploits" 选项会导致 Jenkins 不再 return 403。相反,Jenkins 使用仪表板页面(即默认页面)响应来自容器内的任何 HTTP 请求。
还值得注意的是 DNS 工作正常;主机名解析为正确的 IP 地址。
我要退出 Wireshark。
通过使用 Wireshark,我发现某些东西正在将 HTTP 流量重定向到主机上的端口 8090。一个幸运的 google 让我检查了主机的 IP 表 (iptables -t nat -L -n
),果然有规则将所有端口 80 流量 从任何地方 重定向到端口 8090主人。显然有人为了 Jenkins 用户的利益设置了这个重定向。
解决方案是更改 IP 表以不重定向来自 docker 子网的流量。
之前的表格:
$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 127.0.0.1 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
要更改的命令:
$ sudo iptables -t nat -R PREROUTING 1 ! -s 172.17.0.0/16 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8090
$ sudo iptables -t nat -R OUTPUT 1 ! -s 172.17.0.0/16 -d 127.0.0.1/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8090
生成的 IP 表:
$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- !172.17.0.0/16 0.0.0.0/0 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- !172.17.0.0/16 127.0.0.1 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
我在一台同时安装了 Jenkins 和 Docker 的机器上遇到了一些相当奇怪的行为。为清楚起见,Jenkins 不是 运行 作为 Docker 容器,而是在 jenkins
用户下运行。
当 运行 curl
在一个容器中时,我得到一个 403:
root@ada71c8116bf:/# curl -I www.google.co.uk
HTTP/1.1 403 Forbidden
Date: Tue, 30 May 2017 13:41:07 GMT
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID.f1223778=36hjq9sozhveoe1bfsss1dnq;Path=/;HttpOnly
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/html;charset=UTF-8
X-Hudson: 1.395
X-Jenkins: 2.46.3
X-Jenkins-Session: 2836b130
X-You-Are-Authenticated-As: anonymous
X-You-Are-In-Group-Disabled: JENKINS-39402: use -Dhudson.security.AccessDeniedException2.REPORT_GROUP_HEADERS=true or use /whoAmI to diagnose
X-Required-Permission: hudson.model.Hudson.Read
X-Permission-Implied-By: hudson.security.Permission.GenericRead
X-Permission-Implied-By: hudson.model.Hudson.Administer
Content-Length: 793
Server: Jetty(9.2.z-SNAPSHOT)
在主机上的容器外,我得到了预期的响应:
$ curl -I www.google.co.uk
HTTP/1.1 200 OK
Date: Tue, 30 May 2017 13:40:17 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=104=mMKjBy002X3N_SkhkD_8xuAwpFuw03CFi0iOJjNX81FUHfMT6qTq95LcgRwdhrV_GZoUF9LQ1B9qAQPriN9Er3Bu2JWoqPgvt16TduuVj5QsNs9GiJTQBtaSXWic7G9E; expires=Wed, 29-Nov-2017 13:40:17 GMT; path=/; domain=.google.co.uk; HttpOnly
Transfer-Encoding: chunked
Accept-Ranges: none
Vary: Accept-Encoding
Jenkins 显然是罪魁祸首,但我不知道为什么它会拦截离开容器的 HTTP 流量。 Pinging Google 工作正常,发送 HTTPS 请求也是如此。没有其他机器拥有这个问题(大概是因为他们没有安装 Jenkins)。那么,这是怎么回事?如何让 Jenkins 停止拦截来自 Docker 容器的 HTTP?
更新
关闭 Jenkins 的 "Prevent Cross Site Request Forgery exploits" 选项会导致 Jenkins 不再 return 403。相反,Jenkins 使用仪表板页面(即默认页面)响应来自容器内的任何 HTTP 请求。
还值得注意的是 DNS 工作正常;主机名解析为正确的 IP 地址。
我要退出 Wireshark。
通过使用 Wireshark,我发现某些东西正在将 HTTP 流量重定向到主机上的端口 8090。一个幸运的 google 让我检查了主机的 IP 表 (iptables -t nat -L -n
),果然有规则将所有端口 80 流量 从任何地方 重定向到端口 8090主人。显然有人为了 Jenkins 用户的利益设置了这个重定向。
解决方案是更改 IP 表以不重定向来自 docker 子网的流量。
之前的表格:
$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 127.0.0.1 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
要更改的命令:
$ sudo iptables -t nat -R PREROUTING 1 ! -s 172.17.0.0/16 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8090
$ sudo iptables -t nat -R OUTPUT 1 ! -s 172.17.0.0/16 -d 127.0.0.1/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8090
生成的 IP 表:
$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- !172.17.0.0/16 0.0.0.0/0 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- !172.17.0.0/16 127.0.0.1 tcp dpt:80 redir ports 8090
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0