Documentation
¶
Overview ¶
Package kubeconfig resolves and safety-checks a source-cluster kubeconfig held in a Secret, shared by the watch data plane's SourceClusterResolver and the GitTarget controller's Validated gate so both apply exactly one contract: Flux's value→value.yaml key order, and a REJECT — not Flux's silent strip — of exec auth providers and insecure-skip-tls-verify.
It depends only on client-go's clientcmd (which this repo already has) and never dials: the safety check is a few lines over the parsed kubeconfig, deliberately not a Flux import.
Index ¶
Constants ¶
const ( // ReasonSecretNotFound: spec.kubeConfig.secretRef names a Secret that does not exist. ReasonSecretNotFound = "KubeConfigSecretNotFound" // ReasonKeyNotFound: the Secret exists but has no kubeconfig under the resolved key. ReasonKeyNotFound = "KubeConfigKeyNotFound" // ReasonInvalid: the bytes are not a parseable kubeconfig. ReasonInvalid = "KubeConfigInvalid" // ReasonExecNotAllowed: the kubeconfig carries an exec auth provider (runs a binary in // the operator Pod) and --insecure-kubeconfig-exec is not set. ReasonExecNotAllowed = "KubeConfigExecNotAllowed" // ReasonInsecureTLSNotAllowed: the kubeconfig sets insecure-skip-tls-verify and // --insecure-kubeconfig-tls is not set. ReasonInsecureTLSNotAllowed = "KubeConfigInsecureTLSNotAllowed" // ReasonFileReferenceNotAllowed: the kubeconfig names a credential or CA by file PATH // (tokenFile, client-certificate, client-key, or certificate-authority) instead of embedding // it. client-go reads those paths from the operator Pod's OWN filesystem when it builds the // REST config, so an operator-supplied (attacker-adjacent) kubeconfig could point at in-Pod // Secrets and ship them to a remote API server it names. Always rejected — there is no safe // opt-in, unlike exec/insecure-TLS: require the embedded *-data (or inline token) forms. ReasonFileReferenceNotAllowed = "KubeConfigFileReferenceNotAllowed" // ReasonInClusterNotAuthorized: a KubeProvider sets spec.inCluster, the operator's own // identity, and --in-cluster-kube-providers does not list it. ReasonInClusterNotAuthorized = "InClusterNotAuthorized" )
Reason strings map one-to-one onto the GitTarget Validated=False reasons the controller reports and the e2e plan asserts. They live here so the resolver's errors and the controller's condition reasons can never drift.
Variables ¶
This section is empty.
Functions ¶
func BuildRESTConfig ¶
func BuildRESTConfig(raw []byte, policy SafetyPolicy) (*rest.Config, error)
BuildRESTConfig parses raw kubeconfig bytes, applies the safety policy, and returns the rest.Config to reach the cluster. It is the resolver's one call: parse → reject-unsafe → build. A *RejectionError is returned (as error) when the bytes are unusable, so the caller can surface the same typed reason the controller's Validated gate does. It never dials.
func ParseInClusterProviders ¶ added in v0.54.0
func ParseInClusterProviders(value string) (map[types.NamespacedName]struct{}, error)
ParseInClusterProviders parses the --in-cluster-kube-providers value: a comma-separated list of exact namespace/name entries. Empty entries are ignored; anything else that is not one namespace/name pair is an error naming the entry.
func ResolveKey ¶
ResolveKey selects the kubeconfig bytes from a Secret's data, following Flux's order: an explicit spec key wins; otherwise "value" then "value.yaml". ok is false when no candidate key holds a non-empty value — the caller reports ReasonKeyNotFound. usedKey is the key the bytes came from, for legible messages.
Types ¶
type RejectionError ¶
RejectionError is a typed, legible reason a kubeconfig was not accepted. It carries both the stable Reason (for a condition) and a human Message (for its text).
func AsRejection ¶
func AsRejection(err error) (*RejectionError, bool)
AsRejection extracts the *RejectionError from an error chain, so a caller can read the typed Reason. It returns false for any other error.
func Check ¶
func Check(raw []byte, policy SafetyPolicy) *RejectionError
Check parses raw kubeconfig bytes and applies the safety policy WITHOUT dialing. A nil return means the kubeconfig is well-formed and permitted; a non-nil *RejectionError names exactly which input was wrong (Invalid / ExecNotAllowed / InsecureTLSNotAllowed).
func CheckInCluster ¶ added in v0.54.0
func CheckInCluster(provider types.NamespacedName, policy SafetyPolicy) *RejectionError
CheckInCluster is the consent check for a KubeProvider that sets spec.inCluster: nil when the installation lists it, and a RejectionError naming the flag when it does not.
func (*RejectionError) Error ¶
func (r *RejectionError) Error() string
Error implements error so a RejectionError can flow through the resolver's error return.
type SafetyPolicy ¶
type SafetyPolicy struct {
// AllowExec permits exec auth providers (--insecure-kubeconfig-exec).
AllowExec bool
// AllowInsecureTLS permits insecure-skip-tls-verify (--insecure-kubeconfig-tls).
AllowInsecureTLS bool
// InClusterProviders are the KubeProviders allowed to use spec.inCluster
// (--in-cluster-kube-providers). Empty, none is.
InClusterProviders map[types.NamespacedName]struct{}
}
SafetyPolicy is the operator's opt-in to what this package rejects by default: the two kubeconfig footguns, and the operator's own identity. All default off — the safe posture, diverging from Flux's silent strip.
func (SafetyPolicy) AllowsInCluster ¶ added in v0.54.0
func (p SafetyPolicy) AllowsInCluster(provider types.NamespacedName) bool
AllowsInCluster reports whether the KubeProvider named provider may use the operator's own identity.