From cbc21cf94f3932c535cff76d5b8b38d68a911a2e Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Wed, 21 Jan 2026 10:48:48 +0800 Subject: [PATCH 1/9] API: GeoIP Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/geoip_types.go | 195 ++++++++++++++ api/v1alpha1/securitypolicy_types.go | 6 + api/v1alpha1/zz_generated.deepcopy.go | 245 ++++++++++++++++++ ...ateway.envoyproxy.io_securitypolicies.yaml | 195 ++++++++++++++ ...ateway.envoyproxy.io_securitypolicies.yaml | 195 ++++++++++++++ site/content/en/latest/api/extension_types.md | 188 ++++++++++++++ test/helm/gateway-crds-helm/all.out.yaml | 195 ++++++++++++++ .../envoy-gateway-crds.out.yaml | 195 ++++++++++++++ 8 files changed, 1414 insertions(+) create mode 100644 api/v1alpha1/geoip_types.go diff --git a/api/v1alpha1/geoip_types.go b/api/v1alpha1/geoip_types.go new file mode 100644 index 0000000000..3688172f45 --- /dev/null +++ b/api/v1alpha1/geoip_types.go @@ -0,0 +1,195 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package v1alpha1 + +// GeoIP defines GeoIP enrichment and access control configuration. +type GeoIP struct { + // Source configures how the client IP is extracted before being passed to the provider. + // If unset, Envoy falls back to using the immediate downstream connection address. + // + // +optional + Source *GeoIPSource `json:"source,omitempty"` + + // Provider defines the GeoIP provider configuration. + Provider GeoIPProvider `json:"provider"` + + // Access defines the GeoIP based access control configuration. + // + // +optional + Access *GeoIPAccessControl `json:"access,omitempty"` +} + +// GeoIPSource configures how Envoy determines the client IP address that is passed to the provider. +// +kubebuilder:validation:XValidation:rule="self.type == 'XFF' ? has(self.xff) && !has(self.header) : self.type == 'Header' ? has(self.header) && !has(self.xff) : true",message="When type is XFF, xff must be set (and header unset). When type is Header, header must be set (and xff unset)." +type GeoIPSource struct { + // +kubebuilder:validation:Enum=XFF;Header + // +kubebuilder:validation:Required + Type GeoIPSourceType `json:"type"` + + // XFF configures extraction based on the X-Forwarded-For header chain. + // + // +optional + XFF *GeoIPXFFSource `json:"xff,omitempty"` + + // Header configures extraction from a custom header. + // + // +optional + Header *GeoIPHeaderSource `json:"header,omitempty"` +} + +// GeoIPSourceType enumerates supported client IP sources. +type GeoIPSourceType string + +const ( + // GeoIPSourceTypeXFF instructs Envoy to honor the X-Forwarded-For header count. + GeoIPSourceTypeXFF GeoIPSourceType = "XFF" + // GeoIPSourceTypeHeader instructs Envoy to read a custom request header. + GeoIPSourceTypeHeader GeoIPSourceType = "Header" +) + +// GeoIPXFFSource configures trusted hop count for XFF parsing. +type GeoIPXFFSource struct { + // TrustedHops defines the number of trusted hops from the right side of XFF. + // Defaults to 0 when unset. + // + // +optional + TrustedHops *uint32 `json:"trustedHops,omitempty"` +} + +// GeoIPHeaderSource configures extraction from a custom header. +type GeoIPHeaderSource struct { + // HeaderName is the HTTP header that carries the client IP. + // + // +kubebuilder:validation:MinLength=1 + HeaderName string `json:"headerName"` +} + +// GeoIPProvider defines provider-specific settings. +// +kubebuilder:validation:XValidation:rule="self.type == 'MaxMind' ? has(self.MaxMind) : true",message="MaxMind must be set when type is MaxMind" +type GeoIPProvider struct { + // +kubebuilder:validation:Enum=MaxMind + // +kubebuilder:validation:Required + Type GeoIPProviderType `json:"type"` + + // MaxMind configures the MaxMind provider. + // + // +optional + MaxMind *GeoIPMaxMind `json:"MaxMind,omitempty"` +} + +// GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. +type GeoIPProviderType string + +const ( + // GeoIPProviderTypeMaxMind configures Envoy with the MaxMind provider pointing to local files. + GeoIPProviderTypeMaxMind GeoIPProviderType = "MaxMind" +) + +// GeoIPMaxMind configures the MaxMind provider. +// These database files are expected to be mounted into the Envoy container, and a sidecar container can be used to update the database files. +// +kubebuilder:validation:XValidation:rule="has(self.cityDbPath) || has(self.countryDbPath) || has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath)",message="At least one MaxMind database path must be specified" +type GeoIPMaxMind struct { + // CityDBPath is the path to the City database (.mmdb). + // + // +optional + // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` + CityDBPath *string `json:"cityDbPath,omitempty"` + + // CountryDBPath is the path to the Country database (.mmdb). + // + // +optional + // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` + CountryDBPath *string `json:"countryDbPath,omitempty"` + + // ASNDBPath is the path to the ASN database (.mmdb). + // + // +optional + // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` + ASNDBPath *string `json:"asnDbPath,omitempty"` + + // ISPDBPath is the path to the ISP database (.mmdb). + // + // +optional + // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` + ISPDBPath *string `json:"ispDbPath,omitempty"` + + // AnonymousIPDBPath is the path to the Anonymous IP database (.mmdb). + // + // +optional + // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` + AnonymousIPDBPath *string `json:"anonymousIpDbPath,omitempty"` +} + +// GeoIPAccessControl defines GeoIP-based allow/deny lists. +type GeoIPAccessControl struct { + // DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. + // Defaults to Allow when unset. + // + // +optional + DefaultAction *AuthorizationAction `json:"defaultAction,omitempty"` + + // Rules evaluated in order. The first matching rule's action applies. + // + // +optional + Rules []GeoIPRule `json:"rules,omitempty"` +} + +// GeoIPRule defines a single GeoIP allow/deny rule. +// +kubebuilder:validation:XValidation:rule="has(self.countries) || has(self.regions) || has(self.cities)",message="At least one of countries, regions, or cities must be specified" +type GeoIPRule struct { + // Action is reused from Authorization rules (Allow or Deny). + Action AuthorizationAction `json:"action"` + + // Countries is a list of ISO 3166-1 alpha-2 country codes. + // + // +optional + Countries []string `json:"countries,omitempty"` + + // Regions refines matching to ISO 3166-2 subdivisions. + // + // +optional + Regions []GeoIPRegion `json:"regions,omitempty"` + + // Cities refines matching to specific city names. + // + // +optional + Cities []GeoIPCity `json:"cities,omitempty"` +} + +// GeoIPRegion selects a region within a country. +// +kubebuilder:validation:XValidation:rule="has(self.countryCode) && has(self.regionCode)",message="countryCode and regionCode must both be set" +type GeoIPRegion struct { + // CountryCode is the ISO 3166-1 alpha-2 country code. + // + // +kubebuilder:validation:Pattern=`^[A-Z]{2}$` + CountryCode string `json:"countryCode"` + + // RegionCode is the ISO 3166-2 subdivision code (without country prefix). + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=32 + RegionCode string `json:"regionCode"` +} + +// GeoIPCity selects a city, optionally scoped to a region. +// +kubebuilder:validation:XValidation:rule="has(self.countryCode) && has(self.cityName)",message="countryCode and cityName must be set" +type GeoIPCity struct { + // CountryCode is the ISO 3166-1 alpha-2 country code. + // + // +kubebuilder:validation:Pattern=`^[A-Z]{2}$` + CountryCode string `json:"countryCode"` + + // RegionCode optionally scopes the city to a subdivision (ISO 3166-2 without country prefix). + // + // +optional + // +kubebuilder:validation:MaxLength=32 + RegionCode *string `json:"regionCode,omitempty"` + + // CityName is the city name. + // + // +kubebuilder:validation:MinLength=1 + CityName string `json:"cityName"` +} diff --git a/api/v1alpha1/securitypolicy_types.go b/api/v1alpha1/securitypolicy_types.go index 08cb1e63c6..8901b7f007 100644 --- a/api/v1alpha1/securitypolicy_types.go +++ b/api/v1alpha1/securitypolicy_types.go @@ -82,6 +82,12 @@ type SecurityPolicySpec struct { // +optional ExtAuth *ExtAuth `json:"extAuth,omitempty"` + // GeoIP defines the configuration for GeoIP based request enrichment and access control. + // + // +optional + // +notImplementedHide + GeoIP *GeoIP `json:"geoip,omitempty"` + // Authorization defines the authorization configuration. // // +optional diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d5353074c2..8afca6cc65 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3458,6 +3458,246 @@ func (in *GatewayAPISettings) DeepCopy() *GatewayAPISettings { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIP) DeepCopyInto(out *GeoIP) { + *out = *in + if in.Source != nil { + in, out := &in.Source, &out.Source + *out = new(GeoIPSource) + (*in).DeepCopyInto(*out) + } + in.Provider.DeepCopyInto(&out.Provider) + if in.Access != nil { + in, out := &in.Access, &out.Access + *out = new(GeoIPAccessControl) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIP. +func (in *GeoIP) DeepCopy() *GeoIP { + if in == nil { + return nil + } + out := new(GeoIP) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPAccessControl) DeepCopyInto(out *GeoIPAccessControl) { + *out = *in + if in.DefaultAction != nil { + in, out := &in.DefaultAction, &out.DefaultAction + *out = new(AuthorizationAction) + **out = **in + } + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]GeoIPRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPAccessControl. +func (in *GeoIPAccessControl) DeepCopy() *GeoIPAccessControl { + if in == nil { + return nil + } + out := new(GeoIPAccessControl) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPCity) DeepCopyInto(out *GeoIPCity) { + *out = *in + if in.RegionCode != nil { + in, out := &in.RegionCode, &out.RegionCode + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPCity. +func (in *GeoIPCity) DeepCopy() *GeoIPCity { + if in == nil { + return nil + } + out := new(GeoIPCity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPHeaderSource) DeepCopyInto(out *GeoIPHeaderSource) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPHeaderSource. +func (in *GeoIPHeaderSource) DeepCopy() *GeoIPHeaderSource { + if in == nil { + return nil + } + out := new(GeoIPHeaderSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPMaxMind) DeepCopyInto(out *GeoIPMaxMind) { + *out = *in + if in.CityDBPath != nil { + in, out := &in.CityDBPath, &out.CityDBPath + *out = new(string) + **out = **in + } + if in.CountryDBPath != nil { + in, out := &in.CountryDBPath, &out.CountryDBPath + *out = new(string) + **out = **in + } + if in.ASNDBPath != nil { + in, out := &in.ASNDBPath, &out.ASNDBPath + *out = new(string) + **out = **in + } + if in.ISPDBPath != nil { + in, out := &in.ISPDBPath, &out.ISPDBPath + *out = new(string) + **out = **in + } + if in.AnonymousIPDBPath != nil { + in, out := &in.AnonymousIPDBPath, &out.AnonymousIPDBPath + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPMaxMind. +func (in *GeoIPMaxMind) DeepCopy() *GeoIPMaxMind { + if in == nil { + return nil + } + out := new(GeoIPMaxMind) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPProvider) DeepCopyInto(out *GeoIPProvider) { + *out = *in + if in.MaxMind != nil { + in, out := &in.MaxMind, &out.MaxMind + *out = new(GeoIPMaxMind) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPProvider. +func (in *GeoIPProvider) DeepCopy() *GeoIPProvider { + if in == nil { + return nil + } + out := new(GeoIPProvider) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPRegion) DeepCopyInto(out *GeoIPRegion) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPRegion. +func (in *GeoIPRegion) DeepCopy() *GeoIPRegion { + if in == nil { + return nil + } + out := new(GeoIPRegion) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPRule) DeepCopyInto(out *GeoIPRule) { + *out = *in + if in.Countries != nil { + in, out := &in.Countries, &out.Countries + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Regions != nil { + in, out := &in.Regions, &out.Regions + *out = make([]GeoIPRegion, len(*in)) + copy(*out, *in) + } + if in.Cities != nil { + in, out := &in.Cities, &out.Cities + *out = make([]GeoIPCity, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPRule. +func (in *GeoIPRule) DeepCopy() *GeoIPRule { + if in == nil { + return nil + } + out := new(GeoIPRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPSource) DeepCopyInto(out *GeoIPSource) { + *out = *in + if in.XFF != nil { + in, out := &in.XFF, &out.XFF + *out = new(GeoIPXFFSource) + (*in).DeepCopyInto(*out) + } + if in.Header != nil { + in, out := &in.Header, &out.Header + *out = new(GeoIPHeaderSource) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPSource. +func (in *GeoIPSource) DeepCopy() *GeoIPSource { + if in == nil { + return nil + } + out := new(GeoIPSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPXFFSource) DeepCopyInto(out *GeoIPXFFSource) { + *out = *in + if in.TrustedHops != nil { + in, out := &in.TrustedHops, &out.TrustedHops + *out = new(uint32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPXFFSource. +func (in *GeoIPXFFSource) DeepCopy() *GeoIPXFFSource { + if in == nil { + return nil + } + out := new(GeoIPXFFSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GlobalRateLimit) DeepCopyInto(out *GlobalRateLimit) { *out = *in @@ -7046,6 +7286,11 @@ func (in *SecurityPolicySpec) DeepCopyInto(out *SecurityPolicySpec) { *out = new(ExtAuth) (*in).DeepCopyInto(*out) } + if in.GeoIP != nil { + in, out := &in.GeoIP, &out.GeoIP + *out = new(GeoIP) + (*in).DeepCopyInto(*out) + } if in.Authorization != nil { in, out := &in.Authorization, &out.Authorization *out = new(Authorization) diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index c4a328e8ea..849bd11ca8 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -3117,6 +3117,201 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) + geoip: + description: GeoIP defines the configuration for GeoIP based request + enrichment and access control. + properties: + access: + description: Access defines the GeoIP based access control configuration. + properties: + defaultAction: + description: |- + DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. + Defaults to Allow when unset. + enum: + - Allow + - Deny + type: string + rules: + description: Rules evaluated in order. The first matching + rule's action applies. + items: + description: GeoIPRule defines a single GeoIP allow/deny + rule. + properties: + action: + description: Action is reused from Authorization rules + (Allow or Deny). + enum: + - Allow + - Deny + type: string + cities: + description: Cities refines matching to specific city + names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes the + city to a subdivision (ISO 3166-2 without country + prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within a + country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 subdivision + code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both be + set + rule: has(self.countryCode) && has(self.regionCode) + type: array + required: + - action + type: object + x-kubernetes-validations: + - message: At least one of countries, regions, or cities + must be specified + rule: has(self.countries) || has(self.regions) || has(self.cities) + type: array + type: object + provider: + description: Provider defines the GeoIP provider configuration. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + source: + description: |- + Source configures how the client IP is extracted before being passed to the provider. + If unset, Envoy falls back to using the immediate downstream connection address. + properties: + header: + description: Header configures extraction from a custom header. + properties: + headerName: + description: HeaderName is the HTTP header that carries + the client IP. + minLength: 1 + type: string + required: + - headerName + type: object + type: + description: GeoIPSourceType enumerates supported client IP + sources. + enum: + - XFF + - Header + type: string + xff: + description: XFF configures extraction based on the X-Forwarded-For + header chain. + properties: + trustedHops: + description: |- + TrustedHops defines the number of trusted hops from the right side of XFF. + Defaults to 0 when unset. + format: int32 + type: integer + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: When type is XFF, xff must be set (and header unset). + When type is Header, header must be set (and xff unset). + rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) + : self.type == ''Header'' ? has(self.header) && !has(self.xff) + : true' + required: + - provider + type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index c323b30ba4..3306385b0b 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -3116,6 +3116,201 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) + geoip: + description: GeoIP defines the configuration for GeoIP based request + enrichment and access control. + properties: + access: + description: Access defines the GeoIP based access control configuration. + properties: + defaultAction: + description: |- + DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. + Defaults to Allow when unset. + enum: + - Allow + - Deny + type: string + rules: + description: Rules evaluated in order. The first matching + rule's action applies. + items: + description: GeoIPRule defines a single GeoIP allow/deny + rule. + properties: + action: + description: Action is reused from Authorization rules + (Allow or Deny). + enum: + - Allow + - Deny + type: string + cities: + description: Cities refines matching to specific city + names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes the + city to a subdivision (ISO 3166-2 without country + prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within a + country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 subdivision + code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both be + set + rule: has(self.countryCode) && has(self.regionCode) + type: array + required: + - action + type: object + x-kubernetes-validations: + - message: At least one of countries, regions, or cities + must be specified + rule: has(self.countries) || has(self.regions) || has(self.cities) + type: array + type: object + provider: + description: Provider defines the GeoIP provider configuration. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + source: + description: |- + Source configures how the client IP is extracted before being passed to the provider. + If unset, Envoy falls back to using the immediate downstream connection address. + properties: + header: + description: Header configures extraction from a custom header. + properties: + headerName: + description: HeaderName is the HTTP header that carries + the client IP. + minLength: 1 + type: string + required: + - headerName + type: object + type: + description: GeoIPSourceType enumerates supported client IP + sources. + enum: + - XFF + - Header + type: string + xff: + description: XFF configures extraction based on the X-Forwarded-For + header chain. + properties: + trustedHops: + description: |- + TrustedHops defines the number of trusted hops from the right side of XFF. + Defaults to 0 when unset. + format: int32 + type: integer + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: When type is XFF, xff must be set (and header unset). + When type is Header, header must be set (and xff unset). + rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) + : self.type == ''Header'' ? has(self.header) && !has(self.xff) + : true' + required: + - provider + type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 33cbb8a22a..e52b61f245 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -231,6 +231,8 @@ AuthorizationAction defines the action to be taken if a rule matches. _Appears in:_ - [Authorization](#authorization) - [AuthorizationRule](#authorizationrule) +- [GeoIPAccessControl](#geoipaccesscontrol) +- [GeoIPRule](#geoiprule) | Value | Description | | ----- | ----------- | @@ -2351,6 +2353,192 @@ _Appears in:_ | `enabled` | _[GatewayAPI](#gatewayapi) array_ | true | | | +#### GeoIP + + + +GeoIP defines GeoIP enrichment and access control configuration. + +_Appears in:_ +- [SecurityPolicySpec](#securitypolicyspec) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `source` | _[GeoIPSource](#geoipsource)_ | false | | Source configures how the client IP is extracted before being passed to the provider.
If unset, Envoy falls back to using the immediate downstream connection address. | +| `provider` | _[GeoIPProvider](#geoipprovider)_ | true | | Provider defines the GeoIP provider configuration. | +| `access` | _[GeoIPAccessControl](#geoipaccesscontrol)_ | false | | Access defines the GeoIP based access control configuration. | + + +#### GeoIPAccessControl + + + +GeoIPAccessControl defines GeoIP-based allow/deny lists. + +_Appears in:_ +- [GeoIP](#geoip) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `defaultAction` | _[AuthorizationAction](#authorizationaction)_ | false | | DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data.
Defaults to Allow when unset. | +| `rules` | _[GeoIPRule](#geoiprule) array_ | false | | Rules evaluated in order. The first matching rule's action applies. | + + +#### GeoIPCity + + + +GeoIPCity selects a city, optionally scoped to a region. + +_Appears in:_ +- [GeoIPRule](#geoiprule) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `countryCode` | _string_ | true | | CountryCode is the ISO 3166-1 alpha-2 country code. | +| `regionCode` | _string_ | false | | RegionCode optionally scopes the city to a subdivision (ISO 3166-2 without country prefix). | +| `cityName` | _string_ | true | | CityName is the city name. | + + +#### GeoIPHeaderSource + + + +GeoIPHeaderSource configures extraction from a custom header. + +_Appears in:_ +- [GeoIPSource](#geoipsource) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `headerName` | _string_ | true | | HeaderName is the HTTP header that carries the client IP. | + + +#### GeoIPMaxMind + + + +GeoIPMaxMind configures the MaxMind provider. +These database files are expected to be mounted into the Envoy container, and a sidecar container can be used to update the database files. + +_Appears in:_ +- [GeoIPProvider](#geoipprovider) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cityDbPath` | _string_ | false | | CityDBPath is the path to the City database (.mmdb). | +| `countryDbPath` | _string_ | false | | CountryDBPath is the path to the Country database (.mmdb). | +| `asnDbPath` | _string_ | false | | ASNDBPath is the path to the ASN database (.mmdb). | +| `ispDbPath` | _string_ | false | | ISPDBPath is the path to the ISP database (.mmdb). | +| `anonymousIpDbPath` | _string_ | false | | AnonymousIPDBPath is the path to the Anonymous IP database (.mmdb). | + + +#### GeoIPProvider + + + +GeoIPProvider defines provider-specific settings. + +_Appears in:_ +- [GeoIP](#geoip) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `type` | _[GeoIPProviderType](#geoipprovidertype)_ | true | | | +| `MaxMind` | _[GeoIPMaxMind](#geoipmaxmind)_ | false | | MaxMind configures the MaxMind provider. | + + +#### GeoIPProviderType + +_Underlying type:_ _string_ + +GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. + +_Appears in:_ +- [GeoIPProvider](#geoipprovider) + +| Value | Description | +| ----- | ----------- | +| `MaxMind` | GeoIPProviderTypeMaxMind configures Envoy with the MaxMind provider pointing to local files.
| + + +#### GeoIPRegion + + + +GeoIPRegion selects a region within a country. + +_Appears in:_ +- [GeoIPRule](#geoiprule) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `countryCode` | _string_ | true | | CountryCode is the ISO 3166-1 alpha-2 country code. | +| `regionCode` | _string_ | true | | RegionCode is the ISO 3166-2 subdivision code (without country prefix). | + + +#### GeoIPRule + + + +GeoIPRule defines a single GeoIP allow/deny rule. + +_Appears in:_ +- [GeoIPAccessControl](#geoipaccesscontrol) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `action` | _[AuthorizationAction](#authorizationaction)_ | true | | Action is reused from Authorization rules (Allow or Deny). | +| `countries` | _string array_ | false | | Countries is a list of ISO 3166-1 alpha-2 country codes. | +| `regions` | _[GeoIPRegion](#geoipregion) array_ | false | | Regions refines matching to ISO 3166-2 subdivisions. | +| `cities` | _[GeoIPCity](#geoipcity) array_ | false | | Cities refines matching to specific city names. | + + +#### GeoIPSource + + + +GeoIPSource configures how Envoy determines the client IP address that is passed to the provider. + +_Appears in:_ +- [GeoIP](#geoip) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `type` | _[GeoIPSourceType](#geoipsourcetype)_ | true | | | +| `xff` | _[GeoIPXFFSource](#geoipxffsource)_ | false | | XFF configures extraction based on the X-Forwarded-For header chain. | +| `header` | _[GeoIPHeaderSource](#geoipheadersource)_ | false | | Header configures extraction from a custom header. | + + +#### GeoIPSourceType + +_Underlying type:_ _string_ + +GeoIPSourceType enumerates supported client IP sources. + +_Appears in:_ +- [GeoIPSource](#geoipsource) + +| Value | Description | +| ----- | ----------- | +| `XFF` | GeoIPSourceTypeXFF instructs Envoy to honor the X-Forwarded-For header count.
| +| `Header` | GeoIPSourceTypeHeader instructs Envoy to read a custom request header.
| + + +#### GeoIPXFFSource + + + +GeoIPXFFSource configures trusted hop count for XFF parsing. + +_Appears in:_ +- [GeoIPSource](#geoipsource) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `trustedHops` | _integer_ | false | | TrustedHops defines the number of trusted hops from the right side of XFF.
Defaults to 0 when unset. | + + #### GlobalRateLimit diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index c3b2f14401..66270b7b17 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -50983,6 +50983,201 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) + geoip: + description: GeoIP defines the configuration for GeoIP based request + enrichment and access control. + properties: + access: + description: Access defines the GeoIP based access control configuration. + properties: + defaultAction: + description: |- + DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. + Defaults to Allow when unset. + enum: + - Allow + - Deny + type: string + rules: + description: Rules evaluated in order. The first matching + rule's action applies. + items: + description: GeoIPRule defines a single GeoIP allow/deny + rule. + properties: + action: + description: Action is reused from Authorization rules + (Allow or Deny). + enum: + - Allow + - Deny + type: string + cities: + description: Cities refines matching to specific city + names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes the + city to a subdivision (ISO 3166-2 without country + prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within a + country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 subdivision + code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both be + set + rule: has(self.countryCode) && has(self.regionCode) + type: array + required: + - action + type: object + x-kubernetes-validations: + - message: At least one of countries, regions, or cities + must be specified + rule: has(self.countries) || has(self.regions) || has(self.cities) + type: array + type: object + provider: + description: Provider defines the GeoIP provider configuration. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + source: + description: |- + Source configures how the client IP is extracted before being passed to the provider. + If unset, Envoy falls back to using the immediate downstream connection address. + properties: + header: + description: Header configures extraction from a custom header. + properties: + headerName: + description: HeaderName is the HTTP header that carries + the client IP. + minLength: 1 + type: string + required: + - headerName + type: object + type: + description: GeoIPSourceType enumerates supported client IP + sources. + enum: + - XFF + - Header + type: string + xff: + description: XFF configures extraction based on the X-Forwarded-For + header chain. + properties: + trustedHops: + description: |- + TrustedHops defines the number of trusted hops from the right side of XFF. + Defaults to 0 when unset. + format: int32 + type: integer + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: When type is XFF, xff must be set (and header unset). + When type is Header, header must be set (and xff unset). + rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) + : self.type == ''Header'' ? has(self.header) && !has(self.xff) + : true' + required: + - provider + type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index 52326c3946..a41c441168 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -28964,6 +28964,201 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) + geoip: + description: GeoIP defines the configuration for GeoIP based request + enrichment and access control. + properties: + access: + description: Access defines the GeoIP based access control configuration. + properties: + defaultAction: + description: |- + DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. + Defaults to Allow when unset. + enum: + - Allow + - Deny + type: string + rules: + description: Rules evaluated in order. The first matching + rule's action applies. + items: + description: GeoIPRule defines a single GeoIP allow/deny + rule. + properties: + action: + description: Action is reused from Authorization rules + (Allow or Deny). + enum: + - Allow + - Deny + type: string + cities: + description: Cities refines matching to specific city + names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes the + city to a subdivision (ISO 3166-2 without country + prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within a + country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 alpha-2 + country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 subdivision + code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both be + set + rule: has(self.countryCode) && has(self.regionCode) + type: array + required: + - action + type: object + x-kubernetes-validations: + - message: At least one of countries, regions, or cities + must be specified + rule: has(self.countries) || has(self.regions) || has(self.cities) + type: array + type: object + provider: + description: Provider defines the GeoIP provider configuration. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + source: + description: |- + Source configures how the client IP is extracted before being passed to the provider. + If unset, Envoy falls back to using the immediate downstream connection address. + properties: + header: + description: Header configures extraction from a custom header. + properties: + headerName: + description: HeaderName is the HTTP header that carries + the client IP. + minLength: 1 + type: string + required: + - headerName + type: object + type: + description: GeoIPSourceType enumerates supported client IP + sources. + enum: + - XFF + - Header + type: string + xff: + description: XFF configures extraction based on the X-Forwarded-For + header chain. + properties: + trustedHops: + description: |- + TrustedHops defines the number of trusted hops from the right side of XFF. + Defaults to 0 when unset. + format: int32 + type: integer + type: object + required: + - type + type: object + x-kubernetes-validations: + - message: When type is XFF, xff must be set (and header unset). + When type is Header, header must be set (and xff unset). + rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) + : self.type == ''Header'' ? has(self.header) && !has(self.xff) + : true' + required: + - provider + type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. From ba338efecc705d89da075ea4fc37092ac6cca5bd Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Thu, 19 Feb 2026 12:31:38 +0800 Subject: [PATCH 2/9] update api Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/authorization_types.go | 42 +- api/v1alpha1/envoyproxy_types.go | 11 + api/v1alpha1/geoip_types.go | 128 ++---- api/v1alpha1/securitypolicy_types.go | 6 - api/v1alpha1/zz_generated.deepcopy.go | 162 +++----- .../gateway.envoyproxy.io_envoyproxies.yaml | 56 +++ ...ateway.envoyproxy.io_securitypolicies.yaml | 311 ++++++--------- .../gateway.envoyproxy.io_envoyproxies.yaml | 56 +++ ...ateway.envoyproxy.io_securitypolicies.yaml | 311 ++++++--------- site/content/en/latest/api/extension_types.md | 120 ++---- test/cel-validation/securitypolicy_test.go | 2 +- test/helm/gateway-crds-helm/all.out.yaml | 367 ++++++++---------- .../envoy-gateway-crds.out.yaml | 367 ++++++++---------- 13 files changed, 849 insertions(+), 1090 deletions(-) diff --git a/api/v1alpha1/authorization_types.go b/api/v1alpha1/authorization_types.go index 05b5ef59ae..e904e7f6a9 100644 --- a/api/v1alpha1/authorization_types.go +++ b/api/v1alpha1/authorization_types.go @@ -72,7 +72,7 @@ type Operation struct { // or any other identity that can be extracted from a custom header. // If there are multiple principal types, all principals must match for the rule to match. // -// +kubebuilder:validation:XValidation:rule="(has(self.clientCIDRs) || has(self.jwt) || has(self.headers))",message="at least one of clientCIDRs, jwt, or headers must be specified" +// +kubebuilder:validation:XValidation:rule="(has(self.clientCIDRs) || has(self.jwt) || has(self.headers) || has(self.geoLocation))",message="at least one of clientCIDRs, jwt, headers, or geoLocation must be specified" type Principal struct { // ClientCIDRs are the IP CIDR ranges of the client. // Valid examples are "192.168.1.0/24" or "2001:db8::/64" @@ -128,6 +128,46 @@ type Principal struct { // +kubebuilder:validation:MinItems=1 // +notImplementedHide SourceCIDRs []CIDR `json:"sourceCIDRs,omitempty"` + + // GeoLocation authorizes the request based on geolocation metadata derived from the client IP. + // + // +optional + // +notImplementedHide + GeoLocation *GeoLocationPrincipal `json:"geoLocation,omitempty"` +} + +// GeoLocationPrincipal specifies geolocation-based match criteria for authorization. +// +// +kubebuilder:validation:XValidation:rule="(has(self.countries) || has(self.regions) || has(self.cities) || has(self.asns) || has(self.anonymous))",message="at least one of countries, regions, cities, asns, or anonymous must be specified" +type GeoLocationPrincipal struct { + // Countries is a list of ISO 3166-1 alpha-2 country codes. + // + // +optional + // +kubebuilder:validation:MinItems=1 + Countries []string `json:"countries,omitempty"` + + // Regions refines matching to ISO 3166-2 subdivisions. + // + // +optional + // +kubebuilder:validation:MinItems=1 + Regions []GeoIPRegion `json:"regions,omitempty"` + + // Cities refines matching to specific city names. + // + // +optional + // +kubebuilder:validation:MinItems=1 + Cities []GeoIPCity `json:"cities,omitempty"` + + // ASNs matches the autonomous system numbers associated with the client IP. + // + // +optional + // +kubebuilder:validation:MinItems=1 + ASNs []uint32 `json:"asns,omitempty"` + + // Anonymous matches anonymous network detection signals. + // + // +optional + Anonymous *GeoIPAnonymousMatch `json:"anonymous,omitempty"` } // AuthorizationHeaderMatch specifies how to match against the value of an HTTP header within a authorization rule. diff --git a/api/v1alpha1/envoyproxy_types.go b/api/v1alpha1/envoyproxy_types.go index 4ce860bd39..bf74c9cb4e 100644 --- a/api/v1alpha1/envoyproxy_types.go +++ b/api/v1alpha1/envoyproxy_types.go @@ -198,6 +198,17 @@ type EnvoyProxySpec struct { // +listMapKey=name // +optional DynamicModules []DynamicModuleEntry `json:"dynamicModules,omitempty"` + + // GeoIP defines shared GeoIP provider configuration for this EnvoyProxy fleet. + // + // +optional + GeoIP *EnvoyProxyGeoIP `json:"geoIP,omitempty"` +} + +// EnvoyProxyGeoIP defines shared GeoIP provider settings for EnvoyProxy. +type EnvoyProxyGeoIP struct { + // Provider defines the GeoIP provider configuration used by GeoIP filter instances. + Provider GeoIPProvider `json:"provider"` } // +kubebuilder:validation:Enum=Strict;InsecureSyntax;Disabled diff --git a/api/v1alpha1/geoip_types.go b/api/v1alpha1/geoip_types.go index 3688172f45..f95197c182 100644 --- a/api/v1alpha1/geoip_types.go +++ b/api/v1alpha1/geoip_types.go @@ -5,68 +5,6 @@ package v1alpha1 -// GeoIP defines GeoIP enrichment and access control configuration. -type GeoIP struct { - // Source configures how the client IP is extracted before being passed to the provider. - // If unset, Envoy falls back to using the immediate downstream connection address. - // - // +optional - Source *GeoIPSource `json:"source,omitempty"` - - // Provider defines the GeoIP provider configuration. - Provider GeoIPProvider `json:"provider"` - - // Access defines the GeoIP based access control configuration. - // - // +optional - Access *GeoIPAccessControl `json:"access,omitempty"` -} - -// GeoIPSource configures how Envoy determines the client IP address that is passed to the provider. -// +kubebuilder:validation:XValidation:rule="self.type == 'XFF' ? has(self.xff) && !has(self.header) : self.type == 'Header' ? has(self.header) && !has(self.xff) : true",message="When type is XFF, xff must be set (and header unset). When type is Header, header must be set (and xff unset)." -type GeoIPSource struct { - // +kubebuilder:validation:Enum=XFF;Header - // +kubebuilder:validation:Required - Type GeoIPSourceType `json:"type"` - - // XFF configures extraction based on the X-Forwarded-For header chain. - // - // +optional - XFF *GeoIPXFFSource `json:"xff,omitempty"` - - // Header configures extraction from a custom header. - // - // +optional - Header *GeoIPHeaderSource `json:"header,omitempty"` -} - -// GeoIPSourceType enumerates supported client IP sources. -type GeoIPSourceType string - -const ( - // GeoIPSourceTypeXFF instructs Envoy to honor the X-Forwarded-For header count. - GeoIPSourceTypeXFF GeoIPSourceType = "XFF" - // GeoIPSourceTypeHeader instructs Envoy to read a custom request header. - GeoIPSourceTypeHeader GeoIPSourceType = "Header" -) - -// GeoIPXFFSource configures trusted hop count for XFF parsing. -type GeoIPXFFSource struct { - // TrustedHops defines the number of trusted hops from the right side of XFF. - // Defaults to 0 when unset. - // - // +optional - TrustedHops *uint32 `json:"trustedHops,omitempty"` -} - -// GeoIPHeaderSource configures extraction from a custom header. -type GeoIPHeaderSource struct { - // HeaderName is the HTTP header that carries the client IP. - // - // +kubebuilder:validation:MinLength=1 - HeaderName string `json:"headerName"` -} - // GeoIPProvider defines provider-specific settings. // +kubebuilder:validation:XValidation:rule="self.type == 'MaxMind' ? has(self.MaxMind) : true",message="MaxMind must be set when type is MaxMind" type GeoIPProvider struct { @@ -107,7 +45,7 @@ type GeoIPMaxMind struct { // ASNDBPath is the path to the ASN database (.mmdb). // // +optional - // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` + // +kubebuilder:validation:P attern=`^.*\\.mmdb$` ASNDBPath *string `json:"asnDbPath,omitempty"` // ISPDBPath is the path to the ISP database (.mmdb). @@ -123,42 +61,6 @@ type GeoIPMaxMind struct { AnonymousIPDBPath *string `json:"anonymousIpDbPath,omitempty"` } -// GeoIPAccessControl defines GeoIP-based allow/deny lists. -type GeoIPAccessControl struct { - // DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. - // Defaults to Allow when unset. - // - // +optional - DefaultAction *AuthorizationAction `json:"defaultAction,omitempty"` - - // Rules evaluated in order. The first matching rule's action applies. - // - // +optional - Rules []GeoIPRule `json:"rules,omitempty"` -} - -// GeoIPRule defines a single GeoIP allow/deny rule. -// +kubebuilder:validation:XValidation:rule="has(self.countries) || has(self.regions) || has(self.cities)",message="At least one of countries, regions, or cities must be specified" -type GeoIPRule struct { - // Action is reused from Authorization rules (Allow or Deny). - Action AuthorizationAction `json:"action"` - - // Countries is a list of ISO 3166-1 alpha-2 country codes. - // - // +optional - Countries []string `json:"countries,omitempty"` - - // Regions refines matching to ISO 3166-2 subdivisions. - // - // +optional - Regions []GeoIPRegion `json:"regions,omitempty"` - - // Cities refines matching to specific city names. - // - // +optional - Cities []GeoIPCity `json:"cities,omitempty"` -} - // GeoIPRegion selects a region within a country. // +kubebuilder:validation:XValidation:rule="has(self.countryCode) && has(self.regionCode)",message="countryCode and regionCode must both be set" type GeoIPRegion struct { @@ -193,3 +95,31 @@ type GeoIPCity struct { // +kubebuilder:validation:MinLength=1 CityName string `json:"cityName"` } + +// GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. +type GeoIPAnonymousMatch struct { + // IsAnonymous matches whether the client IP is considered anonymous. + // + // +optional + IsAnonymous *bool `json:"isAnonymous,omitempty"` + + // IsVPN matches whether the client IP is detected as VPN. + // + // +optional + IsVPN *bool `json:"isVPN,omitempty"` + + // IsHosting matches whether the client IP belongs to a hosting provider. + // + // +optional + IsHosting *bool `json:"isHosting,omitempty"` + + // IsTor matches whether the client IP belongs to a Tor exit node. + // + // +optional + IsTor *bool `json:"isTor,omitempty"` + + // IsProxy matches whether the client IP belongs to a public proxy. + // + // +optional + IsProxy *bool `json:"isProxy,omitempty"` +} diff --git a/api/v1alpha1/securitypolicy_types.go b/api/v1alpha1/securitypolicy_types.go index 8901b7f007..08cb1e63c6 100644 --- a/api/v1alpha1/securitypolicy_types.go +++ b/api/v1alpha1/securitypolicy_types.go @@ -82,12 +82,6 @@ type SecurityPolicySpec struct { // +optional ExtAuth *ExtAuth `json:"extAuth,omitempty"` - // GeoIP defines the configuration for GeoIP based request enrichment and access control. - // - // +optional - // +notImplementedHide - GeoIP *GeoIP `json:"geoip,omitempty"` - // Authorization defines the authorization configuration. // // +optional diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 8afca6cc65..2d8f179995 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2649,6 +2649,22 @@ func (in *EnvoyProxyAncestorStatus) DeepCopy() *EnvoyProxyAncestorStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvoyProxyGeoIP) DeepCopyInto(out *EnvoyProxyGeoIP) { + *out = *in + in.Provider.DeepCopyInto(&out.Provider) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyProxyGeoIP. +func (in *EnvoyProxyGeoIP) DeepCopy() *EnvoyProxyGeoIP { + if in == nil { + return nil + } + out := new(EnvoyProxyGeoIP) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EnvoyProxyHostProvider) DeepCopyInto(out *EnvoyProxyHostProvider) { *out = *in @@ -2854,6 +2870,11 @@ func (in *EnvoyProxySpec) DeepCopyInto(out *EnvoyProxySpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.GeoIP != nil { + in, out := &in.GeoIP, &out.GeoIP + *out = new(EnvoyProxyGeoIP) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyProxySpec. @@ -3459,54 +3480,41 @@ func (in *GatewayAPISettings) DeepCopy() *GatewayAPISettings { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIP) DeepCopyInto(out *GeoIP) { +func (in *GeoIPAnonymousMatch) DeepCopyInto(out *GeoIPAnonymousMatch) { *out = *in - if in.Source != nil { - in, out := &in.Source, &out.Source - *out = new(GeoIPSource) - (*in).DeepCopyInto(*out) + if in.IsAnonymous != nil { + in, out := &in.IsAnonymous, &out.IsAnonymous + *out = new(bool) + **out = **in } - in.Provider.DeepCopyInto(&out.Provider) - if in.Access != nil { - in, out := &in.Access, &out.Access - *out = new(GeoIPAccessControl) - (*in).DeepCopyInto(*out) + if in.IsVPN != nil { + in, out := &in.IsVPN, &out.IsVPN + *out = new(bool) + **out = **in } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIP. -func (in *GeoIP) DeepCopy() *GeoIP { - if in == nil { - return nil + if in.IsHosting != nil { + in, out := &in.IsHosting, &out.IsHosting + *out = new(bool) + **out = **in } - out := new(GeoIP) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPAccessControl) DeepCopyInto(out *GeoIPAccessControl) { - *out = *in - if in.DefaultAction != nil { - in, out := &in.DefaultAction, &out.DefaultAction - *out = new(AuthorizationAction) + if in.IsTor != nil { + in, out := &in.IsTor, &out.IsTor + *out = new(bool) **out = **in } - if in.Rules != nil { - in, out := &in.Rules, &out.Rules - *out = make([]GeoIPRule, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.IsProxy != nil { + in, out := &in.IsProxy, &out.IsProxy + *out = new(bool) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPAccessControl. -func (in *GeoIPAccessControl) DeepCopy() *GeoIPAccessControl { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPAnonymousMatch. +func (in *GeoIPAnonymousMatch) DeepCopy() *GeoIPAnonymousMatch { if in == nil { return nil } - out := new(GeoIPAccessControl) + out := new(GeoIPAnonymousMatch) in.DeepCopyInto(out) return out } @@ -3531,21 +3539,6 @@ func (in *GeoIPCity) DeepCopy() *GeoIPCity { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPHeaderSource) DeepCopyInto(out *GeoIPHeaderSource) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPHeaderSource. -func (in *GeoIPHeaderSource) DeepCopy() *GeoIPHeaderSource { - if in == nil { - return nil - } - out := new(GeoIPHeaderSource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GeoIPMaxMind) DeepCopyInto(out *GeoIPMaxMind) { *out = *in @@ -3622,7 +3615,7 @@ func (in *GeoIPRegion) DeepCopy() *GeoIPRegion { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPRule) DeepCopyInto(out *GeoIPRule) { +func (in *GeoLocationPrincipal) DeepCopyInto(out *GeoLocationPrincipal) { *out = *in if in.Countries != nil { in, out := &in.Countries, &out.Countries @@ -3641,59 +3634,24 @@ func (in *GeoIPRule) DeepCopyInto(out *GeoIPRule) { (*in)[i].DeepCopyInto(&(*out)[i]) } } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPRule. -func (in *GeoIPRule) DeepCopy() *GeoIPRule { - if in == nil { - return nil + if in.ASNs != nil { + in, out := &in.ASNs, &out.ASNs + *out = make([]uint32, len(*in)) + copy(*out, *in) } - out := new(GeoIPRule) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPSource) DeepCopyInto(out *GeoIPSource) { - *out = *in - if in.XFF != nil { - in, out := &in.XFF, &out.XFF - *out = new(GeoIPXFFSource) + if in.Anonymous != nil { + in, out := &in.Anonymous, &out.Anonymous + *out = new(GeoIPAnonymousMatch) (*in).DeepCopyInto(*out) } - if in.Header != nil { - in, out := &in.Header, &out.Header - *out = new(GeoIPHeaderSource) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPSource. -func (in *GeoIPSource) DeepCopy() *GeoIPSource { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoLocationPrincipal. +func (in *GeoLocationPrincipal) DeepCopy() *GeoLocationPrincipal { if in == nil { return nil } - out := new(GeoIPSource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPXFFSource) DeepCopyInto(out *GeoIPXFFSource) { - *out = *in - if in.TrustedHops != nil { - in, out := &in.TrustedHops, &out.TrustedHops - *out = new(uint32) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPXFFSource. -func (in *GeoIPXFFSource) DeepCopy() *GeoIPXFFSource { - if in == nil { - return nil - } - out := new(GeoIPXFFSource) + out := new(GeoLocationPrincipal) in.DeepCopyInto(out) return out } @@ -6054,6 +6012,11 @@ func (in *Principal) DeepCopyInto(out *Principal) { *out = make([]CIDR, len(*in)) copy(*out, *in) } + if in.GeoLocation != nil { + in, out := &in.GeoLocation, &out.GeoLocation + *out = new(GeoLocationPrincipal) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Principal. @@ -7286,11 +7249,6 @@ func (in *SecurityPolicySpec) DeepCopyInto(out *SecurityPolicySpec) { *out = new(ExtAuth) (*in).DeepCopyInto(*out) } - if in.GeoIP != nil { - in, out := &in.GeoIP, &out.GeoIP - *out = new(GeoIP) - (*in).DeepCopyInto(*out) - } if in.Authorization != nil { in, out := &in.Authorization, &out.Authorization *out = new(Authorization) diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 55646f0a9b..7d1ade04e0 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -515,6 +515,62 @@ spec: rule: (has(self.before) && !has(self.after)) || (!has(self.before) && has(self.after)) type: array + geoIP: + description: GeoIP defines shared GeoIP provider configuration for + this EnvoyProxy fleet. + properties: + provider: + description: Provider defines the GeoIP provider configuration + used by GeoIP filter instances. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + required: + - provider + type: object ipFamily: description: |- IPFamily specifies the IP family for the EnvoyProxy fleet. diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index 849bd11ca8..a3af515d09 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -272,6 +272,115 @@ spec: type: string minItems: 1 type: array + geoLocation: + description: GeoLocation authorizes the request based + on geolocation metadata derived from the client IP. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. + properties: + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the client + IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean + type: object + asns: + description: ASNs matches the autonomous system + numbers associated with the client IP. + items: + format: int32 + type: integer + minItems: 1 + type: array + cities: + description: Cities refines matching to specific + city names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes + the city to a subdivision (ISO 3166-2 without + country prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + minItems: 1 + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + minItems: 1 + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within + a country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 + subdivision code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both + be set + rule: has(self.countryCode) && has(self.regionCode) + minItems: 1 + type: array + type: object + x-kubernetes-validations: + - message: at least one of countries, regions, cities, + asns, or anonymous must be specified + rule: (has(self.countries) || has(self.regions) || + has(self.cities) || has(self.asns) || has(self.anonymous)) headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -414,9 +523,10 @@ spec: type: array type: object x-kubernetes-validations: - - message: at least one of clientCIDRs, jwt, or headers - must be specified - rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers)) + - message: at least one of clientCIDRs, jwt, headers, or + geoLocation must be specified + rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) + || has(self.geoLocation)) required: - action - principal @@ -3117,201 +3227,6 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) - geoip: - description: GeoIP defines the configuration for GeoIP based request - enrichment and access control. - properties: - access: - description: Access defines the GeoIP based access control configuration. - properties: - defaultAction: - description: |- - DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. - Defaults to Allow when unset. - enum: - - Allow - - Deny - type: string - rules: - description: Rules evaluated in order. The first matching - rule's action applies. - items: - description: GeoIPRule defines a single GeoIP allow/deny - rule. - properties: - action: - description: Action is reused from Authorization rules - (Allow or Deny). - enum: - - Allow - - Deny - type: string - cities: - description: Cities refines matching to specific city - names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. - properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes the - city to a subdivision (ISO 3166-2 without country - prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode - type: object - x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: - type: string - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within a - country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 subdivision - code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both be - set - rule: has(self.countryCode) && has(self.regionCode) - type: array - required: - - action - type: object - x-kubernetes-validations: - - message: At least one of countries, regions, or cities - must be specified - rule: has(self.countries) || has(self.regions) || has(self.cities) - type: array - type: object - provider: - description: Provider defines the GeoIP provider configuration. - properties: - MaxMind: - description: MaxMind configures the MaxMind provider. - properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - type: object - x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) - type: - description: GeoIPProviderType enumerates GeoIP providers - supported by Envoy Gateway. - enum: - - MaxMind - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' - source: - description: |- - Source configures how the client IP is extracted before being passed to the provider. - If unset, Envoy falls back to using the immediate downstream connection address. - properties: - header: - description: Header configures extraction from a custom header. - properties: - headerName: - description: HeaderName is the HTTP header that carries - the client IP. - minLength: 1 - type: string - required: - - headerName - type: object - type: - description: GeoIPSourceType enumerates supported client IP - sources. - enum: - - XFF - - Header - type: string - xff: - description: XFF configures extraction based on the X-Forwarded-For - header chain. - properties: - trustedHops: - description: |- - TrustedHops defines the number of trusted hops from the right side of XFF. - Defaults to 0 when unset. - format: int32 - type: integer - type: object - required: - - type - type: object - x-kubernetes-validations: - - message: When type is XFF, xff must be set (and header unset). - When type is Header, header must be set (and xff unset). - rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) - : self.type == ''Header'' ? has(self.header) && !has(self.xff) - : true' - required: - - provider - type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 9313ea9ead..74f737ab2f 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -514,6 +514,62 @@ spec: rule: (has(self.before) && !has(self.after)) || (!has(self.before) && has(self.after)) type: array + geoIP: + description: GeoIP defines shared GeoIP provider configuration for + this EnvoyProxy fleet. + properties: + provider: + description: Provider defines the GeoIP provider configuration + used by GeoIP filter instances. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + required: + - provider + type: object ipFamily: description: |- IPFamily specifies the IP family for the EnvoyProxy fleet. diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 3306385b0b..0bc143bd3d 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -271,6 +271,115 @@ spec: type: string minItems: 1 type: array + geoLocation: + description: GeoLocation authorizes the request based + on geolocation metadata derived from the client IP. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. + properties: + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the client + IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean + type: object + asns: + description: ASNs matches the autonomous system + numbers associated with the client IP. + items: + format: int32 + type: integer + minItems: 1 + type: array + cities: + description: Cities refines matching to specific + city names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes + the city to a subdivision (ISO 3166-2 without + country prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + minItems: 1 + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + minItems: 1 + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within + a country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 + subdivision code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both + be set + rule: has(self.countryCode) && has(self.regionCode) + minItems: 1 + type: array + type: object + x-kubernetes-validations: + - message: at least one of countries, regions, cities, + asns, or anonymous must be specified + rule: (has(self.countries) || has(self.regions) || + has(self.cities) || has(self.asns) || has(self.anonymous)) headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -413,9 +522,10 @@ spec: type: array type: object x-kubernetes-validations: - - message: at least one of clientCIDRs, jwt, or headers - must be specified - rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers)) + - message: at least one of clientCIDRs, jwt, headers, or + geoLocation must be specified + rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) + || has(self.geoLocation)) required: - action - principal @@ -3116,201 +3226,6 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) - geoip: - description: GeoIP defines the configuration for GeoIP based request - enrichment and access control. - properties: - access: - description: Access defines the GeoIP based access control configuration. - properties: - defaultAction: - description: |- - DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. - Defaults to Allow when unset. - enum: - - Allow - - Deny - type: string - rules: - description: Rules evaluated in order. The first matching - rule's action applies. - items: - description: GeoIPRule defines a single GeoIP allow/deny - rule. - properties: - action: - description: Action is reused from Authorization rules - (Allow or Deny). - enum: - - Allow - - Deny - type: string - cities: - description: Cities refines matching to specific city - names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. - properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes the - city to a subdivision (ISO 3166-2 without country - prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode - type: object - x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: - type: string - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within a - country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 subdivision - code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both be - set - rule: has(self.countryCode) && has(self.regionCode) - type: array - required: - - action - type: object - x-kubernetes-validations: - - message: At least one of countries, regions, or cities - must be specified - rule: has(self.countries) || has(self.regions) || has(self.cities) - type: array - type: object - provider: - description: Provider defines the GeoIP provider configuration. - properties: - MaxMind: - description: MaxMind configures the MaxMind provider. - properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - type: object - x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) - type: - description: GeoIPProviderType enumerates GeoIP providers - supported by Envoy Gateway. - enum: - - MaxMind - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' - source: - description: |- - Source configures how the client IP is extracted before being passed to the provider. - If unset, Envoy falls back to using the immediate downstream connection address. - properties: - header: - description: Header configures extraction from a custom header. - properties: - headerName: - description: HeaderName is the HTTP header that carries - the client IP. - minLength: 1 - type: string - required: - - headerName - type: object - type: - description: GeoIPSourceType enumerates supported client IP - sources. - enum: - - XFF - - Header - type: string - xff: - description: XFF configures extraction based on the X-Forwarded-For - header chain. - properties: - trustedHops: - description: |- - TrustedHops defines the number of trusted hops from the right side of XFF. - Defaults to 0 when unset. - format: int32 - type: integer - type: object - required: - - type - type: object - x-kubernetes-validations: - - message: When type is XFF, xff must be set (and header unset). - When type is Header, header must be set (and xff unset). - rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) - : self.type == ''Header'' ? has(self.header) && !has(self.xff) - : true' - required: - - provider - type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index e52b61f245..a75c24d766 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -231,8 +231,6 @@ AuthorizationAction defines the action to be taken if a rule matches. _Appears in:_ - [Authorization](#authorization) - [AuthorizationRule](#authorizationrule) -- [GeoIPAccessControl](#geoipaccesscontrol) -- [GeoIPRule](#geoiprule) | Value | Description | | ----- | ----------- | @@ -1827,6 +1825,20 @@ _Appears in:_ +#### EnvoyProxyGeoIP + + + +EnvoyProxyGeoIP defines shared GeoIP provider settings for EnvoyProxy. + +_Appears in:_ +- [EnvoyProxySpec](#envoyproxyspec) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `provider` | _[GeoIPProvider](#geoipprovider)_ | true | | Provider defines the GeoIP provider configuration used by GeoIP filter instances. | + + #### EnvoyProxyHostProvider @@ -1921,6 +1933,7 @@ _Appears in:_ | `preserveRouteOrder` | _boolean_ | false | | PreserveRouteOrder determines if the order of matching for HTTPRoutes is determined by Gateway-API
specification (https://gateway-api.sigs.k8s.io/reference/1.4/spec/#httprouterule)
or preserves the order defined by users in the HTTPRoute's HTTPRouteRule list.
Default: False | | `luaValidation` | _[LuaValidation](#luavalidation)_ | false | | LuaValidation determines strictness of the Lua script validation for Lua EnvoyExtensionPolicies
Default: Strict | | `dynamicModules` | _[DynamicModuleEntry](#dynamicmoduleentry) array_ | false | | DynamicModules defines the set of dynamic modules that are allowed to be
used by EnvoyExtensionPolicy resources. Each entry registers a module by
a logical name and specifies the shared library that Envoy will load.
The EnvoyProxy owner is responsible for ensuring the module .so files are available
on the proxy container's filesystem (e.g., via init containers, custom images,
or shared volumes). | +| `geoIP` | _[EnvoyProxyGeoIP](#envoyproxygeoip)_ | false | | GeoIP defines shared GeoIP provider configuration for this EnvoyProxy fleet. | #### EnvoyProxyStatus @@ -2353,35 +2366,22 @@ _Appears in:_ | `enabled` | _[GatewayAPI](#gatewayapi) array_ | true | | | -#### GeoIP - - - -GeoIP defines GeoIP enrichment and access control configuration. - -_Appears in:_ -- [SecurityPolicySpec](#securitypolicyspec) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `source` | _[GeoIPSource](#geoipsource)_ | false | | Source configures how the client IP is extracted before being passed to the provider.
If unset, Envoy falls back to using the immediate downstream connection address. | -| `provider` | _[GeoIPProvider](#geoipprovider)_ | true | | Provider defines the GeoIP provider configuration. | -| `access` | _[GeoIPAccessControl](#geoipaccesscontrol)_ | false | | Access defines the GeoIP based access control configuration. | - - -#### GeoIPAccessControl +#### GeoIPAnonymousMatch -GeoIPAccessControl defines GeoIP-based allow/deny lists. +GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. _Appears in:_ -- [GeoIP](#geoip) +- [GeoLocationPrincipal](#geolocationprincipal) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `defaultAction` | _[AuthorizationAction](#authorizationaction)_ | false | | DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data.
Defaults to Allow when unset. | -| `rules` | _[GeoIPRule](#geoiprule) array_ | false | | Rules evaluated in order. The first matching rule's action applies. | +| `isAnonymous` | _boolean_ | false | | IsAnonymous matches whether the client IP is considered anonymous. | +| `isVPN` | _boolean_ | false | | IsVPN matches whether the client IP is detected as VPN. | +| `isHosting` | _boolean_ | false | | IsHosting matches whether the client IP belongs to a hosting provider. | +| `isTor` | _boolean_ | false | | IsTor matches whether the client IP belongs to a Tor exit node. | +| `isProxy` | _boolean_ | false | | IsProxy matches whether the client IP belongs to a public proxy. | #### GeoIPCity @@ -2391,7 +2391,7 @@ _Appears in:_ GeoIPCity selects a city, optionally scoped to a region. _Appears in:_ -- [GeoIPRule](#geoiprule) +- [GeoLocationPrincipal](#geolocationprincipal) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | @@ -2400,20 +2400,6 @@ _Appears in:_ | `cityName` | _string_ | true | | CityName is the city name. | -#### GeoIPHeaderSource - - - -GeoIPHeaderSource configures extraction from a custom header. - -_Appears in:_ -- [GeoIPSource](#geoipsource) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `headerName` | _string_ | true | | HeaderName is the HTTP header that carries the client IP. | - - #### GeoIPMaxMind @@ -2440,7 +2426,7 @@ _Appears in:_ GeoIPProvider defines provider-specific settings. _Appears in:_ -- [GeoIP](#geoip) +- [EnvoyProxyGeoIP](#envoyproxygeoip) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | @@ -2469,7 +2455,7 @@ _Appears in:_ GeoIPRegion selects a region within a country. _Appears in:_ -- [GeoIPRule](#geoiprule) +- [GeoLocationPrincipal](#geolocationprincipal) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | @@ -2477,66 +2463,22 @@ _Appears in:_ | `regionCode` | _string_ | true | | RegionCode is the ISO 3166-2 subdivision code (without country prefix). | -#### GeoIPRule +#### GeoLocationPrincipal -GeoIPRule defines a single GeoIP allow/deny rule. +GeoLocationPrincipal specifies geolocation-based match criteria for authorization. _Appears in:_ -- [GeoIPAccessControl](#geoipaccesscontrol) +- [Principal](#principal) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `action` | _[AuthorizationAction](#authorizationaction)_ | true | | Action is reused from Authorization rules (Allow or Deny). | | `countries` | _string array_ | false | | Countries is a list of ISO 3166-1 alpha-2 country codes. | | `regions` | _[GeoIPRegion](#geoipregion) array_ | false | | Regions refines matching to ISO 3166-2 subdivisions. | | `cities` | _[GeoIPCity](#geoipcity) array_ | false | | Cities refines matching to specific city names. | - - -#### GeoIPSource - - - -GeoIPSource configures how Envoy determines the client IP address that is passed to the provider. - -_Appears in:_ -- [GeoIP](#geoip) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `type` | _[GeoIPSourceType](#geoipsourcetype)_ | true | | | -| `xff` | _[GeoIPXFFSource](#geoipxffsource)_ | false | | XFF configures extraction based on the X-Forwarded-For header chain. | -| `header` | _[GeoIPHeaderSource](#geoipheadersource)_ | false | | Header configures extraction from a custom header. | - - -#### GeoIPSourceType - -_Underlying type:_ _string_ - -GeoIPSourceType enumerates supported client IP sources. - -_Appears in:_ -- [GeoIPSource](#geoipsource) - -| Value | Description | -| ----- | ----------- | -| `XFF` | GeoIPSourceTypeXFF instructs Envoy to honor the X-Forwarded-For header count.
| -| `Header` | GeoIPSourceTypeHeader instructs Envoy to read a custom request header.
| - - -#### GeoIPXFFSource - - - -GeoIPXFFSource configures trusted hop count for XFF parsing. - -_Appears in:_ -- [GeoIPSource](#geoipsource) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `trustedHops` | _integer_ | false | | TrustedHops defines the number of trusted hops from the right side of XFF.
Defaults to 0 when unset. | +| `asns` | _integer array_ | false | | ASNs matches the autonomous system numbers associated with the client IP. | +| `anonymous` | _[GeoIPAnonymousMatch](#geoipanonymousmatch)_ | false | | Anonymous matches anonymous network detection signals. | #### GlobalRateLimit diff --git a/test/cel-validation/securitypolicy_test.go b/test/cel-validation/securitypolicy_test.go index d05ecc4b9e..4ecbeaf3de 100644 --- a/test/cel-validation/securitypolicy_test.go +++ b/test/cel-validation/securitypolicy_test.go @@ -1301,7 +1301,7 @@ func TestSecurityPolicyTarget(t *testing.T) { }, } }, - wantErrors: []string{"at least one of clientCIDRs, jwt, or headers must be specified"}, + wantErrors: []string{"at least one of clientCIDRs, jwt, headers, or geoLocation must be specified"}, }, { desc: "authorization-jwt-claims-without-jwt-authn", diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 66270b7b17..42f022d315 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -30865,6 +30865,62 @@ spec: rule: (has(self.before) && !has(self.after)) || (!has(self.before) && has(self.after)) type: array + geoIP: + description: GeoIP defines shared GeoIP provider configuration for + this EnvoyProxy fleet. + properties: + provider: + description: Provider defines the GeoIP provider configuration + used by GeoIP filter instances. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + required: + - provider + type: object ipFamily: description: |- IPFamily specifies the IP family for the EnvoyProxy fleet. @@ -48138,6 +48194,115 @@ spec: type: string minItems: 1 type: array + geoLocation: + description: GeoLocation authorizes the request based + on geolocation metadata derived from the client IP. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. + properties: + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the client + IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean + type: object + asns: + description: ASNs matches the autonomous system + numbers associated with the client IP. + items: + format: int32 + type: integer + minItems: 1 + type: array + cities: + description: Cities refines matching to specific + city names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes + the city to a subdivision (ISO 3166-2 without + country prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + minItems: 1 + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + minItems: 1 + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within + a country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 + subdivision code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both + be set + rule: has(self.countryCode) && has(self.regionCode) + minItems: 1 + type: array + type: object + x-kubernetes-validations: + - message: at least one of countries, regions, cities, + asns, or anonymous must be specified + rule: (has(self.countries) || has(self.regions) || + has(self.cities) || has(self.asns) || has(self.anonymous)) headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -48280,9 +48445,10 @@ spec: type: array type: object x-kubernetes-validations: - - message: at least one of clientCIDRs, jwt, or headers - must be specified - rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers)) + - message: at least one of clientCIDRs, jwt, headers, or + geoLocation must be specified + rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) + || has(self.geoLocation)) required: - action - principal @@ -50983,201 +51149,6 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) - geoip: - description: GeoIP defines the configuration for GeoIP based request - enrichment and access control. - properties: - access: - description: Access defines the GeoIP based access control configuration. - properties: - defaultAction: - description: |- - DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. - Defaults to Allow when unset. - enum: - - Allow - - Deny - type: string - rules: - description: Rules evaluated in order. The first matching - rule's action applies. - items: - description: GeoIPRule defines a single GeoIP allow/deny - rule. - properties: - action: - description: Action is reused from Authorization rules - (Allow or Deny). - enum: - - Allow - - Deny - type: string - cities: - description: Cities refines matching to specific city - names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. - properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes the - city to a subdivision (ISO 3166-2 without country - prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode - type: object - x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: - type: string - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within a - country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 subdivision - code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both be - set - rule: has(self.countryCode) && has(self.regionCode) - type: array - required: - - action - type: object - x-kubernetes-validations: - - message: At least one of countries, regions, or cities - must be specified - rule: has(self.countries) || has(self.regions) || has(self.cities) - type: array - type: object - provider: - description: Provider defines the GeoIP provider configuration. - properties: - MaxMind: - description: MaxMind configures the MaxMind provider. - properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - type: object - x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) - type: - description: GeoIPProviderType enumerates GeoIP providers - supported by Envoy Gateway. - enum: - - MaxMind - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' - source: - description: |- - Source configures how the client IP is extracted before being passed to the provider. - If unset, Envoy falls back to using the immediate downstream connection address. - properties: - header: - description: Header configures extraction from a custom header. - properties: - headerName: - description: HeaderName is the HTTP header that carries - the client IP. - minLength: 1 - type: string - required: - - headerName - type: object - type: - description: GeoIPSourceType enumerates supported client IP - sources. - enum: - - XFF - - Header - type: string - xff: - description: XFF configures extraction based on the X-Forwarded-For - header chain. - properties: - trustedHops: - description: |- - TrustedHops defines the number of trusted hops from the right side of XFF. - Defaults to 0 when unset. - format: int32 - type: integer - type: object - required: - - type - type: object - x-kubernetes-validations: - - message: When type is XFF, xff must be set (and header unset). - When type is Header, header must be set (and xff unset). - rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) - : self.type == ''Header'' ? has(self.header) && !has(self.xff) - : true' - required: - - provider - type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index a41c441168..bfb02dc97e 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -8846,6 +8846,62 @@ spec: rule: (has(self.before) && !has(self.after)) || (!has(self.before) && has(self.after)) type: array + geoIP: + description: GeoIP defines shared GeoIP provider configuration for + this EnvoyProxy fleet. + properties: + provider: + description: Provider defines the GeoIP provider configuration + used by GeoIP filter instances. + properties: + MaxMind: + description: MaxMind configures the MaxMind provider. + properties: + anonymousIpDbPath: + description: AnonymousIPDBPath is the path to the Anonymous + IP database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + asnDbPath: + description: ASNDBPath is the path to the ASN database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + cityDbPath: + description: CityDBPath is the path to the City database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + countryDbPath: + description: CountryDBPath is the path to the Country + database (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + ispDbPath: + description: ISPDBPath is the path to the ISP database + (.mmdb). + pattern: ^.*\\.mmdb$ + type: string + type: object + x-kubernetes-validations: + - message: At least one MaxMind database path must be specified + rule: has(self.cityDbPath) || has(self.countryDbPath) || + has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + type: + description: GeoIPProviderType enumerates GeoIP providers + supported by Envoy Gateway. + enum: + - MaxMind + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: MaxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + required: + - provider + type: object ipFamily: description: |- IPFamily specifies the IP family for the EnvoyProxy fleet. @@ -26119,6 +26175,115 @@ spec: type: string minItems: 1 type: array + geoLocation: + description: GeoLocation authorizes the request based + on geolocation metadata derived from the client IP. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. + properties: + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the client + IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean + type: object + asns: + description: ASNs matches the autonomous system + numbers associated with the client IP. + items: + format: int32 + type: integer + minItems: 1 + type: array + cities: + description: Cities refines matching to specific + city names. + items: + description: GeoIPCity selects a city, optionally + scoped to a region. + properties: + cityName: + description: CityName is the city name. + minLength: 1 + type: string + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode optionally scopes + the city to a subdivision (ISO 3166-2 without + country prefix). + maxLength: 32 + type: string + required: + - cityName + - countryCode + type: object + x-kubernetes-validations: + - message: countryCode and cityName must be set + rule: has(self.countryCode) && has(self.cityName) + minItems: 1 + type: array + countries: + description: Countries is a list of ISO 3166-1 alpha-2 + country codes. + items: + type: string + minItems: 1 + type: array + regions: + description: Regions refines matching to ISO 3166-2 + subdivisions. + items: + description: GeoIPRegion selects a region within + a country. + properties: + countryCode: + description: CountryCode is the ISO 3166-1 + alpha-2 country code. + pattern: ^[A-Z]{2}$ + type: string + regionCode: + description: RegionCode is the ISO 3166-2 + subdivision code (without country prefix). + maxLength: 32 + minLength: 1 + type: string + required: + - countryCode + - regionCode + type: object + x-kubernetes-validations: + - message: countryCode and regionCode must both + be set + rule: has(self.countryCode) && has(self.regionCode) + minItems: 1 + type: array + type: object + x-kubernetes-validations: + - message: at least one of countries, regions, cities, + asns, or anonymous must be specified + rule: (has(self.countries) || has(self.regions) || + has(self.cities) || has(self.asns) || has(self.anonymous)) headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -26261,9 +26426,10 @@ spec: type: array type: object x-kubernetes-validations: - - message: at least one of clientCIDRs, jwt, or headers - must be specified - rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers)) + - message: at least one of clientCIDRs, jwt, headers, or + geoLocation must be specified + rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) + || has(self.geoLocation)) required: - action - principal @@ -28964,201 +29130,6 @@ spec: - message: only one of grpc or http can be specified rule: (has(self.grpc) && !has(self.http)) || (!has(self.grpc) && has(self.http)) - geoip: - description: GeoIP defines the configuration for GeoIP based request - enrichment and access control. - properties: - access: - description: Access defines the GeoIP based access control configuration. - properties: - defaultAction: - description: |- - DefaultAction defines how to handle requests that do not match any rule or lack GeoIP data. - Defaults to Allow when unset. - enum: - - Allow - - Deny - type: string - rules: - description: Rules evaluated in order. The first matching - rule's action applies. - items: - description: GeoIPRule defines a single GeoIP allow/deny - rule. - properties: - action: - description: Action is reused from Authorization rules - (Allow or Deny). - enum: - - Allow - - Deny - type: string - cities: - description: Cities refines matching to specific city - names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. - properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes the - city to a subdivision (ISO 3166-2 without country - prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode - type: object - x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: - type: string - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within a - country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 alpha-2 - country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 subdivision - code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both be - set - rule: has(self.countryCode) && has(self.regionCode) - type: array - required: - - action - type: object - x-kubernetes-validations: - - message: At least one of countries, regions, or cities - must be specified - rule: has(self.countries) || has(self.regions) || has(self.cities) - type: array - type: object - provider: - description: Provider defines the GeoIP provider configuration. - properties: - MaxMind: - description: MaxMind configures the MaxMind provider. - properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - type: object - x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) - type: - description: GeoIPProviderType enumerates GeoIP providers - supported by Envoy Gateway. - enum: - - MaxMind - type: string - required: - - type - type: object - x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' - source: - description: |- - Source configures how the client IP is extracted before being passed to the provider. - If unset, Envoy falls back to using the immediate downstream connection address. - properties: - header: - description: Header configures extraction from a custom header. - properties: - headerName: - description: HeaderName is the HTTP header that carries - the client IP. - minLength: 1 - type: string - required: - - headerName - type: object - type: - description: GeoIPSourceType enumerates supported client IP - sources. - enum: - - XFF - - Header - type: string - xff: - description: XFF configures extraction based on the X-Forwarded-For - header chain. - properties: - trustedHops: - description: |- - TrustedHops defines the number of trusted hops from the right side of XFF. - Defaults to 0 when unset. - format: int32 - type: integer - type: object - required: - - type - type: object - x-kubernetes-validations: - - message: When type is XFF, xff must be set (and header unset). - When type is Header, header must be set (and xff unset). - rule: 'self.type == ''XFF'' ? has(self.xff) && !has(self.header) - : self.type == ''Header'' ? has(self.header) && !has(self.xff) - : true' - required: - - provider - type: object jwt: description: JWT defines the configuration for JSON Web Token (JWT) authentication. From 9b7ef6a3ed8694fbccb7ad05c6f5461c1fd73e5f Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Thu, 19 Feb 2026 22:45:50 +0800 Subject: [PATCH 3/9] update api Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/authorization_types.go | 39 ++-- api/v1alpha1/geoip_types.go | 2 + api/v1alpha1/zz_generated.deepcopy.go | 57 +++--- ...ateway.envoyproxy.io_securitypolicies.yaml | 173 +++++++----------- ...ateway.envoyproxy.io_securitypolicies.yaml | 173 +++++++----------- site/content/en/latest/api/extension_types.md | 42 +---- test/cel-validation/securitypolicy_test.go | 2 +- 7 files changed, 195 insertions(+), 293 deletions(-) diff --git a/api/v1alpha1/authorization_types.go b/api/v1alpha1/authorization_types.go index e904e7f6a9..1237551006 100644 --- a/api/v1alpha1/authorization_types.go +++ b/api/v1alpha1/authorization_types.go @@ -72,7 +72,7 @@ type Operation struct { // or any other identity that can be extracted from a custom header. // If there are multiple principal types, all principals must match for the rule to match. // -// +kubebuilder:validation:XValidation:rule="(has(self.clientCIDRs) || has(self.jwt) || has(self.headers) || has(self.geoLocation))",message="at least one of clientCIDRs, jwt, headers, or geoLocation must be specified" +// +kubebuilder:validation:XValidation:rule="(has(self.clientCIDRs) || has(self.jwt) || has(self.headers) || has(self.geoLocations))",message="at least one of clientCIDRs, jwt, headers, or geoLocations must be specified" type Principal struct { // ClientCIDRs are the IP CIDR ranges of the client. // Valid examples are "192.168.1.0/24" or "2001:db8::/64" @@ -129,40 +129,43 @@ type Principal struct { // +notImplementedHide SourceCIDRs []CIDR `json:"sourceCIDRs,omitempty"` - // GeoLocation authorizes the request based on geolocation metadata derived from the client IP. + // GeoLocations authorizes the request based on geolocation metadata derived from the client IP. + // If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. // // +optional + // +kubebuilder:validation:MinItems=1 // +notImplementedHide - GeoLocation *GeoLocationPrincipal `json:"geoLocation,omitempty"` + GeoLocations []GeoLocation `json:"geoLocations,omitempty"` } -// GeoLocationPrincipal specifies geolocation-based match criteria for authorization. +// GeoLocation specifies geolocation-based match criteria for authorization. // -// +kubebuilder:validation:XValidation:rule="(has(self.countries) || has(self.regions) || has(self.cities) || has(self.asns) || has(self.anonymous))",message="at least one of countries, regions, cities, asns, or anonymous must be specified" -type GeoLocationPrincipal struct { - // Countries is a list of ISO 3166-1 alpha-2 country codes. +// +kubebuilder:validation:XValidation:rule="has(self.country) || has(self.region) || has(self.city) || has(self.asn) || has(self.isp) || has(self.anonymous)",message="at least one of country, region, city, asn, isp, or anonymous must be specified" +type GeoLocation struct { + // Country is the country associated with the client IP. // // +optional - // +kubebuilder:validation:MinItems=1 - Countries []string `json:"countries,omitempty"` + Country *string `json:"country,omitempty"` - // Regions refines matching to ISO 3166-2 subdivisions. + // Region is the region associated with the client IP. // // +optional - // +kubebuilder:validation:MinItems=1 - Regions []GeoIPRegion `json:"regions,omitempty"` + Region *string `json:"region,omitempty"` - // Cities refines matching to specific city names. + // City is the city associated with the client IP. // // +optional - // +kubebuilder:validation:MinItems=1 - Cities []GeoIPCity `json:"cities,omitempty"` + City *string `json:"city,omitempty"` - // ASNs matches the autonomous system numbers associated with the client IP. + // ASN is the autonomous system number associated with the client IP. // // +optional - // +kubebuilder:validation:MinItems=1 - ASNs []uint32 `json:"asns,omitempty"` + ASN *uint32 `json:"asn,omitempty"` + + // ISP is the internet service provider associated with the client IP. + // + // +optional + ISP *string `json:"isp,omitempty"` // Anonymous matches anonymous network detection signals. // diff --git a/api/v1alpha1/geoip_types.go b/api/v1alpha1/geoip_types.go index f95197c182..e3c55958c5 100644 --- a/api/v1alpha1/geoip_types.go +++ b/api/v1alpha1/geoip_types.go @@ -97,6 +97,8 @@ type GeoIPCity struct { } // GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. +// +// +kubebuilder:validation:XValidation:rule="has(self.isAnonymous) || has(self.isVPN) || has(self.isHosting) || has(self.isTor) || has(self.isProxy)",message="at least one of isAnonymous, isVPN, isHosting, isTor, or isProxy must be specified" type GeoIPAnonymousMatch struct { // IsAnonymous matches whether the client IP is considered anonymous. // diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2d8f179995..21e4b202fc 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3615,29 +3615,32 @@ func (in *GeoIPRegion) DeepCopy() *GeoIPRegion { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoLocationPrincipal) DeepCopyInto(out *GeoLocationPrincipal) { +func (in *GeoLocation) DeepCopyInto(out *GeoLocation) { *out = *in - if in.Countries != nil { - in, out := &in.Countries, &out.Countries - *out = make([]string, len(*in)) - copy(*out, *in) + if in.Country != nil { + in, out := &in.Country, &out.Country + *out = new(string) + **out = **in } - if in.Regions != nil { - in, out := &in.Regions, &out.Regions - *out = make([]GeoIPRegion, len(*in)) - copy(*out, *in) + if in.Region != nil { + in, out := &in.Region, &out.Region + *out = new(string) + **out = **in } - if in.Cities != nil { - in, out := &in.Cities, &out.Cities - *out = make([]GeoIPCity, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.City != nil { + in, out := &in.City, &out.City + *out = new(string) + **out = **in } - if in.ASNs != nil { - in, out := &in.ASNs, &out.ASNs - *out = make([]uint32, len(*in)) - copy(*out, *in) + if in.ASN != nil { + in, out := &in.ASN, &out.ASN + *out = new(uint32) + **out = **in + } + if in.ISP != nil { + in, out := &in.ISP, &out.ISP + *out = new(string) + **out = **in } if in.Anonymous != nil { in, out := &in.Anonymous, &out.Anonymous @@ -3646,12 +3649,12 @@ func (in *GeoLocationPrincipal) DeepCopyInto(out *GeoLocationPrincipal) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoLocationPrincipal. -func (in *GeoLocationPrincipal) DeepCopy() *GeoLocationPrincipal { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoLocation. +func (in *GeoLocation) DeepCopy() *GeoLocation { if in == nil { return nil } - out := new(GeoLocationPrincipal) + out := new(GeoLocation) in.DeepCopyInto(out) return out } @@ -6012,10 +6015,12 @@ func (in *Principal) DeepCopyInto(out *Principal) { *out = make([]CIDR, len(*in)) copy(*out, *in) } - if in.GeoLocation != nil { - in, out := &in.GeoLocation, &out.GeoLocation - *out = new(GeoLocationPrincipal) - (*in).DeepCopyInto(*out) + if in.GeoLocations != nil { + in, out := &in.GeoLocations, &out.GeoLocations + *out = make([]GeoLocation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index a3af515d09..e18d0527b9 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -272,115 +272,74 @@ spec: type: string minItems: 1 type: array - geoLocation: - description: GeoLocation authorizes the request based - on geolocation metadata derived from the client IP. - properties: - anonymous: - description: Anonymous matches anonymous network - detection signals. - properties: - isAnonymous: - description: IsAnonymous matches whether the - client IP is considered anonymous. - type: boolean - isHosting: - description: IsHosting matches whether the client - IP belongs to a hosting provider. - type: boolean - isProxy: - description: IsProxy matches whether the client - IP belongs to a public proxy. - type: boolean - isTor: - description: IsTor matches whether the client - IP belongs to a Tor exit node. - type: boolean - isVPN: - description: IsVPN matches whether the client - IP is detected as VPN. - type: boolean - type: object - asns: - description: ASNs matches the autonomous system - numbers associated with the client IP. - items: - format: int32 - type: integer - minItems: 1 - type: array - cities: - description: Cities refines matching to specific - city names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. + geoLocations: + description: |- + GeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + items: + description: GeoLocation specifies geolocation-based + match criteria for authorization. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes - the city to a subdivision (ISO 3166-2 without - country prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the + client IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean type: object x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - minItems: 1 - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: + - message: at least one of isAnonymous, isVPN, + isHosting, isTor, or isProxy must be specified + rule: has(self.isAnonymous) || has(self.isVPN) + || has(self.isHosting) || has(self.isTor) + || has(self.isProxy) + asn: + description: ASN is the autonomous system number + associated with the client IP. + format: int32 + type: integer + city: + description: City is the city associated with + the client IP. type: string - minItems: 1 - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within - a country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 - subdivision code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both - be set - rule: has(self.countryCode) && has(self.regionCode) - minItems: 1 - type: array - type: object - x-kubernetes-validations: - - message: at least one of countries, regions, cities, - asns, or anonymous must be specified - rule: (has(self.countries) || has(self.regions) || - has(self.cities) || has(self.asns) || has(self.anonymous)) + country: + description: Country is the country associated + with the client IP. + type: string + isp: + description: ISP is the internet service provider + associated with the client IP. + type: string + region: + description: Region is the region associated with + the client IP. + type: string + type: object + x-kubernetes-validations: + - message: at least one of country, region, city, + asn, isp, or anonymous must be specified + rule: has(self.country) || has(self.region) || has(self.city) + || has(self.asn) || has(self.isp) || has(self.anonymous) + minItems: 1 + type: array headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -524,9 +483,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocation must be specified + geoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocation)) + || has(self.geoLocations)) required: - action - principal diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 0bc143bd3d..1e35021c86 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -271,115 +271,74 @@ spec: type: string minItems: 1 type: array - geoLocation: - description: GeoLocation authorizes the request based - on geolocation metadata derived from the client IP. - properties: - anonymous: - description: Anonymous matches anonymous network - detection signals. - properties: - isAnonymous: - description: IsAnonymous matches whether the - client IP is considered anonymous. - type: boolean - isHosting: - description: IsHosting matches whether the client - IP belongs to a hosting provider. - type: boolean - isProxy: - description: IsProxy matches whether the client - IP belongs to a public proxy. - type: boolean - isTor: - description: IsTor matches whether the client - IP belongs to a Tor exit node. - type: boolean - isVPN: - description: IsVPN matches whether the client - IP is detected as VPN. - type: boolean - type: object - asns: - description: ASNs matches the autonomous system - numbers associated with the client IP. - items: - format: int32 - type: integer - minItems: 1 - type: array - cities: - description: Cities refines matching to specific - city names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. + geoLocations: + description: |- + GeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + items: + description: GeoLocation specifies geolocation-based + match criteria for authorization. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes - the city to a subdivision (ISO 3166-2 without - country prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the + client IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean type: object x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - minItems: 1 - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: + - message: at least one of isAnonymous, isVPN, + isHosting, isTor, or isProxy must be specified + rule: has(self.isAnonymous) || has(self.isVPN) + || has(self.isHosting) || has(self.isTor) + || has(self.isProxy) + asn: + description: ASN is the autonomous system number + associated with the client IP. + format: int32 + type: integer + city: + description: City is the city associated with + the client IP. type: string - minItems: 1 - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within - a country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 - subdivision code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both - be set - rule: has(self.countryCode) && has(self.regionCode) - minItems: 1 - type: array - type: object - x-kubernetes-validations: - - message: at least one of countries, regions, cities, - asns, or anonymous must be specified - rule: (has(self.countries) || has(self.regions) || - has(self.cities) || has(self.asns) || has(self.anonymous)) + country: + description: Country is the country associated + with the client IP. + type: string + isp: + description: ISP is the internet service provider + associated with the client IP. + type: string + region: + description: Region is the region associated with + the client IP. + type: string + type: object + x-kubernetes-validations: + - message: at least one of country, region, city, + asn, isp, or anonymous must be specified + rule: has(self.country) || has(self.region) || has(self.city) + || has(self.asn) || has(self.isp) || has(self.anonymous) + minItems: 1 + type: array headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -523,9 +482,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocation must be specified + geoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocation)) + || has(self.geoLocations)) required: - action - principal diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index a75c24d766..accb4c6e70 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2373,7 +2373,7 @@ _Appears in:_ GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. _Appears in:_ -- [GeoLocationPrincipal](#geolocationprincipal) +- [GeoLocation](#geolocation) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | @@ -2384,20 +2384,6 @@ _Appears in:_ | `isProxy` | _boolean_ | false | | IsProxy matches whether the client IP belongs to a public proxy. | -#### GeoIPCity - - - -GeoIPCity selects a city, optionally scoped to a region. - -_Appears in:_ -- [GeoLocationPrincipal](#geolocationprincipal) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `countryCode` | _string_ | true | | CountryCode is the ISO 3166-1 alpha-2 country code. | -| `regionCode` | _string_ | false | | RegionCode optionally scopes the city to a subdivision (ISO 3166-2 without country prefix). | -| `cityName` | _string_ | true | | CityName is the city name. | #### GeoIPMaxMind @@ -2448,36 +2434,24 @@ _Appears in:_ | `MaxMind` | GeoIPProviderTypeMaxMind configures Envoy with the MaxMind provider pointing to local files.
| -#### GeoIPRegion - - - -GeoIPRegion selects a region within a country. - -_Appears in:_ -- [GeoLocationPrincipal](#geolocationprincipal) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `countryCode` | _string_ | true | | CountryCode is the ISO 3166-1 alpha-2 country code. | -| `regionCode` | _string_ | true | | RegionCode is the ISO 3166-2 subdivision code (without country prefix). | -#### GeoLocationPrincipal +#### GeoLocation -GeoLocationPrincipal specifies geolocation-based match criteria for authorization. +GeoLocation specifies geolocation-based match criteria for authorization. _Appears in:_ - [Principal](#principal) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `countries` | _string array_ | false | | Countries is a list of ISO 3166-1 alpha-2 country codes. | -| `regions` | _[GeoIPRegion](#geoipregion) array_ | false | | Regions refines matching to ISO 3166-2 subdivisions. | -| `cities` | _[GeoIPCity](#geoipcity) array_ | false | | Cities refines matching to specific city names. | -| `asns` | _integer array_ | false | | ASNs matches the autonomous system numbers associated with the client IP. | +| `country` | _string_ | false | | Country is the country associated with the client IP. | +| `region` | _string_ | false | | Region is the region associated with the client IP. | +| `city` | _string_ | false | | City is the city associated with the client IP. | +| `asn` | _integer_ | false | | ASN is the autonomous system number associated with the client IP. | +| `isp` | _string_ | false | | ISP is the internet service provider associated with the client IP. | | `anonymous` | _[GeoIPAnonymousMatch](#geoipanonymousmatch)_ | false | | Anonymous matches anonymous network detection signals. | diff --git a/test/cel-validation/securitypolicy_test.go b/test/cel-validation/securitypolicy_test.go index 4ecbeaf3de..d34fbc47bd 100644 --- a/test/cel-validation/securitypolicy_test.go +++ b/test/cel-validation/securitypolicy_test.go @@ -1301,7 +1301,7 @@ func TestSecurityPolicyTarget(t *testing.T) { }, } }, - wantErrors: []string{"at least one of clientCIDRs, jwt, headers, or geoLocation must be specified"}, + wantErrors: []string{"at least one of clientCIDRs, jwt, headers, or geoLocations must be specified"}, }, { desc: "authorization-jwt-claims-without-jwt-authn", From 45cbc67234f909f5a7fac4ba2f3d85a9fce55e50 Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Mon, 23 Feb 2026 22:09:12 +0800 Subject: [PATCH 4/9] address comments Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/authorization_types.go | 15 +- api/v1alpha1/geoip_types.go | 39 +--- api/v1alpha1/zz_generated.deepcopy.go | 35 ---- .../gateway.envoyproxy.io_envoyproxies.yaml | 1 - ...ateway.envoyproxy.io_securitypolicies.yaml | 17 +- .../gateway.envoyproxy.io_envoyproxies.yaml | 1 - ...ateway.envoyproxy.io_securitypolicies.yaml | 17 +- site/content/en/latest/api/extension_types.md | 12 +- test/helm/gateway-crds-helm/all.out.yaml | 185 ++++++++---------- .../envoy-gateway-crds.out.yaml | 185 ++++++++---------- 10 files changed, 205 insertions(+), 302 deletions(-) diff --git a/api/v1alpha1/authorization_types.go b/api/v1alpha1/authorization_types.go index 1237551006..41bf413ffd 100644 --- a/api/v1alpha1/authorization_types.go +++ b/api/v1alpha1/authorization_types.go @@ -142,29 +142,40 @@ type Principal struct { // // +kubebuilder:validation:XValidation:rule="has(self.country) || has(self.region) || has(self.city) || has(self.asn) || has(self.isp) || has(self.anonymous)",message="at least one of country, region, city, asn, isp, or anonymous must be specified" type GeoLocation struct { - // Country is the country associated with the client IP. + // Country is the country ISO code associated with the client IP. // // +optional + // +kubebuilder:validation:MinLength=2 + // +kubebuilder:validation:MaxLength=2 + // +kubebuilder:validation:Pattern=`^[A-Za-z]{2}$` Country *string `json:"country,omitempty"` - // Region is the region associated with the client IP. + // Region is the region ISO code associated with the client IP. // // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=16 + // +kubebuilder:validation:Pattern=`^[A-Za-z0-9-]+$` Region *string `json:"region,omitempty"` // City is the city associated with the client IP. // // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=128 City *string `json:"city,omitempty"` // ASN is the autonomous system number associated with the client IP. // // +optional + // +kubebuilder:validation:Minimum=1 ASN *uint32 `json:"asn,omitempty"` // ISP is the internet service provider associated with the client IP. // // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=256 ISP *string `json:"isp,omitempty"` // Anonymous matches anonymous network detection signals. diff --git a/api/v1alpha1/geoip_types.go b/api/v1alpha1/geoip_types.go index e3c55958c5..ac9ce1d217 100644 --- a/api/v1alpha1/geoip_types.go +++ b/api/v1alpha1/geoip_types.go @@ -61,42 +61,11 @@ type GeoIPMaxMind struct { AnonymousIPDBPath *string `json:"anonymousIpDbPath,omitempty"` } -// GeoIPRegion selects a region within a country. -// +kubebuilder:validation:XValidation:rule="has(self.countryCode) && has(self.regionCode)",message="countryCode and regionCode must both be set" -type GeoIPRegion struct { - // CountryCode is the ISO 3166-1 alpha-2 country code. - // - // +kubebuilder:validation:Pattern=`^[A-Z]{2}$` - CountryCode string `json:"countryCode"` - - // RegionCode is the ISO 3166-2 subdivision code (without country prefix). - // - // +kubebuilder:validation:MinLength=1 - // +kubebuilder:validation:MaxLength=32 - RegionCode string `json:"regionCode"` -} - -// GeoIPCity selects a city, optionally scoped to a region. -// +kubebuilder:validation:XValidation:rule="has(self.countryCode) && has(self.cityName)",message="countryCode and cityName must be set" -type GeoIPCity struct { - // CountryCode is the ISO 3166-1 alpha-2 country code. - // - // +kubebuilder:validation:Pattern=`^[A-Z]{2}$` - CountryCode string `json:"countryCode"` - - // RegionCode optionally scopes the city to a subdivision (ISO 3166-2 without country prefix). - // - // +optional - // +kubebuilder:validation:MaxLength=32 - RegionCode *string `json:"regionCode,omitempty"` - - // CityName is the city name. - // - // +kubebuilder:validation:MinLength=1 - CityName string `json:"cityName"` -} - // GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. +// If multiple fields are specified, all specified fields must match. +// These signals are not mutually exclusive. A single IP may satisfy multiple +// flags at the same time (for example, a commercial VPN exit IP may also be +// classified as a public proxy, so both IsVPN and IsProxy can be true). // // +kubebuilder:validation:XValidation:rule="has(self.isAnonymous) || has(self.isVPN) || has(self.isHosting) || has(self.isTor) || has(self.isProxy)",message="at least one of isAnonymous, isVPN, isHosting, isTor, or isProxy must be specified" type GeoIPAnonymousMatch struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 21e4b202fc..292309d8a7 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3519,26 +3519,6 @@ func (in *GeoIPAnonymousMatch) DeepCopy() *GeoIPAnonymousMatch { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPCity) DeepCopyInto(out *GeoIPCity) { - *out = *in - if in.RegionCode != nil { - in, out := &in.RegionCode, &out.RegionCode - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPCity. -func (in *GeoIPCity) DeepCopy() *GeoIPCity { - if in == nil { - return nil - } - out := new(GeoIPCity) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GeoIPMaxMind) DeepCopyInto(out *GeoIPMaxMind) { *out = *in @@ -3599,21 +3579,6 @@ func (in *GeoIPProvider) DeepCopy() *GeoIPProvider { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPRegion) DeepCopyInto(out *GeoIPRegion) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPRegion. -func (in *GeoIPRegion) DeepCopy() *GeoIPRegion { - if in == nil { - return nil - } - out := new(GeoIPRegion) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GeoLocation) DeepCopyInto(out *GeoLocation) { *out = *in diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 7d1ade04e0..a86c9c1dd6 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -534,7 +534,6 @@ spec: asnDbPath: description: ASNDBPath is the path to the ASN database (.mmdb). - pattern: ^.*\\.mmdb$ type: string cityDbPath: description: CityDBPath is the path to the City database diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index e18d0527b9..edbcdec6b8 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -315,22 +315,33 @@ spec: description: ASN is the autonomous system number associated with the client IP. format: int32 + minimum: 1 type: integer city: description: City is the city associated with the client IP. + maxLength: 128 + minLength: 1 type: string country: - description: Country is the country associated + description: Country is the country ISO code associated with the client IP. + maxLength: 2 + minLength: 2 + pattern: ^[A-Za-z]{2}$ type: string isp: description: ISP is the internet service provider associated with the client IP. + maxLength: 256 + minLength: 1 type: string region: - description: Region is the region associated with - the client IP. + description: Region is the region ISO code associated + with the client IP. + maxLength: 16 + minLength: 1 + pattern: ^[A-Za-z0-9-]+$ type: string type: object x-kubernetes-validations: diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 74f737ab2f..60820702bb 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -533,7 +533,6 @@ spec: asnDbPath: description: ASNDBPath is the path to the ASN database (.mmdb). - pattern: ^.*\\.mmdb$ type: string cityDbPath: description: CityDBPath is the path to the City database diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 1e35021c86..7cdb21f9a2 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -314,22 +314,33 @@ spec: description: ASN is the autonomous system number associated with the client IP. format: int32 + minimum: 1 type: integer city: description: City is the city associated with the client IP. + maxLength: 128 + minLength: 1 type: string country: - description: Country is the country associated + description: Country is the country ISO code associated with the client IP. + maxLength: 2 + minLength: 2 + pattern: ^[A-Za-z]{2}$ type: string isp: description: ISP is the internet service provider associated with the client IP. + maxLength: 256 + minLength: 1 type: string region: - description: Region is the region associated with - the client IP. + description: Region is the region ISO code associated + with the client IP. + maxLength: 16 + minLength: 1 + pattern: ^[A-Za-z0-9-]+$ type: string type: object x-kubernetes-validations: diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index accb4c6e70..f50b2555f0 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2371,6 +2371,10 @@ _Appears in:_ GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. +If multiple fields are specified, all specified fields must match. +These signals are not mutually exclusive. A single IP may satisfy multiple +flags at the same time (for example, a commercial VPN exit IP may also be +classified as a public proxy, so both IsVPN and IsProxy can be true). _Appears in:_ - [GeoLocation](#geolocation) @@ -2384,8 +2388,6 @@ _Appears in:_ | `isProxy` | _boolean_ | false | | IsProxy matches whether the client IP belongs to a public proxy. | - - #### GeoIPMaxMind @@ -2434,8 +2436,6 @@ _Appears in:_ | `MaxMind` | GeoIPProviderTypeMaxMind configures Envoy with the MaxMind provider pointing to local files.
| - - #### GeoLocation @@ -2447,8 +2447,8 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `country` | _string_ | false | | Country is the country associated with the client IP. | -| `region` | _string_ | false | | Region is the region associated with the client IP. | +| `country` | _string_ | false | | Country is the country ISO code associated with the client IP. | +| `region` | _string_ | false | | Region is the region ISO code associated with the client IP. | | `city` | _string_ | false | | City is the city associated with the client IP. | | `asn` | _integer_ | false | | ASN is the autonomous system number associated with the client IP. | | `isp` | _string_ | false | | ISP is the internet service provider associated with the client IP. | diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 42f022d315..dbbfec241b 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -30884,7 +30884,6 @@ spec: asnDbPath: description: ASNDBPath is the path to the ASN database (.mmdb). - pattern: ^.*\\.mmdb$ type: string cityDbPath: description: CityDBPath is the path to the City database @@ -48194,115 +48193,85 @@ spec: type: string minItems: 1 type: array - geoLocation: - description: GeoLocation authorizes the request based - on geolocation metadata derived from the client IP. - properties: - anonymous: - description: Anonymous matches anonymous network - detection signals. - properties: - isAnonymous: - description: IsAnonymous matches whether the - client IP is considered anonymous. - type: boolean - isHosting: - description: IsHosting matches whether the client - IP belongs to a hosting provider. - type: boolean - isProxy: - description: IsProxy matches whether the client - IP belongs to a public proxy. - type: boolean - isTor: - description: IsTor matches whether the client - IP belongs to a Tor exit node. - type: boolean - isVPN: - description: IsVPN matches whether the client - IP is detected as VPN. - type: boolean - type: object - asns: - description: ASNs matches the autonomous system - numbers associated with the client IP. - items: - format: int32 - type: integer - minItems: 1 - type: array - cities: - description: Cities refines matching to specific - city names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. + geoLocations: + description: |- + GeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + items: + description: GeoLocation specifies geolocation-based + match criteria for authorization. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes - the city to a subdivision (ISO 3166-2 without - country prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the + client IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean type: object x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - minItems: 1 - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: + - message: at least one of isAnonymous, isVPN, + isHosting, isTor, or isProxy must be specified + rule: has(self.isAnonymous) || has(self.isVPN) + || has(self.isHosting) || has(self.isTor) + || has(self.isProxy) + asn: + description: ASN is the autonomous system number + associated with the client IP. + format: int32 + minimum: 1 + type: integer + city: + description: City is the city associated with + the client IP. + maxLength: 128 + minLength: 1 type: string - minItems: 1 - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within - a country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 - subdivision code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both - be set - rule: has(self.countryCode) && has(self.regionCode) - minItems: 1 - type: array - type: object - x-kubernetes-validations: - - message: at least one of countries, regions, cities, - asns, or anonymous must be specified - rule: (has(self.countries) || has(self.regions) || - has(self.cities) || has(self.asns) || has(self.anonymous)) + country: + description: Country is the country ISO code associated + with the client IP. + maxLength: 2 + minLength: 2 + pattern: ^[A-Za-z]{2}$ + type: string + isp: + description: ISP is the internet service provider + associated with the client IP. + maxLength: 256 + minLength: 1 + type: string + region: + description: Region is the region ISO code associated + with the client IP. + maxLength: 16 + minLength: 1 + pattern: ^[A-Za-z0-9-]+$ + type: string + type: object + x-kubernetes-validations: + - message: at least one of country, region, city, + asn, isp, or anonymous must be specified + rule: has(self.country) || has(self.region) || has(self.city) + || has(self.asn) || has(self.isp) || has(self.anonymous) + minItems: 1 + type: array headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -48446,9 +48415,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocation must be specified + geoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocation)) + || has(self.geoLocations)) required: - action - principal diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index bfb02dc97e..bdf1f31851 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -8865,7 +8865,6 @@ spec: asnDbPath: description: ASNDBPath is the path to the ASN database (.mmdb). - pattern: ^.*\\.mmdb$ type: string cityDbPath: description: CityDBPath is the path to the City database @@ -26175,115 +26174,85 @@ spec: type: string minItems: 1 type: array - geoLocation: - description: GeoLocation authorizes the request based - on geolocation metadata derived from the client IP. - properties: - anonymous: - description: Anonymous matches anonymous network - detection signals. - properties: - isAnonymous: - description: IsAnonymous matches whether the - client IP is considered anonymous. - type: boolean - isHosting: - description: IsHosting matches whether the client - IP belongs to a hosting provider. - type: boolean - isProxy: - description: IsProxy matches whether the client - IP belongs to a public proxy. - type: boolean - isTor: - description: IsTor matches whether the client - IP belongs to a Tor exit node. - type: boolean - isVPN: - description: IsVPN matches whether the client - IP is detected as VPN. - type: boolean - type: object - asns: - description: ASNs matches the autonomous system - numbers associated with the client IP. - items: - format: int32 - type: integer - minItems: 1 - type: array - cities: - description: Cities refines matching to specific - city names. - items: - description: GeoIPCity selects a city, optionally - scoped to a region. + geoLocations: + description: |- + GeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + items: + description: GeoLocation specifies geolocation-based + match criteria for authorization. + properties: + anonymous: + description: Anonymous matches anonymous network + detection signals. properties: - cityName: - description: CityName is the city name. - minLength: 1 - type: string - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode optionally scopes - the city to a subdivision (ISO 3166-2 without - country prefix). - maxLength: 32 - type: string - required: - - cityName - - countryCode + isAnonymous: + description: IsAnonymous matches whether the + client IP is considered anonymous. + type: boolean + isHosting: + description: IsHosting matches whether the + client IP belongs to a hosting provider. + type: boolean + isProxy: + description: IsProxy matches whether the client + IP belongs to a public proxy. + type: boolean + isTor: + description: IsTor matches whether the client + IP belongs to a Tor exit node. + type: boolean + isVPN: + description: IsVPN matches whether the client + IP is detected as VPN. + type: boolean type: object x-kubernetes-validations: - - message: countryCode and cityName must be set - rule: has(self.countryCode) && has(self.cityName) - minItems: 1 - type: array - countries: - description: Countries is a list of ISO 3166-1 alpha-2 - country codes. - items: + - message: at least one of isAnonymous, isVPN, + isHosting, isTor, or isProxy must be specified + rule: has(self.isAnonymous) || has(self.isVPN) + || has(self.isHosting) || has(self.isTor) + || has(self.isProxy) + asn: + description: ASN is the autonomous system number + associated with the client IP. + format: int32 + minimum: 1 + type: integer + city: + description: City is the city associated with + the client IP. + maxLength: 128 + minLength: 1 type: string - minItems: 1 - type: array - regions: - description: Regions refines matching to ISO 3166-2 - subdivisions. - items: - description: GeoIPRegion selects a region within - a country. - properties: - countryCode: - description: CountryCode is the ISO 3166-1 - alpha-2 country code. - pattern: ^[A-Z]{2}$ - type: string - regionCode: - description: RegionCode is the ISO 3166-2 - subdivision code (without country prefix). - maxLength: 32 - minLength: 1 - type: string - required: - - countryCode - - regionCode - type: object - x-kubernetes-validations: - - message: countryCode and regionCode must both - be set - rule: has(self.countryCode) && has(self.regionCode) - minItems: 1 - type: array - type: object - x-kubernetes-validations: - - message: at least one of countries, regions, cities, - asns, or anonymous must be specified - rule: (has(self.countries) || has(self.regions) || - has(self.cities) || has(self.asns) || has(self.anonymous)) + country: + description: Country is the country ISO code associated + with the client IP. + maxLength: 2 + minLength: 2 + pattern: ^[A-Za-z]{2}$ + type: string + isp: + description: ISP is the internet service provider + associated with the client IP. + maxLength: 256 + minLength: 1 + type: string + region: + description: Region is the region ISO code associated + with the client IP. + maxLength: 16 + minLength: 1 + pattern: ^[A-Za-z0-9-]+$ + type: string + type: object + x-kubernetes-validations: + - message: at least one of country, region, city, + asn, isp, or anonymous must be specified + rule: has(self.country) || has(self.region) || has(self.city) + || has(self.asn) || has(self.isp) || has(self.anonymous) + minItems: 1 + type: array headers: description: |- Headers authorize the request based on user identity extracted from custom headers. @@ -26427,9 +26396,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocation must be specified + geoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocation)) + || has(self.geoLocations)) required: - action - principal From f9e294265d6d39b62700cfd79aa40a6270af4238 Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Thu, 26 Feb 2026 15:39:19 +0800 Subject: [PATCH 5/9] add db source type Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/envoyproxy_types.go | 1 + api/v1alpha1/geoip_types.go | 58 +++++-- api/v1alpha1/zz_generated.deepcopy.go | 93 ++++++++--- .../gateway.envoyproxy.io_envoyproxies.yaml | 154 ++++++++++++++---- .../gateway.envoyproxy.io_envoyproxies.yaml | 154 ++++++++++++++---- site/content/en/latest/api/extension_types.md | 52 +++++- test/helm/gateway-crds-helm/all.out.yaml | 154 ++++++++++++++---- .../envoy-gateway-crds.out.yaml | 154 ++++++++++++++---- 8 files changed, 657 insertions(+), 163 deletions(-) diff --git a/api/v1alpha1/envoyproxy_types.go b/api/v1alpha1/envoyproxy_types.go index bf74c9cb4e..ad08058116 100644 --- a/api/v1alpha1/envoyproxy_types.go +++ b/api/v1alpha1/envoyproxy_types.go @@ -202,6 +202,7 @@ type EnvoyProxySpec struct { // GeoIP defines shared GeoIP provider configuration for this EnvoyProxy fleet. // // +optional + // +notImplementedHide GeoIP *EnvoyProxyGeoIP `json:"geoIP,omitempty"` } diff --git a/api/v1alpha1/geoip_types.go b/api/v1alpha1/geoip_types.go index ac9ce1d217..05c35277b8 100644 --- a/api/v1alpha1/geoip_types.go +++ b/api/v1alpha1/geoip_types.go @@ -6,7 +6,7 @@ package v1alpha1 // GeoIPProvider defines provider-specific settings. -// +kubebuilder:validation:XValidation:rule="self.type == 'MaxMind' ? has(self.MaxMind) : true",message="MaxMind must be set when type is MaxMind" +// +kubebuilder:validation:XValidation:rule="self.type == 'MaxMind' ? has(self.maxMind) : true",message="maxMind must be set when type is MaxMind" type GeoIPProvider struct { // +kubebuilder:validation:Enum=MaxMind // +kubebuilder:validation:Required @@ -15,7 +15,7 @@ type GeoIPProvider struct { // MaxMind configures the MaxMind provider. // // +optional - MaxMind *GeoIPMaxMind `json:"MaxMind,omitempty"` + MaxMind *GeoIPMaxMind `json:"maxMind,omitempty"` } // GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. @@ -28,39 +28,63 @@ const ( // GeoIPMaxMind configures the MaxMind provider. // These database files are expected to be mounted into the Envoy container, and a sidecar container can be used to update the database files. -// +kubebuilder:validation:XValidation:rule="has(self.cityDbPath) || has(self.countryDbPath) || has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath)",message="At least one MaxMind database path must be specified" +// +kubebuilder:validation:XValidation:rule="has(self.cityDbSource) || has(self.countryDbSource) || has(self.asnDbSource) || has(self.ispDbSource) || has(self.anonymousIpDbSource)",message="at least one MaxMind database source must be specified" type GeoIPMaxMind struct { - // CityDBPath is the path to the City database (.mmdb). + // CityDBSource configures the City database source. // // +optional - // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` - CityDBPath *string `json:"cityDbPath,omitempty"` + CityDBSource *GeoIPDBSource `json:"cityDbSource,omitempty"` - // CountryDBPath is the path to the Country database (.mmdb). + // CountryDBSource configures the Country database source. // // +optional - // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` - CountryDBPath *string `json:"countryDbPath,omitempty"` + CountryDBSource *GeoIPDBSource `json:"countryDbSource,omitempty"` - // ASNDBPath is the path to the ASN database (.mmdb). + // ASNDBSource configures the ASN database source. // // +optional - // +kubebuilder:validation:P attern=`^.*\\.mmdb$` - ASNDBPath *string `json:"asnDbPath,omitempty"` + ASNDBSource *GeoIPDBSource `json:"asnDbSource,omitempty"` - // ISPDBPath is the path to the ISP database (.mmdb). + // ISPDBSource configures the ISP database source. // // +optional - // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` - ISPDBPath *string `json:"ispDbPath,omitempty"` + ISPDBSource *GeoIPDBSource `json:"ispDbSource,omitempty"` + + // AnonymousIPDBSource configures the Anonymous IP database source. + // + // +optional + AnonymousIPDBSource *GeoIPDBSource `json:"anonymousIpDbSource,omitempty"` +} - // AnonymousIPDBPath is the path to the Anonymous IP database (.mmdb). +// GeoIPDBSource defines where a GeoIP .mmdb database can be loaded from. +// +union +// +kubebuilder:validation:XValidation:rule="has(self.local) || has(self.remote)",message="at least one of local or remote must be specified" +type GeoIPDBSource struct { + // Local is a database source from a local file. // // +optional + Local *LocalGeoIPDBSource `json:"local,omitempty"` + + // Remote is a database source fetched from a remote URL. + // TODO: implement this in the future + // +notImplementedHide + // +optional + Remote *RemoteGeoIPDBSource `json:"remote,omitempty"` +} + +// LocalGeoIPDBSource configures a GeoIP database from a local file path. +type LocalGeoIPDBSource struct { + // Path is the path to the database file. + // // +kubebuilder:validation:Pattern=`^.*\\.mmdb$` - AnonymousIPDBPath *string `json:"anonymousIpDbPath,omitempty"` + Path string `json:"path"` } +// RemoteGeoIPDBSource configures a GeoIP database fetched from a remote URL. +// TODO: implement this in the future +// +notImplementedHide +type RemoteGeoIPDBSource struct{} + // GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. // If multiple fields are specified, all specified fields must match. // These signals are not mutually exclusive. A single IP may satisfy multiple diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 292309d8a7..6358613a83 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3520,32 +3520,57 @@ func (in *GeoIPAnonymousMatch) DeepCopy() *GeoIPAnonymousMatch { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoIPMaxMind) DeepCopyInto(out *GeoIPMaxMind) { +func (in *GeoIPDBSource) DeepCopyInto(out *GeoIPDBSource) { *out = *in - if in.CityDBPath != nil { - in, out := &in.CityDBPath, &out.CityDBPath - *out = new(string) + if in.Local != nil { + in, out := &in.Local, &out.Local + *out = new(LocalGeoIPDBSource) **out = **in } - if in.CountryDBPath != nil { - in, out := &in.CountryDBPath, &out.CountryDBPath - *out = new(string) + if in.Remote != nil { + in, out := &in.Remote, &out.Remote + *out = new(RemoteGeoIPDBSource) **out = **in } - if in.ASNDBPath != nil { - in, out := &in.ASNDBPath, &out.ASNDBPath - *out = new(string) - **out = **in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPDBSource. +func (in *GeoIPDBSource) DeepCopy() *GeoIPDBSource { + if in == nil { + return nil } - if in.ISPDBPath != nil { - in, out := &in.ISPDBPath, &out.ISPDBPath - *out = new(string) - **out = **in + out := new(GeoIPDBSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeoIPMaxMind) DeepCopyInto(out *GeoIPMaxMind) { + *out = *in + if in.CityDBSource != nil { + in, out := &in.CityDBSource, &out.CityDBSource + *out = new(GeoIPDBSource) + (*in).DeepCopyInto(*out) } - if in.AnonymousIPDBPath != nil { - in, out := &in.AnonymousIPDBPath, &out.AnonymousIPDBPath - *out = new(string) - **out = **in + if in.CountryDBSource != nil { + in, out := &in.CountryDBSource, &out.CountryDBSource + *out = new(GeoIPDBSource) + (*in).DeepCopyInto(*out) + } + if in.ASNDBSource != nil { + in, out := &in.ASNDBSource, &out.ASNDBSource + *out = new(GeoIPDBSource) + (*in).DeepCopyInto(*out) + } + if in.ISPDBSource != nil { + in, out := &in.ISPDBSource, &out.ISPDBSource + *out = new(GeoIPDBSource) + (*in).DeepCopyInto(*out) + } + if in.AnonymousIPDBSource != nil { + in, out := &in.AnonymousIPDBSource, &out.AnonymousIPDBSource + *out = new(GeoIPDBSource) + (*in).DeepCopyInto(*out) } } @@ -5279,6 +5304,21 @@ func (in *LoadBalancer) DeepCopy() *LoadBalancer { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LocalGeoIPDBSource) DeepCopyInto(out *LocalGeoIPDBSource) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalGeoIPDBSource. +func (in *LocalGeoIPDBSource) DeepCopy() *LocalGeoIPDBSource { + if in == nil { + return nil + } + out := new(LocalGeoIPDBSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LocalJWKS) DeepCopyInto(out *LocalJWKS) { *out = *in @@ -6883,6 +6923,21 @@ func (in *RedisTLSSettings) DeepCopy() *RedisTLSSettings { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RemoteGeoIPDBSource) DeepCopyInto(out *RemoteGeoIPDBSource) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteGeoIPDBSource. +func (in *RemoteGeoIPDBSource) DeepCopy() *RemoteGeoIPDBSource { + if in == nil { + return nil + } + out := new(RemoteGeoIPDBSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RemoteJWKS) DeepCopyInto(out *RemoteJWKS) { *out = *in diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index a86c9c1dd6..9eee6425b2 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -523,38 +523,132 @@ spec: description: Provider defines the GeoIP provider configuration used by GeoIP filter instances. properties: - MaxMind: + maxMind: description: MaxMind configures the MaxMind provider. properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string + anonymousIpDbSource: + description: AnonymousIPDBSource configures the Anonymous + IP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + asnDbSource: + description: ASNDBSource configures the ASN database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + cityDbSource: + description: CityDBSource configures the City database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + countryDbSource: + description: CountryDBSource configures the Country database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + ispDbSource: + description: ISPDBSource configures the ISP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + - message: at least one MaxMind database source must be specified + rule: has(self.cityDbSource) || has(self.countryDbSource) + || has(self.asnDbSource) || has(self.ispDbSource) || has(self.anonymousIpDbSource) type: description: GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. @@ -565,8 +659,8 @@ spec: - type type: object x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + - message: maxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.maxMind) : true' required: - provider type: object diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 60820702bb..0a01bb9853 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -522,38 +522,132 @@ spec: description: Provider defines the GeoIP provider configuration used by GeoIP filter instances. properties: - MaxMind: + maxMind: description: MaxMind configures the MaxMind provider. properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string + anonymousIpDbSource: + description: AnonymousIPDBSource configures the Anonymous + IP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + asnDbSource: + description: ASNDBSource configures the ASN database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + cityDbSource: + description: CityDBSource configures the City database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + countryDbSource: + description: CountryDBSource configures the Country database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + ispDbSource: + description: ISPDBSource configures the ISP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + - message: at least one MaxMind database source must be specified + rule: has(self.cityDbSource) || has(self.countryDbSource) + || has(self.asnDbSource) || has(self.ispDbSource) || has(self.anonymousIpDbSource) type: description: GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. @@ -564,8 +658,8 @@ spec: - type type: object x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + - message: maxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.maxMind) : true' required: - provider type: object diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index f50b2555f0..89ab15e182 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1933,7 +1933,6 @@ _Appears in:_ | `preserveRouteOrder` | _boolean_ | false | | PreserveRouteOrder determines if the order of matching for HTTPRoutes is determined by Gateway-API
specification (https://gateway-api.sigs.k8s.io/reference/1.4/spec/#httprouterule)
or preserves the order defined by users in the HTTPRoute's HTTPRouteRule list.
Default: False | | `luaValidation` | _[LuaValidation](#luavalidation)_ | false | | LuaValidation determines strictness of the Lua script validation for Lua EnvoyExtensionPolicies
Default: Strict | | `dynamicModules` | _[DynamicModuleEntry](#dynamicmoduleentry) array_ | false | | DynamicModules defines the set of dynamic modules that are allowed to be
used by EnvoyExtensionPolicy resources. Each entry registers a module by
a logical name and specifies the shared library that Envoy will load.
The EnvoyProxy owner is responsible for ensuring the module .so files are available
on the proxy container's filesystem (e.g., via init containers, custom images,
or shared volumes). | -| `geoIP` | _[EnvoyProxyGeoIP](#envoyproxygeoip)_ | false | | GeoIP defines shared GeoIP provider configuration for this EnvoyProxy fleet. | #### EnvoyProxyStatus @@ -2388,6 +2387,20 @@ _Appears in:_ | `isProxy` | _boolean_ | false | | IsProxy matches whether the client IP belongs to a public proxy. | +#### GeoIPDBSource + + + +GeoIPDBSource defines where a GeoIP .mmdb database can be loaded from. + +_Appears in:_ +- [GeoIPMaxMind](#geoipmaxmind) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `local` | _[LocalGeoIPDBSource](#localgeoipdbsource)_ | false | | Local is a database source from a local file. | + + #### GeoIPMaxMind @@ -2400,11 +2413,11 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `cityDbPath` | _string_ | false | | CityDBPath is the path to the City database (.mmdb). | -| `countryDbPath` | _string_ | false | | CountryDBPath is the path to the Country database (.mmdb). | -| `asnDbPath` | _string_ | false | | ASNDBPath is the path to the ASN database (.mmdb). | -| `ispDbPath` | _string_ | false | | ISPDBPath is the path to the ISP database (.mmdb). | -| `anonymousIpDbPath` | _string_ | false | | AnonymousIPDBPath is the path to the Anonymous IP database (.mmdb). | +| `cityDbSource` | _[GeoIPDBSource](#geoipdbsource)_ | false | | CityDBSource configures the City database source. | +| `countryDbSource` | _[GeoIPDBSource](#geoipdbsource)_ | false | | CountryDBSource configures the Country database source. | +| `asnDbSource` | _[GeoIPDBSource](#geoipdbsource)_ | false | | ASNDBSource configures the ASN database source. | +| `ispDbSource` | _[GeoIPDBSource](#geoipdbsource)_ | false | | ISPDBSource configures the ISP database source. | +| `anonymousIpDbSource` | _[GeoIPDBSource](#geoipdbsource)_ | false | | AnonymousIPDBSource configures the Anonymous IP database source. | #### GeoIPProvider @@ -2419,7 +2432,7 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `type` | _[GeoIPProviderType](#geoipprovidertype)_ | true | | | -| `MaxMind` | _[GeoIPMaxMind](#geoipmaxmind)_ | false | | MaxMind configures the MaxMind provider. | +| `maxMind` | _[GeoIPMaxMind](#geoipmaxmind)_ | false | | MaxMind configures the MaxMind provider. | #### GeoIPProviderType @@ -3587,6 +3600,20 @@ _Appears in:_ | `RoundRobin` | RoundRobinLoadBalancerType load balancer policy.
| +#### LocalGeoIPDBSource + + + +LocalGeoIPDBSource configures a GeoIP database from a local file path. + +_Appears in:_ +- [GeoIPDBSource](#geoipdbsource) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | _string_ | true | | Path is the path to the database file. | + + #### LocalJWKS @@ -4890,6 +4917,17 @@ _Appears in:_ | `certificateRef` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/reference/1.4/spec/#secretobjectreference)_ | false | | CertificateRef defines the client certificate reference for TLS connections.
Currently only a Kubernetes Secret of type TLS is supported. | +#### RemoteGeoIPDBSource + + + +RemoteGeoIPDBSource configures a GeoIP database fetched from a remote URL. + +_Appears in:_ +- [GeoIPDBSource](#geoipdbsource) + + + #### RemoteJWKS diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index dbbfec241b..e2b9effda9 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -30873,38 +30873,132 @@ spec: description: Provider defines the GeoIP provider configuration used by GeoIP filter instances. properties: - MaxMind: + maxMind: description: MaxMind configures the MaxMind provider. properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string + anonymousIpDbSource: + description: AnonymousIPDBSource configures the Anonymous + IP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + asnDbSource: + description: ASNDBSource configures the ASN database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + cityDbSource: + description: CityDBSource configures the City database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + countryDbSource: + description: CountryDBSource configures the Country database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + ispDbSource: + description: ISPDBSource configures the ISP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + - message: at least one MaxMind database source must be specified + rule: has(self.cityDbSource) || has(self.countryDbSource) + || has(self.asnDbSource) || has(self.ispDbSource) || has(self.anonymousIpDbSource) type: description: GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. @@ -30915,8 +31009,8 @@ spec: - type type: object x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + - message: maxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.maxMind) : true' required: - provider type: object diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index bdf1f31851..bff7c571fa 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -8854,38 +8854,132 @@ spec: description: Provider defines the GeoIP provider configuration used by GeoIP filter instances. properties: - MaxMind: + maxMind: description: MaxMind configures the MaxMind provider. properties: - anonymousIpDbPath: - description: AnonymousIPDBPath is the path to the Anonymous - IP database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - asnDbPath: - description: ASNDBPath is the path to the ASN database - (.mmdb). - type: string - cityDbPath: - description: CityDBPath is the path to the City database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - countryDbPath: - description: CountryDBPath is the path to the Country - database (.mmdb). - pattern: ^.*\\.mmdb$ - type: string - ispDbPath: - description: ISPDBPath is the path to the ISP database - (.mmdb). - pattern: ^.*\\.mmdb$ - type: string + anonymousIpDbSource: + description: AnonymousIPDBSource configures the Anonymous + IP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + asnDbSource: + description: ASNDBSource configures the ASN database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + cityDbSource: + description: CityDBSource configures the City database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + countryDbSource: + description: CountryDBSource configures the Country database + source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) + ispDbSource: + description: ISPDBSource configures the ISP database source. + properties: + local: + description: Local is a database source from a local + file. + properties: + path: + description: Path is the path to the database + file. + pattern: ^.*\\.mmdb$ + type: string + required: + - path + type: object + remote: + description: Remote is a database source fetched from + a remote URL. + type: object + type: object + x-kubernetes-validations: + - message: at least one of local or remote must be specified + rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - - message: At least one MaxMind database path must be specified - rule: has(self.cityDbPath) || has(self.countryDbPath) || - has(self.asnDbPath) || has(self.ispDbPath) || has(self.anonymousIpDbPath) + - message: at least one MaxMind database source must be specified + rule: has(self.cityDbSource) || has(self.countryDbSource) + || has(self.asnDbSource) || has(self.ispDbSource) || has(self.anonymousIpDbSource) type: description: GeoIPProviderType enumerates GeoIP providers supported by Envoy Gateway. @@ -8896,8 +8990,8 @@ spec: - type type: object x-kubernetes-validations: - - message: MaxMind must be set when type is MaxMind - rule: 'self.type == ''MaxMind'' ? has(self.MaxMind) : true' + - message: maxMind must be set when type is MaxMind + rule: 'self.type == ''MaxMind'' ? has(self.maxMind) : true' required: - provider type: object From c7a5b48ff1661f9299005aec39a0a80b1719c306 Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Fri, 27 Feb 2026 21:02:23 +0800 Subject: [PATCH 6/9] fix lint Signed-off-by: Huabing (Robin) Zhao --- internal/gatewayapi/securitypolicy.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 61d63cb009..c423597d0d 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -450,7 +450,8 @@ func validateSecurityPolicyForTCP(p *egv1a1.SecurityPolicy) error { if p.Spec.Authorization == nil || len(p.Spec.Authorization.Rules) == 0 { return nil } - for i, rule := range p.Spec.Authorization.Rules { + for i := range p.Spec.Authorization.Rules { + rule := &p.Spec.Authorization.Rules[i] if rule.Principal.JWT != nil { return fmt.Errorf("rule %d: JWT not supported for TCP", i) } @@ -2086,7 +2087,8 @@ func (t *Translator) buildAuthorization(policy *egv1a1.SecurityPolicy) (*ir.Auth } irAuth.DefaultAction = defaultAction - for i, rule := range authorization.Rules { + for i := range authorization.Rules { + rule := &authorization.Rules[i] irPrincipal := ir.Principal{} for _, cidr := range rule.Principal.ClientCIDRs { From 4537ceee2b9e0b90e2fcd46346938a9466b8aa64 Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Sun, 1 Mar 2026 16:46:47 +0800 Subject: [PATCH 7/9] remove remote Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/geoip_types.go | 17 +------ api/v1alpha1/zz_generated.deepcopy.go | 36 +++------------ .../gateway.envoyproxy.io_envoyproxies.yaml | 45 +++++-------------- .../gateway.envoyproxy.io_envoyproxies.yaml | 45 +++++-------------- site/content/en/latest/api/extension_types.md | 13 +----- test/helm/gateway-crds-helm/all.out.yaml | 45 +++++-------------- .../envoy-gateway-crds.out.yaml | 45 +++++-------------- 7 files changed, 48 insertions(+), 198 deletions(-) diff --git a/api/v1alpha1/geoip_types.go b/api/v1alpha1/geoip_types.go index 05c35277b8..8e42c47d78 100644 --- a/api/v1alpha1/geoip_types.go +++ b/api/v1alpha1/geoip_types.go @@ -57,19 +57,9 @@ type GeoIPMaxMind struct { } // GeoIPDBSource defines where a GeoIP .mmdb database can be loaded from. -// +union -// +kubebuilder:validation:XValidation:rule="has(self.local) || has(self.remote)",message="at least one of local or remote must be specified" type GeoIPDBSource struct { // Local is a database source from a local file. - // - // +optional - Local *LocalGeoIPDBSource `json:"local,omitempty"` - - // Remote is a database source fetched from a remote URL. - // TODO: implement this in the future - // +notImplementedHide - // +optional - Remote *RemoteGeoIPDBSource `json:"remote,omitempty"` + Local LocalGeoIPDBSource `json:"local"` } // LocalGeoIPDBSource configures a GeoIP database from a local file path. @@ -80,11 +70,6 @@ type LocalGeoIPDBSource struct { Path string `json:"path"` } -// RemoteGeoIPDBSource configures a GeoIP database fetched from a remote URL. -// TODO: implement this in the future -// +notImplementedHide -type RemoteGeoIPDBSource struct{} - // GeoIPAnonymousMatch matches anonymous network signals emitted by the GeoIP provider. // If multiple fields are specified, all specified fields must match. // These signals are not mutually exclusive. A single IP may satisfy multiple diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6358613a83..393058f9dd 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3522,16 +3522,7 @@ func (in *GeoIPAnonymousMatch) DeepCopy() *GeoIPAnonymousMatch { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GeoIPDBSource) DeepCopyInto(out *GeoIPDBSource) { *out = *in - if in.Local != nil { - in, out := &in.Local, &out.Local - *out = new(LocalGeoIPDBSource) - **out = **in - } - if in.Remote != nil { - in, out := &in.Remote, &out.Remote - *out = new(RemoteGeoIPDBSource) - **out = **in - } + out.Local = in.Local } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoIPDBSource. @@ -3550,27 +3541,27 @@ func (in *GeoIPMaxMind) DeepCopyInto(out *GeoIPMaxMind) { if in.CityDBSource != nil { in, out := &in.CityDBSource, &out.CityDBSource *out = new(GeoIPDBSource) - (*in).DeepCopyInto(*out) + **out = **in } if in.CountryDBSource != nil { in, out := &in.CountryDBSource, &out.CountryDBSource *out = new(GeoIPDBSource) - (*in).DeepCopyInto(*out) + **out = **in } if in.ASNDBSource != nil { in, out := &in.ASNDBSource, &out.ASNDBSource *out = new(GeoIPDBSource) - (*in).DeepCopyInto(*out) + **out = **in } if in.ISPDBSource != nil { in, out := &in.ISPDBSource, &out.ISPDBSource *out = new(GeoIPDBSource) - (*in).DeepCopyInto(*out) + **out = **in } if in.AnonymousIPDBSource != nil { in, out := &in.AnonymousIPDBSource, &out.AnonymousIPDBSource *out = new(GeoIPDBSource) - (*in).DeepCopyInto(*out) + **out = **in } } @@ -6923,21 +6914,6 @@ func (in *RedisTLSSettings) DeepCopy() *RedisTLSSettings { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RemoteGeoIPDBSource) DeepCopyInto(out *RemoteGeoIPDBSource) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteGeoIPDBSource. -func (in *RemoteGeoIPDBSource) DeepCopy() *RemoteGeoIPDBSource { - if in == nil { - return nil - } - out := new(RemoteGeoIPDBSource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RemoteJWKS) DeepCopyInto(out *RemoteJWKS) { *out = *in diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml index 9eee6425b2..13858fa5c6 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -542,14 +542,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) asnDbSource: description: ASNDBSource configures the ASN database source. properties: @@ -565,14 +560,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) cityDbSource: description: CityDBSource configures the City database source. @@ -589,14 +579,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) countryDbSource: description: CountryDBSource configures the Country database source. @@ -613,14 +598,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) ispDbSource: description: ISPDBSource configures the ISP database source. properties: @@ -636,14 +616,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - message: at least one MaxMind database source must be specified diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 0a01bb9853..029010abf4 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -541,14 +541,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) asnDbSource: description: ASNDBSource configures the ASN database source. properties: @@ -564,14 +559,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) cityDbSource: description: CityDBSource configures the City database source. @@ -588,14 +578,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) countryDbSource: description: CountryDBSource configures the Country database source. @@ -612,14 +597,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) ispDbSource: description: ISPDBSource configures the ISP database source. properties: @@ -635,14 +615,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - message: at least one MaxMind database source must be specified diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 89ab15e182..8d4d82e157 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2398,7 +2398,7 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `local` | _[LocalGeoIPDBSource](#localgeoipdbsource)_ | false | | Local is a database source from a local file. | +| `local` | _[LocalGeoIPDBSource](#localgeoipdbsource)_ | true | | Local is a database source from a local file. | #### GeoIPMaxMind @@ -4917,17 +4917,6 @@ _Appears in:_ | `certificateRef` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/reference/1.4/spec/#secretobjectreference)_ | false | | CertificateRef defines the client certificate reference for TLS connections.
Currently only a Kubernetes Secret of type TLS is supported. | -#### RemoteGeoIPDBSource - - - -RemoteGeoIPDBSource configures a GeoIP database fetched from a remote URL. - -_Appears in:_ -- [GeoIPDBSource](#geoipdbsource) - - - #### RemoteJWKS diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index e2b9effda9..67719d81c0 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -30892,14 +30892,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) asnDbSource: description: ASNDBSource configures the ASN database source. properties: @@ -30915,14 +30910,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) cityDbSource: description: CityDBSource configures the City database source. @@ -30939,14 +30929,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) countryDbSource: description: CountryDBSource configures the Country database source. @@ -30963,14 +30948,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) ispDbSource: description: ISPDBSource configures the ISP database source. properties: @@ -30986,14 +30966,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - message: at least one MaxMind database source must be specified diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index bff7c571fa..acfb69f568 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -8873,14 +8873,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) asnDbSource: description: ASNDBSource configures the ASN database source. properties: @@ -8896,14 +8891,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) cityDbSource: description: CityDBSource configures the City database source. @@ -8920,14 +8910,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) countryDbSource: description: CountryDBSource configures the Country database source. @@ -8944,14 +8929,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) ispDbSource: description: ISPDBSource configures the ISP database source. properties: @@ -8967,14 +8947,9 @@ spec: required: - path type: object - remote: - description: Remote is a database source fetched from - a remote URL. - type: object + required: + - local type: object - x-kubernetes-validations: - - message: at least one of local or remote must be specified - rule: has(self.local) || has(self.remote) type: object x-kubernetes-validations: - message: at least one MaxMind database source must be specified From ea79be817ea949b87ac9d966755e009eb9e0d082 Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Mon, 2 Mar 2026 11:24:32 +0800 Subject: [PATCH 8/9] address comments Signed-off-by: Huabing (Robin) Zhao --- api/v1alpha1/authorization_types.go | 12 +-- api/v1alpha1/zz_generated.deepcopy.go | 96 +++++++++---------- ...ateway.envoyproxy.io_securitypolicies.yaml | 12 +-- ...ateway.envoyproxy.io_securitypolicies.yaml | 12 +-- site/content/en/latest/api/extension_types.md | 40 ++++---- test/helm/gateway-crds-helm/all.out.yaml | 12 +-- .../envoy-gateway-crds.out.yaml | 12 +-- 7 files changed, 98 insertions(+), 98 deletions(-) diff --git a/api/v1alpha1/authorization_types.go b/api/v1alpha1/authorization_types.go index 41bf413ffd..54acaa7512 100644 --- a/api/v1alpha1/authorization_types.go +++ b/api/v1alpha1/authorization_types.go @@ -72,7 +72,7 @@ type Operation struct { // or any other identity that can be extracted from a custom header. // If there are multiple principal types, all principals must match for the rule to match. // -// +kubebuilder:validation:XValidation:rule="(has(self.clientCIDRs) || has(self.jwt) || has(self.headers) || has(self.geoLocations))",message="at least one of clientCIDRs, jwt, headers, or geoLocations must be specified" +// +kubebuilder:validation:XValidation:rule="(has(self.clientCIDRs) || has(self.jwt) || has(self.headers) || has(self.clientIPGeoLocations))",message="at least one of clientCIDRs, jwt, headers, or clientIPGeoLocations must be specified" type Principal struct { // ClientCIDRs are the IP CIDR ranges of the client. // Valid examples are "192.168.1.0/24" or "2001:db8::/64" @@ -129,19 +129,19 @@ type Principal struct { // +notImplementedHide SourceCIDRs []CIDR `json:"sourceCIDRs,omitempty"` - // GeoLocations authorizes the request based on geolocation metadata derived from the client IP. - // If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + // ClientIPGeoLocations authorizes the request based on geolocation metadata derived from the client IP. + // If multiple entries are specified, one of the ClientIPGeoLocation entries must match for the rule to match. // // +optional // +kubebuilder:validation:MinItems=1 // +notImplementedHide - GeoLocations []GeoLocation `json:"geoLocations,omitempty"` + ClientIPGeoLocations []ClientIPGeoLocation `json:"clientIPGeoLocations,omitempty"` } -// GeoLocation specifies geolocation-based match criteria for authorization. +// ClientIPGeoLocation specifies geolocation-based match criteria for authorization. // // +kubebuilder:validation:XValidation:rule="has(self.country) || has(self.region) || has(self.city) || has(self.asn) || has(self.isp) || has(self.anonymous)",message="at least one of country, region, city, asn, isp, or anonymous must be specified" -type GeoLocation struct { +type ClientIPGeoLocation struct { // Country is the country ISO code associated with the client IP. // // +optional diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 393058f9dd..6a8106b2da 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1030,6 +1030,51 @@ func (in *ClientIPDetectionSettings) DeepCopy() *ClientIPDetectionSettings { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClientIPGeoLocation) DeepCopyInto(out *ClientIPGeoLocation) { + *out = *in + if in.Country != nil { + in, out := &in.Country, &out.Country + *out = new(string) + **out = **in + } + if in.Region != nil { + in, out := &in.Region, &out.Region + *out = new(string) + **out = **in + } + if in.City != nil { + in, out := &in.City, &out.City + *out = new(string) + **out = **in + } + if in.ASN != nil { + in, out := &in.ASN, &out.ASN + *out = new(uint32) + **out = **in + } + if in.ISP != nil { + in, out := &in.ISP, &out.ISP + *out = new(string) + **out = **in + } + if in.Anonymous != nil { + in, out := &in.Anonymous, &out.Anonymous + *out = new(GeoIPAnonymousMatch) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientIPGeoLocation. +func (in *ClientIPGeoLocation) DeepCopy() *ClientIPGeoLocation { + if in == nil { + return nil + } + out := new(ClientIPGeoLocation) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClientTLSSettings) DeepCopyInto(out *ClientTLSSettings) { *out = *in @@ -3595,51 +3640,6 @@ func (in *GeoIPProvider) DeepCopy() *GeoIPProvider { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GeoLocation) DeepCopyInto(out *GeoLocation) { - *out = *in - if in.Country != nil { - in, out := &in.Country, &out.Country - *out = new(string) - **out = **in - } - if in.Region != nil { - in, out := &in.Region, &out.Region - *out = new(string) - **out = **in - } - if in.City != nil { - in, out := &in.City, &out.City - *out = new(string) - **out = **in - } - if in.ASN != nil { - in, out := &in.ASN, &out.ASN - *out = new(uint32) - **out = **in - } - if in.ISP != nil { - in, out := &in.ISP, &out.ISP - *out = new(string) - **out = **in - } - if in.Anonymous != nil { - in, out := &in.Anonymous, &out.Anonymous - *out = new(GeoIPAnonymousMatch) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeoLocation. -func (in *GeoLocation) DeepCopy() *GeoLocation { - if in == nil { - return nil - } - out := new(GeoLocation) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GlobalRateLimit) DeepCopyInto(out *GlobalRateLimit) { *out = *in @@ -6011,9 +6011,9 @@ func (in *Principal) DeepCopyInto(out *Principal) { *out = make([]CIDR, len(*in)) copy(*out, *in) } - if in.GeoLocations != nil { - in, out := &in.GeoLocations, &out.GeoLocations - *out = make([]GeoLocation, len(*in)) + if in.ClientIPGeoLocations != nil { + in, out := &in.ClientIPGeoLocations, &out.ClientIPGeoLocations + *out = make([]ClientIPGeoLocation, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index edbcdec6b8..46b4aaf37b 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -272,12 +272,12 @@ spec: type: string minItems: 1 type: array - geoLocations: + clientIPGeoLocations: description: |- - GeoLocations authorizes the request based on geolocation metadata derived from the client IP. - If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + ClientIPGeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the ClientIPGeoLocation entries must match for the rule to match. items: - description: GeoLocation specifies geolocation-based + description: ClientIPGeoLocation specifies geolocation-based match criteria for authorization. properties: anonymous: @@ -494,9 +494,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocations must be specified + clientIPGeoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocations)) + || has(self.clientIPGeoLocations)) required: - action - principal diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 7cdb21f9a2..ba980299ab 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -271,12 +271,12 @@ spec: type: string minItems: 1 type: array - geoLocations: + clientIPGeoLocations: description: |- - GeoLocations authorizes the request based on geolocation metadata derived from the client IP. - If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + ClientIPGeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the ClientIPGeoLocation entries must match for the rule to match. items: - description: GeoLocation specifies geolocation-based + description: ClientIPGeoLocation specifies geolocation-based match criteria for authorization. properties: anonymous: @@ -493,9 +493,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocations must be specified + clientIPGeoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocations)) + || has(self.clientIPGeoLocations)) required: - action - principal diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 8d4d82e157..11652c8ede 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -724,6 +724,25 @@ _Appears in:_ | `customHeader` | _[CustomHeaderExtensionSettings](#customheaderextensionsettings)_ | false | | CustomHeader provides configuration for determining the client IP address for a request based on
a trusted custom HTTP header. This uses the custom_header original IP detection extension.
Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/original_ip_detection/custom_header/v3/custom_header.proto
for more details. | +#### ClientIPGeoLocation + + + +ClientIPGeoLocation specifies geolocation-based match criteria for authorization. + +_Appears in:_ +- [Principal](#principal) + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `country` | _string_ | false | | Country is the country ISO code associated with the client IP. | +| `region` | _string_ | false | | Region is the region ISO code associated with the client IP. | +| `city` | _string_ | false | | City is the city associated with the client IP. | +| `asn` | _integer_ | false | | ASN is the autonomous system number associated with the client IP. | +| `isp` | _string_ | false | | ISP is the internet service provider associated with the client IP. | +| `anonymous` | _[GeoIPAnonymousMatch](#geoipanonymousmatch)_ | false | | Anonymous matches anonymous network detection signals. | + + #### ClientTLSSettings @@ -2376,7 +2395,7 @@ flags at the same time (for example, a commercial VPN exit IP may also be classified as a public proxy, so both IsVPN and IsProxy can be true). _Appears in:_ -- [GeoLocation](#geolocation) +- [ClientIPGeoLocation](#clientipgeolocation) | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | @@ -2449,25 +2468,6 @@ _Appears in:_ | `MaxMind` | GeoIPProviderTypeMaxMind configures Envoy with the MaxMind provider pointing to local files.
| -#### GeoLocation - - - -GeoLocation specifies geolocation-based match criteria for authorization. - -_Appears in:_ -- [Principal](#principal) - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `country` | _string_ | false | | Country is the country ISO code associated with the client IP. | -| `region` | _string_ | false | | Region is the region ISO code associated with the client IP. | -| `city` | _string_ | false | | City is the city associated with the client IP. | -| `asn` | _integer_ | false | | ASN is the autonomous system number associated with the client IP. | -| `isp` | _string_ | false | | ISP is the internet service provider associated with the client IP. | -| `anonymous` | _[GeoIPAnonymousMatch](#geoipanonymousmatch)_ | false | | Anonymous matches anonymous network detection signals. | - - #### GlobalRateLimit diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 67719d81c0..e2642bcb8a 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -48262,12 +48262,12 @@ spec: type: string minItems: 1 type: array - geoLocations: + clientIPGeoLocations: description: |- - GeoLocations authorizes the request based on geolocation metadata derived from the client IP. - If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + ClientIPGeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the ClientIPGeoLocation entries must match for the rule to match. items: - description: GeoLocation specifies geolocation-based + description: ClientIPGeoLocation specifies geolocation-based match criteria for authorization. properties: anonymous: @@ -48484,9 +48484,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocations must be specified + clientIPGeoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocations)) + || has(self.clientIPGeoLocations)) required: - action - principal diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index acfb69f568..7e3e258433 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -26243,12 +26243,12 @@ spec: type: string minItems: 1 type: array - geoLocations: + clientIPGeoLocations: description: |- - GeoLocations authorizes the request based on geolocation metadata derived from the client IP. - If multiple entries are specified, one of the GeoLocation entries must match for the rule to match. + ClientIPGeoLocations authorizes the request based on geolocation metadata derived from the client IP. + If multiple entries are specified, one of the ClientIPGeoLocation entries must match for the rule to match. items: - description: GeoLocation specifies geolocation-based + description: ClientIPGeoLocation specifies geolocation-based match criteria for authorization. properties: anonymous: @@ -26465,9 +26465,9 @@ spec: type: object x-kubernetes-validations: - message: at least one of clientCIDRs, jwt, headers, or - geoLocations must be specified + clientIPGeoLocations must be specified rule: (has(self.clientCIDRs) || has(self.jwt) || has(self.headers) - || has(self.geoLocations)) + || has(self.clientIPGeoLocations)) required: - action - principal From 36fd36344e7faec67f6ec069d5c774820995ce4b Mon Sep 17 00:00:00 2001 From: "Huabing (Robin) Zhao" Date: Mon, 2 Mar 2026 11:31:02 +0800 Subject: [PATCH 9/9] fix test Signed-off-by: Huabing (Robin) Zhao --- test/cel-validation/securitypolicy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cel-validation/securitypolicy_test.go b/test/cel-validation/securitypolicy_test.go index d34fbc47bd..52c86cfbc4 100644 --- a/test/cel-validation/securitypolicy_test.go +++ b/test/cel-validation/securitypolicy_test.go @@ -1301,7 +1301,7 @@ func TestSecurityPolicyTarget(t *testing.T) { }, } }, - wantErrors: []string{"at least one of clientCIDRs, jwt, headers, or geoLocations must be specified"}, + wantErrors: []string{"at least one of clientCIDRs, jwt, headers, or clientIPGeoLocations must be specified"}, }, { desc: "authorization-jwt-claims-without-jwt-authn",