Apache / mod_ssl 可以支持两层操作吗?

Posted

技术标签:

【中文标题】Apache / mod_ssl 可以支持两层操作吗?【英文标题】:Can Apache / mod_ssl support two-tier operation? 【发布时间】:2016-07-26 02:21:32 【问题描述】:

我有一个 Web 服务器,它在本地数据库中维护其大部分内容,但需要查询后端目录服务来检索用户信息。目录查询作为独立操作可以正常工作,但是当 Web 服务器进行查询时,ssl 会返回错误。

服务器基于CentOS 7-2.1511 / Django 1.9.3 / PostgreSQL 9.2.15 / Apache 2.4.6-40 / mod_ssl 1:2.4.6-40 / OpenSSL 1:1.0.1 / Python 3.4.3。 Apache 使用 mod_ssl 服务来自客户端(浏览器)的 https: 请求,我假设 Python 的 ssl.py 使用相同的引擎向目录服务器发出 https: 请求。 Python SSL 表示它的实现基于 OpenSSL。 Yum 显然无法列出 mod_ssl 的依赖项,但我认为它也使用了已安装的 openssl 版本。

以下代码将获取用户的专有名称(从 SSL_CLIENT_CERT 中提取)并使用 RESTful 接口在目录服务器中查询用户的属性:

import requests, urllib

URL = 'https://example.com/rest/user_info/'

def get_user_info(dn)
    query = URL + urllib.parse.quote(dn)
    return requests.get(query, cert=('server.crt', 'server.key'),
                        verify='ca_bundle.crt').json()

当我在服务器的 WSGI 目录中作为用户 apache 在服务器上运行时,例程会正确返回包含用户属性的字典:

$ python
>>> import auth
>>> dn='cn=Me,o=Company,c=US'
>>> attr = auth.get_user_info(dn)

但是当 Apache 从它的 WSGI 脚本 (views.py) 调用具有相同 DN 的相同函数时,它会引发 OSError:

OSError(0, 'Error')
Line 810, /lib64/python3.4/ssl.py

803  def do_handshake(self, block=False):
804      """Perform a TLS/SSL handshake."""
805      self._check_connected()
806      timeout = self.gettimeout()
807      try:
808          if timeout == 0.0 and block:
809              self.settimeout(None)
810          self._sslobj.do_handshake()   

我将按照OpenSSL 的建议开始研究锁定(因为我想不出其他任何会导致这些错误的东西),但很难相信使用 SSL 进行后端查询的网络服务器还不够好——走过的路。问题:

    多线程/锁定/重入是否会导致这些错误的正确树? 是否已有使用 SSL 进行网络服务器后端连接的示例?

【问题讨论】:

首先映入我眼帘的是:您使用证书文件的相对路径。您的工作目录在 Apache 环境中可能有所不同。 好主意,但我从实际运行的代码中简化了示例代码。我的工作目录与服务器上运行的代码相同(Django 应用程序目录/srv/django/myapp),并且我有 SERVER_CERT、SERVER_KEY 和 CA_BUNDLE 的绝对路径变量。我在服务器上有一个 Python 虚拟环境,供 Apache 虚拟主机 WSGIDaemon 命令和我的命令行实验使用,正如我所说,我在 user:group apache:apache 下运行。 【参考方案1】:

我放弃了。以下内容可靠地工作,但以牺牲美观和效率为代价。它首先尝试一个requests 查询,如果它失败了,它会在一个子进程中启动并调用wget。它返回一个元项$method,让页面视图知道内联请求是否失败。

def get_user_info(dn, sub=True, ttl=300):
    query = URL + urllib.parse.quote(dn)
    try:
        info = requests.get(query, cert=(SERVER_CERT, SERVER_KEY),
                            verify=CA_CERT).json()
        info['$method'] = 'requests'
        return info
    except OSError:
        if sub:
            args = ['wget', '-O', '-',
                '--certificate=' + SERVER_CERT,
                '--private-key=' + SERVER_KEY,
                query]
            bytes = subprocess.check_output(args, timeout=5)
            info = json.loads(bytes.decode(encoding='utf-8'))
            info['$method'] = 'subprocess'
            return info
        else:
            raise

如果 OpenSSL 使用上下文而不是全局变量,那肯定会很好。

【讨论】:

以上是关于Apache / mod_ssl 可以支持两层操作吗?的主要内容,如果未能解决你的问题,请参考以下文章

Linux_install mod_ssl openssl apache

X.509 客户端身份验证的 Apache + mod_ssl 中间 CA 自动发现

无法加载 Apache mod_ssl

mod_ssl 2.8.31 是不是适用于 Apache 2.2?

如何在 Apache 2.2.9 中使用 mod_ssl 将 openssl 0.9.8 升级到 1.0.2

apache动静态编译