/* * * Copyright 2020 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ // The client demonstrates how to use the credential reloading feature in // advancedtls to make a mTLS connection to the server. package main import ( "context" "flag" "log" "time" "google.golang.org/grpc" "google.golang.org/grpc/credentials/tls/certprovider/pemfile" pb "google.golang.org/grpc/examples/helloworld/helloworld" "google.golang.org/grpc/security/advancedtls" "google.golang.org/grpc/security/advancedtls/testdata" ) var address = "localhost:50051" const ( // Default timeout for normal connections. defaultTimeout = 2 * time.Second // Intervals that set to monitor the credential updates. credRefreshingInterval = 500 * time.Millisecond ) func main() { tmpKeyFile := flag.String("key", "", "temporary key file path") tmpCertFile := flag.String("cert", "", "temporary cert file path") flag.Parse() if tmpKeyFile == nil || *tmpKeyFile == "" { log.Fatalf("tmpKeyFile is nil or empty.") } if tmpCertFile == nil || *tmpCertFile == "" { log.Fatalf("tmpCertFile is nil or empty.") } // Initialize credential struct using reloading API. identityOptions := pemfile.Options{ CertFile: *tmpCertFile, KeyFile: *tmpKeyFile, RefreshDuration: credRefreshingInterval, } identityProvider, err := pemfile.NewProvider(identityOptions) if err != nil { log.Fatalf("pemfile.NewProvider(%v) failed: %v", identityOptions, err) } rootOptions := pemfile.Options{ RootFile: testdata.Path("client_trust_cert_1.pem"), RefreshDuration: credRefreshingInterval, } rootProvider, err := pemfile.NewProvider(rootOptions) if err != nil { log.Fatalf("pemfile.NewProvider(%v) failed: %v", rootOptions, err) } options := &advancedtls.Options{ IdentityOptions: advancedtls.IdentityCertificateOptions{ IdentityProvider: identityProvider, }, AdditionalPeerVerification: func(*advancedtls.HandshakeVerificationInfo) (*advancedtls.PostHandshakeVerificationResults, error) { return &advancedtls.PostHandshakeVerificationResults{}, nil }, RootOptions: advancedtls.RootCertificateOptions{ RootProvider: rootProvider, }, VerificationType: advancedtls.CertVerification, } clientTLSCreds, err := advancedtls.NewClientCreds(options) if err != nil { log.Fatalf("advancedtls.NewClientCreds(%v) failed: %v", options, err) } // Make a connection using the credentials. conn, err := grpc.NewClient(address, grpc.WithTransportCredentials(clientTLSCreds)) if err != nil { log.Fatalf("grpc.NewClient to %s failed: %v", address, err) } client := pb.NewGreeterClient(conn) // Send the requests every 0.5s. The credential is expected to be changed in // the bash script. We don't cancel the context nor call conn.Close() here, // since the bash script is expected to close the client goroutine. for { ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) _, err = client.SayHello(ctx, &pb.HelloRequest{Name: "gRPC"}, grpc.WaitForReady(true)) if err != nil { log.Fatalf("client.SayHello failed: %v", err) } cancel() time.Sleep(500 * time.Millisecond) } }