我公司网络中有一组 CentOS 服务器。出于安全原因,大多数服务器都没有通用的出站互联网访问权限,除非这是服务器的核心功能要求。
当我需要更新软件包时,这带来了挑战。对于 yum 存储库,我目前从互联网镜像所有需要的存储库,并将镜像在内联网中提供。我在我们的五个环境中分别保留每个存储库的副本:开发、QA、登台和两个生产数据中心。
我目前无法解决特定语言的软件包存储库问题。当服务器需要从 rubygems、PyPI、PECL、CPAN 或 npm 进行更新时,它们必须获取临时的出站互联网访问权限才能获取软件包。有人要求我开始镜像 rubygems 和 PyPI,其余的可能也会随之而来。
所有这些都很笨重,而且效果不佳。我想在一个环境中用单个缓存代理替换它,在其他环境中用四个菊花链代理替换它,以消除完整镜像的复杂性和磁盘开销。此外:
- 它可以是正向代理或反向代理;每个包管理器都支持代理服务器或自定义存储库端点,可以是本地镜像或反向代理。
- 它需要细粒度的访问控制,因此我可以限制哪些客户端 IP 可以连接到哪些 repo 域。
- 客户端需要能够跟踪到未知域的重定向。您的原始请求可能仅限于 rubygems.org,但如果该服务器向随机 CDN 返回 302,您应该能够跟踪它。
- 它应该支持 HTTPS 后端。我不一定需要模拟其他 SSL 服务器,但我应该能够通过 HTTP 重新公开 HTTPS 站点,或者终止并使用不同的证书重新加密。
我最初考虑的是反向代理,Varnish 似乎是唯一允许我在代理内内部解析 302 重定向的代理。但是,Varnish 的免费版本不支持 HTTPS 后端。我现在正在评估 Squid 作为正向代理选项。
这似乎是企业网络中一个相对常见的问题,但我找不到其他人如何解决这个问题的例子。有没有人实施过类似的事情,或者对如何最好地做到这一点有什么想法?
谢谢!
答案1
我们为此使用了 Squid;Squid 的优点在于,您可以相当轻松地根据模式匹配设置对象的单独到期时间,这样就可以相当快速地清除 yum repo 中的元数据。我们拥有的配置实现了这一点:
refresh_pattern (Release|Packages(.gz)*)$ 0 20% 2880
refresh_pattern (\.xml|xml\.gz)$ 0 20% 2880
refresh_pattern ((sqlite.bz2)*)$ 0 20% 2880
refresh_pattern (\.deb|\.udeb)$ 1296000 100% 1296000
refresh_pattern (\.rpm|\.srpm)$ 1296000 100% 1296000
refresh_pattern . 0 20% 4320
答案2
这是代理的明确用例. 普通代理,不是反向代理(又名负载均衡器)。
最知名、免费且开源的是 squidapt-get install squid3
。幸运的是,它是少数几个可以用单个文件轻松安装和配置的优秀开源软件之一/etc/squid3/squid.conf
。
我们将回顾良好的做法和值得了解的经验教训。
官方配置文件稍微修改了一下(删除了5000条无用的注释行)。
# WELCOME TO SQUID 3.4.8
# ----------------------------
#
# This is the documentation for the Squid configuration file.
# This documentation can also be found online at:
# http://www.squid-cache.org/Doc/config/
#
# You may wish to look at the Squid home page and wiki for the
# FAQ and other documentation:
# http://www.squid-cache.org/
# http://wiki.squid-cache.org/SquidFaq
# http://wiki.squid-cache.org/ConfigExamples
#
###########################################################
# ACL
###########################################################
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 1025-65535 # unregistered ports
acl CONNECT method CONNECT
#####################################################
# Recommended minimum Access Permission configuration
#####################################################
# Deny requests to certain unsafe ports
http_access deny !Safe_ports
# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports
# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager
#####################################################
# ACL
#####################################################
# access is limited to our subnets
acl mycompany_net src 10.0.0.0/8
# access is limited to whitelisted domains
# ".example.com" includes all subdomains of example.com
acl repo_domain dstdomain .keyserver.ubuntu.com
acl repo_domain dstdomain .debian.org
acl repo_domain dstdomain .python.org
# clients come from a known subnet AND go to a known domain
http_access allow repo_domain mycompany_net
# And finally deny all other access to this proxy
http_access deny all
#####################################################
# Other
#####################################################
# default proxy port is 3128
http_port 0.0.0.0:3128
# don't forward internal private IP addresses
forwarded_for off
# disable ALL caching
# bandwidth is cheap. debugging cache related bugs is expensive.
cache deny all
# logs
# Note: not sure if squid configures logrotate or not
access_log daemon:/var/log/squid3/access.log squid
access_log syslog:squid.INFO squid
# leave coredumps in the first cache dir
coredump_dir /var/spool/squid3
# force immediaty expiry of items in the cache.
# caching is disabled. This setting is set as an additional precaution.
refresh_pattern . 0 0% 0
客户端配置-环境变量
在所有系统上配置这两个环境变量。
http_proxy=squid.internal.mycompany.com:3128
https_proxy=squid.internal.mycompany.com:3128
大多数 http 客户端库(libcurl、httpclient 等)都是使用环境变量进行自我配置的。大多数应用程序都使用其中一个通用库,因此支持开箱即用的代理(开发人员不必知道他们这样做)。
请注意语法是严格的:
http_proxy
在大多数 Linux 中,变量名必须是小写的。- 变量值不能以
http(s)://
(代理协议不是 http(s))开头。
客户端配置 - 具体
一些应用程序忽略环境变量和/或在设置变量之前作为服务运行(例如 debian apt
)。
这些应用程序将需要特殊配置(例如/etc/apt.conf
)。
HTTPS 代理 - 连接
设计上完全支持 HTTPS 代理。它使用一种特殊的“CONNECT”方法在浏览器和代理之间建立某种隧道。
对这个东西不太了解,但多年来我从来没有遇到过问题。它就是好用。
HTTPS 特殊情况 - 透明代理
关于透明代理的说明。(即代理是隐藏的,它会拦截客户端请求,就像中间人一样)。
透明代理会破坏 HTTPS。客户端不知道有代理,因此没有理由使用特殊的 Connect 方法。
客户端尝试直接 HTTPS 连接……但被拦截。检测到拦截后,到处都会抛出错误。(HTTPS 旨在检测中间人攻击)。
域名和 CDN 白名单
squid 完全支持域和子域白名单。尽管如此,它有时还是会以意想不到的方式失败。
现代网站可以有各种域名重定向和 CDN。当人们没有付出额外努力将所有内容整齐地放在一个域名中时,这将破坏 ACL。
有时会有安装程序或包在运行前需要调用 homeship 或检索外部依赖项。每次都会失败,你对此无能为力。
缓存
提供的配置文件禁用了所有形式的缓存。谨慎一点总比后悔好。
就我个人而言,我目前在云中运行东西,所有实例都至少有 100 Mbps 的连接速度,提供商运行自己的热门软件库(例如 Debian),这些软件库会自动发现。这使得带宽成为我最不关心的商品。
我宁愿完全禁用缓存,也不愿遇到一个会让我绞尽脑汁进行故障排除的缓存错误。互联网上的每个人都不可能正确获取其缓存标头。
但并非所有环境都有相同的要求。您可以付出更多努力并配置缓存。
永远不需要在代理上进行身份验证
有一个选项是要求客户端进行密码验证,通常使用他们的 LDAP 帐户。它将破坏宇宙中的每个浏览器和每个命令行工具。
如果您想在代理上进行身份验证,请不要这样做。
如果管理层想要身份验证,请解释这是不可能的。
如果您是一名开发人员,并且刚刚加入了一家阻止直接互联网连接并强制代理身份验证的公司,请尽快逃离。
结论
我们讨论了常见的配置、常见的错误以及有关代理必须了解的事情。
学习到教训了:
- 有一个很好的开源代理软件(squid)
- 配置简单且容易(一个短文件)
- 所有(可选)安全措施都有利弊
- 大多数高级选项都会破坏某些东西并让你后悔莫及
- 透明代理正在破坏 HTTPS
- 代理身份验证很邪恶
与编程和系统设计一样,管理需求和期望至关重要。
我建议在设置代理时遵循基本原则。一般来说,没有任何特殊过滤的普通代理可以很好地工作,不会带来任何问题。只需记住(自动)配置客户端即可。
答案3
这并不能解决你所有的任务,但也许还是有帮助的。尽管名字如此,apt-cacher-ng不仅适用于 Debian 及其衍生产品,而且
缓存代理。专门用于 Linux 发行商的软件包文件,主要用于 Debian(以及基于 Debian)发行版,但不限于此。
我在与您类似的(基于 Debian)环境的生产中使用它。
但是,据我所知,这不支持 rubygems、PyPI、PECL、CPAN 或 npm,并且不提供细粒度的 ACL。
就我个人而言,我认为研究一下 Squid 是个好主意。如果您最终实施了设置,能否分享一下您的经验?我对它的进展非常感兴趣。
答案4
我们遇到了类似的挑战,并使用本地存储库和基于快照的存储系统解决了该问题。我们基本上更新开发存储库,将其克隆用于测试,将其克隆用于暂存,最后用于生产。这样使用的磁盘数量是有限的,而且都是慢速 SATA 存储,这没关系。
客户端从我们的配置管理中获取存储库信息,因此如果需要的话可以轻松切换。
您可以使用代理服务器上的 ace 来实现您想要的效果,使用用户代理字符串或源 ips/掩码组合并限制它们对某些域的访问,但如果您这样做,我看到的一个问题是包/库的版本不同。因此,如果其中一个主机可以访问 cpan 并请求模块 xxx::yyy,除非客户端指示使用特定版本,否则将从 cpan(或 pypy 或 rubygems)中提取最新版本,该版本可能是也可能不是已缓存在代理中的版本。因此,您最终可能会在同一个环境中得到不同的版本。如果您使用本地存储库,则不会遇到这个问题。