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

  1. Add explicit sourceRanges entries (e.g. 0.0.0.0/0 only if you truly mean public)
  2. Add sourceTags to restrict by instance tag instead
  3. Set disabled: true if the rule is intentionally a placeholder
  4. 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

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


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/f060adbbeeb57b07. Report an issue: GitHub.