2 回答
TA貢獻1911條經(jīng)驗 獲得超7個贊
有幾種方法是可能的。Daniel F 的回答非常好,并展示了一種很好的通用技術(shù)來動態(tài)重新配置服務器。
這里還有一些技術(shù)更具體地適用于 Twisted 中的 TLS 支持。
DefaultOpenSSLContextFactory首先,您可以從實例中重新加載 OpenSSL“上下文”對象。當需要重新加載證書時,運行:
sslContext._context = None
sslContext.cacheContext()
該cacheContext調(diào)用將創(chuàng)建一個新的 OpenSSL 上下文,在此過程中重新讀取證書文件。這確實有依賴私有接口 ( _context) 及其與非真正公共接口 ( cacheContext) 交互的缺點。
你也可以實現(xiàn)你自己的版本,DefaultOpenSSLContextFactory這樣你就不必依賴這些東西了。 DefaultOpenSSLContextFactory并沒有真正做太多。這是一個完全刪除緩存行為的復制/粘貼/編輯:
class DefaultOpenSSLContextFactory(ContextFactory):
"""
L{DefaultOpenSSLContextFactory} is a factory for server-side SSL context
objects. These objects define certain parameters related to SSL
handshakes and the subsequent connection.
"""
_context = None
def __init__(self, privateKeyFileName, certificateFileName,
sslmethod=SSL.SSLv23_METHOD, _contextFactory=SSL.Context):
"""
@param privateKeyFileName: Name of a file containing a private key
@param certificateFileName: Name of a file containing a certificate
@param sslmethod: The SSL method to use
"""
self.privateKeyFileName = privateKeyFileName
self.certificateFileName = certificateFileName
self.sslmethod = sslmethod
self._contextFactory = _contextFactory
def getContext(self):
"""
Return an SSL context.
"""
ctx = self._contextFactory(self.sslmethod)
# Disallow SSLv2! It's insecure! SSLv3 has been around since
# 1996. It's time to move on.
ctx.set_options(SSL.OP_NO_SSLv2)
ctx.use_certificate_file(self.certificateFileName)
ctx.use_privatekey_file(self.privateKeyFileName)
當然,這會為每個可能不受歡迎的連接重新加載證書文件。您可以重新添加自己的緩存邏輯,并使用適合您的證書刷新系統(tǒng)的控制界面。這也有一個缺點,那DefaultOpenSSLContextFactory就是一開始就不是一個非常好的 SSL 上下文工廠。它不遵循 TLS 配置的當前最佳實踐。
所以你可能真的想twisted.internet.ssl.CertificateOptions改用。這有一個類似的_context緩存,您可以清除它:
sslContext = CertificateOptions(...) # Or PrivateCertificate(...).options(...)
...
sslContext._context = None
它會在發(fā)現(xiàn)上下文時自動重新生成上下文,None因此至少您不必以cacheContext這種方式調(diào)用。但是,您再次依賴于私有接口。
另一種更類似于 Daniel F 建議的技術(shù)是為已經(jīng)在監(jiān)聽的套接字提供一個新工廠。這避免了stopListening和之間的服務短暫中斷l(xiāng)istenSSL。這將是這樣的:
from twisted.protocols.tls import TLSMemoryBIOFactory
# DefaultOpenSSLContextFactory or CertificateOptions or whatever
newContextFactory = ...
tlsWebsiteFactory = TLSMemoryBIOFactory(
newContextFactory,
isClient=False,
websiteFactory,
)
listeningPortFileno = sslPort.fileno()
websiteFactory.sslPort.stopReading()
websiteFactory.sslPort = reactor.adoptStreamPort(
listeningPortFileno,
AF_INET,
tlsWebsiteFactory,
)
這基本上只是讓反應堆停止為sslPort具有過時配置的舊設備提供服務,并告訴它開始為新工廠上該端口的底層套接字服務事件。在這種方法中,您必須下降到稍低級別的 TLS 接口,因為您不能采用“TLS 端口”,因為沒有這樣的東西。相反,您采用 TCP 端口并自己應用必要的 TLS 包裝(這正是 listenSSL 在幕后為您所做的)。
請注意,這種方法比其他方法更受限制,因為并非所有反應器都提供filenooradoptStreamPort方法。如果您想在受支持的地方使用它并在其他地方優(yōu)雅地降級,您可以測試各種對象提供的接口。
另請注意,因為TLSMemoryBIOFactory無論如何它總是在幕后工作,如果你有對它的引用,你也可以旋轉(zhuǎn)它的私有接口:
tlsMemoryBIOFactory._connectionCreator = IOpenSSLServerConnectionCreator(
newContextFactory,
)
它將開始將其用于新連接。但是,再次,私人...
TA貢獻1859條經(jīng)驗 獲得超6個贊
有可能的。
reactor.listenSSL返回一個twisted.internet.tcp.Port實例,您可以將其存儲在可訪問的位置,例如服務器的網(wǎng)站資源中,以便您以后可以訪問它:
website_resource = Website()
website_factory = server.Site(website_resource)
website_resource.sslPort = reactor.listenSSL( # <---
port=https_server_port,
factory=website_factory,
contextFactory=sslContext,
interface=https_server_interface
)
然后稍后在您的 http 處理程序(render函數(shù))中,您可以執(zhí)行以下操作:
if request.path == b'/server/reload-certificates':
request.setHeader("connection", "close")
self.sslPort.connectionLost(reason=None)
self.sslPort.stopListening()
self.sslListen()
return b'ok'
self.sslListen初始設置代碼在哪里:
website_resource = Website()
website_factory = server.Site(website_resource)
def sslListen():
sslContext = ssl.DefaultOpenSSLContextFactory(
'/home/user/certs/letsencrypt-privkey.pem',
'/home/user/certs/letsencrypt-fullchain.pem',
)
website_resource.sslPort = reactor.listenSSL(
port=https_server_port,
factory=website_factory,
contextFactory=sslContext,
interface=https_server_interface
)
website_resource.sslListen = sslListen # <---
sslListen() # invoke once initially
# ...
reactor.run()
請注意,這request.setHeader("connection", "close")是可選的。它指示瀏覽器應該關(guān)閉連接,而不是在下一次獲取服務器時重用它(HTTP/1.1 連接通常保持打開至少 30 秒以便重用)。
如果connection: close未發(fā)送標頭,那么一切仍然有效,連接仍然有效且可用,但仍將使用舊證書,如果您只是重新加載證書以在更新后刷新它們,這應該沒certbot問題他們。來自其他瀏覽器的新連接將立即開始使用新證書。
添加回答
舉報
