Skip to content

--skip-consumers creates consumers instead of plugins when using default_lookup_tags #1844

@alphayogi22

Description

@alphayogi22

Summary

When using --skip-consumers flag combined with default_lookup_tags.consumers to reference existing consumers for consumer-scoped plugin creation, deck is creating consumers instead of creating plugins.
This issue appears related to #532 which reported similar behavior.

Expected Behavior

When running deck gateway diff with:

  • --skip-consumers flag
  • default_lookup_tags.consumers configured to reference existing consumers by tag
  • A plugin scoped to both a consumer and service

The output should show:

creating plugin rate-limiting-advanced for service my-service and consumer my-consumer-username
Summary:
  Created: 1

Actual Behavior

With --skip-consumers, deck outputs:

creating consumer my-consumer-username
creating consumer another-consumer
Summary:
  Created: 2

The plugin is NOT created. Instead, consumers are being created even though --skip-consumers should prevent consumer operations.

Steps to Reproduce

1. Ensure a consumer exists in Kong with a specific tag

Consumer in Konnect:

  • Username: my-consumer-username
  • Tags: ["MyConsumerTag"]

2. Create a deck state file

deck-test-minimal.json:

{
  "_format_version": "3.0",
  "services": [{
    "name": "my-service",
    "host": "example.com",
    "port": 443,
    "protocol": "https",
    "path": "/api",
    "tags": ["my-service"]
  }],
  "plugins": [{
    "name": "rate-limiting-advanced",
    "consumer": "my-consumer-username",
    "service": "my-service",
    "config": {
      "limit": [30000],
      "window_size": [60],
      "strategy": "local",
      "window_type": "fixed",
      "namespace": "my-namespace"
    },
    "tags": ["my-service"]
  }],
  "_konnect": {
    "control_plane_name": "my-control-plane"
  },
  "_info": {
    "select_tags": ["my-service"],
    "default_lookup_tags": {
      "consumers": ["MyConsumerTag"]
    }
  }
}

3. Run deck diff WITH --skip-consumers

deck gateway diff --konnect-addr https://eu.api.konghq.com \
  --konnect-token "$TOKEN" \
  --skip-ca-certificates \
  --skip-consumers \
  deck-test-minimal.json

Output (INCORRECT):
It is creating all the consumers again with the same tags (Why????)

creating consumer my-consumer-username
creating consumer another-consumer
Summary:
  Created: 2

4. Run deck diff WITHOUT --skip-consumers

deck gateway diff --konnect-addr https://eu.api.konghq.com \
  --konnect-token "$TOKEN" \
  --skip-ca-certificates \
  deck-test-minimal.json

Output (CORRECT):

creating plugin rate-limiting-advanced for service my-service and consumer my-consumer-username
Summary:
  Created: 1

Suspected Root Cause

After investigating the deck source code, we believe the issue is in cmd/common.go — specifically the order of operations between --skip-consumers processing and default_lookup_tags loading.

Code Location 1: SkipConsumers filter (runs FIRST)

// https://github.com/Kong/deck/blob/main/cmd/common.go ~lines 160-165
if dumpConfig.SkipConsumers {
    targetContent.Consumers = []file.FConsumer{}           // Clears consumers
    targetContent.ConsumerGroups = []file.FConsumerGroupObject{}
    targetContent.Plugins = RemoveConsumerPlugins(targetContent.Plugins)  // ← Removes consumer-scoped plugins!
}

Code Location 2: Lookup tag processing (runs AFTER)

// https://github.com/Kong/deck/blob/main/cmd/common.go ~lines 323-339
if dumpConfig.LookUpSelectorTagsConsumers != nil {
    consumersGlobal, err := dump.GetAllConsumers(ctx, kongClient,
        dumpConfig.LookUpSelectorTagsConsumers)
    // ... unconditionally appends to targetContent.Consumers
}

The Problem

  1. --skip-consumers executes first and calls RemoveConsumerPlugins(), which strips our consumer-scoped plugin from the target state
  2. default_lookup_tags executes after and loads consumers into the state for foreign key resolution
  3. Result: The consumer-scoped plugin is removed, but the looked-up consumers are added to the managed state
  4. During reconciliation, deck sees these consumers as "new" and plans to create them, while the plugin is never created

Expected Behavior

I think Consumers loaded via default_lookup_tags should be treated as reference-only entities for foreign key resolution, they should NOT be added to the managed sync state. Additionally, RemoveConsumerPlugins() should not remove plugins that reference consumers loaded via default_lookup_tags, since those consumers are not being "managed" by this sync operation.

Use Case

We're building tooling that generates deck configuration files for API gateway management. Our use case involves:

  1. Service-level rate limiting global rate limits applied to all traffic for a service
  2. Consumer-service rate limiting per-consumer rate limit overrides for specific services

For consumer-service rate limiting:

  • Consumers already exist in Kong (managed separately by another team/process)
  • We use default_lookup_tags.consumers to reference them by tag for foreign key resolution
  • We create rate-limiting-advanced plugins scoped to both consumer and service
  • We use --skip-consumers because we do NOT want to manage consumer lifecycle

This pattern should allow us to create consumer-scoped plugins while leaving the consumers themselves untouched.

Questions

  1. Is --skip-consumers intentionally removing consumer-scoped plugins via RemoveConsumerPlugins()? If so, this conflicts with the default_lookup_tags use case.
  2. Should consumers loaded via default_lookup_tags be excluded from the --skip-consumers filter since they're meant for reference only?
  3. Why are lookup-tag consumers being shown as "creating" when --skip-consumers is set?

Related Issues

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions