failed to complete security handshake on grpc?

huangapple go评论150阅读模式
英文:

failed to complete security handshake on grpc?

问题

我已经多次更改了服务器和客户端上的端口号,但服务器始终获取到错误的端口号。

当我执行客户端时,服务器将记录以下内容:
2017/05/07 15:06:07 grpc: Server.Serve failed to complete security handshake from "127.0.0.1:32763": remote error: tls: bad certificate
而在客户端方面,我得到了以下内容:
2017/05/07 15:06:07 Failed to dial localhost:8070: connection error: desc = "transport: x509: certificate is not valid for any names, but wanted to match localhost:8070"; please retry. rpc error: code = Internal desc = connection error: desc = "transport: x509: certificate is not valid for any names, but wanted to match localhost:8070"

我有以下代码用于 server.go:

func serve() {
    addr := "localhost:8070"
    crt, key := certificate.CreatePemKey()
    certificate, err := tls.X509KeyPair(crt, key)
    if err != nil {
        fmt.Println(err)
    }

    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("F:/GIAG3.crt")
    if err != nil {
        fmt.Println(err)
    }

    if ok := certPool.AppendCertsFromPEM(ca); !ok {
        fmt.Println("unable to append certificate")
    }

    lis, err := net.Listen("tcp", addr)
    if err != nil {
        fmt.Println("could not list on %s: %s", addr, err)
    }

    // 创建 TLS 凭证
    creds := credentials.NewTLS(&tls.Config{
        ClientAuth:   tls.RequireAndVerifyClientCert,
        Certificates: []tls.Certificate{certificate},
        ClientCAs:    certPool,
    })

    srv := grpc.NewServer(grpc.Creds(creds))
    pb.RegisterPingerServer(srv, &server{})

    if err := srv.Serve(lis); err != nil {
        fmt.Println("grpc serve error: %s", err)
    }
}

以及 client.go:

func testDial2() {
    addr := "localhost:8070"
    crt, key := certificate.CreatePemKey()
    certificate, err := tls.X509KeyPair(crt, key)
    if err != nil {
        fmt.Println(err)
    }

    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("F:/GIAG3.crt")
    if err != nil {
        fmt.Println(err)
    }

    if ok := certPool.AppendCertsFromPEM(ca); !ok {
        fmt.Println("unable to append certificate")
    }

    creds := credentials.NewTLS(&tls.Config{
        ServerName:   addr,
        Certificates: []tls.Certificate{certificate},
        RootCAs:      certPool,
    })

    conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds))
    if err != nil {
        fmt.Println(err)
    }

    defer conn.Close()
    c := pb.NewPingerClient(conn)
    r, err := c.Ping(context.Background(), &pb.Payload{Message: "Ping"})
    if err != nil {
        fmt.Println(err)
    }
    log.Printf("%s", r.Message)
}

这是 CreatePemKey 的代码,它基于此示例 https://golang.org/src/crypto/tls/generate_cert.go

func publicKey(priv interface{}) interface{} {
    switch k := priv.(type) {
    case *rsa.PrivateKey:
        return &k.PublicKey
    case *ecdsa.PrivateKey:
        return &k.PublicKey
    default:
        return nil
    }
}

func pemBlockForKey(priv interface{}) *pem.Block {
    switch k := priv.(type) {
    case *rsa.PrivateKey:
        return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
    case *ecdsa.PrivateKey:
        b, err := x509.MarshalECPrivateKey(k)
        if err != nil {
            fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
            os.Exit(2)
        }
        return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
    default:
        return nil
    }
}

func CreatePemKey() (certpem, keypem []byte) {
    priv, _ := rsa.GenerateKey(rand.Reader, 2048)
    notBefore := time.Now()
    notAfter := notBefore.AddDate(1, 0, 0)
    serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)

    template := x509.Certificate{
        SerialNumber: serialNumber,
        Subject: pkix.Name{
            Organization: []string{"Acme Co"},
        },
        NotBefore:             notBefore,
        NotAfter:              notAfter,
        KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
        BasicConstraintsValid: true,
    }
    // template.IPAddresses = append(template.IPAddresses, net.ParseIP("localhost"))
    template.IsCA = true
    derbytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
    certpem = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derbytes})
    keypem = pem.EncodeToMemory(pemBlockForKey(priv))
    return certpem, keypem
}

顺便提一下,GIAG3.crt 是从这里获取的 https://pki.goog/

请帮助我,谢谢。

英文:

I've already changed many times the port number on the server and client, but the server always get the incorrect port number.

when I execute the client the server will log this:
2017/05/07 15:06:07 grpc: Server.Serve failed to complete security handshake from "127.0.0.1:32763": remote error: tls: bad certificate
and on the client side, i got this:
2017/05/07 15:06:07 Failed to dial localhost:8070: connection error: desc = "transport: x509: certificate is not valid for any names, but wanted to match localhost:8070"; please retry.
rpc error: code = Internal desc = connection error: desc = "transport: x509: certificate is not valid for any names, but wanted to match localhost:8070"

I have this code for the server.go

func serve() {
addr := "localhost:8070"
crt, key := certificate.CreatePemKey()
certificate, err := tls.X509KeyPair(crt, key)
if err != nil {
fmt.Println(err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile("F:/GIAG3.crt")
if err != nil {
fmt.Println(err)
}
if ok := certPool.AppendCertsFromPEM(ca); !ok {
fmt.Println("unable to append certificate")
}
lis, err := net.Listen("tcp", addr)
if err != nil {
fmt.Println("could not list on %s: %s", addr, err)
}
// Create the TLS credentials
creds := credentials.NewTLS(&tls.Config{
ClientAuth:   tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{certificate},
ClientCAs:    certPool,
})
srv := grpc.NewServer(grpc.Creds(creds))
pb.RegisterPingerServer(srv, &server{})
if err := srv.Serve(lis); err != nil {
fmt.Println("grpc serve error: %s", err)
}
}

and this is for the client.go

func testDial2() {
addr := "localhost:8070"
crt, key := certificate.CreatePemKey()
certificate, err := tls.X509KeyPair(crt, key)
if err != nil {
fmt.Println(err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile("F:/GIAG3.crt")
if err != nil {
fmt.Println(err)
}
if ok := certPool.AppendCertsFromPEM(ca); !ok {
fmt.Println("unable to append certificate")
}
creds := credentials.NewTLS(&tls.Config{
ServerName:   addr,
Certificates: []tls.Certificate{certificate},
RootCAs:      certPool,
})
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds))
if err != nil {
fmt.Println(err)
}
defer conn.Close()
c := pb.NewPingerClient(conn)
r, err := c.Ping(context.Background(), &pb.Payload{Message: "Ping"})
if err != nil {
fmt.Println(err)
}
log.Printf("%s", r.Message)
}

this is for the CreatePemKey, it is based on this example https://golang.org/src/crypto/tls/generate_cert.go

func publicKey(priv interface{}) interface{} {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
default:
return nil
}
}
func pemBlockForKey(priv interface{}) *pem.Block {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
case *ecdsa.PrivateKey:
b, err := x509.MarshalECPrivateKey(k)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
os.Exit(2)
}
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
default:
return nil
}
}
func CreatePemKey() (certpem, keypem []byte) {
priv, _ := rsa.GenerateKey(rand.Reader, 2048)
notBefore := time.Now()
notAfter := notBefore.AddDate(1, 0, 0)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore:             notBefore,
NotAfter:              notAfter,
KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
// template.IPAddresses = append(template.IPAddresses, net.ParseIP("localhost"))
template.IsCA = true
derbytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
certpem = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derbytes})
keypem = pem.EncodeToMemory(pemBlockForKey(priv))
return certpem, keypem
}

BTW the GIAG3.crt is came from here https://pki.goog/

Please help me, thanks

答案1

得分: 4

如果您的服务器证书没有域定义,并且没有由GIAG3签名(就像您的示例一样),您应该在客户端配置中添加InsecureSkipVerify(这允许您跳过服务器名称和服务器证书的验证),这将修复无效名称的问题。

creds := credentials.NewTLS(&tls.Config{
    ServerName:         addr,
    Certificates:       []tls.Certificate{certificate},
    RootCAs:            certPool,
    InsecureSkipVerify: true,
})

但是您将遇到另一个问题,因为客户端使用的是自签名证书,而服务器要求使用由GIAG3签名的证书进行身份验证(tls.RequireAndVerifyClientCert),因此您有几个选项:

  • 使用由GIAG3签名的证书作为客户端证书。
  • 将身份验证类型降级为tls.RequireAnyClientCert,这允许您在进行身份验证时使用任何证书(可以是由GIAG3签名或未签名的证书),客户端只需要在连接时使用任何证书。
  • 删除客户端证书的身份验证。
英文:

If your server certificate doesn't have the domain definition and it's not signed by GIAG3 (like your example), you should add InsecureSkipVerify (this allow you skip the validation of the server name and the server certificate) in the client configuration, that will fix the issue with the invalid name.

<!-- language: go -->

creds := credentials.NewTLS(&amp;tls.Config{
ServerName:   addr,
Certificates: []tls.Certificate{certificate},
RootCAs:      certPool,
InsecureSkipVerify: true,
})

But you'll have another problem, because the client is using a self-signed certificate, and the server required a certificate signed by GIAG3 for the authentication (tls.RequireAndVerifyClientCert), so you have some options with this,

  • you use a certificate signed by GIAG3 for the client.
  • reduce the authentication type to tls.RequireAnyClientCert, this allow you use any certificate at the moment of the auth (it could be or not signed by GIAG3), the client just need to use any certificate when it's connected.
  • remove the client authentication with certificate.

答案2

得分: 3

如果你在journalctl -u docker中找到了这个日志:

mai 29 10:33:04 ca275nt dockerd[1523]: time=&quot;2019-05-29T10:33:04.454362399-03:00&quot; level=warning msg=&quot;grpc: Server.Serve failed to complete security handshake from \&quot;192.168.0.45:58392\&quot;: remote error: tls: bad certificate&quot; module=grpc    

这可能与来自另一个Swarm集群节点的docker swarm请求相关,该节点尝试使用无效的令牌连接到Docker Swarm主节点。

你可以通过运行以下命令来查找无效的集群节点主机名:

nslookup 192.168.0.45                                                                                                                                          
45.0.168.192.in-addr.arpa       name = hostabc.domain.com.
45.0.168.192.in-addr.arpa       name = hostabc.
可以从权威答案中找到:

在报告的主机上运行docker swarm leave来解决这个问题。

我知道这与主要问题无关,但我在搜索docker "grpc: Server.Serve failed to complete security handshake from"时找到了这个问题。我认为将故障排除放在这里可以为其他人节省一些时间。

英文:

If you found this log in journalctl -u docker:

mai 29 10:33:04 ca275nt dockerd[1523]: time=&quot;2019-05-29T10:33:04.454362399-03:00&quot; level=warning msg=&quot;grpc: Server.Serve failed to complete security handshake from \&quot;192.168.0.45:58392\&quot;: remote error: tls: bad certificate&quot; module=grpc    

It can be related with docker swarm requests from another swarm cluster node host trying to connect to docker swarm master node with a invalid token.

You can discover the invalid cluster node hostname with:

nslookup 192.168.0.45                                                                                                                                          
45.0.168.192.in-addr.arpa       name = hostabc.domain.com.
45.0.168.192.in-addr.arpa       name = hostabc.
Authoritative answers can be found from:

By running a docker swarm leave on the reported host, resolve the issue.

I know it's not related with the main question, but I was searching for:
docker &quot;grpc: Server.Serve failed to complete security handshake from&quot; and this was the first question. then I think it's useful to put the troubleshooting here to save some time to others.

huangapple
  • 本文由 发表于 2017年5月7日 15:42:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/43829022.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定