@@ -43,6 +43,7 @@ const (
4343 defaultForwardAccessToken = false
4444 defaultRefreshToken = true
4545 defaultPassThroughAuthHeader = false
46+ defaultOIDCHTTPTimeout = 5 * time .Second
4647
4748 // nolint: gosec
4849 oidcHMACSecretName = "envoy-oidc-hmac"
@@ -55,6 +56,10 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security
5556 resources * resource.Resources ,
5657 xdsIR resource.XdsIRMap ,
5758) []* egv1a1.SecurityPolicy {
59+ // Cache is only reused during one translation across multiple routes and gateways.
60+ // The failed fetches will be retried in the next translation when the provider resources are reconciled again.
61+ t .oidcDiscoveryCache = newOIDCDiscoveryCache ()
62+
5863 // SecurityPolicies are already sorted by the provider layer
5964
6065 // First build a map out of the routes and gateways for faster lookup since users might have thousands of routes or more.
@@ -1419,7 +1424,7 @@ func (t *Translator) buildOIDCProvider(policy *egv1a1.SecurityPolicy, resources
14191424 // EG assumes that the issuer url uses the same protocol and CA as the token endpoint.
14201425 // If we need to support different protocols or CAs, we need to add more fields to the OIDCProvider CRD.
14211426 if provider .TokenEndpoint == nil || provider .AuthorizationEndpoint == nil {
1422- discoveredConfig , err := fetchEndpointsFromIssuer (provider .Issuer , providerTLS )
1427+ discoveredConfig , err := t . fetchEndpointsFromIssuer (provider .Issuer , providerTLS )
14231428 if err != nil {
14241429 return nil , err
14251430 }
@@ -1507,7 +1512,25 @@ func (o *OpenIDConfig) validate() error {
15071512 return nil
15081513}
15091514
1510- func fetchEndpointsFromIssuer (issuerURL string , providerTLS * ir.TLSUpstreamConfig ) (* OpenIDConfig , error ) {
1515+ func (t * Translator ) fetchEndpointsFromIssuer (issuerURL string , providerTLS * ir.TLSUpstreamConfig ) (* OpenIDConfig , error ) {
1516+ if config , cachedErr , ok := t .oidcDiscoveryCache .Get (issuerURL ); ok {
1517+ if cachedErr != nil {
1518+ return nil , cachedErr
1519+ }
1520+ return config , nil
1521+ }
1522+
1523+ config , err := discoverEndpointsFromIssuer (issuerURL , providerTLS )
1524+ if err != nil {
1525+ t .oidcDiscoveryCache .Set (issuerURL , nil , err )
1526+ return nil , err
1527+ }
1528+
1529+ t .oidcDiscoveryCache .Set (issuerURL , config , nil )
1530+ return config , nil
1531+ }
1532+
1533+ func discoverEndpointsFromIssuer (issuerURL string , providerTLS * ir.TLSUpstreamConfig ) (* OpenIDConfig , error ) {
15111534 var (
15121535 tlsConfig * tls.Config
15131536 err error
@@ -1519,7 +1542,7 @@ func fetchEndpointsFromIssuer(issuerURL string, providerTLS *ir.TLSUpstreamConfi
15191542 }
15201543 }
15211544
1522- client := & http.Client {}
1545+ client := & http.Client {Timeout : defaultOIDCHTTPTimeout }
15231546 if tlsConfig != nil {
15241547 client .Transport = & http.Transport {
15251548 TLSClientConfig : tlsConfig ,
@@ -1564,6 +1587,47 @@ func fetchEndpointsFromIssuer(issuerURL string, providerTLS *ir.TLSUpstreamConfi
15641587 return & config , nil
15651588}
15661589
1590+ // oidcDiscoveryCache is a cache for auto-discovered OIDC configurations from the issuer's well-known URL.
1591+ // The cache is only used within the current translation, so no need to lock it or expire entries.
1592+ type oidcDiscoveryCache struct {
1593+ entries map [string ]cachedOIDCEntry
1594+ }
1595+
1596+ type cachedOIDCEntry struct {
1597+ config * OpenIDConfig
1598+ err error
1599+ }
1600+
1601+ func newOIDCDiscoveryCache () * oidcDiscoveryCache {
1602+ return & oidcDiscoveryCache {
1603+ entries : make (map [string ]cachedOIDCEntry ),
1604+ }
1605+ }
1606+
1607+ func (c * oidcDiscoveryCache ) Get (issuer string ) (* OpenIDConfig , error , bool ) {
1608+ if c == nil {
1609+ return nil , nil , false
1610+ }
1611+
1612+ entry , ok := c .entries [issuer ]
1613+ if ! ok {
1614+ return nil , nil , false
1615+ }
1616+
1617+ return entry .config , entry .err , true
1618+ }
1619+
1620+ func (c * oidcDiscoveryCache ) Set (issuer string , cfg * OpenIDConfig , err error ) {
1621+ if c == nil {
1622+ return
1623+ }
1624+
1625+ c .entries [issuer ] = cachedOIDCEntry {
1626+ config : cfg ,
1627+ err : err ,
1628+ }
1629+ }
1630+
15671631func retryable (code int ) bool {
15681632 return code >= 500 &&
15691633 (code != http .StatusNotImplemented &&
0 commit comments