Docker 容器虚拟主机 SSL 配置

Posted

技术标签:

【中文标题】Docker 容器虚拟主机 SSL 配置【英文标题】:Docker Container Virtual Host SSL Configuration 【发布时间】:2018-04-22 20:17:38 【问题描述】:

我有以下设置并且工作正常(我在 Docker 1.6 上):

一个 Docker 容器充当在单个 Docker 容器中运行的其他 Web 应用程序的虚拟主机代理。 (我应该补充一点,我不是配置服务器或网络方面的专家。)

我一直在尝试将 SSL 添加到设置中,但收效甚微。每个容器都会在主机上挂载证书的文件目录。例如,一旦我使用以下内容运行容器:

docker run -d -P --name build \
    -v /home/applications/src/ssl-cert:/etc/ssl/certs \
    -e "DBL=mysql:dbname=build;host=192.168.0.1;port=3306" \
    -e "DB_USER=foo" -e "DB_PASS=bar" \
    --link mysql56:mysql \
    --add-host dockerhost:`/sbin/ip addr | grep 'eth0' | grep 'inet' | cut -d'/' -f1 | awk 'print $2'` \
    -p 8001:80 -p 4431:443 \
     repos/build:latest

如果我尝试连接到https://build.example.com,我会收到证书错误并且无法连接。容器的 Apache 配置在 default-ssl.conf 中为证书文件提供了适当的配置(如果这是一个独立实例,则可以使用):

<VirtualHost _default_:443>
    ServerAdmin webmaster@localhost

    DocumentRoot /var/www/html/

    # Enable/Disable SSL for this virtual host.
    SSLEngine on

    SSLProtocol all -SSLv2 -SSLv3
    SSLHonorCipherOrder On
    SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS

    SSLCertificateFile /etc/ssl/certs/build.crt
    SSLCertificateKeyFile /etc/ssl/certs/build.key
    SSLCACertificateFile /etc/ssl/certs/digicert/digicertca.crt

    #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>
    <Directory /usr/lib/cgi-bin>
        SSLOptions +StdEnvVars
    </Directory>

    BrowserMatch "MSIE [2-6]" \
        nokeepalive ssl-unclean-shutdown \
        downgrade-1.0 force-response-1.0
    # MSIE 7 and newer should be able to use keepalive
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

</VirtualHost>

然后我尝试为代理容器运行以下命令:

docker run -it -d -P --name apache_proxy \
    -v /home/applications/src/ssl-cert:/etc/ssl/certs \
    -p 8000:80 -p 443:443 \
    repos/apache-proxy:latest

此容器也包含相同的 default-ssl.conf。

我尝试在几种不同的配置中运行它:

仅在 Apache 代理容器中运行 SSL 配置 仅在构建应用程序容器中运行 SSL 配置 在两个容器中运行 SSL 配置

如果感觉好像我错过了一些明显的东西,但无法确定它会是什么。在这样的配置中运行 SSL 时,我有什么遗漏吗?

【问题讨论】:

apache 启动时没有任何抱怨吗?什么是确切的 ssl 错误? Apache 启动并运行 fin @Robert。没有 SSL 错误保存,该站点将无法运行。 我想澄清一下:“我收到证书错误,无法连接。”能否提供详细信息? 我收到 503 错误。 您应该在 apache 错误日志中看到有关该 503 的更多详细信息。 【参考方案1】:

通常,如果您的服务器在 apache 服务器后面运行,您只需将 Apache 配置为使用 SSL 证书即可。 如果 Apache 是唯一的“外部”暴露服务器并且其他服务器不能从外部直接访问

您需要 apache 通过 url 或端口代理到其他服务器,例如:

<VirtualHost *:443>
    ServerName SERVERNAME_HERE

    SSLProtocol all -SSLv2 -SSLv3
    SSLHonorCipherOrder On
    SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS

    SSLCertificateFile /etc/ssl/certs/build.crt
    SSLCertificateKeyFile /etc/ssl/certs/build.key
    SSLCACertificateFile /etc/ssl/certs/digicert/digicertca.crt

    # Proxy pass to other server
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass / http://OTHER_SERVER_IP_WITHIN_DOCKER_NETWORK:8081/
    ProxyPassReverse / http://OTHER_SERVER_IP_WITHIN_DOCKER_NETWORK:8081/

<!--Other config-->
</VirtualHost>

希望对你有所帮助...

【讨论】:

【参考方案2】:

当我们想为反向代理后面的主机添加 SSL 时,我们可以通过三种方式配置主机:

Edge:反向代理解密传入的 HTTPS 流量并通过纯文本 HTTP 与后端服务器通信。 直通:后端服务器解密所有流量,反向代理只是将 HTTPS 请求转发给它们。 混合:反向代理解密 HTTPS 流量,然后重新加密发往后端服务器的流量。

第一个选项是最容易设置的——我们只需要在反向代理上安装证书和配置 SSL。第二种“直通”方法使后端服务器能够独立管理其 SSL 配置,但反向代理现在是“盲目的”,因为它无法读取加密流量,而我们可能想要为(例如)日志记录做这件事。当代理必须读取流量但我们也不信任代理和后端服务器之间的网络时,我们将使用第三种混合配置。

根据问题中的信息,第一个选项似乎最合适,因为我们信任反向代理和后端服务器之间的内部 Docker 网络。我们可以从后端服务器中删除 SSL 配置,并将来自反向代理的请求转发到它们的标准 HTTP 端口。

此设置需要两个额外的组件:

在代理上配置了基于名称的虚拟主机,用于转发每个后端服务的请求。 一个单个证书,可保护所有后端域名(作为多个主题或作为通配符,如*.example.com) .

这是我们可以构建的示例虚拟主机配置部分:

<VirtualHost *:443>
    ServerName build.example.com
    ProxyRequests Off
    ProxyPreserveHost On 
    ProxyPass / http://build:8001/ 
    ProxyPassReverse / http://build:8001/
</VirtualHost>
<VirtualHost *:443>
    ServerName cicd.example.com
    ProxyRequests Off
    ProxyPreserveHost On 
    ProxyPass / http://cicd:8002/ 
    ProxyPassReverse / http://cicd:8002/
</VirtualHost>

...记得在 default 虚拟主机块中配置 SSL 指令。如果我们链接容器或在同一个 Docker 网络上运行它们,我们可以在我们的 httpd.conf 中使用它们的容器名称作为主机名,如上所示。


说到网络,这个问题似乎表明我们需要仔细查看Docker networking,因为我没有看到任何表明容器被配置为相互通信的提示(503 响应状态支持这个假设)。反向代理容器必须将请求转发到每个后端容器,但它不能这样做,除非我们 link the containers(deprecated)或在容器之间创建一个内部 user-defined network:

$ docker network create build_network
$ docker run --network build_network --name apache_proxy ...
$ docker run --network build_network --name build ...
$ docker run --network build_network --name cicd ...

当我们在同一个用户定义的网络上运行容器时,它们可以通过 Docker 的内部 DNS 解析器通过容器名称解析其他容器的 IP 地址(或者如果我们将 --hostname 参数指定给 docker run,则可以通过备用主机名解析其他容器的 IP 地址)。另请注意,因为每个容器代表离散主机,我们不需要增加它们的端口号(80018002 等)。我们可以使用端口 80 来处理来自内部网络上每个容器的 HTTP 流量。

            +────────────────── Docker Host ─────────────────+
            │  +────────────── build_network ─────────────+  │
            │  │                                          │  │
  Client ────────────── apache_proxy (:443 → :443)        │  │
            │  │           ├── build (:80)                │  │
            │  │           └── cicd  (:80)                │  │
            │  +──────────────────────────────────────────+  │
            +────────────────────────────────────────────────+

【讨论】:

这里有很多很好的信息。我将在本周晚些时候回到办公室并进行设置和测试。 在网络上,ProxyPass / http://172.17.42.1:8001 用于(例如)在 Docker 网络上传递数据。这是“老派”,看起来这只老狗需要学习一些新技巧。 简而言之:升级 Docker 以利用其网络功能并在此处使用基本的 VH 指令以及之前设置的更明确的指令将为我们提供适当的设置以使其成功。谢谢! @Jay 抱歉——我把“1.6”误读为“1.16”……有一段时间没看到 1.6 的盒子了!可能是时候升级了 :) 很高兴这成功了!

以上是关于Docker 容器虚拟主机 SSL 配置的主要内容,如果未能解决你的问题,请参考以下文章

Docker编写多个SSL虚拟主机

如何安装和配置 Rex-Ray?- 每天5分钟玩转 Docker 容器技术(74)

docker 怎么把宿主机的文件拷贝到运行的容器中

如何安装和配置 Rex-Ray?- 每天5分钟玩转 Docker 容器技术(74)

docker容器中运行windows虚拟机

docker从容器中怎么访问宿主机