cloudflare

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

internal/cloudflare/interfaces.go

Index

Constants

View Source
const (
	SecretKeyAPIToken  = "apiToken"
	SecretKeyAccountID = "accountID"
)

Secret data keys where Cloudflare credentials are expected.

Variables

View Source
var ErrPhaseEntrypointNotFound = errors.New("phase entrypoint not found")

ErrPhaseEntrypointNotFound is returned by GetPhaseEntrypoint when no entrypoint ruleset has been created yet for the requested phase. The caller should treat this as "start from scratch" and proceed to UpsertPhaseEntrypoint.

View Source
var ErrRegistryMalformed = errors.New("txt registry: malformed payload")

ErrRegistryMalformed is returned when a TXT payload cannot be parsed as an external-dns registry entry.

This error deliberately covers BOTH cases:

  1. The TXT is not an external-dns registry record at all (e.g. an SPF record, a user-managed TXT, or any other non-registry payload whose heritage key is missing or not "external-dns").
  2. The TXT looks like a registry record but is structurally invalid (e.g. missing owner, malformed resource tuple, missing '=' separator).

Callers MUST NOT try to distinguish these two cases: both mean "do not treat this TXT as ownership metadata." Wrapping them under a single sentinel keeps adoption logic simple — any error from DecodeRegistryPayload means "ignore this record for registry purposes."

View Source
var ErrSecretNotLabeled = errors.New(
	"secret exists but is not labeled cloudflare.io/managed=true")

ErrSecretNotLabeled is returned by GetCredentials when the referenced Secret exists in the API server but is missing the cloudflare.io/managed=true label, so the operator's cache filter has excluded it. Distinct from a genuine NotFound — see GetCredentials.

View Source
var ErrZoneNotFound = errors.New("zone not found")

ErrZoneNotFound is returned by GetZone when the Cloudflare API responds with 404. Callers can distinguish not-found from transient errors with errors.Is.

Functions

func AffixName added in v0.6.0

func AffixName(fqdn, recordType string, cfg AffixConfig) string

AffixName returns the companion-TXT record name for a managed record at fqdn with the given record type. Matches external-dns's default affix scheme.

func DecryptPayload added in v0.6.0

func DecryptPayload(input string, keys [][]byte) (string, error)

DecryptPayload attempts to decrypt a base64-encoded AES-256-CBC ciphertext using any key in keys (tried in order). If the input does not parse as base64 or does not look encrypted at all, it is returned verbatim (plaintext passthrough). If the input is encrypted but no key decrypts it cleanly, returns an error.

"Looks encrypted" is determined by base64 decoding successfully to at least two AES blocks (IV + one block of ciphertext).

func EncodeRegistryPayload added in v0.6.0

func EncodeRegistryPayload(p RegistryPayload) string

EncodeRegistryPayload produces the canonical quoted wire form of a RegistryPayload.

func EncryptPayload added in v0.6.0

func EncryptPayload(plaintext string, key []byte) (string, error)

EncryptPayload produces a base64-encoded AES-256-CBC ciphertext of plaintext using key. The output format is external-dns-compatible:

base64( IV[16] || PKCS#7-padded-ciphertext )

key MUST be 32 bytes (AES-256).

func IsBadRequest added in v0.12.0

func IsBadRequest(err error) bool

IsBadRequest reports whether err originated from a Cloudflare API 400 response. The user must edit the spec; the operator cannot fix this.

func IsNotFound added in v0.12.0

func IsNotFound(err error) bool

IsNotFound reports whether err originated from a Cloudflare API 404 response. Wrapped errors are unwrapped via errors.As.

func IsPermissionDenied added in v0.6.1

func IsPermissionDenied(err error) bool

IsPermissionDenied reports whether err originated from a Cloudflare API 403 response. The most common cause is a missing token scope (e.g., Zone:Bot Management Write) or a plan that does not permit the requested setting (e.g., bot_management on a Free zone). Wrapped errors are unwrapped via errors.As.

func IsPlanTierRequired added in v0.12.0

func IsPlanTierRequired(err error) bool

IsPlanTierRequired reports whether err is a Cloudflare 403 carrying an error code in planTierErrorCodes. Distinguishes plan-restricted features (e.g. BotManagement on Free) from token-permission denials.

func IsTunnelHasActiveConnections added in v0.17.0

func IsTunnelHasActiveConnections(err error) bool

IsTunnelHasActiveConnections reports whether err is a Cloudflare 400 carrying error code 1022. Cloudflare returns this when DeleteTunnel is called while cloudflared replicas are still connected. The operator handles this by scaling its managed connector Deployment to zero before calling DeleteTunnel, but a transient drain-tail can still surface this error briefly after pods exit; in that case the caller should requeue with backoff.

func NewCloudflareClient

func NewCloudflareClient(apiToken string) *cfgo.Client

NewCloudflareClient creates a new Cloudflare API client from an API token.

Types

type AffixConfig added in v0.6.0

type AffixConfig struct {
	Prefix              string
	Suffix              string
	WildcardReplacement string
}

AffixConfig controls how the companion TXT's record name is derived from the managed record's FQDN. Defaults (all empty strings) yield external-dns's default affix scheme.

type BotManagementConfig

type BotManagementConfig struct {
	EnableJS  *bool
	FightMode *bool
}

BotManagementConfig represents bot management settings. Pointer fields allow distinguishing between "unset" and "set to false".

type ClientFactory

type ClientFactory struct {
	// contains filtered or unexported fields
}

ClientFactory creates Cloudflare API clients from Kubernetes Secrets.

k8sClient is the cached client used for steady-state Secret reads. apiReader is the manager's uncached API reader, used only to disambiguate the cache-miss path (label-filtered vs. truly missing). In tests where the cache and API server are not distinguished, the same reader may be passed for both fields.

func NewClientFactory

func NewClientFactory(k8sClient client.Client, apiReader client.Reader) *ClientFactory

NewClientFactory creates a new ClientFactory. apiReader must be the manager's non-caching API reader (mgr.GetAPIReader()) so the disambiguation path bypasses the (label-filtered) cache.

func (*ClientFactory) GetAPIToken

func (f *ClientFactory) GetAPIToken(ctx context.Context, secretName, namespace string) (string, error)

GetAPIToken reads a Cloudflare API token from a Kubernetes Secret.

func (*ClientFactory) GetCredentials added in v0.5.0

func (f *ClientFactory) GetCredentials(ctx context.Context, secretName, namespace string) (Credentials, error)

GetCredentials reads the Cloudflare API token (required) and Account ID (optional, empty string if not set) from a single Kubernetes Secret.

On cache miss (k8sClient returns IsNotFound), GetCredentials does a single uncached read via apiReader to disambiguate:

  • apiReader also returns IsNotFound → the original cache error is returned (downstream surfaces ReasonSecretNotFound as today).
  • apiReader returns the Secret → the Secret exists in the API server but the cache filter has excluded it; ErrSecretNotLabeled is returned so reconcilers can surface the actionable ReasonSecretNotLabeled message.
  • apiReader returns any other error → that error is returned (rare, e.g. transient API server unavailability on the slow path).

The fallback runs only on the cache-miss path. Steady-state credential reads remain fully cached.

type Credentials added in v0.5.0

type Credentials struct {
	APIToken  string
	AccountID string
}

Credentials holds the Cloudflare API token and, optionally, the Account ID read from a single Kubernetes Secret.

type DNSClient

type DNSClient interface {
	GetRecord(ctx context.Context, zoneID, recordID string) (*DNSRecord, error)
	ListRecordsByNameAndType(ctx context.Context, zoneID, name, recordType string) ([]DNSRecord, error)
	CreateRecord(ctx context.Context, zoneID string, params DNSRecordParams) (*DNSRecord, error)
	UpdateRecord(ctx context.Context, zoneID, recordID string, params DNSRecordParams) (*DNSRecord, error)
	DeleteRecord(ctx context.Context, zoneID, recordID string) error
}

DNSClient manages Cloudflare DNS records.

func NewDNSClientFromCF

func NewDNSClientFromCF(cf *cfgo.Client) DNSClient

NewDNSClientFromCF creates a DNSClient from a cloudflare-go Client.

type DNSRecord

type DNSRecord struct {
	ID      string
	Name    string
	Type    string
	Content string
	Proxied bool
	TTL     int
	Data    map[string]any
}

DNSRecord represents a Cloudflare DNS record.

type DNSRecordParams

type DNSRecordParams struct {
	Name     string
	Type     string
	Content  string
	Proxied  *bool
	TTL      int
	Priority *int
	Data     map[string]any
}

DNSRecordParams are parameters for creating/updating a DNS record.

type RegistryPayload added in v0.6.0

type RegistryPayload struct {
	Owner           string
	SourceKind      string
	SourceNamespace string
	SourceName      string
}

RegistryPayload is the decoded external-dns-compatible TXT registry entry.

Wire format:

"heritage=external-dns,external-dns/owner=<owner>,external-dns/resource=<kind>/<ns>/<name>"

SourceKind / SourceNamespace / SourceName may be empty for legacy external-dns registry entries that only carry owner information. Callers should treat missing resource information as "adoptable but unlinked".

func DecodeRegistryPayload added in v0.6.0

func DecodeRegistryPayload(raw string) (RegistryPayload, error)

DecodeRegistryPayload parses the wire form produced by EncodeRegistryPayload. Accepts both quoted and unquoted forms (Cloudflare's DNS API sometimes strips surrounding quotes on read).

type RuleLogging added in v0.7.0

type RuleLogging struct {
	Enabled *bool
}

RuleLogging configures per-rule logging behavior. Pointer Enabled so callers can distinguish "unset" (nil) from "set to false".

type Ruleset

type Ruleset struct {
	ID          string
	Name        string
	Description string
	Phase       string
	Rules       []RulesetRule
}

Ruleset represents a Cloudflare Ruleset.

type RulesetClient

type RulesetClient interface {
	// GetPhaseEntrypoint returns the zone's entrypoint ruleset for the given
	// phase. Returns ErrPhaseEntrypointNotFound when the entrypoint has not
	// been created yet (no Update has ever been made for that phase on this
	// zone). Any other error indicates an API / transport failure.
	GetPhaseEntrypoint(ctx context.Context, zoneID, phase string) (*Ruleset, error)

	// UpsertPhaseEntrypoint writes the given rules to the zone's entrypoint
	// ruleset for the given phase. Creates the entrypoint if it does not
	// already exist, otherwise replaces its rule set.
	UpsertPhaseEntrypoint(ctx context.Context, zoneID, phase string, params RulesetParams) (*Ruleset, error)
}

RulesetClient manages a zone's phase-entrypoint rulesets.

Cloudflare has two ruleset kinds: "zone" (the phase entrypoint — one per phase per zone, what the dashboard surfaces as Security rules / Custom rules / Rate limiting rules / etc.) and "custom" (standalone rulesets, a Business+ feature). The operator manages the phase entrypoint so it works on all plans.

func NewRulesetClientFromCF

func NewRulesetClientFromCF(cf *cfgo.Client) RulesetClient

NewRulesetClientFromCF creates a RulesetClient from a cloudflare-go Client.

type RulesetParams

type RulesetParams struct {
	Name        string
	Description string
	Phase       string
	Rules       []RulesetRule
}

RulesetParams are parameters for creating/updating a ruleset.

type RulesetRule

type RulesetRule struct {
	ID               string
	Action           string
	Expression       string
	Description      string
	Enabled          bool
	ActionParameters map[string]any
	Logging          *RuleLogging
}

RulesetRule is a single rule in a ruleset.

type Tunnel

type Tunnel struct {
	ID   string
	Name string
}

Tunnel represents a Cloudflare Tunnel.

type TunnelClient

type TunnelClient interface {
	GetTunnel(ctx context.Context, accountID, tunnelID string) (*Tunnel, error)
	ListTunnelsByName(ctx context.Context, accountID, name string) ([]Tunnel, error)
	CreateTunnel(ctx context.Context, accountID string, params TunnelParams) (*Tunnel, error)
	DeleteTunnel(ctx context.Context, accountID, tunnelID string) error
}

TunnelClient manages Cloudflare Tunnels.

func NewTunnelClientFromCF

func NewTunnelClientFromCF(cf *cfgo.Client) TunnelClient

NewTunnelClientFromCF creates a TunnelClient from a cloudflare-go Client.

type TunnelParams

type TunnelParams struct {
	Name         string
	TunnelSecret string
}

TunnelParams are parameters for creating a tunnel.

type Zone

type Zone struct {
	ID                  string
	Name                string
	Status              string // initializing, pending, active, moved
	Type                string // full, partial, secondary
	Paused              bool
	NameServers         []string
	OriginalNameServers []string
	OriginalRegistrar   string
	VerificationKey     string
	ActivatedOn         *time.Time
}

Zone represents a Cloudflare Zone (lifecycle information).

type ZoneClient

type ZoneClient interface {
	GetSettings(ctx context.Context, zoneID string) ([]ZoneSetting, error)
	UpdateSetting(ctx context.Context, zoneID, settingID string, value any) error
	GetBotManagement(ctx context.Context, zoneID string) (*BotManagementConfig, error)
	UpdateBotManagement(ctx context.Context, zoneID string, config BotManagementConfig) error
}

ZoneClient manages Cloudflare Zone settings and bot management.

func NewZoneClientFromCF

func NewZoneClientFromCF(cf *cfgo.Client) ZoneClient

NewZoneClientFromCF creates a ZoneClient from a cloudflare-go Client.

type ZoneLifecycleClient

type ZoneLifecycleClient interface {
	CreateZone(ctx context.Context, accountID string, params ZoneLifecycleParams) (*Zone, error)
	GetZone(ctx context.Context, zoneID string) (*Zone, error)
	ListZonesByName(ctx context.Context, accountID, name string) ([]Zone, error)
	EditZone(ctx context.Context, zoneID string, params ZoneLifecycleEditParams) (*Zone, error)
	DeleteZone(ctx context.Context, zoneID string) error
	TriggerActivationCheck(ctx context.Context, zoneID string) error
}

ZoneLifecycleClient manages Cloudflare Zone lifecycle (create/get/list/edit/delete).

func NewZoneLifecycleClientFromCF

func NewZoneLifecycleClientFromCF(cf *cfgo.Client) ZoneLifecycleClient

NewZoneLifecycleClientFromCF creates a ZoneLifecycleClient from a cloudflare-go Client.

type ZoneLifecycleEditParams

type ZoneLifecycleEditParams struct {
	Paused *bool
}

ZoneLifecycleEditParams are parameters for editing a zone.

type ZoneLifecycleParams

type ZoneLifecycleParams struct {
	Name string
	Type string // full, partial, secondary
}

ZoneLifecycleParams are parameters for creating a zone.

type ZoneSetting

type ZoneSetting struct {
	ID    string
	Value any
}

ZoneSetting is a key-value pair for a zone setting.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL