- 谁需要在对服务器的一个请求中使用几种类型的授权;
- 谁想要在不考虑如何保护特定服务的情况下向公共Internet开放Kubernetes / Docker世界的服务;
- 认为一切都已经由某人完成,并希望使世界变得更加方便和安全。
通过Kubernetes提供的前言服务具有丰富的授权方法集。一种更流行的方法是Authorization:Bearer标头-例如:JWT授权(JSON Web令牌),其中在一个标头中传输了许多密钥,因此还有值。还有一些基本授权,例如用于注册表(Docker映像存储库)的授权。该授权不使用cookie,并且会由浏览器自动添加到服务器的所有请求中(Safari除外-我们尚未决定是否有细微差别)。
问题1:
我无法在Storage OS界面中通过Firefox和Safari登录,显示了Loader,仅此而已。
迷你假设:
代理问题。快速检查显示了结果:如果授权不使用代理(使用证书的通用安全访问),则一切正常。那怎么办?
在分析了网络堆栈之后,我们意识到正在使用Authorization标头,但是,在较早的配置Rancher服务的代理期间,发现此标头已传递给代理服务,并且包含证书的授权数据,因此决定在完成授权过程后简单地将其删除(FakeBasicAuth )。
问题2:
在许多Web服务器中,通过模拟基本授权(实际上是在干扰用户请求)来实现带有个人证书的授权,这可能是为了减少Web服务器主代码中的更改。此方法称为FakeBasicAuth。设置了此类标头后,Web服务器将覆盖来自用户的授权标头。
假设:
- FakeBasicAuth标头的范围使自己受到更大的限制,因此可以还原原始标头以传输到代理资源,以便仅传输原始标头(如果有)。
- 可以设计Authorization标头的范围,以便在激活FakeBasicAuth机制之前先保存标头,然后再恢复。
可见状态-用途:
Storage OS授权,您可以配置此服务,同时保持使服务可用于外部Internet的统一方法。
附加目标:
统一,快速和安全的http访问,同时保持所有可能的http服务(例如,用于移动应用程序或Registry Docker的REST API)的功能。
怎么检查?
- docker login Registry-rancher.xxx.ru-使用密钥和登录名/密码。
- storageos-rancher.xxx.ru/#/登录-使用配置密钥中的登录名和密码secret rancher.xxx.ru/p/c-84bnv:p-qj9qm / secrets / kube-system:init-secr ...(在Safari中不起作用)。
- Registry - ui -rancher.xxx.ru-使用浏览器和注册表中的登录名/密码。对于那些认真阅读的人来说,诀窍是:您可以使用此界面代替标准的docker login Registry-rancher.xxx.ru-内置了对注册表的代理。
测试假设:
1.根据以往的经验,让我们尝试在Internet上找到一种针对此类请求的方法:通过cert进行apache身份验证外部基础。
关于ldap或多或少有足够的文章。通过这种方式:
RewriteEngine on
RewriteCond %{IS_SUBREQ} ^false$
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader set REMOTE_USER %{RU}e
然后通过构造将标题传递给其他标题
RequestHeader add Authorization "expr=%{env:zt-auth-before}" "expr=%{env:zt-auth-before} =~/.{1,}/"
但是,不幸的是,这种构造并不意味着创建相同的标头,用户请求的标头,并且env的格式不正确。
因此,基于标准重写的方法被证明是无用且复杂的。
2.如果我们不能做到这一点作为标准,那么我们就需要求助于LUA,我们先前看到,但是也有一些处理证书之前,从文章的框图再次执行,看看请求处理块lua_load_resty_core和module_lua_writinghooks指令与早期的建筑。
事实证明,我们可以使用相同的脚本(ZeroTech我们如何通过websockets与Apple Safari和客户端证书成为朋友)以保留Authorization标头,然后再将其替换为FakeBasicAuth。
LuaHookAccessChecker /usr/local/etc/apache24/sslincludes/websocket_token.lua handler early
在Lua中,现在看起来像这样:
require 'apache2'
function handler(r)
local fmt = '%Y%m%d%H%M%S'
local timeout = 3600 -- 1 hour
local auth = r.headers_in['Authorization']
r.notes['zt-cert-timeout'] = timeout
r.notes['zt-cert-date-next'] = os.date(fmt,os.time()+timeout)
r.notes['zt-cert-date-halfnext'] = os.date(fmt,os.time()+ (timeout/2))
r.notes['zt-cert-date-now'] = os.date(fmt,os.time())
if auth ~= nil then
r.notes['zt-auth-before'] = auth
end
return apache2.OK
end
注意:
新设计以粗体显示。并且由于我们知道从Lua获得的env仅可用于expr表达式,因此我们在加密zt-cert令牌的旁边添加了一个结构:
#向用户发送传出的cookie
Header set Set-Cookie "expr=zt-cert=%{sha1:...
#将标头传递给代理服务
RequestHeader add Authorization "expr=%{env:zt-auth-before}" "expr=%{env:zt-auth-before} =~/.{1,}/"
通过将数据传回用户到浏览器来检查是否有数据可以传输到服务:
Header add Authorization "expr=%{env:zt-auth-before}" "expr=%{env:zt-auth-before} =~/.{1,}/"
这里最有趣的事情是一种检查数据是否存在的方法,以免如果标头不是来自用户浏览器之外的,则不将标头传输到代理服务。构造的第二部分对此负责:
"expr=%{env:zt-auth-before} =~/.{1,}/"
完成:
Internet上目前没有现成的解决方案,因为我不想“重新发明轮子”,所以花了大约三个小时来搜索和尝试测试变体。
添加了5行,其中3条可以安全删除。你怎么看?-在文章的评论中写下您的答案选项。
我不想写这段经历,因为实际上只有两行,并且授权标题将到达收件人,但是我还是决定共享信息,因为它使用了以前对证书研究的丰富知识(我们正在谈论本文)。另外,几乎没有胆子敢于用未知的语言编写自己的东西并且如此简单。