-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
135 lines (112 loc) · 3.32 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"context"
"encoding/json"
"io"
"log"
"net/http"
"github.com/avast/retry-go"
"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/jwt"
"github.com/spiffe/go-spiffe/v2/svid/jwtsvid"
"github.com/spiffe/go-spiffe/v2/workloadapi"
)
const (
audience = "oidc-discovery"
)
func main() {
ctx := context.Background()
// Get a client for the workload api
workloadApiClient, err := workloadapi.New(ctx)
if err != nil {
log.Fatalf("Failed to create workload api client: %v", err)
}
// Get a jwt svid, setting the desired audience
// Retry to allow the spiffe controller manager to see the pod, and register the workload
var svid *jwtsvid.SVID
err = retry.Do(
func() error {
svid, err = workloadApiClient.FetchJWTSVID(ctx, jwtsvid.Params{Audience: audience})
if err != nil {
return err
}
return nil
},
retry.Attempts(25),
retry.Context(ctx),
)
if err != nil {
_ = workloadApiClient.Close()
log.Fatalf("Failed to retrieve a jwt svid: %v", err)
}
// Close the workload api client
_ = workloadApiClient.Close()
// Convert the jwt svid into a string and print
svidStr := svid.Marshal()
printSvidString(svidStr)
// Parse the string into a jwt.JSONWebToken
parsedToken, err := jwt.ParseSigned(svidStr)
if err != nil {
log.Fatal(err)
}
// Get the headers and claims from the parsed token and print
headers := parsedToken.Headers[0]
claims := &jwt.Claims{}
parsedToken.UnsafeClaimsWithoutVerification(claims)
printParsedToken(headers, claims)
// Get the oidc discovery document
resp, err := http.Get("http://spire-spiffe-oidc-discovery-provider.spire/.well-known/openid-configuration")
if err != nil {
log.Fatal(err)
}
bytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Printf("OIDC Discovery Document from http://spire-spiffe-oidc-discovery-provider.spire/.well-known/openid-configuration: \n%s\n\n", string(bytes))
// And we're only interested in the jwks uri
var discoveryDocument DiscoveryDocument
err = json.Unmarshal(bytes, &discoveryDocument)
if err != nil {
log.Fatal(err)
}
// Get the jwks
resp, err = http.Get(discoveryDocument.JWKSUri)
if err != nil {
log.Fatal(err)
}
bytes, err = io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Printf("JSON Web Key Set: %s\n\n", string(bytes))
// Unmarshall the response into a jose.JSONWebKeySet
var keySet jose.JSONWebKeySet
err = json.Unmarshal(bytes, &keySet)
if err != nil {
log.Fatal(err)
}
// Parse the SVID string into a jose.JSONWebSignature
jws, err := jose.ParseSigned(svidStr)
if err != nil {
log.Fatal(err)
}
// Get the key that signed the svid
key := keySet.Key(parsedToken.Headers[0].KeyID)[0]
// Verify the signature on the jwt svid
verified, err := jws.Verify(key)
if err != nil {
log.Fatal(err)
}
// Print the verified claims
log.Printf("Verified claims:\n%s\n\n", string(verified))
}
type DiscoveryDocument struct {
JWKSUri string `json:"jwks_uri"`
}
func printParsedToken(headers jose.Header, claims *jwt.Claims) {
log.Printf("Parsed Token\nHeaders: \nalg: %s\nkid: %s\nClaims: \niss: %s\nsub: %s\naud: %s\niat: %s\nexp: %s\n\n", headers.Algorithm, headers.KeyID, claims.Issuer, claims.Subject, claims.Audience, claims.IssuedAt.Time(), claims.Expiry.Time())
}
func printSvidString(svidStr string) {
log.Printf("JWT SVID\n%s\n\n", svidStr)
}