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 faf2780f29..d7c48bc706 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3364,6 +3364,246 @@ func (in *GatewayAPIs) DeepCopy() *GatewayAPIs { 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 @@ -6839,6 +7079,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 856b1d5dc6..33961f04f1 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 @@ -2948,6 +2948,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/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 19431df117..7799aaf5b3 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -2947,6 +2947,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 e899bf38a0..da6b1a9e0a 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -230,6 +230,8 @@ AuthorizationAction defines the action to be taken if a rule matches. _Appears in:_ - [Authorization](#authorization) - [AuthorizationRule](#authorizationrule) +- [GeoIPAccessControl](#geoipaccesscontrol) +- [GeoIPRule](#geoiprule) | Value | Description | | ----- | ----------- | @@ -2300,6 +2302,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 54c86a6150..6ea0ba8ec4 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -48759,6 +48759,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 a5a4ada671..4fb224dca6 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -27939,6 +27939,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.