in pilot/pkg/security/authn/v1beta1/policy_applier.go [208:363]
func convertToEnvoyJwtConfig(jwtRules []*v1beta1.JWTRule, push *model.PushContext) *envoy_jwt.JwtAuthentication {
if len(jwtRules) == 0 {
return nil
}
providers := map[string]*envoy_jwt.JwtProvider{}
// Each element of innerAndList is the requirement for each provider, in the form of
// {provider OR `allow_missing`}
// This list will be ANDed (if have more than one provider) for the final requirement.
innerAndList := []*envoy_jwt.JwtRequirement{}
// This is an (or) list for all providers. This will be OR with the innerAndList above so
// it can pass the requirement in the case that providers share the same location.
outterOrList := []*envoy_jwt.JwtRequirement{}
for i, jwtRule := range jwtRules {
provider := &envoy_jwt.JwtProvider{
Issuer: jwtRule.Issuer,
Audiences: jwtRule.Audiences,
Forward: jwtRule.ForwardOriginalToken,
ForwardPayloadHeader: jwtRule.OutputPayloadToHeader,
PayloadInMetadata: jwtRule.Issuer,
}
for _, location := range jwtRule.FromHeaders {
provider.FromHeaders = append(provider.FromHeaders, &envoy_jwt.JwtHeader{
Name: location.Name,
ValuePrefix: location.Prefix,
})
}
provider.FromParams = jwtRule.FromParams
if features.EnableRemoteJwks && jwtRule.JwksUri != "" {
// Use remote jwks if jwksUri is non empty. Parse the jwksUri to get the cluster name,
// generate the jwt filter config using remoteJwks.
// If failed to parse the cluster name, fallback to let istiod to fetch the jwksUri.
// TODO: Implement the logic to auto-generate the cluster so that when the flag is enabled,
// it will always let envoy to fetch the jwks for consistent behavior.
u, _ := url.Parse(jwtRule.JwksUri)
hostAndPort := strings.Split(u.Host, ":")
host := hostAndPort[0]
// TODO: Default port based on scheme ?
port := 80
if len(hostAndPort) == 2 {
var err error
if port, err = strconv.Atoi(hostAndPort[1]); err != nil {
port = 80 // If port is not specified or there is an error in parsing default to 80.
}
}
_, cluster, err := extensionproviders.LookupCluster(push, host, port)
if err == nil && len(cluster) > 0 {
// This is a case of URI pointing to mesh cluster. Setup Remote Jwks and let Envoy fetch the key.
provider.JwksSourceSpecifier = &envoy_jwt.JwtProvider_RemoteJwks{
RemoteJwks: &envoy_jwt.RemoteJwks{
HttpUri: &core.HttpUri{
Uri: jwtRule.JwksUri,
HttpUpstreamType: &core.HttpUri_Cluster{
Cluster: cluster,
},
Timeout: &durationpb.Duration{Seconds: 5},
},
CacheDuration: &durationpb.Duration{Seconds: 5 * 60},
},
}
} else {
provider.JwksSourceSpecifier = push.JwtKeyResolver.BuildLocalJwks(jwtRule.JwksUri, jwtRule.Issuer, "")
}
} else {
// Use inline jwks as existing flow, either jwtRule.jwks is non empty or let istiod to fetch the jwtRule.jwksUri
provider.JwksSourceSpecifier = push.JwtKeyResolver.BuildLocalJwks(jwtRule.JwksUri, jwtRule.Issuer, jwtRule.Jwks)
}
name := fmt.Sprintf("origins-%d", i)
providers[name] = provider
innerAndList = append(innerAndList, &envoy_jwt.JwtRequirement{
RequiresType: &envoy_jwt.JwtRequirement_RequiresAny{
RequiresAny: &envoy_jwt.JwtRequirementOrList{
Requirements: []*envoy_jwt.JwtRequirement{
{
RequiresType: &envoy_jwt.JwtRequirement_ProviderName{
ProviderName: name,
},
},
{
RequiresType: &envoy_jwt.JwtRequirement_AllowMissing{
AllowMissing: &emptypb.Empty{},
},
},
},
},
},
})
outterOrList = append(outterOrList, &envoy_jwt.JwtRequirement{
RequiresType: &envoy_jwt.JwtRequirement_ProviderName{
ProviderName: name,
},
})
}
// If there is only one provider, simply use an OR of {provider, `allow_missing`}.
if len(innerAndList) == 1 {
return &envoy_jwt.JwtAuthentication{
Rules: []*envoy_jwt.RequirementRule{
{
Match: &route.RouteMatch{
PathSpecifier: &route.RouteMatch_Prefix{
Prefix: "/",
},
},
RequirementType: &envoy_jwt.RequirementRule_Requires{
Requires: innerAndList[0],
},
},
},
Providers: providers,
BypassCorsPreflight: true,
}
}
// If there are more than one provider, filter should OR of
// {P1, P2 .., AND of {OR{P1, allow_missing}, OR{P2, allow_missing} ...}}
// where the innerAnd enforce a token, if provided, must be valid, and the
// outer OR aids the case where providers share the same location (as
// it will always fail with the innerAND).
outterOrList = append(outterOrList, &envoy_jwt.JwtRequirement{
RequiresType: &envoy_jwt.JwtRequirement_RequiresAll{
RequiresAll: &envoy_jwt.JwtRequirementAndList{
Requirements: innerAndList,
},
},
})
return &envoy_jwt.JwtAuthentication{
Rules: []*envoy_jwt.RequirementRule{
{
Match: &route.RouteMatch{
PathSpecifier: &route.RouteMatch_Prefix{
Prefix: "/",
},
},
RequirementType: &envoy_jwt.RequirementRule_Requires{
Requires: &envoy_jwt.JwtRequirement{
RequiresType: &envoy_jwt.JwtRequirement_RequiresAny{
RequiresAny: &envoy_jwt.JwtRequirementOrList{
Requirements: outterOrList,
},
},
},
},
},
},
Providers: providers,
BypassCorsPreflight: true,
}
}