当前位置: 首页 > 面试题库 >

有没有一种方法可以在没有停机的情况下更新net / http服务器中的TLS证书?

颛孙霖
2023-03-14
问题内容

我有一个简单的https服务器,提供了一个简单的页面,例如(简洁起见,没有错误处理):

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, "hello!")
    })

    xcert, _ := tls.LoadX509KeyPair("cert1.crt", "key1.pem")

    tlsConf := &tls.Config{
        Certificates: []tls.Certificate{xcert},
    }

    srv := &http.Server{
        Addr:      ":https",
        Handler:   mux,
        TLSConfig: tlsConf,
    }

    srv.ListenAndServeTLS("", "")
}

我想使用“ 让我们加密
TLS”证书通过https提供内容。我希望能够进行证书续订并更新服务器中的证书,而无需停机。

我尝试运行goroutine更新tlsConf

go func(c *tls.Config) {
        xcert, _ := tls.LoadX509KeyPair("cert2.crt", "key2.pem")

        select {
        case <-time.After(3 * time.Minute):
            c.Certificates = []tls.Certificate{xcert}
            c.BuildNameToCertificate()
            fmt.Println("cert switched!")
        }

    }(tlsConf)

但是,这不起作用,因为服务器不会“读入”更改后的配置。无论如何,有没有要求服务器重新加载TLSConfig


问题答案:

有:您可以使用tls.ConfigGetCertificate成员而不是填充Certificates。首先,定义一个封装证书和重载功能的数据结构(SIGHUP在此示例中,在接收到信号时):

type keypairReloader struct {
        certMu   sync.RWMutex
        cert     *tls.Certificate
        certPath string
        keyPath  string
}

func NewKeypairReloader(certPath, keyPath string) (*keypairReloader, error) { 
        result := &keypairReloader{
                certPath: certPath,
                keyPath:  keyPath,
        }
        cert, err := tls.LoadX509KeyPair(certPath, keyPath)
        if err != nil {
                return nil, err
        }
        result.cert = &cert
        go func() {
                c := make(chan os.Signal, 1)
                signal.Notify(c, syscall.SIGHUP)
                for range c {
                        log.Printf("Received SIGHUP, reloading TLS certificate and key from %q and %q", *tlsCertPath, *tlsKeyPath)
                        if err := result.maybeReload(); err != nil {
                                log.Printf("Keeping old TLS certificate because the new one could not be loaded: %v", err)
                        }
                }
        }()
        return result, nil
}

func (kpr *keypairReloader) maybeReload() error { 
        newCert, err := tls.LoadX509KeyPair(kpr.certPath, kpr.keyPath)
        if err != nil {
                return err
        }
        kpr.certMu.Lock()
        defer kpr.certMu.Unlock()
        kpr.cert = &newCert
        return nil
}

func (kpr *keypairReloader) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) { 
        return func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
                kpr.certMu.RLock()
                defer kpr.certMu.RUnlock()
                return kpr.cert, nil
        }
}

然后,在您的服务器代码中,使用:

kpr, err := NewKeypairReloader(*tlsCertPath, *tlsKeyPath)
if err != nil {
    log.Fatal(err)
}
srv.TLSConfig.GetCertificate = kpr.GetCertificateFunc()

我最近在RobustIRC中实现了这种模式。



 类似资料:
  • 问题内容: 我刚刚收到Java更新通知,说Update 17已经发布,所以我运行了更新,发现只有我的公共JRE被更新了。我仍然只有JDK的Update 16。 有没有办法自动提供最新的JDK? 当然,更新不应该放弃旧版本。这应该手动完成,因为Eclipse仍在使用旧版本。更新设置后,我将手动删除旧的JDK。 问题答案: 不在Windows上。如果要通过带有自动更新程序的Linux发行版来获取JDK

  • 我想在无需密码验证的情况下通过SFTP服务器上传文件。在这里,我也不想使用私钥。我的公钥已共享到目标SFTP服务器。我可以使用username@hostname作为来自filezilla的url,没有密码或私钥引用。我想从java代码中实现同样的功能。我还研究了j2shh、maverick和jsch API,但每个地方都需要密码或私钥进行身份验证。有什么方法可以通过使用连接到服务器吗usernam

  • 我想在我的spring web应用程序中添加几个过滤器,但至少现在不会有任何关于安全性的内容。所以。没有spring-security我所能做的就是在web.xml中定义多个过滤器(定义过滤器的旧方法)。要能够使用spring过滤器链,我需要为我的项目添加spring-security作为依赖项,这似乎很奇怪。也许我做错了什么,而且确实有过滤器链可以在没有spring-security依赖的情况下

  • 我试图使用confluent的模式注册表使我的应用程序工作,但此时我并不是生产者的完全控制者,你甚至可以将它们视为不绑定confluent产品的遗留应用程序。 我正在查看融合信息,似乎所有消息都应该在有效负载中包含一个魔法字节和模式ID https://docs.confluent.io/3.2.0/schema-registry/docs/serializer-formatter.html 或者

  • 问题内容: 我非常喜欢使用docker-compose。 例如。在我的服务器上,当我想通过较小的更改来更新我的应用程序时,我只需要完美运行即可。 但是有时候,我需要重建(例如,我添加了一个npm依赖项,需要再次运行)。 在这种情况下,我愿意。 我希望这能: 创建我的容器的新实例 停止现有的容器(在较新的容器完成建造之后) 开始新的 (可选)删除旧的,但是可以手动完成 但是实际上,它似乎又重新启动了