[IDENTITY-7450] Support Global Key - Store & Use#3377
[IDENTITY-7450] Support Global Key - Store & Use#3377Taohao Wang (taohaowang) wants to merge 3 commits into
Conversation
|
🎉 All Contributor License Agreements have been signed. Ready to merge. |
There was a problem hiding this comment.
Pull request overview
This PR adds first-class support for org-scoped “Global” API keys in the CLI’s local state so they can be stored, selected via confluent api-key use, and used as a fallback for Kafka client operations when no cluster-scoped key is configured.
Changes:
- Extend
config.Contextto persist Global API key pairs and an “active” Global key, including validation and secret encrypt/decrypt helpers. - Update Kafka produce/consume + client config generation to resolve credentials via a new
Context.ResolveKafkaAPIKey()(cluster-scoped preferred, Global fallback). - Update
api-key create,api-key store, andapi-key useto detect/store/use Global API keys and persist the active Global selection.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/keystore/keystore.go | Deletes Global keys on DeleteAPIKey; adds Global key store/has helpers. |
| pkg/config/context.go | Adds Global API key storage to context, validation, encryption helpers, and Kafka credential resolution logic. |
| pkg/config/context_test.go | Adds unit tests for Global API key storage and Kafka credential resolution behavior. |
| pkg/config/config_test.go | Initializes GlobalAPIKeys in test contexts to match new context shape. |
| internal/kafka/confluent_kafka.go | Threads *config.Context into producer/consumer creation to support Global credential resolution. |
| internal/kafka/confluent_kafka_configs.go | Builds Kafka config using Context.ResolveKafkaAPIKey() instead of cluster-only fields. |
| internal/kafka/command_topic.go | Allows Kafka topic produce/consume to proceed without cluster-scoped key if an active Global key exists. |
| internal/kafka/command_topic_produce.go | Passes context into producer creation and API key validation helper. |
| internal/kafka/command_topic_consume.go | Passes context into consumer creation and API key validation helper. |
| internal/kafka/command_clientconfig_create.go | Uses resolved credentials (cluster/global) when templating client configs and validating creds. |
| internal/api-key/command_use.go | Supports api-key use selecting a stored Global key when --resource isn’t set. |
| internal/api-key/command_store.go | Detects Global keys (via --resource global or server Kind) and stores them in the Global keystore. |
| internal/api-key/command_create.go | Stores Global key secrets locally on creation and supports --use activating the Global key. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func (c *Context) StoreGlobalAPIKey(pair *APIKeyPair) error { | ||
| if c.GlobalAPIKeys == nil { | ||
| c.GlobalAPIKeys = map[string]*APIKeyPair{} | ||
| } | ||
| c.GlobalAPIKeys[pair.Key] = pair | ||
| return c.EncryptGlobalAPIKeys() | ||
| } |
| func (c *Context) ResolveKafkaAPIKey(kcc *KafkaClusterConfig) (string, string, error) { | ||
| if kcc != nil && kcc.APIKey != "" { | ||
| if pair, ok := kcc.APIKeys[kcc.APIKey]; ok { | ||
| if err := pair.DecryptSecret(); err != nil { | ||
| return "", "", err | ||
| } | ||
| return pair.Key, pair.Secret, nil | ||
| } | ||
| } | ||
| if pair := c.GetActiveGlobalAPIKeyPair(); pair != nil { | ||
| if err := pair.DecryptSecret(); err != nil { | ||
| return "", "", err | ||
| } | ||
| return pair.Key, pair.Secret, nil | ||
| } | ||
| return "", "", nil | ||
| } |
| func (c *Context) StoreGlobalAPIKey(pair *APIKeyPair) error { | ||
| if c.GlobalAPIKeys == nil { | ||
| c.GlobalAPIKeys = map[string]*APIKeyPair{} | ||
| } | ||
| c.GlobalAPIKeys[pair.Key] = pair | ||
| return c.EncryptGlobalAPIKeys() | ||
| } |
| func (c *Context) ResolveKafkaAPIKey(kcc *KafkaClusterConfig) (string, string, error) { | ||
| if kcc != nil && kcc.APIKey != "" { | ||
| if pair, ok := kcc.APIKeys[kcc.APIKey]; ok { | ||
| if err := pair.DecryptSecret(); err != nil { | ||
| return "", "", err | ||
| } | ||
| return pair.Key, pair.Secret, nil | ||
| } | ||
| } | ||
| if pair := c.GetActiveGlobalAPIKeyPair(); pair != nil { | ||
| if err := pair.DecryptSecret(); err != nil { | ||
| return "", "", err | ||
| } | ||
| return pair.Key, pair.Secret, nil | ||
| } | ||
| return "", "", nil | ||
| } |
…oken cluster key, add tests.
|




Release Notes
Breaking Changes
New Features
confluent api-key create,store, andusenow support org-scoped Global API keys. Global keys are stored locally (separate from cluster-scoped keys) and can be selected as the active key withconfluent api-key use <key>.confluent kafka topic produce/consumeandconfluent kafka client-config createnow fall back to the active Global API key when the target cluster has no cluster-scoped API key configured. (?)Bug Fixes
Checklist
Whatsection below whether this PR applies to Confluent Cloud, Confluent Platform, or both.Test & Reviewsection below.Blast Radiussection below.What
Blast Radius
References
https://confluentinc.atlassian.net/browse/IDENTITY-7450
Test & Review