26
"github.com/google/uuid"
27
"google.golang.org/grpc"
28
"google.golang.org/grpc/credentials"
29
"google.golang.org/grpc/credentials/insecure"
30
"google.golang.org/grpc/metadata"
31
"google.golang.org/protobuf/types/known/durationpb"
33
"istio.io/istio/pkg/bootstrap/platform"
34
"istio.io/istio/pkg/env"
35
"istio.io/istio/pkg/log"
36
sec_model "istio.io/istio/pkg/model"
37
"istio.io/istio/pkg/security"
38
"istio.io/istio/security/pkg/nodeagent/caclient"
39
gcapb "istio.io/istio/security/proto/providers/google"
42
const hubIDPPrefix = "https://gkehub.googleapis.com/"
45
googleCAClientLog = log.RegisterScope("googleca", "Google CA client debugging")
46
envGkeClusterURL = env.Register("GKE_CLUSTER_URL", "", "The url of GKE cluster").Get()
49
type googleCAClient struct {
52
client gcapb.MeshCertificateServiceClient
57
func NewGoogleCAClient(endpoint string, tls bool, provider *caclient.TokenProvider) (security.Client, error) {
63
var opts grpc.DialOption
66
opts, err = c.getTLSDialOption()
71
opts = grpc.WithTransportCredentials(insecure.NewCredentials())
74
conn, err := grpc.Dial(endpoint,
76
grpc.WithPerRPCCredentials(provider),
77
security.CARetryInterceptor(),
80
googleCAClientLog.Errorf("Failed to connect to endpoint %s: %v", endpoint, err)
81
return nil, fmt.Errorf("failed to connect to endpoint %s", endpoint)
85
c.client = gcapb.NewMeshCertificateServiceClient(conn)
90
func (cl *googleCAClient) CSRSign(csrPEM []byte, certValidTTLInSec int64) ([]string, error) {
91
req := &gcapb.MeshCertificateRequest{
92
RequestId: uuid.New().String(),
94
Validity: &durationpb.Duration{Seconds: certValidTTLInSec},
97
out := metadata.New(nil)
98
gkeClusterURL := envGkeClusterURL
99
if envGkeClusterURL == "" && platform.IsGCP() {
100
gkeClusterURL = platform.NewGCP().Metadata()[platform.GCPClusterURL]
102
zone := parseZone(gkeClusterURL)
104
out["x-goog-request-params"] = []string{fmt.Sprintf("location=locations/%s", zone)}
107
ctx := metadata.NewOutgoingContext(context.Background(), out)
108
resp, err := cl.client.CreateCertificate(ctx, req)
110
googleCAClientLog.Errorf("Failed to create certificate: %v", err)
111
googleCAClientLog.Debugf("Original request %v, resp %v", req, resp)
115
if len(resp.CertChain) <= 1 {
116
googleCAClientLog.Errorf("CertChain length is %d, expected more than 1", len(resp.CertChain))
117
return nil, errors.New("invalid response cert chain")
119
googleCAClientLog.Infof("Cert created with GoogleCA %s chain length %d", zone, len(resp.CertChain))
121
return resp.CertChain, nil
124
func (cl *googleCAClient) Close() {
126
err := cl.conn.Close()
128
googleCAClientLog.Infof("CAClient Connection is not closed: %v", err)
133
func (cl *googleCAClient) getTLSDialOption() (grpc.DialOption, error) {
135
pool, err := x509.SystemCertPool()
137
googleCAClientLog.Errorf("could not get SystemCertPool: %v", err)
138
return nil, errors.New("could not get SystemCertPool")
140
tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12, RootCAs: pool}
141
sec_model.EnforceGoCompliance(tlsConfig)
142
creds := credentials.NewTLS(tlsConfig)
143
return grpc.WithTransportCredentials(creds), nil
147
func (cl *googleCAClient) GetRootCertBundle() ([]string, error) {
148
return []string{}, nil
151
func parseZone(clusterURL string) string {
153
if strings.HasPrefix(clusterURL, hubIDPPrefix) {
158
rgx := regexp.MustCompile(`.*/projects/(.*)/locations/(.*)/clusters/.*`)
159
rs := rgx.FindStringSubmatch(clusterURL)