Documentation
¶
Overview ¶
Package prefixlist provides utilities for fetching and managing IP prefix lists from various cloud providers.
Example ¶
Example demonstrates basic usage of the prefix list system.
package main
import (
"context"
"fmt"
"net/netip"
"github.com/rs/zerolog"
"github.com/dioad/net/authz/prefixlist"
)
func main() {
logger := zerolog.Nop()
// Create a multi-provider with GitLab provider
gitlabProvider := prefixlist.NewGitLabProvider()
multiProvider := prefixlist.NewMultiProvider([]prefixlist.Provider{gitlabProvider}, logger)
ctx := context.Background()
_, err := multiProvider.Prefixes(ctx)
if err != nil {
panic(err)
}
// Check if an IP is in the allowed list
addr, err := netip.ParseAddr("34.74.90.65")
if err != nil {
panic(err)
}
if multiProvider.Contains(addr) {
fmt.Println("IP is allowed")
} else {
fmt.Println("IP is denied")
}
}
Output: IP is allowed
Index ¶
- func RegisterProvider(name string, constructor ProviderConstructor)
- type AWSProvider
- type AtlassianProvider
- type CloudflareProvider
- type Config
- type FastlyProvider
- type GitHubProvider
- type GitLabProvider
- type GoogleProvider
- type HTTPJSONProvider
- type HTTPTextProvider
- type HetznerProvider
- type Listener
- type MultiProvider
- type Provider
- type ProviderConfig
- type ProviderConstructor
- type TransformFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RegisterProvider ¶ added in v0.54.0
func RegisterProvider(name string, constructor ProviderConstructor)
RegisterProvider registers a provider constructor for a given provider name. The name is case-insensitive and will be normalized to lowercase.
This function is typically called in an init() function in the provider's source file. For example, to add a new provider:
func init() {
RegisterProvider("myprovider", func(cfg ProviderConfig) (Provider, error) {
// Parse configuration and create provider
return NewMyProvider(cfg.Filter["option"]), nil
})
}
This registration-based approach reduces cyclomatic complexity by eliminating the need for a large switch statement in the factory function.
Types ¶
type AWSProvider ¶
type AWSProvider struct {
*HTTPJSONProvider[awsIPRanges]
// contains filtered or unexported fields
}
AWSProvider fetches IP ranges from AWS.
func NewAWSProvider ¶
func NewAWSProvider(service, region string) *AWSProvider
NewAWSProvider creates a new AWS prefix list provider.
type AtlassianProvider ¶
type AtlassianProvider struct {
*HTTPJSONProvider[atlassianIPRanges]
// contains filtered or unexported fields
}
AtlassianProvider fetches IP ranges from Atlassian.
func NewAtlassianProvider ¶
func NewAtlassianProvider(regions, products []string) *AtlassianProvider
NewAtlassianProvider creates a new Atlassian prefix list provider regions: optional list of regions to filter by (e.g., ["global", "us-east-1"]) products: optional list of products to filter by (e.g., ["jira", "confluence"]) Only prefixes with "egress" direction are included.
type CloudflareProvider ¶
type CloudflareProvider struct {
*HTTPTextProvider
}
CloudflareProvider fetches IP ranges from Cloudflare.
func NewCloudflareProvider ¶
func NewCloudflareProvider(ipv6 bool) *CloudflareProvider
NewCloudflareProvider creates a new Cloudflare prefix list provider.
type Config ¶
type Config struct {
// Providers lists the enabled providers
Providers []ProviderConfig `mapstructure:"providers" yaml:"providers"`
}
Config represents the configuration for prefix list providers.
type FastlyProvider ¶
type FastlyProvider struct {
*HTTPJSONProvider[fastlyIPRanges]
}
FastlyProvider fetches IP ranges from Fastly CDN.
func NewFastlyProvider ¶
func NewFastlyProvider() *FastlyProvider
NewFastlyProvider creates a new Fastly prefix list provider.
type GitHubProvider ¶
type GitHubProvider struct {
*HTTPJSONProvider[githubMeta]
// contains filtered or unexported fields
}
GitHubProvider fetches IP ranges from GitHub's meta API.
func NewGitHubProvider ¶
func NewGitHubProvider(filter string) *GitHubProvider
NewGitHubProvider creates a new GitHub prefix list provider.
type GitLabProvider ¶
type GitLabProvider struct {
// contains filtered or unexported fields
}
GitLabProvider provides static IP ranges for GitLab webhooks.
func NewGitLabProvider ¶
func NewGitLabProvider() *GitLabProvider
NewGitLabProvider creates a new GitLab prefix list provider.
func (*GitLabProvider) Contains ¶
func (p *GitLabProvider) Contains(addr netip.Addr) bool
Contains reports whether addr is contained in any of the provider's prefixes.
func (*GitLabProvider) Name ¶
func (p *GitLabProvider) Name() string
Name returns the provider's name.
type GoogleProvider ¶
type GoogleProvider struct {
*HTTPJSONProvider[googleIPRanges]
// contains filtered or unexported fields
}
GoogleProvider fetches IP ranges from Google Cloud.
func NewGoogleProvider ¶
func NewGoogleProvider(scopes, services []string) *GoogleProvider
NewGoogleProvider creates a new Google Cloud prefix list provider scopes: optional list of scopes to filter by (e.g., ["us-central1", "europe-west1"]) services: optional list of services to filter by (e.g., ["Google Cloud"])
type HTTPJSONProvider ¶
type HTTPJSONProvider[T any] struct { // contains filtered or unexported fields }
HTTPJSONProvider is a generic provider that fetches JSON data and transforms it into prefixes.
func NewHTTPJSONProvider ¶
func NewHTTPJSONProvider[T any](name, url string, config httpcache.CacheConfig, transform TransformFunc[T]) *HTTPJSONProvider[T]
NewHTTPJSONProvider creates a new HTTP JSON-based provider Parameters:
- name: the name of the provider (e.g., "github", "aws")
- url: the HTTP endpoint to fetch from
- config: caching configuration
- transform: function to transform the JSON response into prefixes
func (*HTTPJSONProvider[T]) Contains ¶
func (p *HTTPJSONProvider[T]) Contains(addr netip.Addr) bool
Contains reports whether addr is contained in any of the provider's prefixes.
func (*HTTPJSONProvider[T]) Name ¶
func (p *HTTPJSONProvider[T]) Name() string
Name returns the provider's name.
type HTTPTextProvider ¶
type HTTPTextProvider struct {
// contains filtered or unexported fields
}
HTTPTextProvider is a provider for HTTP endpoints that return plain text lists of prefixes.
func NewHTTPTextProvider ¶
func NewHTTPTextProvider(name, url string, config httpcache.CacheConfig) *HTTPTextProvider
NewHTTPTextProvider creates a new HTTP text-based provider The endpoint is expected to return a plain text list of CIDR ranges (one per line).
func (*HTTPTextProvider) Contains ¶
func (p *HTTPTextProvider) Contains(addr netip.Addr) bool
Contains reports whether addr is contained in any of the provider's prefixes.
func (*HTTPTextProvider) Name ¶
func (p *HTTPTextProvider) Name() string
Name returns the provider's name.
type HetznerProvider ¶
type HetznerProvider struct {
// contains filtered or unexported fields
}
HetznerProvider provides static IP ranges for Hetzner Cloud.
func NewHetznerProvider ¶
func NewHetznerProvider() *HetznerProvider
NewHetznerProvider creates a new Hetzner prefix list provider.
func (*HetznerProvider) Contains ¶
func (p *HetznerProvider) Contains(addr netip.Addr) bool
Contains reports whether addr is contained in any of the provider's prefixes.
func (*HetznerProvider) Name ¶
func (p *HetznerProvider) Name() string
Name returns the provider's name.
type Listener ¶
type Listener struct {
// contains filtered or unexported fields
}
Listener wraps a net.Listener and filters connections based on prefix lists.
Example ¶
ExampleListener demonstrates using the prefix list listener.
package main
import (
"context"
"fmt"
"net"
"github.com/rs/zerolog"
"github.com/dioad/net/authz/prefixlist"
)
func main() {
logger := zerolog.Nop()
ctx := context.Background()
// Create a base listener
baseListener, err := (&net.ListenConfig{}).Listen(ctx, "tcp", "127.0.0.1:0")
if err != nil {
panic(err)
}
defer func() { _ = baseListener.Close() }()
// Create a multi-provider with GitLab provider
gitlabProvider := prefixlist.NewGitLabProvider()
multiProvider := prefixlist.NewMultiProvider([]prefixlist.Provider{gitlabProvider}, logger)
_, err = multiProvider.Prefixes(ctx)
if err != nil {
panic(err)
}
// Wrap with prefix list listener
plListener := prefixlist.NewListener(baseListener, multiProvider, logger)
fmt.Printf("Listening on %s with prefix list filtering\n", plListener.Addr().Network())
// Now only connections from allowed IPs will be accepted
// conn, err := plListener.Accept()
}
Output: Listening on tcp with prefix list filtering
func NewListener ¶
NewListener creates a new prefix list filtering listener.
func (*Listener) Accept ¶
Accept waits for and returns the next connection, filtering based on prefix lists.
type MultiProvider ¶
type MultiProvider struct {
// contains filtered or unexported fields
}
MultiProvider wraps multiple providers and implements the Provider interface.
func NewMultiProvider ¶
func NewMultiProvider(providers []Provider, logger zerolog.Logger) *MultiProvider
NewMultiProvider creates a new multi-provider that wraps multiple providers.
func NewMultiProviderFromConfig ¶
func NewMultiProviderFromConfig(cfg Config, logger zerolog.Logger) (*MultiProvider, error)
NewMultiProviderFromConfig creates a MultiProvider from configuration.
Example ¶
ExampleNewMultiProviderFromConfig demonstrates creating a multi-provider from configuration.
package main
import (
"context"
"fmt"
"github.com/rs/zerolog"
"github.com/dioad/net/authz/prefixlist"
)
func main() {
logger := zerolog.Nop()
config := prefixlist.Config{
Providers: []prefixlist.ProviderConfig{
{
Name: "github",
Enabled: true,
Filter: map[string]string{"service": "hooks"}, // Only GitHub webhook IPs
},
{
Name: "gitlab",
Enabled: true,
},
},
}
multiProvider, err := prefixlist.NewMultiProviderFromConfig(config, logger)
if err != nil {
panic(err)
}
ctx := context.Background()
_, err = multiProvider.Prefixes(ctx)
if err != nil {
panic(err)
}
fmt.Println("MultiProvider created with multiple providers")
}
Output: MultiProvider created with multiple providers
func (*MultiProvider) Contains ¶
func (m *MultiProvider) Contains(addr netip.Addr) bool
Contains checks if an IP address is in any of the wrapped providers' prefix lists. Like the other Provider implementations in this package, it fetches (and caches) prefixes on demand rather than requiring the caller to call Prefixes first.
func (*MultiProvider) GetPrefixes ¶
func (m *MultiProvider) GetPrefixes() []netip.Prefix
GetPrefixes returns a copy of all current prefixes.
func (*MultiProvider) Name ¶
func (m *MultiProvider) Name() string
Name returns a combined name of all providers.
type Provider ¶
type Provider interface {
// Name returns the provider name (e.g., "github", "cloudflare")
Name() string
// Prefixes returns the current list of IP prefixes from the provider
Prefixes(ctx context.Context) ([]netip.Prefix, error)
// Contains checks if an IP address is in the provider's prefix list
Contains(addr netip.Addr) bool
}
Provider defines the interface for fetching IP prefix lists from different sources.
func NewProviderFromConfig ¶
func NewProviderFromConfig(cfg ProviderConfig) (Provider, error)
NewProviderFromConfig creates a provider instance from configuration. It looks up the provider by name in the registry and invokes its constructor. The provider must be registered via RegisterProvider before it can be instantiated.
type ProviderConfig ¶
type ProviderConfig struct {
// Name is the provider name (github, cloudflare, google, atlassian, gitlab, aws)
Name string `mapstructure:"name" yaml:"name"`
// Enabled controls whether this provider is active
Enabled bool `mapstructure:"enabled" yaml:"enabled"`
// Filter optionally filters prefixes using a map of key-value pairs
// Examples:
// GitHub: {"service": "hooks"} or {"service": "actions"}
// AWS: {"service": "EC2", "region": "us-east-1"}
// Google: {"scope": "us-central1", "service": "Google Cloud"}
// Atlassian: {"region": "global", "product": "jira"}
// Cloudflare: {"version": "ipv6"}
Filter map[string]string `mapstructure:"filter" yaml:"filter,omitempty"`
}
ProviderConfig represents configuration for a single provider.
type ProviderConstructor ¶ added in v0.54.0
type ProviderConstructor func(cfg ProviderConfig) (Provider, error)
ProviderConstructor is a function that creates a Provider from configuration. It receives a ProviderConfig and returns a Provider instance or an error.
Custom providers can implement their own constructors and register them using RegisterProvider in an init() function. This allows for easy extension of the provider factory without modifying the core factory code.