Skip to content

Commit 091506a

Browse files
committed
Add bootstrap helpers that uses just a token.
1 parent 50598e3 commit 091506a

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

ca/bootstrap.go

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package ca
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"strings"
7+
8+
"github.com/pkg/errors"
9+
"github.com/smallstep/cli/jose"
10+
"gopkg.in/square/go-jose.v2/jwt"
11+
)
12+
13+
type tokenClaims struct {
14+
SHA string `json:"sha"`
15+
jose.Claims
16+
}
17+
18+
// Bootstrap is a helper function that initializes a client with the
19+
// configuration in the bootstrap token.
20+
func Bootstrap(token string) (*Client, error) {
21+
tok, err := jwt.ParseSigned(token)
22+
if err != nil {
23+
return nil, errors.Wrap(err, "error parsing token")
24+
}
25+
var claims tokenClaims
26+
if err := tok.UnsafeClaimsWithoutVerification(&claims); err != nil {
27+
return nil, errors.Wrap(err, "error parsing ott")
28+
}
29+
30+
// Validate bootstrap token
31+
switch {
32+
case len(claims.SHA) == 0:
33+
return nil, errors.New("invalid bootstrap token: sha claim is not present")
34+
case !strings.HasPrefix(strings.ToLower(claims.Audience[0]), "http"):
35+
return nil, errors.New("invalid bootstrap token: aud claim is not a url")
36+
}
37+
38+
return NewClient(claims.Audience[0], WithRootSHA256(claims.SHA))
39+
}
40+
41+
// BootstrapServer is a helper function that returns an http.Server configured
42+
// with the given address and handler, and prepared to use TLS connections. The
43+
// certificate will automatically rotate if necessary.
44+
//
45+
// Usage:
46+
// srv, err := ca.BootstrapServer(":443", token, handler)
47+
// if err != nil {
48+
// return err
49+
// }
50+
// srv.ListenAndServeTLS("", "")
51+
func BootstrapServer(addr, token string, handler http.Handler) (*http.Server, error) {
52+
client, err := Bootstrap(token)
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
req, pk, err := CreateSignRequest(token)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
sign, err := client.Sign(req)
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
tlsConfig, err := client.GetServerTLSConfig(context.Background(), sign, pk)
68+
if err != nil {
69+
return nil, err
70+
}
71+
72+
return &http.Server{
73+
Addr: addr,
74+
Handler: handler,
75+
TLSConfig: tlsConfig,
76+
}, nil
77+
}
78+
79+
// BootstrapClient is a helper function that using the given bootstrap token
80+
// return an http.Client configured with a Transport prepared to do TLS
81+
// connections using the client certificate returned by the certificate
82+
// authority. The certificate will automatically rotate if necessary.
83+
//
84+
// Usage:
85+
// client, err := ca.BootstrapClient(token)
86+
// if err != nil {
87+
// return err
88+
// }
89+
// resp, err := client.Get("https://internal.smallstep.com")
90+
func BootstrapClient(token string) (*http.Client, error) {
91+
client, err := Bootstrap(token)
92+
if err != nil {
93+
return nil, err
94+
}
95+
96+
req, pk, err := CreateSignRequest(token)
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
sign, err := client.Sign(req)
102+
if err != nil {
103+
return nil, err
104+
}
105+
106+
transport, err := client.Transport(context.Background(), sign, pk)
107+
if err != nil {
108+
return nil, err
109+
}
110+
111+
return &http.Client{
112+
Transport: transport,
113+
}, nil
114+
}

0 commit comments

Comments
 (0)