Skip to content

bug: litellm_key ignores user-supplied key value — write-only field never read in mapResourceDataToKey #39

Description

@christianherweg0807

Summary

The litellm_key resource accepts an optional key input field (declared WriteOnly: true, added in v0.2.0) that is intended to let users supply a pre-determined key value to /key/generate. However, the supplied value is silently ignored — mapResourceDataToKey never reads the key field, so Key.Key is always empty when CreateKey is called. LiteLLM then generates its own key, which never matches the value the caller provided.

Root Cause

d.Get("key") always returns "" for write-only attributes — this is intentional SDK behaviour: the Terraform Plugin SDK v2 clears write-only fields from ResourceData after plan to prevent state persistence. The correct approach is d.GetRawConfig().GetAttr("key"), which reads the value from the raw plan config before it is cleared.

mapResourceDataToKey in resource_key.go (line 204) reads every other field from ResourceData but has no handling for key:

// resource_key.go line 204 — key field is never read
func mapResourceDataToKey(d *schema.ResourceData, key *Key) {
    key.Models = expandStringList(d.Get("models").([]interface{}))
    key.UserID = d.Get("user_id").(string)
    key.TeamID = d.Get("team_id").(string)
    // ... all other fields ...
    // "key" is never set on key.Key
}

Additionally, resourceKeyCreate calls d.Set("key", createdKey.Key) before resourceKeyRead, which immediately overwrites it with nil (SDK clears write-only fields on Read):

// resource_key.go line 155 — key is overwritten to nil by resourceKeyRead
d.Set("key", createdKey.Key)
return resourceKeyRead(ctx, d, m)  // clears write-only → key lost

Proposed Fix

Two changes in resource_key.go:

1. Read the supplied key via GetRawConfig in mapResourceDataToKey:

func mapResourceDataToKey(d *schema.ResourceData, key *Key) {
    if rawKey := d.GetRawConfig().GetAttr("key"); rawKey.IsKnown() && !rawKey.IsNull() {
        key.Key = rawKey.AsString()
    }
    key.Models = expandStringList(d.Get("models").([]interface{}))
    // ...
}

2. Re-set the write-only value after resourceKeyRead in resourceKeyCreate:

// Before:
d.Set("key", createdKey.Key)
return resourceKeyRead(ctx, d, m)

// After:
diags := resourceKeyRead(ctx, d, m)
d.Set("key", createdKey.Key)
return diags

Reproduction

resource "random_password" "vkey" {
  length  = 22
  special = false
}

resource "litellm_key" "team" {
  key       = "sk-${random_password.vkey.result}"
  team_id   = litellm_team.team.id
  key_alias = "my-team-vkey"
  duration  = "90d"
}

After terraform apply, the key registered in LiteLLM does not match "sk-${random_password.vkey.result}" — LiteLLM generated its own key and the supplied value was dropped.

Why This Matters

Without this fix it is impossible to use litellm_key in combination with aws_ssm_parameter (or any other resource) to deliver the key value to consumers — the key output is write-only and cannot be referenced, and the supplied input is silently ignored, leaving no way to retrieve the actual key value from Terraform.

Environment

  • Provider: BerriAI/litellm v0.2.1
  • Terraform: >= 1.11
  • LiteLLM: OSS (non-Enterprise)

Metadata

Metadata

Assignees

No one assigned

    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