@@ -38,6 +38,7 @@ import (
38
38
39
39
"google.golang.org/grpc/credentials/tls/certprovider"
40
40
"google.golang.org/grpc/grpclog"
41
+ "google.golang.org/grpc/internal/credentials/spiffe"
41
42
)
42
43
43
44
const defaultCertRefreshDuration = 1 * time .Hour
@@ -61,18 +62,23 @@ type Options struct {
61
62
// RootFile is the file that holds trusted root certificate(s).
62
63
// Optional.
63
64
RootFile string
65
+ // SPIFFEBundleMapFile is the file that holds the spiffe bundle map.
66
+ // If a given provider configures both the RootFile and the
67
+ // SPIFFEBundleMapFile, the SPIFFEBundleMapFile will be preferred.
68
+ // Optional.
69
+ SPIFFEBundleMapFile string
64
70
// RefreshDuration is the amount of time the plugin waits before checking
65
71
// for updates in the specified files.
66
72
// Optional. If not set, a default value (1 hour) will be used.
67
73
RefreshDuration time.Duration
68
74
}
69
75
70
76
func (o Options ) canonical () []byte {
71
- return []byte (fmt .Sprintf ("%s:%s:%s:%s" , o .CertFile , o .KeyFile , o .RootFile , o .RefreshDuration ))
77
+ return []byte (fmt .Sprintf ("%s:%s:%s:%s:%s " , o .CertFile , o .KeyFile , o .RootFile , o . SPIFFEBundleMapFile , o .RefreshDuration ))
72
78
}
73
79
74
80
func (o Options ) validate () error {
75
- if o .CertFile == "" && o .KeyFile == "" && o .RootFile == "" {
81
+ if o .CertFile == "" && o .KeyFile == "" && o .RootFile == "" && o . SPIFFEBundleMapFile == "" {
76
82
return fmt .Errorf ("pemfile: at least one credential file needs to be specified" )
77
83
}
78
84
if keySpecified , certSpecified := o .KeyFile != "" , o .CertFile != "" ; keySpecified != certSpecified {
@@ -124,13 +130,14 @@ func newProvider(o Options) certprovider.Provider {
124
130
// files and provides the most up-to-date key material for consumption by
125
131
// credentials implementation.
126
132
type watcher struct {
127
- identityDistributor distributor
128
- rootDistributor distributor
129
- opts Options
130
- certFileContents []byte
131
- keyFileContents []byte
132
- rootFileContents []byte
133
- cancel context.CancelFunc
133
+ identityDistributor distributor
134
+ rootDistributor distributor
135
+ opts Options
136
+ certFileContents []byte
137
+ keyFileContents []byte
138
+ rootFileContents []byte
139
+ spiffeBundleMapFileContents []byte
140
+ cancel context.CancelFunc
134
141
}
135
142
136
143
// distributor wraps the methods on certprovider.Distributor which are used by
@@ -191,14 +198,43 @@ func (w *watcher) updateRootDistributor() {
191
198
return
192
199
}
193
200
201
+ // If SPIFFEBundleMap is set, use it and DON'T use the RootFile, even if it
202
+ // fails
203
+ if w .opts .SPIFFEBundleMapFile != "" {
204
+ w .maybeUpdateSPIFFEBundleMap ()
205
+ } else {
206
+ w .maybeUpdateRootFile ()
207
+ }
208
+ }
209
+
210
+ func (w * watcher ) maybeUpdateSPIFFEBundleMap () {
211
+ spiffeBundleMapContents , err := os .ReadFile (w .opts .SPIFFEBundleMapFile )
212
+ if err != nil {
213
+ logger .Warningf ("spiffeBundleMapFile (%s) read failed: %v" , w .opts .SPIFFEBundleMapFile , err )
214
+ return
215
+ }
216
+ // If the file contents have not changed, skip updating the distributor.
217
+ if bytes .Equal (w .spiffeBundleMapFileContents , spiffeBundleMapContents ) {
218
+ return
219
+ }
220
+ bundleMap , err := spiffe .BundleMapFromBytes (spiffeBundleMapContents )
221
+ if err != nil {
222
+ logger .Warning ("Failed to parse spiffe bundle map" )
223
+ return
224
+ }
225
+ w .spiffeBundleMapFileContents = spiffeBundleMapContents
226
+ w .rootDistributor .Set (& certprovider.KeyMaterial {SPIFFEBundleMap : bundleMap }, nil )
227
+ }
228
+
229
+ func (w * watcher ) maybeUpdateRootFile () {
194
230
rootFileContents , err := os .ReadFile (w .opts .RootFile )
195
231
if err != nil {
196
232
logger .Warningf ("rootFile (%s) read failed: %v" , w .opts .RootFile , err )
197
233
return
198
234
}
199
235
trustPool := x509 .NewCertPool ()
200
236
if ! trustPool .AppendCertsFromPEM (rootFileContents ) {
201
- logger .Warning ("failed to parse root certificate" )
237
+ logger .Warning ("Failed to parse root certificate" )
202
238
return
203
239
}
204
240
// If the file contents have not changed, skip updating the distributor.
@@ -249,6 +285,7 @@ func (w *watcher) KeyMaterial(ctx context.Context) (*certprovider.KeyMaterial, e
249
285
if err != nil {
250
286
return nil , err
251
287
}
288
+ km .SPIFFEBundleMap = rootKM .SPIFFEBundleMap
252
289
km .Roots = rootKM .Roots
253
290
}
254
291
return km , nil
0 commit comments