Grpc-go: Does grpc-go support SSL/TLS mutual authentication?

Created on 18 Oct 2015  路  3Comments  路  Source: grpc/grpc-go

I want to secure my grpc traffic and authenticate client based on client certificate just like etcd(I have achieved this on etcd cluster and etcd clients).

I have read the sample code from grpc-auth-support.md, and I think it only acheives server-side authentication, because client does NOT provide its certificate.

So, does grpc-go support TLS mutual authentication? If yes, can anyone show some sample code?

Most helpful comment

Many thanks to @psanford. Below is my sample code:

client side:

    // load peer cert/key, cacert
    peerCert, err := tls.LoadX509KeyPair(config.PeerCert, config.PeerKey)
    if err != nil {
        log.Error("load peer cert/key error:%v", err)
        return nil, err
    }
    caCert, err := ioutil.ReadFile(config.CACert)
    if err != nil {
        log.Error("read ca cert file error:%v", err)
        return nil, err
    }
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)

    ta := credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{peerCert},
        RootCAs:      caCertPool,
    })
    conn, err := grpc.Dial(config.ServerAddr, grpc.WithTransportCredentials(ta))
    if err != nil {
        return nil, err
    }

Server side:

    // load peer cert/key, ca cert
    peerCert, err := tls.LoadX509KeyPair(config.PeerCert, config.PeerKey)
    if err != nil {
        log.Error("load peer cert/key error:%v", err)
        return
    }
    caCert, err := ioutil.ReadFile(config.CACert)
    if err != nil {
        log.Error("read ca cert file error:%v", err)
        return
    }
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    ta := credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{peerCert},
        ClientCAs:    caCertPool,
        ClientAuth:   tls.RequireAndVerifyClientCert,
    })

    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", cs.port))
    if err != nil {
        log.Error("server listen on port %d error:%v", cs.port, err)
        return
    }
    s := grpc.NewServer(grpc.Creds(ta))
    proto.RegisterSomerServer(s, cs)
    go s.Serve(lis)

All 3 comments

You can use client certs without much difficulty. credentials.NewTLS(c *tls.Config) just takes a plain old crypto/tls.Config so its just like any other go tls program that supports client certs. On the tls.Config you set the client Certificates on the client and the client CAs and ClientAuth: tls.RequireAndVerifyClientCert on the server.

Many thanks to @psanford. Below is my sample code:

client side:

    // load peer cert/key, cacert
    peerCert, err := tls.LoadX509KeyPair(config.PeerCert, config.PeerKey)
    if err != nil {
        log.Error("load peer cert/key error:%v", err)
        return nil, err
    }
    caCert, err := ioutil.ReadFile(config.CACert)
    if err != nil {
        log.Error("read ca cert file error:%v", err)
        return nil, err
    }
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)

    ta := credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{peerCert},
        RootCAs:      caCertPool,
    })
    conn, err := grpc.Dial(config.ServerAddr, grpc.WithTransportCredentials(ta))
    if err != nil {
        return nil, err
    }

Server side:

    // load peer cert/key, ca cert
    peerCert, err := tls.LoadX509KeyPair(config.PeerCert, config.PeerKey)
    if err != nil {
        log.Error("load peer cert/key error:%v", err)
        return
    }
    caCert, err := ioutil.ReadFile(config.CACert)
    if err != nil {
        log.Error("read ca cert file error:%v", err)
        return
    }
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    ta := credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{peerCert},
        ClientCAs:    caCertPool,
        ClientAuth:   tls.RequireAndVerifyClientCert,
    })

    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", cs.port))
    if err != nil {
        log.Error("server listen on port %d error:%v", cs.port, err)
        return
    }
    s := grpc.NewServer(grpc.Creds(ta))
    proto.RegisterSomerServer(s, cs)
    go s.Serve(lis)

Is it possible to allow mutual authentication based on the peers public key and not depending on a CA? I've managed to read the client public key from the server, but not the opposite.

Was this page helpful?
0 / 5 - 0 ratings