forked from grpc/grpc-go
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
advancedtls: add examples for reloading from file system (grpc#3976)
* add examples for reloading from file system
- Loading branch information
1 parent
a223251
commit 18a4d41
Showing
8 changed files
with
738 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
security/advancedtls/examples/credential_reloading_from_files/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Credential Reloading From Files | ||
|
||
Credential reloading is a feature supported in the advancedtls library. | ||
A very common way to achieve this is to reload from files. | ||
|
||
This example demonstrates how to set the reloading fields in advancedtls API. | ||
Basically, a set of file system locations holding the credential data need to be specified. | ||
Once the credential data needs to be updated, users just change the credential data in the file system, and gRPC will pick up the changes automatically. | ||
|
||
This example only shows how to set the API, without demonstrating the way to reload credentials on file system. | ||
To learn more about how to do that in Go, please see `advancedtls_integration_test.go`. | ||
|
||
A couple of things to note: | ||
1. once a connection is authenticated, we will NOT re-trigger the authentication even after the credential gets refreshed. | ||
2. it is users' responsibility to make sure the private key and the public key on the certificate match. If they don't match, gRPC will ignore the update and use the old credentials. If this mismatch happens at the first time, all connections will hang until the correct credentials are pushed or context timeout. | ||
|
||
## Try it | ||
In directory `security/advancedtls/examples`: | ||
|
||
``` | ||
go run server/main.go | ||
``` | ||
|
||
``` | ||
go run client/main.go | ||
``` |
99 changes: 99 additions & 0 deletions
99
security/advancedtls/examples/credential_reloading_from_files/client/main.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* | ||
* 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" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"google.golang.org/grpc" | ||
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. | ||
defaultConnTimeout = 10 * time.Second | ||
// Intervals that set to monitor the credential updates. | ||
credRefreshingInterval = 1 * time.Minute | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
// TODO(ZhenLian): change function signatures to reflect the changes in | ||
// https://github.com/grpc/grpc-go/pull/3981. | ||
identityOptions := advancedtls.PEMFileProviderOptions{ | ||
CertFile: testdata.Path("client_cert_1.pem"), | ||
KeyFile: testdata.Path("client_key_1.pem"), | ||
IdentityInterval: credRefreshingInterval, | ||
} | ||
identityProvider, err := advancedtls.NewPEMFileProvider(identityOptions) | ||
if err != nil { | ||
log.Fatalf("advancedtls.NewPEMFileProvider(%v) failed: %v", identityOptions, err) | ||
} | ||
rootOptions := advancedtls.PEMFileProviderOptions{ | ||
TrustFile: testdata.Path("client_trust_cert_1.pem"), | ||
RootInterval: credRefreshingInterval, | ||
} | ||
rootProvider, err := advancedtls.NewPEMFileProvider(rootOptions) | ||
if err != nil { | ||
log.Fatalf("advancedtls.NewPEMFileProvider(%v) failed: %v", rootOptions, err) | ||
} | ||
|
||
options := &advancedtls.ClientOptions{ | ||
IdentityOptions: advancedtls.IdentityCertificateOptions{ | ||
IdentityProvider: identityProvider, | ||
}, | ||
VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) { | ||
return &advancedtls.VerificationResults{}, nil | ||
}, | ||
RootOptions: advancedtls.RootCertificateOptions{ | ||
RootProvider: rootProvider, | ||
}, | ||
VType: advancedtls.CertVerification, | ||
} | ||
clientTLSCreds, err := advancedtls.NewClientCreds(options) | ||
if err != nil { | ||
log.Fatalf("advancedtls.NewClientCreds(%v) failed: %v", options, err) | ||
} | ||
|
||
// At initialization, the connection should be good. | ||
ctx, cancel := context.WithTimeout(context.Background(), defaultConnTimeout) | ||
defer cancel() | ||
conn, err := grpc.DialContext(ctx, address, grpc.WithTransportCredentials(clientTLSCreds)) | ||
if err != nil { | ||
log.Fatalf("grpc.DialContext to %s failed: %v", address, err) | ||
} | ||
greetClient := pb.NewGreeterClient(conn) | ||
reply, err := greetClient.SayHello(ctx, &pb.HelloRequest{Name: "gRPC"}, grpc.WaitForReady(true)) | ||
if err != nil { | ||
log.Fatalf("greetClient.SayHello failed: %v", err) | ||
} | ||
defer conn.Close() | ||
fmt.Printf("Getting message from server: %s...\n", reply.Message) | ||
} |
105 changes: 105 additions & 0 deletions
105
security/advancedtls/examples/credential_reloading_from_files/server/main.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* | ||
* 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 server demonstrates how to use the credential reloading feature in | ||
// advancedtls to serve mTLS connections from the client. | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"net" | ||
"time" | ||
|
||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/security/advancedtls" | ||
"google.golang.org/grpc/security/advancedtls/testdata" | ||
|
||
pb "google.golang.org/grpc/examples/helloworld/helloworld" | ||
) | ||
|
||
var port = ":50051" | ||
|
||
// Intervals that set to monitor the credential updates. | ||
const credRefreshingInterval = 1 * time.Minute | ||
|
||
type greeterServer struct { | ||
pb.UnimplementedGreeterServer | ||
} | ||
|
||
// sayHello is a simple implementation of the pb.GreeterServer SayHello method. | ||
func (greeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { | ||
return &pb.HelloReply{Message: "Hello " + in.Name}, nil | ||
} | ||
|
||
func main() { | ||
flag.Parse() | ||
fmt.Printf("server starting on port %s...\n", port) | ||
|
||
// TODO(ZhenLian): change function signatures to reflect the changes in | ||
// https://github.com/grpc/grpc-go/pull/3981. | ||
identityOptions := advancedtls.PEMFileProviderOptions{ | ||
CertFile: testdata.Path("server_cert_1.pem"), | ||
KeyFile: testdata.Path("server_key_1.pem"), | ||
IdentityInterval: credRefreshingInterval, | ||
} | ||
identityProvider, err := advancedtls.NewPEMFileProvider(identityOptions) | ||
if err != nil { | ||
log.Fatalf("advancedtls.NewPEMFileProvider(%v) failed: %v", identityOptions, err) | ||
} | ||
defer identityProvider.Close() | ||
rootOptions := advancedtls.PEMFileProviderOptions{ | ||
TrustFile: testdata.Path("server_trust_cert_1.pem"), | ||
RootInterval: credRefreshingInterval, | ||
} | ||
rootProvider, err := advancedtls.NewPEMFileProvider(rootOptions) | ||
if err != nil { | ||
log.Fatalf("advancedtls.NewPEMFileProvider(%v) failed: %v", rootOptions, err) | ||
} | ||
defer rootProvider.Close() | ||
|
||
// Start a server and create a client using advancedtls API with Provider. | ||
options := &advancedtls.ServerOptions{ | ||
IdentityOptions: advancedtls.IdentityCertificateOptions{ | ||
IdentityProvider: identityProvider, | ||
}, | ||
RootOptions: advancedtls.RootCertificateOptions{ | ||
RootProvider: rootProvider, | ||
}, | ||
RequireClientCert: true, | ||
VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) { | ||
return &advancedtls.VerificationResults{}, nil | ||
}, | ||
VType: advancedtls.CertVerification, | ||
} | ||
serverTLSCreds, err := advancedtls.NewServerCreds(options) | ||
if err != nil { | ||
log.Fatalf("advancedtls.NewServerCreds(%v) failed: %v", options, err) | ||
} | ||
s := grpc.NewServer(grpc.Creds(serverTLSCreds)) | ||
lis, err := net.Listen("tcp", port) | ||
if err != nil { | ||
log.Fatalf("failed to listen: %v", err) | ||
} | ||
pb.RegisterGreeterServer(s, greeterServer{}) | ||
if err := s.Serve(lis); err != nil { | ||
log.Fatalf("failed to serve: %v", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
#!/bin/bash | ||
# | ||
# 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. | ||
# | ||
|
||
set +e | ||
|
||
export TMPDIR=$(mktemp -d) | ||
trap "rm -rf ${TMPDIR}" EXIT | ||
|
||
clean () { | ||
for i in {1..10}; do | ||
jobs -p | xargs -n1 pkill -P | ||
# A simple "wait" just hangs sometimes. Running `jobs` seems to help. | ||
sleep 1 | ||
if jobs | read; then | ||
return | ||
fi | ||
done | ||
echo "$(tput setaf 1) clean failed to kill tests $(tput sgr 0)" | ||
jobs | ||
pstree | ||
exit 1 | ||
} | ||
|
||
fail () { | ||
echo "$(tput setaf 1) $1 $(tput sgr 0)" | ||
clean | ||
exit 1 | ||
} | ||
|
||
pass () { | ||
echo "$(tput setaf 2) $1 $(tput sgr 0)" | ||
} | ||
|
||
EXAMPLES=( | ||
"credential_reloading_from_files" | ||
) | ||
|
||
declare -A EXPECTED_SERVER_OUTPUT=( | ||
["credential_reloading_from_files"]="" | ||
) | ||
|
||
declare -A EXPECTED_CLIENT_OUTPUT=( | ||
["credential_reloading_from_files"]="Getting message from server: Hello gRPC..." | ||
) | ||
|
||
cd ./security/advancedtls/examples | ||
|
||
for example in ${EXAMPLES[@]}; do | ||
echo "$(tput setaf 4) testing: ${example} $(tput sgr 0)" | ||
|
||
# Build server | ||
if ! go build -o /dev/null ./${example}/*server/*.go; then | ||
fail "failed to build server" | ||
else | ||
pass "successfully built server" | ||
fi | ||
|
||
# Build client | ||
if ! go build -o /dev/null ./${example}/*client/*.go; then | ||
fail "failed to build client" | ||
else | ||
pass "successfully built client" | ||
fi | ||
|
||
# Start server | ||
SERVER_LOG="$(mktemp)" | ||
go run ./$example/*server/*.go &> $SERVER_LOG & | ||
|
||
CLIENT_LOG="$(mktemp)" | ||
if ! timeout 20 go run ${example}/*client/*.go &> $CLIENT_LOG; then | ||
fail "client failed to communicate with server | ||
got server log: | ||
$(cat $SERVER_LOG) | ||
got client log: | ||
$(cat $CLIENT_LOG) | ||
" | ||
else | ||
pass "client successfully communitcated with server" | ||
fi | ||
|
||
# Check server log for expected output if expecting an | ||
# output | ||
if [ -n "${EXPECTED_SERVER_OUTPUT[$example]}" ]; then | ||
if ! grep -q "${EXPECTED_SERVER_OUTPUT[$example]}" $SERVER_LOG; then | ||
fail "server log missing output: ${EXPECTED_SERVER_OUTPUT[$example]} | ||
got server log: | ||
$(cat $SERVER_LOG) | ||
got client log: | ||
$(cat $CLIENT_LOG) | ||
" | ||
else | ||
pass "server log contains expected output: ${EXPECTED_SERVER_OUTPUT[$example]}" | ||
fi | ||
fi | ||
|
||
# Check client log for expected output if expecting an | ||
# output | ||
if [ -n "${EXPECTED_CLIENT_OUTPUT[$example]}" ]; then | ||
if ! grep -q "${EXPECTED_CLIENT_OUTPUT[$example]}" $CLIENT_LOG; then | ||
fail "client log missing output: ${EXPECTED_CLIENT_OUTPUT[$example]} | ||
got server log: | ||
$(cat $SERVER_LOG) | ||
got client log: | ||
$(cat $CLIENT_LOG) | ||
" | ||
else | ||
pass "client log contains expected output: ${EXPECTED_CLIENT_OUTPUT[$example]}" | ||
fi | ||
fi | ||
clean | ||
echo "" | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module google.golang.org/grpc/security/advancedtls/examples | ||
|
||
go 1.15 | ||
|
||
require ( | ||
google.golang.org/grpc v1.33.1 | ||
google.golang.org/grpc/examples v0.0.0-20201020200225-9519efffeb5d | ||
google.golang.org/grpc/security/advancedtls v0.0.0-20201020200225-9519efffeb5d | ||
) |
Oops, something went wrong.