kubernetes/kops · error
either SourceRanges or SourceTags should be specified when D
Error message
either SourceRanges or SourceTags should be specified when Disabled is false
What it means
FirewallRule.Normalize validates the spec before apply: with Disabled=false, a rule with neither SourceRanges nor SourceTags is rejected, because GCE would interpret it as allowing 0.0.0.0/0 — almost never intended. kOps fails fast instead of opening the rule to the internet.
Source
Thrown at upup/pkg/fi/cloudup/gcetasks/firewallrule.go:103
// Ignore "system" fields
actual.Lifecycle = e.Lifecycle
actual.Family = e.Family
return actual, nil
}
func (e *FirewallRule) Run(c *fi.CloudupContext) error {
return fi.CloudupDefaultDeltaRunMethod(e, c)
}
// Normalize applies some validation that isn't technically required,
// but avoids some problems with surprising behaviours.
func (e *FirewallRule) Normalize(c *fi.CloudupContext) error {
if !e.Disabled {
// Treat it as an error if SourceRanges _and_ SourceTags empty with Disabled=false
// this is interpreted as SourceRanges="0.0.0.0/0", which is likely not what was intended.
if len(e.SourceRanges) == 0 && len(e.SourceTags) == 0 {
return fmt.Errorf("either SourceRanges or SourceTags should be specified when Disabled is false")
}
}
// Treat it as an error if SourceRanges _and_ SourceTags both set;
// this is interpreted as OR, not AND, which is likely not what was intended.
if len(e.SourceRanges) != 0 && len(e.SourceTags) != 0 {
return fmt.Errorf("SourceRanges and SourceTags should not both be specified")
}
name := fi.ValueOf(e.Name)
// Make sure we've split the ipv4 / ipv6 addresses.
// A single firewall rule can't mix ipv4 and ipv6 addresses, so we split them into two rules.
for _, sourceRange := range e.SourceRanges {
_, cidr, err := net.ParseCIDR(sourceRange)
if err != nil {
return fmt.Errorf("sourceRange %q is not valid: %w", sourceRange, err)
}View on GitHub (pinned to 4c8573c808)
Solutions
- Add explicit sourceRanges entries (e.g. 0.0.0.0/0 only if you truly mean public)
- Add sourceTags to restrict by instance tag instead
- Set disabled: true if the rule is intentionally a placeholder
- Re-run kops update after fixing the manifest
Example fix
// before firewallRule: name: my-rule disabled: false // after firewallRule: name: my-rule disabled: false sourceRanges: ["10.0.0.0/8"]
Defensive patterns
Strategy: validation
Validate before calling
func validateFirewallSource(rule FirewallRuleSpec) error {
if !rule.Disabled && len(rule.SourceRanges) == 0 && len(rule.SourceTags) == 0 {
return fmt.Errorf("firewall rule %s: set sourceRanges or sourceTags, or disabled: true", rule.Name)
}
return nil
} Prevention
- Always fill sourceRanges or sourceTags on enabled rules
- Use disabled: true for intentional placeholders
- Lint cluster manifests before kops update
- Default-deny: never rely on empty-source semantics
When it happens
Trigger: A cluster spec defines a GCE firewallRule (e.g. in a cluster manifest) with disabled: false (or unset) and both sourceRanges and sourceTags empty.
Common situations: Authoring a new firewall rule and forgetting to fill sourceRanges; templating that renders empty ranges; copying a rule and deleting its source fields while re-enabling it.
Related errors
- SourceRanges and SourceTags should not both be specified
- sourceRange %q is not valid: %w
- must set Family when using SourceRanges
- ipv4 ranges should not be in a ipv6-named rule (found %s in
- error deleting FirewallRule %s: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/f060adbbeeb57b07.
Report an issue: GitHub.