Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion api/v1alpha1/authorization_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.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"
Expand Down Expand Up @@ -128,6 +128,60 @@ type Principal struct {
// +kubebuilder:validation:MinItems=1
// +notImplementedHide
SourceCIDRs []CIDR `json:"sourceCIDRs,omitempty"`

// 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
ClientIPGeoLocations []ClientIPGeoLocation `json:"clientIPGeoLocations,omitempty"`
}

// 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 ClientIPGeoLocation struct {
// 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 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.
//
// +optional
Anonymous *GeoIPAnonymousMatch `json:"anonymous,omitempty"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a list ?

Copy link
Copy Markdown
Member Author

@zhaohuabing zhaohuabing Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GeoLocations []GeoLocation supports OR, and GeoIPAnonymousMatch has multiple options which are ANDed, so we don't need a list here.

}

// AuthorizationHeaderMatch specifies how to match against the value of an HTTP header within a authorization rule.
Expand Down
12 changes: 12 additions & 0 deletions api/v1alpha1/envoyproxy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,18 @@ type EnvoyProxySpec struct {
// +listMapKey=name
// +optional
DynamicModules []DynamicModuleEntry `json:"dynamicModules,omitempty"`

// GeoIP defines shared GeoIP provider configuration for this EnvoyProxy fleet.
//
// +optional
// +notImplementedHide
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"`
Comment thread
zhaohuabing marked this conversation as resolved.
}

// +kubebuilder:validation:Enum=Strict;InsecureSyntax;Disabled
Expand Down
105 changes: 105 additions & 0 deletions api/v1alpha1/geoip_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// 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

// 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.
Comment thread
zhaohuabing marked this conversation as resolved.
// +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 {
// CityDBSource configures the City database source.
//
// +optional
CityDBSource *GeoIPDBSource `json:"cityDbSource,omitempty"`

// CountryDBSource configures the Country database source.
//
// +optional
CountryDBSource *GeoIPDBSource `json:"countryDbSource,omitempty"`

// ASNDBSource configures the ASN database source.
//
// +optional
ASNDBSource *GeoIPDBSource `json:"asnDbSource,omitempty"`

// ISPDBSource configures the ISP database source.
//
// +optional
ISPDBSource *GeoIPDBSource `json:"ispDbSource,omitempty"`

// AnonymousIPDBSource configures the Anonymous IP database source.
//
// +optional
AnonymousIPDBSource *GeoIPDBSource `json:"anonymousIpDbSource,omitempty"`
}

// GeoIPDBSource defines where a GeoIP .mmdb database can be loaded from.
type GeoIPDBSource struct {
// Local is a database source from a local file.
Local LocalGeoIPDBSource `json:"local"`
}

// 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$`
Path string `json:"path"`
}

// 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 {
// 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"`
}
Loading
Loading