Files
higress/pkg/ingress/kube/gateway/istio/references_collection.go
2025-11-26 10:15:00 +08:00

166 lines
4.9 KiB
Go

// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package istio
import (
"fmt"
"k8s.io/apimachinery/pkg/types"
gateway "sigs.k8s.io/gateway-api/apis/v1beta1"
creds "istio.io/istio/pilot/pkg/model/credentials"
"istio.io/istio/pkg/config"
"istio.io/istio/pkg/config/schema/collections"
"istio.io/istio/pkg/config/schema/gvk"
"istio.io/istio/pkg/kube/krt"
)
// Reference stores a reference to a namespaced GVK, as used by ReferenceGrant
type Reference struct {
Kind config.GroupVersionKind
Namespace gateway.Namespace
}
func (refs Reference) String() string {
return refs.Kind.String() + "/" + string(refs.Namespace)
}
type ReferencePair struct {
To, From Reference
}
func (r ReferencePair) String() string {
return fmt.Sprintf("%s->%s", r.From, r.To)
}
type ReferenceGrants struct {
collection krt.Collection[ReferenceGrant]
index krt.Index[ReferencePair, ReferenceGrant]
}
func ReferenceGrantsCollection(referenceGrants krt.Collection[*gateway.ReferenceGrant], opts krt.OptionsBuilder) krt.Collection[ReferenceGrant] {
return krt.NewManyCollection(referenceGrants, func(ctx krt.HandlerContext, obj *gateway.ReferenceGrant) []ReferenceGrant {
rp := obj.Spec
results := make([]ReferenceGrant, 0, len(rp.From)*len(rp.To))
for _, from := range rp.From {
fromKey := Reference{
Namespace: from.Namespace,
}
ref := normalizeReference(&from.Group, &from.Kind, config.GroupVersionKind{})
switch ref {
case gvk.KubernetesGateway, gvk.HTTPRoute, gvk.GRPCRoute, gvk.TLSRoute, gvk.TCPRoute, gvk.XListenerSet:
fromKey.Kind = ref
default:
// Not supported type. Not an error; may be for another controller
continue
}
for _, to := range rp.To {
toKey := Reference{
Namespace: gateway.Namespace(obj.Namespace),
}
ref := normalizeReference(&to.Group, &to.Kind, config.GroupVersionKind{})
switch ref {
case gvk.ConfigMap, gvk.Secret, gvk.Service, gvk.InferencePool:
toKey.Kind = ref
default:
continue
}
rg := ReferenceGrant{
Source: config.NamespacedName(obj),
From: fromKey,
To: toKey,
AllowAll: false,
AllowedName: "",
}
if to.Name != nil {
rg.AllowedName = string(*to.Name)
} else {
rg.AllowAll = true
}
results = append(results, rg)
}
}
return results
}, opts.WithName("ReferenceGrants")...)
}
func BuildReferenceGrants(collection krt.Collection[ReferenceGrant]) ReferenceGrants {
idx := krt.NewIndex(collection, "toFrom", func(o ReferenceGrant) []ReferencePair {
return []ReferencePair{{
To: o.To,
From: o.From,
}}
})
return ReferenceGrants{
collection: collection,
index: idx,
}
}
type ReferenceGrant struct {
Source types.NamespacedName
From Reference
To Reference
AllowAll bool
AllowedName string
}
func (g ReferenceGrant) ResourceName() string {
return g.Source.String() + "/" + g.From.String() + "/" + g.To.String()
}
func (refs ReferenceGrants) SecretAllowed(ctx krt.HandlerContext, kind config.GroupVersionKind, resourceName string, namespace string) bool {
p, err := creds.ParseResourceName(resourceName, "", "", "")
if err != nil {
log.Warnf("failed to parse resource name %q: %v", resourceName, err)
return false
}
resourceKind := config.GroupVersionKind{Kind: p.ResourceKind.String()}
resourceSchema, resourceSchemaFound := collections.All.FindByGroupKind(resourceKind)
if resourceSchemaFound {
resourceKind = resourceSchema.GroupVersionKind()
}
from := Reference{Kind: kind, Namespace: gateway.Namespace(namespace)}
to := Reference{Kind: resourceKind, Namespace: gateway.Namespace(p.Namespace)}
pair := ReferencePair{From: from, To: to}
grants := krt.FetchOrList(ctx, refs.collection, krt.FilterIndex(refs.index, pair))
for _, g := range grants {
if g.AllowAll || g.AllowedName == p.Name {
return true
}
}
return false
}
func (refs ReferenceGrants) BackendAllowed(ctx krt.HandlerContext,
k config.GroupVersionKind,
toGVK config.GroupVersionKind,
backendName gateway.ObjectName,
backendNamespace gateway.Namespace,
routeNamespace string,
) bool {
from := Reference{Kind: k, Namespace: gateway.Namespace(routeNamespace)}
to := Reference{Kind: toGVK, Namespace: backendNamespace}
pair := ReferencePair{From: from, To: to}
grants := krt.Fetch(ctx, refs.collection, krt.FilterIndex(refs.index, pair))
for _, g := range grants {
if g.AllowAll || g.AllowedName == string(backendName) {
return true
}
}
return false
}