@@ -51,6 +51,17 @@ type verifierWithConfig struct {
5151 * oidc.Config
5252}
5353
54+ type bearerTokenTransport struct {
55+ Transport http.RoundTripper
56+ Token string
57+ }
58+
59+ func (t * bearerTokenTransport ) RoundTrip (req * http.Request ) (* http.Response , error ) {
60+ req = req .Clone (req .Context ())
61+ req .Header .Set ("Authorization" , "Bearer " + t .Token )
62+ return t .Transport .RoundTrip (req )
63+ }
64+
5465type FulcioConfig struct {
5566 OIDCIssuers map [string ]OIDCIssuer `json:"OIDCIssuers,omitempty" yaml:"oidc-issuers,omitempty"`
5667
@@ -292,55 +303,99 @@ func httpClientForIssuer(iss OIDCIssuer) (*http.Client, error) {
292303}
293304
294305func (fc * FulcioConfig ) prepare () error {
295- if _ , ok := fc .GetIssuer ("https://kubernetes.default.svc" ); ok {
296- // Add the Kubernetes cluster's CA to the system CA pool, and to
297- // the default transport.
306+ fc .verifiers = make (map [string ][]* verifierWithConfig , len (fc .OIDCIssuers ))
307+ for _ , iss := range fc .OIDCIssuers {
308+ if err := fc .insertVerifier (iss ); err != nil {
309+ log .Logger .Errorf ("error creating provider for issuer URL %q: %v" , iss .IssuerURL , err )
310+ continue
311+ }
312+ }
313+
314+ _ , verifierPresent := fc .verifiers [k8sIssuerURL ]
315+ k8sIssuer , issuerConfigured := fc .GetIssuer (k8sIssuerURL )
316+ if issuerConfigured && ! verifierPresent {
317+ // configure static validator for k8s that cover metaIssuers
318+ if err := fc .insertVerifier (k8sIssuer ); err != nil {
319+ log .Logger .Errorf ("error creating provider for issuer URL %q: %v" , k8sIssuer .IssuerURL , err )
320+ }
321+ }
322+
323+ cache , err := lru.New2Q [string , []* verifierWithConfig ](100 /* size */ )
324+ if err != nil {
325+ return fmt .Errorf ("lru: %w" , err )
326+ }
327+ fc .lru = cache
328+ return nil
329+ }
330+
331+ var (
332+ k8sCA = "/var/run/fulcio/ca.crt"
333+ // k8sTokenFile specifies the standard path where Kubernetes automatically
334+ // mounts the projected service account token for a pod.
335+ // This path is publicly known and not a sensitive credential itself,
336+ // hence the Gosec G101 warning is a false positive and is suppressed.
337+ // #nosec G101
338+ k8sTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
339+ k8sIssuerURL = "https://kubernetes.default.svc"
340+ )
341+
342+ func (fc * FulcioConfig ) insertVerifier (iss OIDCIssuer ) error {
343+ var client * http.Client
344+ if iss .IssuerURL == k8sIssuerURL {
345+ var transport http.RoundTripper
346+ // Add the Kubernetes cluster's CA to the client's CA pool
298347 rootCAs , _ := x509 .SystemCertPool ()
299348 if rootCAs == nil {
300349 rootCAs = x509 .NewCertPool ()
301350 }
302- const k8sCA = "/var/run/fulcio/ca.crt"
303351 certs , err := os .ReadFile (k8sCA )
304352 if err != nil {
305- return fmt .Errorf ("read file: %w" , err )
353+ return fmt .Errorf ("unable to read cluster CA file: %w" , err )
306354 }
307355 if ok := rootCAs .AppendCertsFromPEM (certs ); ! ok {
308- return fmt .Errorf ("unable to append certs" )
356+ return fmt .Errorf ("unable to append cluster certs" )
309357 }
310358
311- t := originalTransport .(* http.Transport ).Clone ()
359+ t := http . DefaultTransport .(* http.Transport ).Clone ()
312360 t .TLSClientConfig .RootCAs = rootCAs
313- http .DefaultTransport = t
314- } else {
315- // If we parse a config that doesn't include a cluster issuer
316- // signed with the cluster'sCA, then restore the original transport
317- // (in case we overwrote it)
318- http .DefaultTransport = originalTransport
319- }
361+ transport = t
320362
321- fc .verifiers = make (map [string ][]* verifierWithConfig , len (fc .OIDCIssuers ))
322- for _ , iss := range fc .OIDCIssuers {
323- ctx , cancel := context .WithTimeout (context .Background (), defaultOIDCDiscoveryTimeout )
324- defer cancel ()
325- client , err := httpClientForIssuer (iss )
326- if err != nil {
327- log .Logger .Errorf ("error creating http client for issuer URL %q: %v" , iss .IssuerURL , err )
328- continue
363+ if _ , err := os .Stat (k8sTokenFile ); err != nil {
364+ if errors .Is (err , os .ErrNotExist ) {
365+ log .Logger .Warnf ("Kubernetes token file can't be found on path: %s" , k8sTokenFile )
366+ } else {
367+ return err
368+ }
369+ } else {
370+ // add the authentication header
371+ tokenBytes , err := os .ReadFile (k8sTokenFile )
372+ if err != nil {
373+ return fmt .Errorf ("unable to read cluster token file: %w" , err )
374+ }
375+ transport = & bearerTokenTransport {
376+ Transport : transport ,
377+ Token : string (tokenBytes ),
378+ }
329379 }
330- provider , err := oidc .NewProvider (oidc .ClientContext (ctx , client ), iss .IssuerURL )
380+
381+ client = & http.Client {Transport : transport }
382+
383+ } else {
384+ var err error
385+ client , err = httpClientForIssuer (iss )
331386 if err != nil {
332- log .Logger .Errorf ("error creating provider for issuer URL %q: %v" , iss .IssuerURL , err )
333- } else {
334- cfg := & oidc.Config {ClientID : iss .ClientID }
335- fc .verifiers [iss .IssuerURL ] = []* verifierWithConfig {{provider .Verifier (cfg ), cfg }}
387+ return err
336388 }
337389 }
338390
339- cache , err := lru.New2Q [string , []* verifierWithConfig ](100 /* size */ )
391+ ctx , cancel := context .WithTimeout (context .Background (), defaultOIDCDiscoveryTimeout )
392+ defer cancel ()
393+ provider , err := oidc .NewProvider (oidc .ClientContext (ctx , client ), iss .IssuerURL )
340394 if err != nil {
341- return fmt . Errorf ( "lru: %w" , err )
395+ return err
342396 }
343- fc .lru = cache
397+ cfg := & oidc.Config {ClientID : iss .ClientID }
398+ fc .verifiers [iss .IssuerURL ] = []* verifierWithConfig {{provider .Verifier (cfg ), cfg }}
344399 return nil
345400}
346401
@@ -507,8 +562,6 @@ var DefaultConfig = &FulcioConfig{
507562 },
508563}
509564
510- var originalTransport = http .DefaultTransport
511-
512565type configKey struct {}
513566
514567func With (ctx context.Context , cfg * FulcioConfig ) context.Context {
0 commit comments