Skip to content

ibm_resource_key: role = "NONE" not persisted in state on import causing forced replacement #6706

@massimoschembri

Description

@massimoschembri

⏺ ### Terraform CLI and Terraform IBM Provider Version

OpenTofu v1.x                                                                                                                                                                                                                                    
provider registry.opentofu.org/ibm-cloud/ibm v1.86.1                                                                                                                                                                                             

Affected Resource(s)

  • ibm_resource_key

Terraform Configuration Files

resource "ibm_resource_key" "key" {
  name                 = "my-cos-key"                                                                                                                                                                                                            
  role                 = "NONE"                                                                                                                                                                                                                  
  resource_instance_id = ibm_resource_instance.instance.id                                                                                                                                                                                       
                                                                                                                                                                                                                                                 
  parameters = {                                                                                                                                                                                                                                 
    "HMAC" = true                                                                                                                                                                                                                                
  }                                                                                                                                                                                                                                              
}                                                                                                                                                                                                                                              

Debug Output

N/A

Panic Output

N/A

Expected Behavior

When importing an ibm_resource_key resource that was created with role = "NONE", the
Read function should populate role = "NONE" in the state, so that subsequent plans show
no diff and no replacement is required.

Actual Behavior

After importing an ibm_resource_key created with role = "NONE", the state has
role = null. On the next plan, Terraform detects a diff between the config
(role = "NONE") and the state (null) on a ForceNew field, and plans to destroy
and recreate
the resource key. This silently rotates all HMAC credentials, breaking
any consumers relying on them.

Root Cause

In resourceIBMResourceKeyRead, the role field is only written to state inside the
if resourceKey.Credentials != nil && resourceKey.Credentials.IamRoleCRN != nil block:

// resource_ibm_resource_key.go, lines 372–401                                                                                                                                                                                                   
if resourceKey.Credentials != nil && resourceKey.Credentials.IamRoleCRN != nil {                                                                                                                                                                 
    roleCrn := *resourceKey.Credentials.IamRoleCRN                                                                                                                                                                                               
    // ... look up role name from CRN ...                                                                                                                                                                                                        
    d.Set("role", RoleName)                                                                                                                                                                                                                      
}                                                                                                                                                                                                                                                
// no else branch — role is never set when IamRoleCRN is nil                                                                                                                                                                                   

When a key is created with role = "NONE", no IAM role is assigned and IamRoleCRN
is nil in the API response. The entire block is skipped and d.Set("role", ...) is
never called.

During a normal Create flow this goes unnoticed: d is pre-populated with the
config value role = "NONE" before Create is called, and since SDK v2 preserves
Computed + Optional values not explicitly overwritten by Read, the state retains
"NONE" correctly.

During Import, d starts completely empty. Read is the only opportunity to populate
state from the API. Since IamRoleCRN is nil, role is never written and the state
ends up with null.

Steps to Reproduce

  1. Create an ibm_resource_key with role = "NONE" via terraform apply
  2. Delete the resource from state: terraform state rm ibm_resource_key.key
  3. Add an import block pointing to the existing resource key CRN
  4. Run terraform plan
  5. Observe + role = "NONE" # forces replacement — the resource is planned for destroy
    and recreate despite the role being unchanged

Fix

Add an else branch to explicitly set role = "NONE" when IamRoleCRN is nil:

if resourceKey.Credentials != nil && resourceKey.Credentials.IamRoleCRN != nil {                                                                                                                                                               
    roleCrn := *resourceKey.Credentials.IamRoleCRN
    // ... existing role lookup logic ...                                                                                                                                                                                                        
    d.Set("role", RoleName)
} else {                                                                                                                                                                                                                                         
    d.Set("role", "NONE")                                                                                                                                                                                                                      
}

This makes Read idempotent for both cases: keys with an IAM role (CRN present) and keys
with no IAM role ("NONE"). The IBM Cloud API confirms this behaviour: keys created with
role = "NONE" have no iam_role_crn in their credentials response, which is what
triggers the missing branch.

Important Factoids

The issue is specific to import. Resources created fresh via terraform apply are
unaffected because Terraform SDK v2 preserves Computed + Optional field values carried
over from the config through the Create → Read lifecycle. The bug only surfaces when the
prior state is absent, i.e. during import or after terraform state rm.

References

  • IBM Cloud Resource Controller API — resource key credentials do not include
    iam_role_crn when created with no IAM role ("NONE")
  • Terraform SDK v2 behaviour: Computed + Optional attributes retain prior state when
    not set during Read

Metadata

Metadata

Assignees

No one assigned

    Labels

    service/Resource ManagementIssues related to Resource Manager or Resource controller Issues

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions