首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我无法让`golang.org/x/crypto/acme/autocert`‘工作(对于gRPC),我得到一个`acme_account+key`文件而没有X509证书

我无法让`golang.org/x/crypto/acme/autocert`‘工作(对于gRPC),我得到一个`acme_account+key`文件而没有X509证书
EN

Stack Overflow用户
提问于 2021-11-25 18:16:18
回答 1查看 346关注 0票数 2

更新经过多次调试后,我发现了Get "https://acme-v02.api.letsencrypt.org/directory": x509: certificate signed by unknown authority和怀疑(!?)这是最近加密根证书过期的结果。

我接受这样的观点:“这个包正在进行中,没有API稳定性的保证。”但是,如果它不再起作用(而且更有可能发生问题),那么也许可以将回购标记为龙来了

代码产生了一个acme_account+key (EC PRIVATE KEY),但没有一个证书要求我让autocert披露(日志)它的魔力,以了解我的错误所在。

代码本质上是repo的Manager示例,其中包含来自此回答的输入。我假设GetCertificate阻塞了ACME流的完成。

代码:

代码语言:javascript
复制
package main

import (
    "crypto/tls"
    "flag"
    "fmt"
    "log"
    "net"
    "net/http"

    "golang.org/x/crypto/acme/autocert"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/health"
    healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

const (
    email string = "my@email.com"

var (
    host = flag.String("host", "foo.example.org", "Fully-qualified domain name")
    port = flag.Uint("port", 443, "gRPC service port")
    path = flag.String("path", "", "Folder location for certificate")
)

func main() {
    flag.Parse()

    if *host == "" {
        log.Fatal("Flag --host is required")
    }
    log.Printf("Host: %s", *host)
    log.Printf("Port: %d", *port)

    if *path == "" {
        log.Fatal("Flag --path is required")
    }
    log.Printf("Path: %s", *path)

    addr := fmt.Sprintf(":%d", *port)

    lis, err := net.Listen("tcp", addr)
    if err != nil {
        log.Fatalf("failed to listen: %s", err)
    }

    m := &autocert.Manager{
        Cache:      autocert.DirCache(*path),
        Prompt:     autocert.AcceptTOS,
        HostPolicy: autocert.HostWhitelist(*host),
        Email:      email,
    }

    go func() {
        log.Println("Starting HTTP server w/ autocert handler")
        if err := http.ListenAndServe(":http", m.HTTPHandler(nil)); err != nil {
            log.Fatalf("HTTP failure\n%s", err)
        }
    }()

    tlsConfig := &tls.Config{
        ClientAuth: tls.RequireAndVerifyClientCert,
        GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
            cert, err := m.GetCertificate(hello)
            if err != nil {
                log.Fatalf("GetCertificate\n%s", err)
            }
            return cert, err
        },
    }

    opts := grpc.Creds(credentials.NewTLS(tlsConfig))
    server := grpc.NewServer(opts)

    healthcheck := health.NewServer()
    healthpb.RegisterHealthServer(server, healthcheck)

    log.Println("Starting gRPC server")
    if err := server.Serve(lis); err != nil {
        log.Fatalf("gRPC failure\n%s", err)
    }
}

我将部署到一个()容器VM中,等效的docker命令是:

代码语言:javascript
复制
docker run \
--name=autocert \
--detach \
--net=host \
--volume=/tmp/certs:/certs \
${IMAGE} \
--host=${HOST} \
--port=${PORT} \
--path=/certs

和集装箱日志:

代码语言:javascript
复制
2021/11/25 17:30:00 Host: [HOST]
2021/11/25 17:30:00 Port: 443
2021/11/25 17:30:00 Path: /certs
2021/11/25 17:30:00 Starting gRPC server
2021/11/25 17:30:00 Starting HTTP server

主机的/tmp/certs目录接收acme_account+key (我很难找到谷歌解释过),但怀疑(!?)是域验证的初始阶段。它包含一个私钥(BEGIN EC PRIVATE KEY)。

即使在服务器运行了一段时间之后,也不会有更多的文件被保存。

我没有收到电子邮件,让我们加密在配置的电子邮件地址。

不幸的是,虽然使用起来很容易,但autocert生成的日志很少,我一直无法确定是否能够记录正在(希望)发生的ACME流。

由于为GetCertificate添加了匿名函数,所以不再创建acme_account+key (我删除了前一个文件以检查是否重新创建了它),因此我无法从它收集任何日志记录--,但从未调用。这要么是因为我的匿名函数不正确,要么是因为我超过了针对ACME端点的请求。删除函数并恢复到m.GetCertificate并不会导致acme_account+key的重新创建,所以我感到很困惑。

autocert Manager类型记录了我没有设置的*acme.Client字段。该评论描述“如果Client.Key为零,将生成一个新的ECDSAP-256密钥”,这也许是我正在经历的,但它并没有解释我应该做些什么。应该将此值设置为acme_account+key的内容吗?:

我试着解码私钥,创建一个crypto.Signer并把它传递到&acme.Client{Key: key}中,但是没有明显的区别。

代码语言:javascript
复制
// Client is used to perform low-level operations, such as account registration
// and requesting new certificates.
//
// If Client is nil, a zero-value acme.Client is used with DefaultACMEDirectory
// as the directory endpoint.
// If the Client.Key is nil, a new ECDSA P-256 key is generated and,
// if Cache is not nil, stored in cache.
//
// Mutating the field after the first call of GetCertificate method will have no effect.
Client *acme.Client

显然,我用得不对。我没有从“让我们加密”中接收到证书,因此我无法从端点获得证书,也无法调用gRPC端点:

代码语言:javascript
复制
openssl s_client -showcerts -connect ${HOST}:${PORT}

grpcurl \
-proto health.proto \
${HOST}:${PORT} \
grpc.health.v1.Health/Check
Failed to dial target host "${HOST}:${PORT}": remote error: tls: internal error

如能提供指导,将不胜感激。

EN

回答 1

Stack Overflow用户

发布于 2021-11-26 21:32:20

‍♂️

呃:-(

我开始使用SCRATCH,没有复制CA证书

一旦容器获得了CA证书,一切都几乎完美无缺。

我仍然在尝试使用:

代码语言:javascript
复制
tlsConfig := &tls.Config{
  ClientAuth: tls.RequireAndVerifyClientCert,
  GetCertificate: m.GetCertificate
}

和am使用m.TLSConfig()

因此,autocert的工作就像对待(尽管很难调试自己造成的错误)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70115693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档