{"record":{"id":"f060adbbeeb57b07","repo":"kubernetes/kops","slug":"either-sourceranges-or-sourcetags-should-be-specif","errorCode":null,"errorMessage":"either SourceRanges or SourceTags should be specified when Disabled is false","messagePattern":"either SourceRanges or SourceTags should be specified when Disabled is false","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gcetasks/firewallrule.go","lineNumber":103,"sourceCode":"\t// Ignore \"system\" fields\n\tactual.Lifecycle = e.Lifecycle\n\tactual.Family = e.Family\n\n\treturn actual, nil\n}\n\nfunc (e *FirewallRule) Run(c *fi.CloudupContext) error {\n\treturn fi.CloudupDefaultDeltaRunMethod(e, c)\n}\n\n// Normalize applies some validation that isn't technically required,\n// but avoids some problems with surprising behaviours.\nfunc (e *FirewallRule) Normalize(c *fi.CloudupContext) error {\n\tif !e.Disabled {\n\t\t// Treat it as an error if SourceRanges _and_ SourceTags empty with Disabled=false\n\t\t// this is interpreted as SourceRanges=\"0.0.0.0/0\", which is likely not what was intended.\n\t\tif len(e.SourceRanges) == 0 && len(e.SourceTags) == 0 {\n\t\t\treturn fmt.Errorf(\"either SourceRanges or SourceTags should be specified when Disabled is false\")\n\t\t}\n\t}\n\n\t// Treat it as an error if SourceRanges _and_ SourceTags both set;\n\t// this is interpreted as OR, not AND, which is likely not what was intended.\n\tif len(e.SourceRanges) != 0 && len(e.SourceTags) != 0 {\n\t\treturn fmt.Errorf(\"SourceRanges and SourceTags should not both be specified\")\n\t}\n\n\tname := fi.ValueOf(e.Name)\n\n\t// Make sure we've split the ipv4 / ipv6 addresses.\n\t// A single firewall rule can't mix ipv4 and ipv6 addresses, so we split them into two rules.\n\tfor _, sourceRange := range e.SourceRanges {\n\t\t_, cidr, err := net.ParseCIDR(sourceRange)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"sourceRange %q is not valid: %w\", sourceRange, err)\n\t\t}","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gcetasks/firewallrule.go#L85-L121","documentation":"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.","triggerScenarios":"A cluster spec defines a GCE firewallRule (e.g. in a cluster manifest) with disabled: false (or unset) and both sourceRanges and sourceTags empty.","commonSituations":"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.","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"],"exampleFix":"// before\nfirewallRule:\n  name: my-rule\n  disabled: false\n// after\nfirewallRule:\n  name: my-rule\n  disabled: false\n  sourceRanges: [\"10.0.0.0/8\"]","handlingStrategy":"validation","validationCode":"func validateFirewallSource(rule FirewallRuleSpec) error {\n  if !rule.Disabled && len(rule.SourceRanges) == 0 && len(rule.SourceTags) == 0 {\n    return fmt.Errorf(\"firewall rule %s: set sourceRanges or sourceTags, or disabled: true\", rule.Name)\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["gcp","gce","firewall","validation","security"],"backgroundTag":"missing-firewall-source","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}