snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Testing / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Testing / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
This commit is contained in:
306
examples/features/advancedtls/client/main.go
Normal file
306
examples/features/advancedtls/client/main.go
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2024 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Binary client is an example client demonstrating use of advancedtls, to set
|
||||
// up a secure gRPC client connection with various TLS authentication methods.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
pb "google.golang.org/grpc/examples/features/proto/echo"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/credentials/tls/certprovider"
|
||||
"google.golang.org/grpc/credentials/tls/certprovider/pemfile"
|
||||
"google.golang.org/grpc/security/advancedtls"
|
||||
)
|
||||
|
||||
const credRefreshInterval = 1 * time.Minute
|
||||
const serverAddr = "localhost"
|
||||
const goodServerPort string = "50051"
|
||||
const revokedServerPort string = "50053"
|
||||
const insecurePort string = "50054"
|
||||
const message string = "Hello"
|
||||
|
||||
// -- TLS --
|
||||
|
||||
func makeRootProvider(credsDirectory string) certprovider.Provider {
|
||||
rootOptions := pemfile.Options{
|
||||
RootFile: filepath.Join(credsDirectory, "ca_cert.pem"),
|
||||
RefreshDuration: credRefreshInterval,
|
||||
}
|
||||
rootProvider, err := pemfile.NewProvider(rootOptions)
|
||||
if err != nil {
|
||||
fmt.Printf("Error %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return rootProvider
|
||||
}
|
||||
|
||||
func makeIdentityProvider(revoked bool, credsDirectory string) certprovider.Provider {
|
||||
var certFile string
|
||||
if revoked {
|
||||
certFile = filepath.Join(credsDirectory, "client_cert_revoked.pem")
|
||||
} else {
|
||||
certFile = filepath.Join(credsDirectory, "client_cert.pem")
|
||||
}
|
||||
identityOptions := pemfile.Options{
|
||||
CertFile: certFile,
|
||||
KeyFile: filepath.Join(credsDirectory, "client_key.pem"),
|
||||
RefreshDuration: credRefreshInterval,
|
||||
}
|
||||
identityProvider, err := pemfile.NewProvider(identityOptions)
|
||||
if err != nil {
|
||||
fmt.Printf("Error %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return identityProvider
|
||||
}
|
||||
|
||||
func runClientWithProviders(rootProvider certprovider.Provider, identityProvider certprovider.Provider, crlProvider advancedtls.CRLProvider, port string, shouldFail bool) {
|
||||
options := &advancedtls.Options{
|
||||
// Setup the certificates to be used
|
||||
IdentityOptions: advancedtls.IdentityCertificateOptions{
|
||||
IdentityProvider: identityProvider,
|
||||
},
|
||||
// Setup the roots to be used
|
||||
RootOptions: advancedtls.RootCertificateOptions{
|
||||
RootProvider: rootProvider,
|
||||
},
|
||||
// Tell the client to verify the server cert
|
||||
VerificationType: advancedtls.CertVerification,
|
||||
}
|
||||
|
||||
// Configure revocation and CRLs
|
||||
options.RevocationOptions = &advancedtls.RevocationOptions{
|
||||
CRLProvider: crlProvider,
|
||||
}
|
||||
|
||||
clientTLSCreds, err := advancedtls.NewClientCreds(options)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fullServerAddr := serverAddr + ":" + port
|
||||
runWithCredentials(clientTLSCreds, fullServerAddr, !shouldFail)
|
||||
}
|
||||
|
||||
func tlsWithCRLsToGoodServer(credsDirectory string) {
|
||||
rootProvider := makeRootProvider(credsDirectory)
|
||||
defer rootProvider.Close()
|
||||
identityProvider := makeIdentityProvider(false, credsDirectory)
|
||||
defer identityProvider.Close()
|
||||
crlProvider := makeCRLProvider(credsDirectory)
|
||||
defer crlProvider.Close()
|
||||
|
||||
runClientWithProviders(rootProvider, identityProvider, crlProvider, goodServerPort, false)
|
||||
}
|
||||
|
||||
func tlsWithCRLsToRevokedServer(credsDirectory string) {
|
||||
rootProvider := makeRootProvider(credsDirectory)
|
||||
defer rootProvider.Close()
|
||||
identityProvider := makeIdentityProvider(false, credsDirectory)
|
||||
defer identityProvider.Close()
|
||||
crlProvider := makeCRLProvider(credsDirectory)
|
||||
defer crlProvider.Close()
|
||||
|
||||
runClientWithProviders(rootProvider, identityProvider, crlProvider, revokedServerPort, true)
|
||||
}
|
||||
|
||||
func tlsWithCRLs(credsDirectory string) {
|
||||
tlsWithCRLsToGoodServer(credsDirectory)
|
||||
tlsWithCRLsToRevokedServer(credsDirectory)
|
||||
}
|
||||
|
||||
func makeCRLProvider(crlDirectory string) *advancedtls.FileWatcherCRLProvider {
|
||||
options := advancedtls.FileWatcherOptions{
|
||||
CRLDirectory: crlDirectory,
|
||||
}
|
||||
provider, err := advancedtls.NewFileWatcherCRLProvider(options)
|
||||
if err != nil {
|
||||
fmt.Printf("Error making CRL Provider: %v\nExiting...", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return provider
|
||||
}
|
||||
|
||||
// --- Custom Verification ---
|
||||
func customVerificationSucceed(info *advancedtls.HandshakeVerificationInfo) (*advancedtls.PostHandshakeVerificationResults, error) {
|
||||
// Looks at info for what you care about as the custom verification implementer
|
||||
if info.ServerName != "localhost:50051" {
|
||||
return nil, fmt.Errorf("expected servername of localhost:50051, got %v", info.ServerName)
|
||||
}
|
||||
return &advancedtls.PostHandshakeVerificationResults{}, nil
|
||||
}
|
||||
|
||||
func customVerificationFail(info *advancedtls.HandshakeVerificationInfo) (*advancedtls.PostHandshakeVerificationResults, error) {
|
||||
// Looks at info for what you care about as the custom verification implementer
|
||||
if info.ServerName != "ExampleDesignedToFail" {
|
||||
return nil, fmt.Errorf("expected servername of ExampleDesignedToFail, got %v", info.ServerName)
|
||||
}
|
||||
return &advancedtls.PostHandshakeVerificationResults{}, nil
|
||||
}
|
||||
|
||||
func customVerification(credsDirectory string) {
|
||||
runClientWithCustomVerification(credsDirectory, goodServerPort)
|
||||
|
||||
}
|
||||
|
||||
func runClientWithCustomVerification(credsDirectory string, port string) {
|
||||
rootProvider := makeRootProvider(credsDirectory)
|
||||
defer rootProvider.Close()
|
||||
identityProvider := makeIdentityProvider(false, credsDirectory)
|
||||
defer identityProvider.Close()
|
||||
fullServerAddr := serverAddr + ":" + port
|
||||
{
|
||||
// Run with the custom verification func that will succeed
|
||||
options := &advancedtls.Options{
|
||||
// Setup the certificates to be used
|
||||
IdentityOptions: advancedtls.IdentityCertificateOptions{
|
||||
IdentityProvider: identityProvider,
|
||||
},
|
||||
// Setup the roots to be used
|
||||
RootOptions: advancedtls.RootCertificateOptions{
|
||||
RootProvider: rootProvider,
|
||||
},
|
||||
// Tell the client to verify the server cert
|
||||
VerificationType: advancedtls.CertVerification,
|
||||
AdditionalPeerVerification: customVerificationSucceed,
|
||||
}
|
||||
|
||||
clientTLSCreds, err := advancedtls.NewClientCreds(options)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
runWithCredentials(clientTLSCreds, fullServerAddr, true)
|
||||
}
|
||||
{
|
||||
// Run with the custom verification func that will fail
|
||||
options := &advancedtls.Options{
|
||||
// Setup the certificates to be used
|
||||
IdentityOptions: advancedtls.IdentityCertificateOptions{
|
||||
IdentityProvider: identityProvider,
|
||||
},
|
||||
// Setup the roots to be used
|
||||
RootOptions: advancedtls.RootCertificateOptions{
|
||||
RootProvider: rootProvider,
|
||||
},
|
||||
// Tell the client to verify the server cert
|
||||
VerificationType: advancedtls.CertVerification,
|
||||
AdditionalPeerVerification: customVerificationFail,
|
||||
}
|
||||
|
||||
clientTLSCreds, err := advancedtls.NewClientCreds(options)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
runWithCredentials(clientTLSCreds, fullServerAddr, false)
|
||||
}
|
||||
}
|
||||
|
||||
// -- credentials.NewTLS example --
|
||||
func credentialsNewTLSExample(credsDirectory string) {
|
||||
cert, err := tls.LoadX509KeyPair(filepath.Join(credsDirectory, "client_cert.pem"), filepath.Join(credsDirectory, "client_key.pem"))
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
rootPem, err := os.ReadFile(filepath.Join(credsDirectory, "ca_cert.pem"))
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
root := x509.NewCertPool()
|
||||
if !root.AppendCertsFromPEM(rootPem) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: root,
|
||||
}
|
||||
|
||||
// Directly create credentials from a tls.Config.
|
||||
creds := credentials.NewTLS(config)
|
||||
port := goodServerPort
|
||||
fullServerAddr := serverAddr + ":" + port
|
||||
runWithCredentials(creds, fullServerAddr, true)
|
||||
|
||||
}
|
||||
|
||||
// -- Insecure --
|
||||
func insecureCredentialsExample() {
|
||||
creds := insecure.NewCredentials()
|
||||
port := insecurePort
|
||||
fullServerAddr := serverAddr + ":" + port
|
||||
runWithCredentials(creds, fullServerAddr, true)
|
||||
}
|
||||
|
||||
// -- Main and Runner --
|
||||
|
||||
// All of these examples differ in how they configure the
|
||||
// credentials.TransportCredentials object. Once we have that, actually making
|
||||
// the calls with gRPC is the same.
|
||||
func runWithCredentials(creds credentials.TransportCredentials, fullServerAddr string, shouldSucceed bool) {
|
||||
conn, err := grpc.NewClient(fullServerAddr, grpc.WithTransportCredentials(creds))
|
||||
if err != nil {
|
||||
fmt.Printf("Error during grpc.NewClient %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewEchoClient(conn)
|
||||
req := &pb.EchoRequest{
|
||||
Message: message,
|
||||
}
|
||||
context, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := client.UnaryEcho(context, req)
|
||||
defer cancel()
|
||||
|
||||
if shouldSucceed && err != nil {
|
||||
fmt.Printf("Error during client.UnaryEcho %v\n", err)
|
||||
} else if !shouldSucceed && err == nil {
|
||||
fmt.Printf("Should have failed but didn't, got response: %v\n", resp)
|
||||
}
|
||||
|
||||
}
|
||||
func main() {
|
||||
credsDirectory := flag.String("credentials_directory", "", "Path to the creds directory of this example repo")
|
||||
flag.Parse()
|
||||
|
||||
if *credsDirectory == "" {
|
||||
fmt.Println("Must set credentials_directory argument to this repo's creds directory")
|
||||
os.Exit(1)
|
||||
}
|
||||
tlsWithCRLs(*credsDirectory)
|
||||
customVerification(*credsDirectory)
|
||||
credentialsNewTLSExample(*credsDirectory)
|
||||
insecureCredentialsExample()
|
||||
}
|
||||
Reference in New Issue
Block a user