examples: adding a gRPC client example.

This commit is contained in:
rithu john 2017-02-20 08:45:32 -08:00
parent bb896a8222
commit fa2f76bcdb
10 changed files with 327 additions and 4 deletions

View File

@ -88,6 +88,8 @@ func main() {
}
```
A clear working example of the Dex gRPC client can be found [here][../examples/grpc-client/README.md].
## Authentication and access control
The dex API does not provide any authentication or authorization beyond TLS client auth.

View File

@ -23,7 +23,7 @@ export GO15VENDOREXPERIMENT=1
LD_FLAGS="-w -X $(REPO_PATH)/version.Version=$(VERSION)"
build: bin/dex bin/example-app
build: bin/dex bin/example-app bin/grpc-client
bin/dex: check-go-version
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex
@ -31,6 +31,9 @@ bin/dex: check-go-version
bin/example-app: check-go-version
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/example-app
bin/grpc-client: check-go-version
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/examples/grpc-client
.PHONY: release-binary
release-binary:
@go build -o _output/bin/dex -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex

View File

@ -24,8 +24,8 @@ web:
# from the HTTP endpoints.
# grpc:
# addr: 127.0.0.1:5557
# tlsCert: /etc/dex/grpc.crt
# tlsKey: /etc/dex/grpc.key
# tlsCert: examples/grpc-client/server.crt
# tlsKey: examples/grpc-client/server.key
# tlsClientCA: /etc/dex/client.crt
# Uncomment this block to enable configuration for the expiration time durations.

5
examples/grpc-client/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.key
*.crt
*.csr
index.*
serial*

View File

@ -0,0 +1,62 @@
# Running a Dex gRPC client
Using gRPC, a client application can directly call methods on a server application as if it was a local object. The schema for Dex's gRPC API calls is defined in [`api/api.proto`][api-proto]. [`client.go`][client] is an example client program that makes a bunch of API calls to the dex server. For further details on the Dex API refer [`Documentation/api.md`][api-docs].
## Generating Credentials
Before running the client or the server, TLS credentials have to be setup for secure communication. Run the `cred-gen` script to create TLS credentials for running this example. This script generates a `ca.crt`, `server.crt`, `server.key`, `client.crt`, and `client.key`.
```
# Used to set certificate subject alt names.
export SAN=IP.1:127.0.0.1
# Run the script
./examples/grpc-client/cert-gen
```
To verify that the server and client certificates were signed by the CA, run the following commands:
```
openssl verify -CAfile ca.crt server.crt
openssl verify -CAfile ca.crt client.crt
```
## Running the Dex server
To expose the gRPC service, the gRPC option must be enabled via the dex config file as shown below.
```yaml
# Enables the gRPC API.
grpc:
addr: 127.0.0.1:5557
tlsCert: server.crt
tlsKey: server.key
```
Start an instance of the dex server with an in-memory data store:
```
./bin/dex serve examples/grpc-client/config.yaml
```
## Running the Dex client
Finally run the Dex client providing the CA certificate, client certificate and client key as arguments.
```
./bin/grpc-client -ca-crt=ca.crt -client-crt=client.crt -client-key=client.key
```
Running the gRPC client will cause the following API calls to be made to the server
1. CreatePassword
2. ListPasswords
3. DeletePassword
## Cleaning up
Run the following command to destroy all the credentials files that were created by the `cert-gen` script:
```
./examples/grpc-client/cert-destory
```
[api-proto]: ../../api/api.proto
[client]: client.go
[api-docs]: ../../Documentation/api.md

View File

@ -0,0 +1,4 @@
#!/bin/bash
rm -f ca.key ca.crt server.key server.csr server.crt client.key client.csr client.crt index.* serial*
rm -rf certs crl newcerts

35
examples/grpc-client/cert-gen Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
if [ -z $SAN ]
then echo "Set SAN with a DNS or IP(e.g. export SAN=IP.1:127.0.0.1,IP.2:172.18.0.2)."
exit 1
fi
echo "Creating CA, server cert/key, and client cert/key..."
# Creating basic files/directories
mkdir -p {certs,crl,newcerts}
touch index.txt
echo 1000 > serial
# CA private key (unencrypted)
openssl genrsa -out ca.key 4096
# Certificate Authority (self-signed certificate)
openssl req -config examples/grpc-client/openssl.conf -new -x509 -days 3650 -sha256 -key ca.key -extensions v3_ca -out ca.crt -subj "/CN=fake-ca"
# Server private key (unencrypted)
openssl genrsa -out server.key 2048
# Server certificate signing request (CSR)
openssl req -config examples/grpc-client/openssl.conf -new -sha256 -key server.key -out server.csr -subj "/CN=fake-server"
# Certificate Authority signs CSR to grant a certificate
openssl ca -batch -config examples/grpc-client/openssl.conf -extensions server_cert -days 365 -notext -md sha256 -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
# Client private key (unencrypted)
openssl genrsa -out client.key 2048
# Signed client certificate signing request (CSR)
openssl req -config examples/grpc-client/openssl.conf -new -sha256 -key client.key -out client.csr -subj "/CN=fake-client"
# Certificate Authority signs CSR to grant a certificate
openssl ca -batch -config examples/grpc-client/openssl.conf -extensions usr_cert -days 365 -notext -md sha256 -in client.csr -out client.crt -cert ca.crt -keyfile ca.key
# Remove CSR's
rm *.csr

View File

@ -0,0 +1,106 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"io/ioutil"
"log"
"github.com/coreos/dex/api"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func newDexClient(hostAndPort, caPath, clientCrt, clientKey string) (api.DexClient, error) {
cPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile(caPath)
if err != nil {
return nil, fmt.Errorf("invalid CA crt file: %s", caPath)
}
if cPool.AppendCertsFromPEM(caCert) != true {
return nil, fmt.Errorf("failed to parse CA crt")
}
clientCert, err := tls.LoadX509KeyPair(clientCrt, clientKey)
if err != nil {
return nil, fmt.Errorf("invalid client crt file: %s", caPath)
}
clientTLSConfig := &tls.Config{
RootCAs: cPool,
Certificates: []tls.Certificate{clientCert},
}
creds := credentials.NewTLS(clientTLSConfig)
conn, err := grpc.Dial(hostAndPort, grpc.WithTransportCredentials(creds))
if err != nil {
return nil, fmt.Errorf("dail: %v", err)
}
return api.NewDexClient(conn), nil
}
func main() {
caCrt := flag.String("ca-crt", "", "CA certificate")
clientCrt := flag.String("client-crt", "", "Client certificate")
clientKey := flag.String("client-key", "", "Client key")
flag.Parse()
if *clientCrt == "" || *caCrt == "" || *clientKey == "" {
log.Fatal("Please provide CA & client certificates and client key. Usage: ./client -ca_crt=<path ca.crt> -client_crt=<path client.crt> -client_key=<path client key>")
}
client, err := newDexClient("127.0.0.1:5557", *caCrt, *clientCrt, *clientKey)
if err != nil {
log.Fatalf("failed creating dex client: %v ", err)
}
p := api.Password{
Email: "test@example.com",
// bcrypt hash of the value "test1" with cost 10
Hash: []byte("$2a$10$XVMN/Fid.Ks4CXgzo8fpR.iU1khOMsP5g9xQeXuBm1wXjRX8pjUtO"),
Username: "test",
UserId: "test",
}
createReq := &api.CreatePasswordReq{
Password: &p,
}
// Create password.
if resp, err := client.CreatePassword(context.TODO(), createReq); err != nil || resp.AlreadyExists {
if resp.AlreadyExists {
log.Fatalf("Password %s already exists", createReq.Password.Email)
}
log.Fatalf("failed to create password: %v", err)
} else {
log.Printf("Created password with email %s", createReq.Password.Email)
}
// List all passwords.
resp, err := client.ListPasswords(context.TODO(), &api.ListPasswordReq{})
if err != nil {
log.Fatalf("failed to list password: %v", err)
}
log.Print("Listing Passwords:\n")
for _, pass := range resp.Passwords {
log.Printf("%+v", pass)
}
deleteReq := &api.DeletePasswordReq{
Email: p.Email,
}
// Delete password with email = test@example.com.
if resp, err := client.DeletePassword(context.TODO(), deleteReq); err != nil || resp.NotFound {
if resp.NotFound {
log.Fatalf("Password %s not found", deleteReq.Email)
}
log.Fatalf("failed to delete password: %v", err)
} else {
log.Printf("Deleted password with email %s", deleteReq.Email)
}
}

View File

@ -0,0 +1,24 @@
issuer: http://127.0.0.1:5556/dex
storage:
type: sqlite3
config:
file: examples/dex.db
# Configuration for the HTTP endpoints.
web:
http: 0.0.0.0:5556
grpc:
addr: 127.0.0.1:5557
tlsCert: server.crt
tlsKey: server.key
connectors:
- type: mockCallback
id: mock
name: Example
# Let dex keep a list of passwords which can be used to login to dex.
enablePasswordDB: true

View File

@ -0,0 +1,82 @@
# OpenSSL configuration file.
# Adapted from https://github.com/coreos/matchbox/blob/master/examples/etc/matchbox/openssl.conf
# default environment variable values
SAN =
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = .
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
# certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/intermediate-ca.crl
crl_extensions = crl_ext
default_crl_days = 30
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
[ policy_loose ]
# Allow the CA to sign a range of certificates.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# `man req`
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
default_md = sha256
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
# Certificate extensions (`man x509v3_config`)
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
basicConstraints = CA:FALSE
nsCertType = client
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
[ server_cert ]
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = $ENV::SAN