Skip to content

Commit b6eb32f

Browse files
committed
fix: K8s API does not accept unauthorized requests
Signed-off-by: Jan Bouska <[email protected]>
1 parent 07b0302 commit b6eb32f

File tree

2 files changed

+300
-110
lines changed

2 files changed

+300
-110
lines changed

pkg/config/config.go

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
5465
type 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

273284
func 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

294337
func (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+
347382
type IssuerType string
348383

349384
func (it IssuerType) String() string {
@@ -507,8 +542,6 @@ var DefaultConfig = &FulcioConfig{
507542
},
508543
}
509544

510-
var originalTransport = http.DefaultTransport
511-
512545
type configKey struct{}
513546

514547
func With(ctx context.Context, cfg *FulcioConfig) context.Context {

0 commit comments

Comments
 (0)