@@ -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
@@ -271,6 +282,38 @@ func (fc *FulcioConfig) ToIssuers() []*fulciogrpc.OIDCIssuer {
271282}
272283
273284func httpClientForIssuer (iss OIDCIssuer ) (* http.Client , error ) {
285+ transportProvider := func (transport * http.Transport ) http.RoundTripper {
286+ return transport
287+ }
288+ if iss .Type == IssuerTypeKubernetes {
289+ // Add the Kubernetes cluster's CA to the client's CA pool
290+ certs , err := os .ReadFile (k8sCA )
291+ if err != nil {
292+ return nil , fmt .Errorf ("unable to read cluster CA file: %w" , err )
293+ }
294+ iss .CACert = string (certs )
295+
296+ if _ , err := os .Stat (k8sTokenFile ); err == nil {
297+ // add the authentication header
298+ tokenBytes , err := os .ReadFile (k8sTokenFile )
299+ if err != nil {
300+ return nil , fmt .Errorf ("unable to read cluster token file: %w" , err )
301+ }
302+ transportProvider = func (transport * http.Transport ) http.RoundTripper {
303+ return & bearerTokenTransport {
304+ Transport : transport ,
305+ Token : string (tokenBytes ),
306+ }
307+ }
308+ } else {
309+ if errors .Is (err , os .ErrNotExist ) {
310+ log .Logger .Warnf ("Kubernetes token file can't be found on path: %s" , k8sTokenFile )
311+ } else {
312+ return nil , err
313+ }
314+ }
315+ }
316+
274317 if iss .CACert != "" {
275318 rootCAs , _ := x509 .SystemCertPool ()
276319 if rootCAs == nil {
@@ -286,53 +329,17 @@ func httpClientForIssuer(iss OIDCIssuer) (*http.Client, error) {
286329 MinVersion : tls .VersionTLS12 ,
287330 },
288331 }
289- return & http.Client {Transport : transport }, nil
332+ return & http.Client {Transport : transportProvider ( transport ) }, nil
290333 }
291334 return http .DefaultClient , nil
292335}
293336
294337func (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.
298- rootCAs , _ := x509 .SystemCertPool ()
299- if rootCAs == nil {
300- rootCAs = x509 .NewCertPool ()
301- }
302- const k8sCA = "/var/run/fulcio/ca.crt"
303- certs , err := os .ReadFile (k8sCA )
304- if err != nil {
305- return fmt .Errorf ("read file: %w" , err )
306- }
307- if ok := rootCAs .AppendCertsFromPEM (certs ); ! ok {
308- return fmt .Errorf ("unable to append certs" )
309- }
310-
311- t := originalTransport .(* http.Transport ).Clone ()
312- 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- }
320-
321338 fc .verifiers = make (map [string ][]* verifierWithConfig , len (fc .OIDCIssuers ))
322339 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
329- }
330- provider , err := oidc .NewProvider (oidc .ClientContext (ctx , client ), iss .IssuerURL )
331- if err != nil {
340+ if err := fc .insertVerifier (iss ); err != nil {
332341 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 }}
342+ continue
336343 }
337344 }
338345
@@ -344,6 +351,34 @@ func (fc *FulcioConfig) prepare() error {
344351 return nil
345352}
346353
354+ var (
355+ k8sCA = "/var/run/fulcio/ca.crt"
356+ // k8sTokenFile specifies the standard path where Kubernetes automatically
357+ // mounts the projected service account token for a pod.
358+ // This path is publicly known and not a sensitive credential itself,
359+ // hence the Gosec G101 warning is a false positive and is suppressed.
360+ // #nosec G101
361+ k8sTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
362+ k8sIssuerURL = "https://kubernetes.default.svc"
363+ )
364+
365+ func (fc * FulcioConfig ) insertVerifier (iss OIDCIssuer ) error {
366+ client , err := httpClientForIssuer (iss )
367+ if err != nil {
368+ return err
369+ }
370+
371+ ctx , cancel := context .WithTimeout (context .Background (), defaultOIDCDiscoveryTimeout )
372+ defer cancel ()
373+ provider , err := oidc .NewProvider (oidc .ClientContext (ctx , client ), iss .IssuerURL )
374+ if err != nil {
375+ return err
376+ }
377+ cfg := & oidc.Config {ClientID : iss .ClientID }
378+ fc .verifiers [iss .IssuerURL ] = []* verifierWithConfig {{provider .Verifier (cfg ), cfg }}
379+ return nil
380+ }
381+
347382type IssuerType string
348383
349384func (it IssuerType ) String () string {
@@ -507,8 +542,6 @@ var DefaultConfig = &FulcioConfig{
507542 },
508543}
509544
510- var originalTransport = http .DefaultTransport
511-
512545type configKey struct {}
513546
514547func With (ctx context.Context , cfg * FulcioConfig ) context.Context {
0 commit comments