Skip to content

Terraform support Global API Key#929

Open
Taohao Wang (taohaowang) wants to merge 2 commits intomasterfrom
identity-6365-global-key-support
Open

Terraform support Global API Key#929
Taohao Wang (taohaowang) wants to merge 2 commits intomasterfrom
identity-6365-global-key-support

Conversation

@taohaowang
Copy link

@taohaowang Taohao Wang (taohaowang) commented Jan 30, 2026

Release Notes

New Features
Support Global API key from Terraform

Bug Fixes
NA

Examples
Please refer to https://confluentinc.atlassian.net/wiki/spaces/~712020ba3ea6a8cdb24e61b11d46bc2b8c41b6/pages/5092836879/How+to+Test+Cli+Terraform+Locally

Checklist

  • I can successfully build and use a custom Terraform provider binary for Confluent.
  • I have verified my PR with real Confluent Cloud resources in a pre-prod or production environment, or both.
  • I have attached manual Terraform verification results or screenshots in the Test & Review section below.
  • I have included appropriate Terraform acceptance or unit tests for any new resource, data source, or functionality.
  • I have included appropriate Terraform live testing for any new resource, data source, or functionality.
  • I have included a testing thread with main.tf file in #terraform-provider-development-testing.
  • I have included rate limit/load testing results.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have updated the corresponding documentation and include relevant examples for this PR.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Check this box if the feature is enabled for certain organizations only

What

Support Global API key management from Terraform.

Blast Radius

This is a new feature for Global API key, relatively low impact on existing customer use cases.

References

https://confluentinc.atlassian.net/wiki/spaces/~712020ba3ea6a8cdb24e61b11d46bc2b8c41b6/pages/5092836879/How+to+Test+Cli+Terraform+Locally
https://confluentinc.atlassian.net/browse/IDENTITY-6365

Test & Review

test-global-api-key terraform init               
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of confluentinc/confluent from the dependency lock file
- Using previously-installed confluentinc/confluent v2.59.0

╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ Skip terraform init when using provider development overrides. It is not necessary and may error
│ unexpectedly.
╵
Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
➜  test-global-api-key terraform validate           
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵
Success! The configuration is valid, but there were some validation warnings as shown
above.

➜  test-global-api-key terraform plan
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # confluent_api_key.global_key will be created
  + resource "confluent_api_key" "global_key" {
      + description            = "Testing global API key support"
      + disable_wait_for_ready = false
      + display_name           = "test-global-api-key"
      + id                     = (known after apply)
      + secret                 = (sensitive value)

      + managed_resource {
          + api_version = "global/v1"
          + id          = "global"
          + kind        = "Global"
        }

      + owner {
          + api_version = (known after apply)
          + id          = (known after apply)
          + kind        = (known after apply)
        }
    }

  # confluent_service_account.test_sa will be created
  + resource "confluent_service_account" "test_sa" {
      + api_version  = (known after apply)
      + description  = "Service account for testing global API key"
      + display_name = "test-global-api-key-sa"
      + id           = (known after apply)
      + kind         = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + global_api_key_id     = (known after apply)
  + global_api_key_secret = (sensitive value)

────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly
these actions if you run "terraform apply" now.
➜  test-global-api-key terraform apply
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # confluent_api_key.global_key will be created
  + resource "confluent_api_key" "global_key" {
      + description            = "Testing global API key support"
      + disable_wait_for_ready = false
      + display_name           = "test-global-api-key"
      + id                     = (known after apply)
      + secret                 = (sensitive value)

      + managed_resource {
          + api_version = "global/v1"
          + id          = "global"
          + kind        = "Global"
        }

      + owner {
          + api_version = (known after apply)
          + id          = (known after apply)
          + kind        = (known after apply)
        }
    }

  # confluent_service_account.test_sa will be created
  + resource "confluent_service_account" "test_sa" {
      + api_version  = (known after apply)
      + description  = "Service account for testing global API key"
      + display_name = "test-global-api-key-sa"
      + id           = (known after apply)
      + kind         = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + global_api_key_id     = (known after apply)
  + global_api_key_secret = (sensitive value)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: 

Apply cancelled.
➜  test-global-api-key terraform apply
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # confluent_api_key.global_key will be created
  + resource "confluent_api_key" "global_key" {
      + description            = "Testing global API key support"
      + disable_wait_for_ready = false
      + display_name           = "test-global-api-key"
      + id                     = (known after apply)
      + secret                 = (sensitive value)

      + managed_resource {
          + api_version = "global/v1"
          + id          = "global"
          + kind        = "Global"
        }

      + owner {
          + api_version = (known after apply)
          + id          = (known after apply)
          + kind        = (known after apply)
        }
    }

  # confluent_service_account.test_sa will be created
  + resource "confluent_service_account" "test_sa" {
      + api_version  = (known after apply)
      + description  = "Service account for testing global API key"
      + display_name = "test-global-api-key-sa"
      + id           = (known after apply)
      + kind         = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + global_api_key_id     = (known after apply)
  + global_api_key_secret = (sensitive value)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

confluent_service_account.test_sa: Creating...
╷
│ Error: error creating Service Account "test-global-api-key-sa": 402 Payment Required: Unable to create service account for organization: Your organization is currently limited to 1000 service accounts
│ 
│   with confluent_service_account.test_sa,
│   on main.tf line 16, in resource "confluent_service_account" "test_sa":
│   16: resource "confluent_service_account" "test_sa" {
│ 
╵
➜  test-global-api-key terraform apply
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # confluent_api_key.global_key will be created
  + resource "confluent_api_key" "global_key" {
      + description            = "Testing global API key support"
      + disable_wait_for_ready = false
      + display_name           = "test-global-api-key"
      + id                     = (known after apply)
      + secret                 = (sensitive value)

      + managed_resource {
          + api_version = "global/v1"
          + id          = "global"
          + kind        = "Global"
        }

      + owner {
          + api_version = (known after apply)
          + id          = (known after apply)
          + kind        = (known after apply)
        }
    }

  # confluent_service_account.test_sa will be created
  + resource "confluent_service_account" "test_sa" {
      + api_version  = (known after apply)
      + description  = "Service account for testing global API key"
      + display_name = "test-global-api-key-sa"
      + id           = (known after apply)
      + kind         = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + global_api_key_id     = (known after apply)
  + global_api_key_secret = (sensitive value)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

confluent_service_account.test_sa: Creating...
confluent_service_account.test_sa: Creation complete after 1s [id=sa-stgcdo8jjwd]
confluent_api_key.global_key: Creating...
confluent_api_key.global_key: Still creating... [00m10s elapsed]
confluent_api_key.global_key: Creation complete after 17s [id=J7BSZ3XT2DOMCFEL]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

global_api_key_id = "J7BSZ3XT2DOMCFEL"
global_api_key_secret = <sensitive>
➜  test-global-api-key terraform output -json global_api_key_secret
"cflt3fqwr6Fr3dx3urszviQAse/iWQcaEeg6UVcwlOXggfxPRUX4HXXt77RG9I/A"
➜  test-global-api-key terraform plan
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵
confluent_service_account.test_sa: Refreshing state... [id=sa-stgcdo8jjwd]
confluent_api_key.global_key: Refreshing state... [id=J7BSZ3XT2DOMCFEL]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences,
so no changes are needed.
➜  test-global-api-key # Note the API key ID from output
export API_KEY_ID=$(terraform output -raw global_api_key_id)
export API_KEY_SECRET=$(terraform output -raw global_api_key_secret)

# Remove from state
terraform state rm confluent_api_key.global_key

# Re-import it
export API_KEY_SECRET="<the_secret_you_noted>"
terraform import confluent_api_key.global_key $API_KEY_ID
Removed confluent_api_key.global_key
Successfully removed 1 resource instance(s).
confluent_api_key.global_key: Importing from ID "J7BSZ3XT2DOMCFEL"...
confluent_api_key.global_key: Import prepared!
  Prepared confluent_api_key for import
confluent_api_key.global_key: Refreshing state... [id=J7BSZ3XT2DOMCFEL]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

➜  test-global-api-key terraform destroy
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - confluentinc/confluent in /Users/taohaowang/confluent-repo/terraform-provider-confluent/bin/darwin-arm64
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may
│ cause the state to become incompatible with published releases.
╵
confluent_service_account.test_sa: Refreshing state... [id=sa-stgcdo8jjwd]
confluent_api_key.global_key: Refreshing state... [id=J7BSZ3XT2DOMCFEL]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # confluent_api_key.global_key will be destroyed
  - resource "confluent_api_key" "global_key" {
      - description            = "Testing global API key support" -> null
      - disable_wait_for_ready = false -> null
      - display_name           = "test-global-api-key" -> null
      - id                     = "J7BSZ3XT2DOMCFEL" -> null
      - secret                 = (sensitive value) -> null

      - managed_resource {
          - api_version = "global/v1" -> null
          - id          = "global" -> null
          - kind        = "Global" -> null
        }

      - owner {
          - api_version = "iam/v2" -> null
          - id          = "sa-stgcdo8jjwd" -> null
          - kind        = "ServiceAccount" -> null
        }
    }

  # confluent_service_account.test_sa will be destroyed
  - resource "confluent_service_account" "test_sa" {
      - api_version  = "iam/v2" -> null
      - description  = "Service account for testing global API key" -> null
      - display_name = "test-global-api-key-sa" -> null
      - id           = "sa-stgcdo8jjwd" -> null
      - kind         = "ServiceAccount" -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Changes to Outputs:
  - global_api_key_id     = "J7BSZ3XT2DOMCFEL" -> null
  - global_api_key_secret = (sensitive value) -> null

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

confluent_api_key.global_key: Destroying... [id=J7BSZ3XT2DOMCFEL]
confluent_api_key.global_key: Destruction complete after 0s
confluent_service_account.test_sa: Destroying... [id=sa-stgcdo8jjwd]
confluent_service_account.test_sa: Destruction complete after 2s

Destroy complete! Resources: 2 destroyed.

Copilot AI review requested due to automatic review settings January 30, 2026 14:56
@taohaowang Taohao Wang (taohaowang) requested a review from a team as a code owner January 30, 2026 14:56
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for Global API Keys in the Terraform provider, enabling users to create, update, and delete API keys scoped to global resources rather than specific Kafka clusters or environments.

Changes:

  • Added Global API Key resource type with appropriate validation and synchronization logic
  • Implemented test coverage for Global API Key lifecycle operations including creation, update, and deletion
  • Added documentation example for Global API Key resource configuration

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
internal/testdata/apikey/create_global_api_key.json Test fixture for Global API Key creation response
internal/testdata/apikey/read_created_global_api_key.json Test fixture for reading a newly created Global API Key
internal/testdata/apikey/read_updated_global_api_key.json Test fixture for reading an updated Global API Key
internal/testdata/apikey/read_deleted_global_api_key.json Test fixture for reading a deleted Global API Key
internal/provider/utils_wait.go Added synchronization logic for Global API Keys to wait for proper propagation
internal/provider/resource_api_key_test.go Added comprehensive test coverage for Global API Key lifecycle
internal/provider/resource_api_key.go Added Global API Key type support and validation logic
docs/resources/confluent_api_key.md Added documentation example for Global API Key usage

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@danielayaz
Copy link
Member

Can you please create a live test for this in resource_api_key_live_test.go?

if err := waitForCreatedTableflowApiKeyToSync(ctx, tableflowRestClient, c.isAcceptanceTestMode); err != nil {
return fmt.Errorf("error waiting for Tableflow API Key %q to sync: %s", createdApiKey.GetId(), createDescriptiveError(err))
}
} else if isGlobalApiKey(createdApiKey) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the global API key supposed to be resource specific? Or Global is considered as a special resource?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we use global as the associated resource id for global API key.

return apiKey.Spec.Resource.GetKind() == tableflowKind && apiKey.Spec.Resource.GetId() == tableflowKindInLowercase
}

func isGlobalApiKey(apiKey apikeys.IamV2ApiKey) bool {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the backend service suppose to return the lower case global as the Id?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it will return lower case global.

WillReturn(
string(readDeletedGlobalApiKeyResponse),
contentTypeJSONHeader,
http.StatusForbidden,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be 404 instead of 403?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are following the same pattern with other resource api keys e.g. Kafka, Flink, ...

The reason here is more from security perspective: an attacker probing key IDs can't distinguish between "this key never existed" and "this key was deleted," making enumeration and reconnaissance harder.

@taohaowang
Copy link
Author

Live Test Result (linked to stag):

TF_ACC=1 TF_ACC_PROD=1 go test ./internal/provider/ -v -run "TestAccGlobalApiKey.*Live" -tags "live_test,core" -timeout 120m
=== RUN   TestAccGlobalApiKeyLive
=== PAUSE TestAccGlobalApiKeyLive
=== RUN   TestAccGlobalApiKeyUpdateLive
=== PAUSE TestAccGlobalApiKeyUpdateLive
=== CONT  TestAccGlobalApiKeyLive
=== CONT  TestAccGlobalApiKeyUpdateLive
--- PASS: TestAccGlobalApiKeyLive (7.98s)
--- PASS: TestAccGlobalApiKeyUpdateLive (10.87s)
PASS
ok      github.com/confluentinc/terraform-provider-confluent/internal/provider  11.381s

Daniel Ayaz (@danielayaz) Channing Dong (@channingdong)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants