Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds gRPC Server-side TLS Support #204

Closed
wants to merge 37 commits into from
Closed

Conversation

danehans
Copy link
Collaborator

@danehans danehans commented Mar 14, 2018

Adds gRPC Server-side TLS support to Fortio grpc client and server. Addresses TODO: option to specify certs. in fgrpc/grpcrunner.go.

@ldemailly
Copy link
Member

ldemailly commented Mar 15, 2018

I don't think we should put self signed certs in the release docker image

maybe it can be a volume/mount like the json data dir ?

for testing we can have indeed a script generating a sample

@ldemailly ldemailly self-requested a review March 15, 2018 04:52
@danehans
Copy link
Collaborator Author

Thank you for taking a look at the PR.

I don't think we should put self signed certs in the release docker image

Agreed, that is why I did not update release/Dockerfile.

maybe it can be a volume/mount like the json data dir ?

I'm not familiar with how the json data dir is mounted. Do you have a pointer?

for testing we can have indeed a script generating a sample

Agreed, I wanted to make sure we can perform e2e testing on the feature. This is why I updated the non-release Docker image. Maybe I don't understand how the non-release and release images work with one another.

@ldemailly
Copy link
Member

Thank you for taking a look at the PR.

I haven't yet, really. will now

I'm not familiar with how the json data dir is mounted. Do you have a pointer?

https://github.com/istio/fortio/blob/master/Dockerfile#L33

Agreed, I wanted to make sure we can perform e2e testing on the feature. This is why I updated the non-release Docker image. Maybe I don't understand how the non-release and release images work with one another.

Dockerfile is the release for istio/fortio
there is additional code in release/ that extract a tgz out of it but it's secondary

Copy link
Member

@ldemailly ldemailly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh in addition to all the technical issues/details below,

I'm really not a fan of adding all this code - it might grow on me though once simplified and working but... not sure.... I'll give it some more thoughts

Dockerfile Outdated
@@ -20,10 +20,17 @@ RUN /usr/local/go/bin/go version
RUN CGO_ENABLED=0 GOOS=darwin /usr/local/go/bin/go build -a -ldflags -s -o fortio.go18.mac istio.io/fortio
# Just check it stays compiling on Windows (would need to set the rsrcDir too)
RUN CGO_ENABLED=0 GOOS=windows go build -a -o fortio.exe istio.io/fortio
# Generate TLS assets for secure grpc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undo all this

ftls/ftls.go Outdated
// See the License for the specific language governing permissions and
// limitations under the License.

package ftls
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need a brand new top level package just for this

it can be a file inside fnet

ftls/ftls.go Outdated

// NewCertPool creates an x509 certPool with the provided CA files.
func NewCertPool(CAFiles []string) (*x509.CertPool, error) {
certPool := x509.NewCertPool()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems overly complicated for a testing tool we only need
https://godoc.org/google.golang.org/grpc/credentials#NewClientTLSFromFile
no ?

(though maybe it is worth having this for http tls too)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this would be needed to setup one or more trusted CA for authorizing client/server connections.

}
creds := credentials.NewTLS(tlsCfg)
opts = grpc.WithTransportCredentials(creds)
case strings.HasPrefix(serverAddr, "https://"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the switch between standard CA vs custom CA should be based on https:// prefix
it's a config option, to be added to grpcoptions

fgrpc/pingsrv.go Outdated
grpcServer := grpc.NewServer()
var opts []grpc.ServerOption
if secure {
tlsCfg, err := ftls.NewCredentials(false, ftls.DefaultServerCert, ftls.DefaultServerKey,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if they are hard coded what is the point of passing constants.
we need some grpcoptions struct to control tls instead of just 1 boolean

ftls/info.go Outdated
// ClientConfig returns a tls.Config for client use.
func (info *TLSInfo) ClientConfig() (*tls.Config, error) {
// CA for verifying the server
pool, err := NewCertPool([]string{info.CAFile})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would you put both the standard CA and additional one in 1 config ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change CAFile to be of type []string that represent one or more paths to trusted CA certs. Provide the slice to NewCertPool. Create a cmdline flag that allows a user to specify multiple comma-separated cert paths. Is that acceptable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd rather have just the NewClientTLSFromFile for now I think; and less code

@codecov
Copy link

codecov bot commented Mar 16, 2018

Codecov Report

Merging #204 into master will increase coverage by 0.2%.
The diff coverage is 87.5%.

Impacted file tree graph

@@           Coverage Diff            @@
##           master    #204     +/-   ##
========================================
+ Coverage    90.2%   90.5%   +0.2%     
========================================
  Files          10      10             
  Lines        1906    1899      -7     
========================================
- Hits         1720    1718      -2     
+ Misses        119     116      -3     
+ Partials       67      65      -2
Impacted Files Coverage Δ
fgrpc/pingsrv.go 88.1% <84.6%> (+0.9%) ⬆️
fgrpc/grpcrunner.go 90.8% <90.9%> (+2.6%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update be80813...81b16cd. Read the comment docs.

@danehans
Copy link
Collaborator Author

@ldemailly Thanks for your review. I addressed your comments and have updated the PR. The purpose of this PR is to address TODO: option to specify certs. I should have created an issue to discuss my intentions before getting this far. If my approach is unwanted, let me know how you would like to address the TODO.

@danehans
Copy link
Collaborator Author

OK. I'll strip most of this stuff out and update the PR.

@ldemailly
Copy link
Member

Sorry been crazy busy... will look more soon

Copy link
Member

@ldemailly ldemailly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README.md Outdated
@@ -77,8 +77,12 @@ target is a url (http load tests) or host:port (grpc health test). flags are:
-grpc-port string
grpc server port. Can be in the form of host:port, ip:port or port.
(default "8079")
-grpc-secure
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we still need a way to standard TLS no?

Copy link
Collaborator Author

@danehans danehans Mar 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR provides backwards compatibility. Instead of passing the -grpc-secure bool, Dial will use the one of the following:

A. The cert from -server-cert if it's provided. I can easily add the flag back in, but IMO it no longer adds value.
B. Us nil creds if dest is an https prefix (this provides backwards compatibility)
C. Insecure Dial if A or C do not apply.

I thought this is a cleaner approach than setting the bool and cert/key flags. IMO having both sets of flags causes user confusion. Using the legacy bool flag made sense, a user flips the secure/insecure switch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following - how do I get the previous behavior exactly ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous behavior is accomplished by using an https prefix with the grpc destination.
For example:

grpc client

fortio grpcping https://fortio.istio.io

or any client that uses GRPCRunnerOptions

fortio curl -loglevel debug http://localhost:8080/fortio/fetch/localhost:8080/fortio/?url=https://fortio.istio.io:443&load=Start&qps=-1&json=on&n=100&runner=grpc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ic I missed that - does it work with fortio load -grpc https://... too ? (it should I guess as destination is passed down unchanged if I recall)

we should put tls/no tls in the (json) result object

we should probably document that behavior somewhere (that grpc host:port is insecure unless a cert is given and https://host:port is secure)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it work with fortio load -grpc https://... too ?

It does. I extensively tested this patch today. I documented the details here.

we should probably document that behavior somewhere (that grpc host:port is insecure unless a cert is given and https://host:port is secure)

I updated the Readme.

fortio_main.go Outdated
goMaxProcsFlag = flag.Int("gomaxprocs", 0, "Setting for runtime.GOMAXPROCS, <1 doesn't change the default")
profileFlag = flag.String("profile", "", "write .cpu and .mem profiles to file")
grpcFlag = flag.Bool("grpc", false, "Use GRPC (health check) for load testing")
serverCertFlag = flag.String("server-cert", "",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a new line to minimize the diff
(go can be annoying with reformatting to align - also as mentioned I think the grpc-secure flag is still needed, the cert,ca,key are optional)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do. For clarity, the ca flag was dropped since refactoring this PR based on your initial feedback.

fortio_main.go Outdated
@@ -162,7 +165,7 @@ func main() {
}
case "server":
isServer = true
fgrpc.PingServer(*grpcPortFlag, fgrpc.DefaultHealthServiceName)
fgrpc.PingServer(*grpcPortFlag, *serverCertFlag, *serverKeyFlag, fgrpc.DefaultHealthServiceName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we should add some GRPC(Server)Options instead of 5 string params
(shared between the client and server maybe)
but maybe that can be a followup

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to address that in a follow-on PR. This PR has been around for a while. I opened issue
#220 and assigned myself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k, ty

fortio_main.go Outdated
@@ -249,7 +252,7 @@ func fortioLoad(justCurl bool, percList []float64) {
o := fgrpc.GRPCRunnerOptions{
RunnerOptions: ro,
Destination: url,
Secure: *grpcSecureFlag,
Cert: *serverCertFlag,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the 2 are different

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. See my response above and let me know your thoughts. I want to make sure we're on the same page before I rebase this PR (it was a PITA the last time I rebased).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k

ui/uihandler.go Outdated
@@ -153,6 +153,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
qps, _ := strconv.ParseFloat(r.FormValue("qps"), 64) // nolint: gas
durStr := r.FormValue("t")
grpcSecure := (r.FormValue("grpc-secure") == "on")
cert := r.FormValue("cert")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for this I think we should just use the flags (if you want a fortio UI using different cert, start a new one with different cert path)

Copy link
Collaborator Author

@danehans danehans Mar 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I see, the challenge with that approach is:

  1. uihandler.go creates instance o of the fgrpc.GRPCRunnerOptions object .
  2. The flags created in fortio_main.go are not available to uihandler.go or any other pkg for that matter. Therefore, the Cert field in o can not be populated based on any flags.

I believe what you are asking for can be accomplished by putting Fortio flags into a pkg (i.e. cli ) and having fortio_main.go and any other dependent pkg's import cli. If this has your interest, please create an Issue, assign me and I'll work on refactoring the Fortio cli into a separate pkg. However, I don't think that work should block this PR.

Copy link
Member

@ldemailly ldemailly Mar 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could also pass those global options to ui.Serve()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, assuming the cli options are in a separate pkg. As I mentioned, I am happy to take on this Fortio cli refactoring. Just create an Issue and assign me. Until then, I think providing a field to enter the cert path is a reasonable option.

Copy link
Collaborator Author

@danehans danehans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up review!

README.md Outdated
@@ -77,8 +77,12 @@ target is a url (http load tests) or host:port (grpc health test). flags are:
-grpc-port string
grpc server port. Can be in the form of host:port, ip:port or port.
(default "8079")
-grpc-secure
Copy link
Collaborator Author

@danehans danehans Mar 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR provides backwards compatibility. Instead of passing the -grpc-secure bool, Dial will use the one of the following:

A. The cert from -server-cert if it's provided. I can easily add the flag back in, but IMO it no longer adds value.
B. Us nil creds if dest is an https prefix (this provides backwards compatibility)
C. Insecure Dial if A or C do not apply.

I thought this is a cleaner approach than setting the bool and cert/key flags. IMO having both sets of flags causes user confusion. Using the legacy bool flag made sense, a user flips the secure/insecure switch.

fortio_main.go Outdated
goMaxProcsFlag = flag.Int("gomaxprocs", 0, "Setting for runtime.GOMAXPROCS, <1 doesn't change the default")
profileFlag = flag.String("profile", "", "write .cpu and .mem profiles to file")
grpcFlag = flag.Bool("grpc", false, "Use GRPC (health check) for load testing")
serverCertFlag = flag.String("server-cert", "",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do. For clarity, the ca flag was dropped since refactoring this PR based on your initial feedback.

fortio_main.go Outdated
@@ -162,7 +165,7 @@ func main() {
}
case "server":
isServer = true
fgrpc.PingServer(*grpcPortFlag, fgrpc.DefaultHealthServiceName)
fgrpc.PingServer(*grpcPortFlag, *serverCertFlag, *serverKeyFlag, fgrpc.DefaultHealthServiceName)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to address that in a follow-on PR. This PR has been around for a while. I opened issue
#220 and assigned myself.

fortio_main.go Outdated
@@ -249,7 +252,7 @@ func fortioLoad(justCurl bool, percList []float64) {
o := fgrpc.GRPCRunnerOptions{
RunnerOptions: ro,
Destination: url,
Secure: *grpcSecureFlag,
Cert: *serverCertFlag,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. See my response above and let me know your thoughts. I want to make sure we're on the same page before I rebase this PR (it was a PITA the last time I rebased).

ui/uihandler.go Outdated
@@ -153,6 +153,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
qps, _ := strconv.ParseFloat(r.FormValue("qps"), 64) // nolint: gas
durStr := r.FormValue("t")
grpcSecure := (r.FormValue("grpc-secure") == "on")
cert := r.FormValue("cert")
Copy link
Collaborator Author

@danehans danehans Mar 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I see, the challenge with that approach is:

  1. uihandler.go creates instance o of the fgrpc.GRPCRunnerOptions object .
  2. The flags created in fortio_main.go are not available to uihandler.go or any other pkg for that matter. Therefore, the Cert field in o can not be populated based on any flags.

I believe what you are asking for can be accomplished by putting Fortio flags into a pkg (i.e. cli ) and having fortio_main.go and any other dependent pkg's import cli. If this has your interest, please create an Issue, assign me and I'll work on refactoring the Fortio cli into a separate pkg. However, I don't think that work should block this PR.

log.Infof("Using server certificate %v to construct TLS credentials", cert)
opts = append(opts, grpc.WithTransportCredentials(creds))
case strings.HasPrefix(serverAddr, "https://"):
creds := credentials.NewTLS(nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ic this is where the https/tls behaviour is

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, all the intelligence is in Dial.

README.md Outdated
@@ -77,8 +77,12 @@ target is a url (http load tests) or host:port (grpc health test). flags are:
-grpc-port string
grpc server port. Can be in the form of host:port, ip:port or port.
(default "8079")
-grpc-secure
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ic I missed that - does it work with fortio load -grpc https://... too ? (it should I guess as destination is passed down unchanged if I recall)

we should put tls/no tls in the (json) result object

we should probably document that behavior somewhere (that grpc host:port is insecure unless a cert is given and https://host:port is secure)

fortio_main.go Outdated
@@ -162,7 +165,7 @@ func main() {
}
case "server":
isServer = true
fgrpc.PingServer(*grpcPortFlag, fgrpc.DefaultHealthServiceName)
fgrpc.PingServer(*grpcPortFlag, *serverCertFlag, *serverKeyFlag, fgrpc.DefaultHealthServiceName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k, ty

fortio_main.go Outdated
@@ -249,7 +252,7 @@ func fortioLoad(justCurl bool, percList []float64) {
o := fgrpc.GRPCRunnerOptions{
RunnerOptions: ro,
Destination: url,
Secure: *grpcSecureFlag,
Cert: *serverCertFlag,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k

fortio_main.go Outdated
@@ -312,20 +315,19 @@ func fortioLoad(justCurl bool, percList []float64) {
}

func grpcClient() {
if len(flag.Args()) != 1 {
if len(flag.Args()) < 1 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which case is that change for ?

iPort := PingServer("0", "", "", "foo")
iAddr := fmt.Sprintf("localhost:%d", iPort)
t.Logf("test insecure grpc ping server running, will connect to %s", iAddr)
sPort := PingServer("0", "../testdata/server.crt", "../testdata/server.key",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this relative path making success dependent on where it is ran from ? (somehow doubt it works from both parent or different directories?)

not sure we need a new directory - tbd if go testing has provision for files relative to test files?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested by copying the cert/key from the testdata directory to the project's root directory and updating the following in grpcrunner_test.go:

	svrCrt = "../server.crt"
	svrKey = "../server.key"

The tests passed.

not sure we need a new directory - tbd if go testing has provision for files relative to test files?

I like the idea of storing all test data for a project in a specific directory. I think it's clean and makes it very apparent to devs. Let me know where I should move the test cert/key if you want me to remove the directory.

@ldemailly
Copy link
Member

this is good, do you have time to raise the coverage ? (for instance pass invalid credentials, connect to the wrong port/settings,...)

@ldemailly
Copy link
Member

where is -cacert ? I see in the example you pass a cert to the client, I assume that implies it expects that cert, but it should be a CA instead ?

README.md Outdated
Use secure transport (tls) for GRPC
-cert
Full path to the server certificate required for secure grpc.
Used by grpcping and server. (default "") means secure grpc is disabled.
Copy link
Member

@ldemailly ldemailly Mar 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:

"unless https:// destination is used, in which case standard TLS is expected (with valid server certificates signed by the internet standard CAs)"

or some such

//var creds credentials.TransportCredentials
switch {
case cert != "":
creds, err := credentials.NewClientTLSFromFile(cert, "")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder here if we're confusing client and server cert

we should be able to do mTLS by providing an optional client cert; and expect a server cert signed by a custom CA

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the name of this PR to properly reflect the implemented functionality. This PR originally provided mTLS, but I simplified things based on your initial feedback. This PR will allow clients (i.e. grpcping) to authenticate the Fortio gRPC server and encrypt the data exchanged. In my original PR, the server cert was fetched from the CA (Fortio server). Since refactoring, the server cert must be shipped with the client-side application. This blog provides details of the original and current approach for this PR. Let me know how you would like to proceed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section provides a detailed explanation of the basic TLS handshake implemented by this PR.

@danehans danehans changed the title Adds gRPC mTLS Support Adds gRPC Server-side TLS Support Mar 29, 2018
@danehans
Copy link
Collaborator Author

@ldemailly will this PR be ready to merge after I fix the conflicts?

Copy link
Member

@ldemailly ldemailly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

almost, see below

Makefile Outdated
# go test ./... and others run in vendor/ and cause problems (!)
PACKAGES:=$(shell find . -type d -print | egrep -v "/(\.|vendor|static|templates|release|docs|json)")
PACKAGES:=$(shell find . -type d -print | egrep -v "/(\.|vendor|static|templates|release|docs|json|cert-tmp)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$(CERT_TEMP) ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Makefile Outdated
@@ -14,25 +14,41 @@ TAG:=$(USER)$(shell date +%y%m%d_%H%M%S)

DOCKER_TAG = $(DOCKER_PREFIX)$(IMAGE):$(TAG)

CERT_TEMP := ./cert-tmp/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CERT_TEMP_DIR := ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

README.md Outdated
UI starting - visit:
http://localhost:8080/fortio/
Https redirector running on :8081
Fortio 0.9.0 grpc ping server listening on port :8079
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when merging make sure there is 0.9.1 everywhere

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like docs are now using 0.10.0. I have changed to 0.10.0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's actually 0.10.1 now :-)

README.md Outdated
* A `grpcping` using TLS. First, start Fortio server with the `-cert` and `-key` flags.
`/path/to/fortio/server.crt` and `/path/to/fortio/server.key` are paths to the TLS certificate and key that
you are responsible for providing. Creating a TLS certificate is outside the scope of this document. This example uses
`localhost` in the `Subject Alternative Name` (SAN) of the certificate. The SAN should match the domain name that
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove that part (localhost san) as it doesn't matter / is also out of scope ? - or mentioned the makefile can generate test only certs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

README.md Outdated
Next, run the `load` command with the `-cacert` flag:
```
$ fortio load -cacert /etc/ssl/certs/ca.crt -grpc localhost:8079

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing close 3 ` - please make sure you preview/look over the changes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Webtest.sh Outdated
CERT=/etc/ssl/certs/ca-certificates.crt
TEST_CERT_VOL=/etc/ssl/certs/fortio
BUILD_IMAGE_TAG=v7
BUILD_IMAGE=istio/fortio.build:$BUILD_IMAGE_TAG
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change so it works with https://github.com/istio/fortio/blob/master/Makefile#L112

ie: add the file name to the list and use istio/fortio.build:v7 directly so sed finds it when we go to v8

@@ -78,8 +78,10 @@ var (
goMaxProcsFlag = flag.Int("gomaxprocs", 0, "Setting for runtime.GOMAXPROCS, <1 doesn't change the default")
profileFlag = flag.String("profile", "", "write .cpu and .mem profiles to file")
grpcFlag = flag.Bool("grpc", false, "Use GRPC (health check by default, add -ping for ping) for load testing")
grpcSecureFlag = flag.Bool("grpc-secure", false, "Use secure transport (tls) for GRPC")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that change isn't reflected in the README.md

see release/updateFlags.sh for how to update

we also need to document somewhere that https:// replaces -grpc-secure

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the readme to remove the -secure-grpc flag and ran the updateFlags.sh script.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@danehans
Copy link
Collaborator Author

@ldemailly thanks for the feedback. I need a couple days to wrap-up something I'm working on and I'll push a new commit that addresses your concerns.

@ldemailly
Copy link
Member

thanks for your patience and flexibility !

Copy link
Collaborator Author

@danehans danehans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting ready to push my latest commit that addresses your feedback.

@@ -78,8 +78,10 @@ var (
goMaxProcsFlag = flag.Int("gomaxprocs", 0, "Setting for runtime.GOMAXPROCS, <1 doesn't change the default")
profileFlag = flag.String("profile", "", "write .cpu and .mem profiles to file")
grpcFlag = flag.Bool("grpc", false, "Use GRPC (health check by default, add -ping for ping) for load testing")
grpcSecureFlag = flag.Bool("grpc-secure", false, "Use secure transport (tls) for GRPC")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the readme to remove the -secure-grpc flag and ran the updateFlags.sh script.

README.md Outdated
* A `grpcping` using TLS. First, start Fortio server with the `-cert` and `-key` flags.
`/path/to/fortio/server.crt` and `/path/to/fortio/server.key` are paths to the TLS certificate and key that
you are responsible for providing. Creating a TLS certificate is outside the scope of this document. This example uses
`localhost` in the `Subject Alternative Name` (SAN) of the certificate. The SAN should match the domain name that
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Makefile Outdated
@@ -14,25 +14,41 @@ TAG:=$(USER)$(shell date +%y%m%d_%H%M%S)

DOCKER_TAG = $(DOCKER_PREFIX)$(IMAGE):$(TAG)

CERT_TEMP := ./cert-tmp/
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Makefile Outdated
# go test ./... and others run in vendor/ and cause problems (!)
PACKAGES:=$(shell find . -type d -print | egrep -v "/(\.|vendor|static|templates|release|docs|json)")
PACKAGES:=$(shell find . -type d -print | egrep -v "/(\.|vendor|static|templates|release|docs|json|cert-tmp)")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

README.md Outdated
UI starting - visit:
http://localhost:8080/fortio/
Https redirector running on :8081
Fortio 0.9.0 grpc ping server listening on port :8079
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like docs are now using 0.10.0. I have changed to 0.10.0.

README.md Outdated
Next, run the `load` command with the `-cacert` flag:
```
$ fortio load -cacert /etc/ssl/certs/ca.crt -grpc localhost:8079

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -78,8 +78,10 @@ var (
goMaxProcsFlag = flag.Int("gomaxprocs", 0, "Setting for runtime.GOMAXPROCS, <1 doesn't change the default")
profileFlag = flag.String("profile", "", "write .cpu and .mem profiles to file")
grpcFlag = flag.Bool("grpc", false, "Use GRPC (health check by default, add -ping for ping) for load testing")
grpcSecureFlag = flag.Bool("grpc-secure", false, "Use secure transport (tls) for GRPC")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Collaborator Author

@danehans danehans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting ready to push my latest commit that addresses your feedback.

@danehans
Copy link
Collaborator Author

danehans commented May 2, 2018

@ldemailly do you mind reviewing when you have a moment?

@ldemailly
Copy link
Member

looking now

@ldemailly
Copy link
Member

getting some github (unicorn) errors when I try to open this PR somehow)

qq: why did you remove TestExitedPingServer ?

Copy link
Member

@ldemailly ldemailly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really almost there now - Thanks!

A few comment and you only need to update where I prefixed by "NeedFix" (4 places)

# switch to report mode
docker stop $DOCKERID
docker rm $DOCKERNAME
docker stop $DOCKERSECID
docker rm $DOCKERSECNAME
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably be "trap"ed too but I guess we can clean that up later

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the trap is used for the final Fortio instance, the report mode server. I stop/rm the Docker assets for the secure grpc instance of Fortio server before the script starts the report mode Fortio server.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trap means cleanup like a finally, in case of error in any of tbe tests

if err != nil {
log.Errf("failed to conect to %s with tls %v: %v", serverAddr, tls, err)
log.Errf("failed to connect to %s: %v", serverAddr, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NeedFix: when an error occurs it is very important to log all the input, please add cacert and override to the statement

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

// Dial dials grpc using insecure or tls transport security when serverAddr
// has prefixHTTPS or cert is provided. If override is set to a non empty string,
// it will override the virtual host name of authority in requests.
func Dial(serverAddr string, cacert, override string) (conn *grpc.ClientConn, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NeedFix: either put the type for all 3 or only once but here it's odd to have string 2 out of 3 args

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

},
Destination: sDest,
CACert: caCrt,
CertOverride: "invalidName",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have a positive test of CertOverride (where it is set yet works ?)

{
name: "insecure runner with payload",
runnerOpts: GRPCRunnerOptions{
RunnerOptions: periodic.RunnerOptions{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NeedFix: there is a lot of copy paste of this section, why not have the runner options in a variable ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I find table tests easier to read when testing multiple test cases. WOuld you rather I follow the existing pattern for the test? Something like this:

func TestGRPCRunner(t *testing.T) {
	log.SetLogLevel(log.Info)
	iPort := PingServer("0", "", "", "bar", 0)
	iDest := fmt.Sprintf("localhost:%d", iPort)
	sPort := PingServer("0", svrCrt, svrKey, "bar", 0)
	sDest := fmt.Sprintf("localhost:%d", sPort)
	ro := periodic.RunnerOptions{
		QPS:        100,
		Resolution: 0.00001,
	}

	opts := GRPCRunnerOptions{
		RunnerOptions: ro,
		Destination: iDest,
		Profiler:    "test.profile",
	}
	res, err := RunGRPCTest(&opts)
	if err != nil {
		t.Error(err)
		return
	}
	totalReq := res.DurationHistogram.Count
	ok := res.RetCodes[grpc_health_v1.HealthCheckResponse_SERVING]
	if totalReq != ok {
		t.Errorf("Mismatch between requests %d and ok %v", totalReq, res.RetCodes)
	}
	// Test a grpc runner with TLS enabled.
	opts.Destination = sDest
	opts.CACert = caCrt
	res, err = RunGRPCTest(&opts)
	if err != nil {
		t.Error(err)
		return
	}
	totalReq = res.DurationHistogram.Count
	ok = res.RetCodes[grpc_health_v1.HealthCheckResponse_SERVING]
	if totalReq != ok {
		t.Errorf("Mismatch between requests %d and ok %v", totalReq, res.RetCodes)
	}
}

Keep in mind the above example is only exercising 2 test cases.

{
name: "insecure runner",
runnerOpts: GRPCRunnerOptions{
RunnerOptions: periodic.RunnerOptions{
Copy link
Member

@ldemailly ldemailly May 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NeedFix: same

log.Fatalf("Invalid TLS credentials: %v\n", err)
}
log.Infof("Using server certificate %v to construct TLS credentials", cert)
log.Infof("Using server key %v to construct TLS credentials", key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could probably be a single log info instead of 2 but it's ok as is too

Copy link
Collaborator Author

@danehans danehans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my feedback and example refactor of TestGRPCRunner. I would like to make sure we're on the same page before I refactor TestGRPCRunner and TestGRPCRunnerWithError.

# switch to report mode
docker stop $DOCKERID
docker rm $DOCKERNAME
docker stop $DOCKERSECID
docker rm $DOCKERSECNAME
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the trap is used for the final Fortio instance, the report mode server. I stop/rm the Docker assets for the secure grpc instance of Fortio server before the script starts the report mode Fortio server.

// Dial dials grpc using insecure or tls transport security when serverAddr
// has prefixHTTPS or cert is provided. If override is set to a non empty string,
// it will override the virtual host name of authority in requests.
func Dial(serverAddr string, cacert, override string) (conn *grpc.ClientConn, err error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

if err != nil {
log.Errf("failed to conect to %s with tls %v: %v", serverAddr, tls, err)
log.Errf("failed to connect to %s: %v", serverAddr, err)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

{
name: "insecure runner with payload",
runnerOpts: GRPCRunnerOptions{
RunnerOptions: periodic.RunnerOptions{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I find table tests easier to read when testing multiple test cases. WOuld you rather I follow the existing pattern for the test? Something like this:

func TestGRPCRunner(t *testing.T) {
	log.SetLogLevel(log.Info)
	iPort := PingServer("0", "", "", "bar", 0)
	iDest := fmt.Sprintf("localhost:%d", iPort)
	sPort := PingServer("0", svrCrt, svrKey, "bar", 0)
	sDest := fmt.Sprintf("localhost:%d", sPort)
	ro := periodic.RunnerOptions{
		QPS:        100,
		Resolution: 0.00001,
	}

	opts := GRPCRunnerOptions{
		RunnerOptions: ro,
		Destination: iDest,
		Profiler:    "test.profile",
	}
	res, err := RunGRPCTest(&opts)
	if err != nil {
		t.Error(err)
		return
	}
	totalReq := res.DurationHistogram.Count
	ok := res.RetCodes[grpc_health_v1.HealthCheckResponse_SERVING]
	if totalReq != ok {
		t.Errorf("Mismatch between requests %d and ok %v", totalReq, res.RetCodes)
	}
	// Test a grpc runner with TLS enabled.
	opts.Destination = sDest
	opts.CACert = caCrt
	res, err = RunGRPCTest(&opts)
	if err != nil {
		t.Error(err)
		return
	}
	totalReq = res.DurationHistogram.Count
	ok = res.RetCodes[grpc_health_v1.HealthCheckResponse_SERVING]
	if totalReq != ok {
		t.Errorf("Mismatch between requests %d and ok %v", totalReq, res.RetCodes)
	}
}

Keep in mind the above example is only exercising 2 test cases.

Copy link
Collaborator Author

@danehans danehans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my feedback and example refactor of TestGRPCRunner. I would like to make sure we're on the same page before I refactor TestGRPCRunner and TestGRPCRunnerWithError.

Webtest.sh Outdated
@@ -14,6 +14,9 @@ DOCKERID=$(docker run -d --ulimit nofile=$FILE_LIMIT --name $DOCKERNAME istio/fo
function cleanup {
docker stop $DOCKERID
docker rm $DOCKERNAME
docker stop $DOCKERSECID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in theory should have an if that it is set/started (as it's not started right away unlike DOCKERID) but it's ok, you didn't have to change it (for that reason as well - I'll try - one test is interrupt or have a test error out and see if it still finishes correctly/cleansup without too many additional errors)

log.Errf("Invalid TLS credentials: %v\n", err)
return nil, err
}
log.Infof("Using CA certificate %v to construct TLS credentials", cacert)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: here too (override logging)

if totalReq != ok {
t.Errorf("Mismatch between requests %d and ok %v", totalReq, res.RetCodes)
for _, test := range tests {
switch {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't mean to have to put a big switch here :( why can't those be above directly ?

@ldemailly
Copy link
Member

closing for #249 (this PR makes github choke so redone there)
to see history/comments check with incognito window (and/or when github fixes that bug)

@ldemailly ldemailly closed this May 21, 2018
ldemailly added a commit that referenced this pull request May 22, 2018
Add support for custom CA and certificates and key, and thus mTLS, for fortio's GRPC client/server

Work by @danehans in #204 with my support/reviews/tweaks

commits:

* Adds gRPC mTLS Support

* Addresses @ldemailly 3/15/18 feedback

* Move cert log msgs and fix typo

* Addresses round 2 of @ldemailly comments

* Added docs and minor fixups

* Updated Dial return error

* Updates 2nd ping server fail test with new params

* Removes unneeded var declaration in Dial func

* Realigns flags in fortio_main

* Updates cert/key flags and updates readme

* Adds more details to docs

* Updates e2e/ut, docs and Dial func to support vhost override

* Implements new -ca-cert flag

* Generates certs, adds e2e and -cacert flag

* Removes openssl dep

* Adds logs to certgen and fixes remote docker bind mount

* reverts to certgen script and ui

* Updates makefile/Webtest/Certgen and ui https func

* Add make deps to docker compose

* Fixes make command in Dockerfile.test for CI

* Added Make dep and cleaned-up addHTTPS func

* Adds add'l Dial func test cases

* Addresses @ldemailly comments

* Adds TestExitedPingServer test

* Refactor PingServer test for failed crt/key

* use 0.10.1 like rest of readme

* Addresses ldemailly feedback

* Removed docker stop/rm from trap

* Fix make test

2nd make test would error out because of cert-tmp

* Fix clean and error handling for test (new docker images)

* Switch v to 0.11.0

Except for json which should be 0.9.0 (format as it was when it was
added)

* Fixing test to not check for test.name to set options (!)

* Even more cleanup of duplicate

* Sync the readme and the flags from the code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants