File: README.md

package info (click to toggle)
golang-github-spiffe-go-spiffe 2.5.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,116 kB
  • sloc: makefile: 157
file content (146 lines) | stat: -rw-r--r-- 4,960 bytes parent folder | download | duplicates (2)
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
136
137
138
139
140
141
142
143
144
145
146
# HTTP over TLS with JWT

This example shows how two services using HTTP can communicate using TLS with the server presenting an X509 SVID and expecting a client to authenticate with a JWT-SVID. The SVIDs are retrieved, and authentication is accomplished, via the SPIFFE Workload API.

The **HTTP server** creates a [workloadapi.X509Source](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2/workloadapi?tab=doc#X509Source).

```go
source, err := workloadapi.NewX509Source(ctx, clientOptions)
```

The socket path is provided as a client option. If the socket path is not provided, the value from the `SPIFFE_ENDPOINT_SOCKET` environment variable is used.

```go
source, err := workloadapi.NewX509Source(ctx)
```

The **HTTP server** then uses [workloadapi.X509Source](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2/workloadapi?tab=doc#X509Source) to create a `tls.Config` for TLS that will present the server X509-SVID.

The `tls.Config` is used when creating the HTTP server.

```go
tlsConfig := tlsconfig.TLSServerConfig(source)

server := &http.Server{
    Addr:      ":8443",
    TLSConfig: tlsConfig,
}
```

The server creates a JWTSource to obtain up-to-date JWT bundles from the Workload API.

```go
jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions)
```

A middleware is added to authenticate client JWT-SVIDs provided in the `Authorization` header.
This middleware validates the token using the [jwtsvid.ParseAndValidate](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2/svid/jwtsvid?tab=doc#ParseAndValidate) using bundles obtained from the JWTSource.

```go
svid, err := jwtsvid.ParseAndValidate(token, a.jwtSource, a.audiences)
```

As an alternative to verifying the JWT-SVIDs directly, the Workload API can also be used:

```go
client, err := workloadapi.New(ctx)
if err != nil {
	log.Fatalf("Unable to connect to Workload API: %v", err)
}
svid, err := client.ValidateJWTSVID(ctx, token, audiences[0])
```

On the other side, the **HTTP client** uses the [workloadapi.X509Source](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2/workloadapi?tab=doc#X509Source) to create a `tls.Config` for TLS that authenticates the server certificate and verifies that it has the SPIFFE ID `spiffe://examples.org/server`. 

```go
serverID := spiffeid.RequireFromString("spiffe://example.org/server")
tlsConfig := tlsconfig.TLSClientConfig(source, tlsconfig.AuthorizeID(serverID))

client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: tlsConfig,
    },
}
```

The client fetches a JWT-SVID from the Workload API (via the JWTSource) and adds it as a bearer token in the `Authorization` header.

```go
svid, err := jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{
	Audience: audience,
})
if err != nil {
    log.Fatalf("Unable to fetch SVID: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", svid.Marshal()))
```

That is it! The go-spiffe library fetches and automatically renews the X.509 SVID for the server and validates the client JWT SVIDs using the Workload API.

As soon as the TLS connection is established, the client sends an HTTP request to the server and gets a response.

## Building
Build the client workload:
```bash
cd examples/spiffe-jwt/client
go build
```

Build the server workload:
```bash
cd examples/spiffe-jwt/server
go build
```

## Running
This example assumes the following preconditions:
- There is a SPIRE Server and Agent up and running.
- There is a Unix workload attestor configured.
- The trust domain is `example.org`
- The agent SPIFFE ID is `spiffe://example.org/host`.
- There is a `server-workload` and `client-workload` user in the system.

### 1. Create the registration entries
Create the registration entries for the client and server workloads:

Server:
```bash
./spire-server entry create -spiffeID spiffe://example.org/server \
                            -parentID spiffe://example.org/host \
                            -selector unix:user:server-workload
```

Client: 
```bash
./spire-server entry create -spiffeID spiffe://example.org/client \
                            -parentID spiffe://example.org/host \
                            -selector unix:user:client-workload
```

### 2. Start the server
Start the server with the `server-workload` user:
```bash
sudo -u server-workload ./server
```

### 3. Run the client
Run the client with the `client-workload` user:
```bash
sudo -u client-workload ./client
```

The server should display a log `Request received` and client `Success!!!`

To demonstrate a failure, an alternate audience value can be used. The server is expecting its own SPIFFE ID as the audience value and will reject the token if it doesn't match.

```
sudo -u client-workload ./client spiffe://example.org/some-other-server

Unauthorized
```

When the token is rejected, the server log shows:

```
Invalid token: jwtsvid: expected audience in ["spiffe://example.org/server"] (audience=["spiffe://example.org/some-other-server"])
```