From 42dfd3ecec40b551d903edeb524b3f9277abe1a5 Mon Sep 17 00:00:00 2001 From: rithu leena john Date: Wed, 2 Nov 2016 14:07:05 -0700 Subject: [PATCH] cmd/dex: add option for gRPC client auth CA. --- Documentation/api.md | 2 ++ cmd/dex/config.go | 7 ++++--- cmd/dex/serve.go | 36 ++++++++++++++++++++++++++++++++---- examples/config-dev.yaml | 1 + 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Documentation/api.md b/Documentation/api.md index 39f404d3..a7a5612b 100644 --- a/Documentation/api.md +++ b/Documentation/api.md @@ -15,6 +15,8 @@ grpc: # Server certs. If TLS credentials aren't provided dex will generate self-signed ones. tlsCert: /etc/dex/grpc.crt tlsKey: /etc/dex/grpc.key + # Client auth CA. + tlsClientCA: /etc/dex/client.crt ``` ## Generating clients diff --git a/cmd/dex/config.go b/cmd/dex/config.go index b1beb850..69b4f12c 100644 --- a/cmd/dex/config.go +++ b/cmd/dex/config.go @@ -88,9 +88,10 @@ type Web struct { // GRPC is the config for the gRPC API. type GRPC struct { // The port to listen on. - Addr string `yaml:"addr"` - TLSCert string `yaml:"tlsCert"` - TLSKey string `yaml:"tlsKey"` + Addr string `yaml:"addr"` + TLSCert string `yaml:"tlsCert"` + TLSKey string `yaml:"tlsKey"` + TLSClientCA string `yaml:"tlsClientCA"` } // Storage holds app's storage configuration. diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go index b3ccba92..489a20c0 100644 --- a/cmd/dex/serve.go +++ b/cmd/dex/serve.go @@ -1,6 +1,8 @@ package main import ( + "crypto/tls" + "crypto/x509" "errors" "fmt" "io/ioutil" @@ -67,6 +69,7 @@ func serve(cmd *cobra.Command, args []string) error { {c.GRPC.TLSCert != "" && c.GRPC.Addr == "", "no address specified for gRPC"}, {c.GRPC.TLSKey != "" && c.GRPC.Addr == "", "no address specified for gRPC"}, {(c.GRPC.TLSCert == "") != (c.GRPC.TLSKey == ""), "must specific both a gRPC TLS cert and key"}, + {c.GRPC.TLSCert == "" && c.GRPC.TLSClientCA != "", "cannot specify gRPC TLS client CA without a gRPC TLS cert"}, } for _, check := range checks { @@ -77,11 +80,36 @@ func serve(cmd *cobra.Command, args []string) error { var grpcOptions []grpc.ServerOption if c.GRPC.TLSCert != "" { - opt, err := credentials.NewServerTLSFromFile(c.GRPC.TLSCert, c.GRPC.TLSKey) - if err != nil { - return fmt.Errorf("load grpc certs: %v", err) + if c.GRPC.TLSClientCA != "" { + // Parse certificates from certificate file and key file for server. + cert, err := tls.LoadX509KeyPair(c.GRPC.TLSCert, c.GRPC.TLSKey) + if err != nil { + return fmt.Errorf("parsing certificate file: %v", err) + } + + // Parse certificates from client CA file to a new CertPool. + cPool := x509.NewCertPool() + clientCert, err := ioutil.ReadFile(c.GRPC.TLSClientCA) + if err != nil { + return fmt.Errorf("reading from client CA file: %v", err) + } + if cPool.AppendCertsFromPEM(clientCert) != true { + return errors.New("failed to parse client CA") + } + + tlsConfig := tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: cPool, + } + grpcOptions = append(grpcOptions, grpc.Creds(credentials.NewTLS(&tlsConfig))) + } else { + opt, err := credentials.NewServerTLSFromFile(c.GRPC.TLSCert, c.GRPC.TLSKey) + if err != nil { + return fmt.Errorf("load grpc certs: %v", err) + } + grpcOptions = append(grpcOptions, grpc.Creds(opt)) } - grpcOptions = append(grpcOptions, grpc.Creds(opt)) } connectors := make([]server.Connector, len(c.Connectors)) diff --git a/examples/config-dev.yaml b/examples/config-dev.yaml index 9f2885f0..84af2fbb 100644 --- a/examples/config-dev.yaml +++ b/examples/config-dev.yaml @@ -22,6 +22,7 @@ web: # addr: 127.0.0.1:5557 # tlsCert: /etc/dex/grpc.crt # tlsKey: /etc/dex/grpc.key +# tlsClientCA: /etc/dex/client.crt # Instead of reading from an external storage, use this list of clients. #