Hiding NICE CXone OAuth client_secret in Terraform state file

I’m trying to set up a secure Terraform provider configuration for our NICE CXone environment. The goal is to automate some routing queue updates without hardcoding secrets. The problem is the client_secret ends up in the .tfstate file in plain text if I’m not careful. This is a security risk for our team.

I’ve tried using a local_sensitive variable. Here’s the I’m using:

locals {
 sensitive_client_secret = var.cxone_client_secret
}

provider "nicecxone" {
 base_url = "https://api.mypurecloud.com"
 client_id = var.cxone_client_id
 client_secret = local.sensitive_client_secret
}

When I run terraform plan, it shows the secret is masked in the output. That’s good. But when I check the state file, the value is still there. I can see it if I open the JSON state file directly. The sensitive flag on locals doesn’t seem to encrypt the state file. It just hides it from the console output.

I also tried using external data source to fetch the secret from AWS Secrets Manager. That works for fetching, but the provider still needs the value passed to it. The provider configuration block seems to store the resolved value in the state.

data "external" "cxone_secret" {
 program = ["bash", "fetch_secret.sh"]
}

The script returns the secret, but again, it’s in the state. I need a way to keep it out of the state file entirely or have it encrypted. Is there a pattern for this? Or do I need to use a remote backend with encryption at rest? Even with S3 backend encryption, the secret is technically in the file, just encrypted. I want it gone. Or at least not stored by Terraform at all.

Does the CXone provider support using a token directly instead of client_id/secret? If I generate a token outside Terraform, I can pass it as a variable. But the token expires. That’s not ideal for IaC. I need a long-lived solution.

Any ideas on how to handle this? I’m stuck.

Are you storing the state remotely in S3 or Azure Blob with encryption enabled? Local state files are risky regardless of variable sensitivity flags.

If you’re using sensitive = true on the variable, Terraform hides it in CLI output, but the decrypted value still hits the state file on disk. The fix isn’t in HCL logic; it’s in state backend configuration.

terraform {
 backend "s3" {
 bucket = "my-terraform-state"
 key = "cxone/terraform.tfstate"
 region = "us-east-1"
 encrypt = true
 dynamodb_table = "terraform-locks"
 }
}

variable "cxone_client_secret" {
 type = string
 sensitive = true
}

We handle this for Genesys Cloud credentials by forcing remote state with server-side encryption. Never trust local state for OAuth secrets. If you’re on a shared drive, move it.