kubernetes/kops · error

SourceRanges and SourceTags should not both be specified

Error message

SourceRanges and SourceTags should not both be specified

What it means

GCE treats SourceRanges and SourceTags as OR, not AND, which developers usually do not expect. Normalize rejects specs that set both so kOps never creates a rule that is broader than the author intended.

Source

Thrown at upup/pkg/fi/cloudup/gcetasks/firewallrule.go:110

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)
		}

		if e.Family == "" {
			// This is our own requirement, just for consistency checking.
			// Previous we used the name, but that was confused when the cluster name was ipv6.example.com
			return fmt.Errorf("must set Family when using SourceRanges")
		}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Keep only sourceRanges if CIDR restriction is intended
  2. Keep only sourceTags if tag-based restriction is intended
  3. Split into two separate FirewallRule tasks if you genuinely need both rule types
  4. Re-run kops update after editing the manifest

Example fix

// before
sourceRanges: ["10.0.0.0/8"]
sourceTags: ["my-tag"]
// after
sourceRanges: ["10.0.0.0/8"]
Defensive patterns

Strategy: validation

Validate before calling

func validateExclusiveSources(rule FirewallRuleSpec) error {
  if len(rule.SourceRanges) != 0 && len(rule.SourceTags) != 0 {
    return fmt.Errorf("rule %s: use sourceRanges OR sourceTags, not both (GCE ORs them)", rule.Name)
  }
  return nil
}

Prevention

When it happens

Trigger: A firewallRule in the cluster spec has non-empty sourceRanges AND non-empty sourceTags simultaneously.

Common situations: Merging two rule configs during refactoring; assuming the fields combine as AND; copy-pasting rules that each had only one of the fields.

Related errors


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