kubernetes/kops · error

error deleting FirewallRule

Error message

error deleting FirewallRule %s: %v

What it means

Wraps a failure from Compute Firewalls().Delete in deleteFirewallRule during cluster teardown. NotFound is handled as already-deleted success, so this surfaces genuine delete failures: permission denied, rate limits, server errors, or firewall rules locked by other GCP features. Message includes the firewall rule's SelfLink and the raw error.

Solutions

  1. Check IAM for compute.firewalls.delete on the project (or host project in shared VPC).
  2. If the rule is owned by GKE/another controller, delete it via that system or in the console rather than kops.
  3. Retry the delete; 429/5xx failures are typically transient.
  4. Confirm the rule is not recreated by an active controller; remove the source of recreation first.
  5. If already deleted, re-run — NotFound is treated as success.
Defensive patterns

Strategy: retry

Validate before calling

// confirm the firewall rule still exists and is kOps-owned before delete
fw, err := computeService.Firewalls.Get(project, ruleName).Do()
if err != nil { /* 404 means already gone */ }
if fw != nil && !strings.Contains(fw.Description, clusterTag) {
    return fmt.Errorf("firewall %s not owned by this cluster", ruleName)
}

Type guard

func isGCEAPIError(err error) (*googleapi.Error, bool) {
    var gerr *googleapi.Error
    return gerr, errors.As(err, &gerr)
}

Try / catch

err := deleteFirewallRule(t)
var gerr *googleapi.Error
if err != nil {
    if errors.As(err, &gerr) && gerr.Code == 404 { return nil } // fine
    if errors.As(err, &gerr) && (gerr.Code == 429 || gerr.Code >= 500) {
        // retry with backoff
    }
    return err
}

Prevention

When it happens

Trigger: c.Compute().Firewalls().Delete(u.Project, u.Name) returns 403 (missing compute.firewalls.delete), 429 quota, 5xx, or a conflict because the rule is managed/locked by another system (e.g. GKE control plane, shared VPC host project policies).

Common situations: Shared VPC setups where the kops service account lacks firewall permissions on the host project; firewall rules recreated by GKE or another controller racing the delete; expired/rotated credentials mid-teardown; transient GCP outages.

Related errors


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

Appendix: source

Thrown at pkg/resources/gce/gce.go:723

// deleteFirewallRule is the helper function to delete a Resource for a Firewall object
func deleteFirewallRule(cloud fi.Cloud, r *resources.Resource) error {
	c := cloud.(gce.GCECloud)
	t := r.Obj.(*compute.Firewall)

	klog.V(2).Infof("Deleting GCE FirewallRule %s", t.SelfLink)
	u, err := gce.ParseGoogleCloudURL(t.SelfLink)
	if err != nil {
		return err
	}

	op, err := c.Compute().Firewalls().Delete(u.Project, u.Name)
	if err != nil {
		if gce.IsNotFound(err) {
			klog.Infof("FirewallRule not found, assuming deleted: %q", t.SelfLink)
			return nil
		}
		return fmt.Errorf("error deleting FirewallRule %s: %v", t.SelfLink, err)
	}

	return c.WaitForOp(op)
}

func (d *clusterDiscoveryGCE) listRoutes(ctx context.Context, resourceMap map[string]*resources.Resource) ([]*resources.Resource, error) {
	c := d.gceCloud

	var resourceTrackers []*resources.Resource

	instancesToDelete := make(map[string]*resources.Resource)
	migsToDelete := make(map[string]*resources.Resource)
	for _, resource := range resourceMap {
		switch resource.Type {
		case typeInstance:
			instancesToDelete[resource.ID] = resource
		case typeInstanceGroupManager:
			migsToDelete[resource.ID] = resource

View on GitHub (pinned to 4c8573c808)