Add new example and docs on the client SDK.
This commit is contained in:
parent
7eb8aeb1f1
commit
6617c93732
2 changed files with 287 additions and 4 deletions
152
examples/basic-client/client.go
Normal file
152
examples/basic-client/client.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/smallstep/certificates/ca"
|
||||
)
|
||||
|
||||
func printResponse(name string, v interface{}) {
|
||||
b, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("%s response:\n%s\n\n", name, b)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s <token>\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
token := os.Args[1]
|
||||
|
||||
// To create the client using ca.NewClient we need:
|
||||
// * The CA address "https://localhost:9000"
|
||||
// * The root certificate fingerprint
|
||||
// 84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d to get
|
||||
// the root fingerprint we can use `step certificate fingerprint root_ca.crt`
|
||||
client, err := ca.NewClient("https://localhost:9000", ca.WithRootSHA256("84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Other ways to initialize the client would be:
|
||||
// * With the Bootstrap functionality (recommended):
|
||||
// client, err := ca.Bootstrap(token)
|
||||
// * Using the root certificate instead of the fingerprint:
|
||||
// client, err := ca.NewClient("https://localhost:9000", ca.WithRootFile("../pki/secrets/root_ca.crt"))
|
||||
|
||||
// Get the health of the CA
|
||||
health, err := client.Health()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
printResponse("Health", health)
|
||||
|
||||
// Get and verify a root CA
|
||||
root, err := client.Root("84a033e84196f73bd593fad7a63e509e57fd982f02084359c4e8c5c864efc27d")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
printResponse("Root", root)
|
||||
|
||||
// We can use ca.CreateSignRequest to generate a new sign request with a
|
||||
// randomly generated key.
|
||||
req, pk, err := ca.CreateSignRequest(token)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sign, err := client.Sign(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
printResponse("Sign", sign)
|
||||
|
||||
// Renew a certificate with a transport that contains the previous
|
||||
// certificate. We should created a context that allows us to finish the
|
||||
// renewal goroutine.∑
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel() // Finish the renewal goroutine
|
||||
tr, err := client.Transport(ctx, sign, pk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
renew, err := client.Renew(tr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
printResponse("Renew", renew)
|
||||
|
||||
// Get tls.Config for a server
|
||||
ctxServer, cancelServer := context.WithCancel(context.Background())
|
||||
defer cancelServer()
|
||||
tlsConfig, err := client.GetServerTLSConfig(ctxServer, sign, pk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// An http server will use the tls.Config like:
|
||||
_ = &http.Server{
|
||||
Addr: ":443",
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Hello world"))
|
||||
}),
|
||||
TLSConfig: tlsConfig,
|
||||
}
|
||||
|
||||
// Get tls.Config for a client
|
||||
ctxClient, cancelClient := context.WithCancel(context.Background())
|
||||
defer cancelClient()
|
||||
tlsConfig, err = client.GetClientTLSConfig(ctxClient, sign, pk)
|
||||
// An http.Client will need to create a transport first
|
||||
_ = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
// Options set in http.DefaultTransport
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
// But we can just use client.Transport to get the default configuration
|
||||
ctxTransport, cancelTransport := context.WithCancel(context.Background())
|
||||
defer cancelTransport()
|
||||
tr, err = client.Transport(ctxTransport, sign, pk)
|
||||
// And http.Client will use the transport like
|
||||
_ = &http.Client{
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
// Get provisioners and provisioner keys. In this example we add two
|
||||
// optional arguments with the initial cursor and a limit.
|
||||
//
|
||||
// A server or a client should not need this functionality, they are used to
|
||||
// sign (private key) and verify (public key) tokens. The step cli can be
|
||||
// used for this purpose.
|
||||
provisioners, err := client.Provisioners(ca.WithProvisionerCursor(""), ca.WithProvisionerLimit(100))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
printResponse("Provisioners", provisioners)
|
||||
// Get encrypted key
|
||||
key, err := client.ProvisionerKey("DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
printResponse("Provisioner Key", key)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue