![](/img/trans.png)
[英]Kubernetes Python Client: connecting to a pod/service using Autobahn websocket/Twisted using bearer token
[英]Websocket Autobahn Python client: how to connect to server using server and client certificates?
websocket客户端(使用Autobahn / Python和Twisted)需要连接到websocket服务器:客户端需要将其客户端证书提供给服务器,客户端需要检查服务器的证书。 例如,在设置Kubernetes minikube安装期间创建了这些证书。 尤其是:
~/.minikube/ca.crt
(从我理解的X509格式)。 ~/.minikube/client.crt
带有密钥~/.minikube/client.key
。 我已经检查过我可以使用curl
成功使用这些证书+密钥来发出Kubernetes远程API调用。
从Autobahn的echo_tls / client.py示例中我了解到我可能需要使用ssl.ClientContextFactory()
。 这里的ssl
指的是自动扭曲导入的pyopenssl
包。
但是,我无法弄清楚如何将证书传递给工厂?
经过一些试验和错误,我现在已经到了下面的解决方案。 为了帮助其他人,我不仅会显示代码,还会提供参考设置来测试驱动示例代码。
首先,安装minikube,然后启动minikube实例; 我已经使用minikube 1.0.0进行了测试,然后运行Kubernetes 1.14,这是撰写本文时的最新内容。 然后启动一个简单的websocket服务器,它只显示发送给它的内容,并将发回给你连接的websocket客户端的任何输入。
minikube start
kubectl run wsserver --generator=run-pod/v1 --rm -i --tty \
--image ubuntu:disco -- bash -c "\
apt-get update && apt-get install -y wget && \
wget https://github.com/vi/websocat/releases/download/v1.4.0/websocat_1.4.0_ssl1.1_amd64.deb && \
dpkg -i webso*.deb && \
websocat -vv -s 0.0.0.0:8000"
接下来是Python代码。 它尝试连接到我们刚刚从minikube通过Kubernetes的远程API启动的wsserver,使用远程API作为其反向代理。 minikube设置通常使用客户端和服务器的相互SSL / TLS身份验证,因此这是一个“硬”测试。 请注意,还有其他方法,例如服务器证书和承载令牌(而不是客户端证书)。
import kubernetes.client.configuration
from urllib.parse import urlparse
from twisted.internet import reactor
from twisted.internet import ssl
from twisted.python import log
from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS
import sys
if __name__ == '__main__':
log.startLogging(sys.stdout)
class EchoClientProto(WebSocketClientProtocol):
def onOpen(self):
print('onOpen')
self.sendMessage('testing...\n'.encode('utf8'))
def onMessage(self, payload, isBinary):
print('onMessage')
if not isBinary:
print('message %s' % payload.decode('utf8'))
def onClose(self, wasClean, code, reason):
print('onClose', wasClean, code, reason)
print('stopping reactor...')
reactor.stop()
# Select the Kubernetes cluster context of the minikube instance,
# and see what client and server certificates need to be used in
# order to talk to the minikube's remote API instance...
kubernetes.config.load_kube_config(context='minikube')
ccfg = kubernetes.client.configuration.Configuration._default
print('Kubernetes API server CA certificate at %s' % ccfg.ssl_ca_cert)
with open(ccfg.ssl_ca_cert) as ca_cert:
trust_root = ssl.Certificate.loadPEM(ca_cert.read())
print('Kubernetes client key at %s' % ccfg.key_file)
print('Kubernetes client certificate at %s' % ccfg.cert_file)
with open(ccfg.key_file) as cl_key:
with open(ccfg.cert_file) as cl_cert:
client_cert = ssl.PrivateCertificate.loadPEM(cl_key.read() + cl_cert.read())
# Now for the real meat: construct the secure websocket URL that connects
# us with the example wsserver inside the minikube cluster, via the
# remote API proxy verb.
ws_url = 'wss://%s/api/v1/namespaces/default/pods/wsserver:8000/proxy/test' % urlparse(ccfg.host).netloc
print('will contact: %s' % ws_url)
factory = WebSocketClientFactory(ws_url)
factory.protocol = EchoClientProto
# We need to attach the client and server certificates to our websocket
# factory so it can successfully connect to the remote API.
context = ssl.optionsForClientTLS(
trust_root.getSubject().commonName.decode('utf8'),
trustRoot=trust_root,
clientCertificate=client_cert
)
connectWS(factory, context)
print('starting reactor...')
reactor.run()
print('reactor stopped.')
使用optionsForClientTLS
附加客户端和服务器证书时,棘手的部分是Twisted / SSL希望被告知我们要与之交谈的服务器名称。 这也需要通知虚拟服务器他们需要提供多个服务器证书中的哪一个 - 在有任何HTTP头之前!
不幸的是,现在这是一个丑陋的领域 - 我很乐意在这里得到反馈! 简单地使用urlparse(ccfg.host).hostname
可以在某些minikube实例上运行,但不能在其他实例上使用。 我还没弄清楚为什么看似相似的实例表现不同。
我目前的解决方法是从服务器的证书中简单地使用主题的CN(通用名称)。 当远程API服务器的URL使用IP地址文字而不是DNS名称(或至少是标签)时,可能更强大的方式可能只是采用这种策略。
唉,运行python3 wssex.py
上面的Python 3代码。 如果脚本正确连接,那么您应该看到类似于2019-05-03 12:34:56+9600 [-] {"peer": "tcp4:192.168.99.100:8443", "headers": {"sec-websocket-accept": ...
的日志消息2019-05-03 12:34:56+9600 [-] {"peer": "tcp4:192.168.99.100:8443", "headers": {"sec-websocket-accept": ...
此外,您之前启动的websocket服务器应显示日志消息,例如[INFO websocat::net_peer] Incoming TCP connection from Some(V4(172.17.0.1:35222))
等等。
这证明客户端脚本已通过安全websocket成功连接到minikube的远程API,通过身份验证和访问控制,现在连接到minikube内的(不安全)websocket演示服务器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.