func (p *TLSPeer) DialGRPC(ctx context.Context, addr string, expectPeer ExpectPeerFunc, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
	config, err := p.GetConfig(ctx, expectPeer)
	if err != nil {
		return nil, err
	}
	return grpc.DialContext(ctx, addr, append([]grpc.DialOption{
		grpc.WithTransportCredentials(credentials.NewTLS(config)),
	}, opts...)...)
}
DialGRPC dials the gRPC endpoint addr using the peer TLS configuration.
package spiffe
import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"net"
	"sync"
	"github.com/spiffe/go-spiffe/workload"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)
type TLSPeerOption func(*TLSPeer) error
func WithWorkloadAPIAddr(addr string) func(*TLSPeer) error {
	return func(p *TLSPeer) error {
		p.addr = addr
		return nil
	}
}
func WithLogger(log Logger) func(*TLSPeer) error {
	return func(p *TLSPeer) error {
		p.log = log
		return nil
	}
}
type TLSPeer struct {
	log    Logger
	addr   string
	client *workload.X509SVIDClient
	readyOnce sync.Once
	ready     chan struct{}
	mu    sync.RWMutex
	cert  *tls.Certificate
	roots map[string]*x509.CertPool
}
func NewTLSPeer(opts ...TLSPeerOption) (*TLSPeer, error) {
	p := &TLSPeer{
		ready: make(chan struct{}),
	}
	for _, opt := range opts {
		if err := opt(p); err != nil {
			return nil, err
		}
	}
	if p.log == nil {
		p.log = nullLogger{}
	}
	var dialOpts []workload.DialOption
	if p.addr != "" {
		dialOpts = append(dialOpts, workload.WithAddr(p.addr))
	}
	client, err := workload.NewX509SVIDClient(&tlsPeerWatcher{p: p}, dialOpts...)
	if err != nil {
		return nil, err
	}
	client.Start()
	p.client = client
	return p, nil
}
func (p *TLSPeer) Close() error {
	return p.client.Stop()
}
func (p *TLSPeer) WaitUntilReady(ctx context.Context) error {
	select {
	case <-p.ready:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
func (p *TLSPeer) GetCertificate() (*tls.Certificate, error) {
	p.mu.RLock()
	defer p.mu.RUnlock()
	if p.cert == nil {
		return nil, errors.New("workload does not have a certificate yet")
	}
	return p.cert, nil
}
func (p *TLSPeer) GetRoots() (map[string]*x509.CertPool, error) {
	p.mu.RLock()
	defer p.mu.RUnlock()
	if p.roots == nil {
		return nil, errors.New("workload does not have roots yet")
	}
	return p.roots, nil
}
func (p *TLSPeer) Dial(ctx context.Context, network, address string, expectPeer ExpectPeerFunc) (net.Conn, error) {
	rawConn, err := new(net.Dialer).DialContext(ctx, network, address)
	if err != nil {
		return nil, err
	}
	config, err := p.GetConfig(ctx, expectPeer)
	if err != nil {
		rawConn.Close()
		return nil, err
	}
	tlsConn := tls.Client(rawConn, config)
	if err := tlsConn.Handshake(); err != nil {
		tlsConn.Close()
		return nil, err
	}
	return tlsConn, nil
}
func (p *TLSPeer) Listen(ctx context.Context, network, address string, expectPeer ExpectPeerFunc) (net.Listener, error) {
	inner, err := net.Listen(network, address)
	if err != nil {
		return nil, err
	}
	l, err := p.NewListener(ctx, inner, expectPeer)
	if err != nil {
		inner.Close()
		return nil, err
	}
	return l, nil
}
func (p *TLSPeer) NewListener(ctx context.Context, inner net.Listener, expectPeer ExpectPeerFunc) (net.Listener, error) {
	config, err := p.GetConfig(ctx, expectPeer)
	if err != nil {
		return nil, err
	}
	return tls.NewListener(inner, config), nil
}
func (p *TLSPeer) GetConfig(ctx context.Context, expectPeer ExpectPeerFunc) (*tls.Config, error) {
	if expectPeer == nil {
		return nil, errors.New("authorize callback is required")
	}
	if err := p.WaitUntilReady(ctx); err != nil {
		return nil, err
	}
	return &tls.Config{
		ClientAuth:            tls.RequireAnyClientCert,
		InsecureSkipVerify:    true,
		GetCertificate:        AdaptGetCertificate(p),
		GetClientCertificate:  AdaptGetClientCertificate(p),
		VerifyPeerCertificate: AdaptVerifyPeerCertificate(p, expectPeer),
	}, nil
}