8

I am using terraform to create a parameter in the AWS Parameter Store.

resource "aws_ssm_parameter" "username" {
  name      = "username"
  type      = "SecureString"
  value     = "to_be_defined"
  overwrite = false
}

provider "aws" {
  version = "~> 1.53"
}

When I run terraform apply for the first time, if the parameter does not exist terraform creates the parameter. However, if I run it again (usually with a different value) I get the error

ParameterAlreadyExists: The parameter already exists. To overwrite this value, set the overwrite option in the request to true

If I understand correctly, this is due to the behaviour of AWS Cli (not specific to the provider).

The current behavior for overwrite = false is

If the parameter does not exist, create it
If the parameter exists, throw exception

What I want to achieve is

If the parameter does not exist, create it
If the parameter exists, do nothing

I did not find a way in AWS CLI documentation to achieve the desired behavior.

I would like to know if there is any way to achieve the desired behaviour using terraform (or directly via AWS CLI)

Ankit
  • 6,772
  • 11
  • 48
  • 84
  • Why would you want it do nothing? The whole point of a resource being in Terraform's state is for it to manage it and update it to the expected value, potentially correcting drift. If you don't want that then you shouldn't be using Terraform to create/manage the resource. – ydaetskcoR Jun 12 '19 at 19:34
  • Good point @ydaetskcoR. I think I was trying to hack terraform for something it is not designed for, during the build process. I will see if I can use terraform to do what is was intended for; store state. – Ankit Jun 13 '19 at 16:31

1 Answers1

14

I agree with @ydaetskcoR that you should maintain the value with terraform state as well.

But if you insist to ignore the value to be updated if the SSM key is exist, you can use lifecycle ignore_changes(https://www.terraform.io/docs/configuration/resources.html#ignore_changes)

So in your case, you can update the code to

resource "aws_ssm_parameter" "username" {
  name      = "username"
  type      = "SecureString"
  value     = "to_be_defined"
  overwrite = false

  lifecycle {
    ignore_changes = [
      value,
    ]
  }
}

overwrite - (Optional) Overwrite an existing parameter. If not specified, will default to false if the resource has not been created by terraform to avoid overwrite of existing resource and will default to true otherwise (terraform lifecycle rules should then be used to manage the update behavior).

By the way, it is not good design to manage SecureString SSM key/value with terraform, because its tfstate file is not encrypted.

Joshua Schlichting
  • 3,110
  • 6
  • 28
  • 54
BMW
  • 42,880
  • 12
  • 99
  • 116
  • Thanks. I think I will see if I can use terraform to represent state as @ydaetskcoR suggested. Good point about security with the state. However, I am storing state in S3 and do encrypt it using kms key. – Ankit Jun 13 '19 at 16:32
  • Any time I need to use `ignore_changes` is normally a big red flag that I'm doing something wrong or Terraform is not the right tool for the job. In fact the only 2 places I have an `ignore_changes` in my reasonably large Terraform code base is to handle a couple of bugs in the AWS provider. – ydaetskcoR Jun 13 '19 at 17:43
  • Any time I need to use `ignore_changes` is normally a big red flag that I'm doing something wrong or Terraform is not the right tool for the job. In fact the only 2 places I have an `ignore_changes` in my reasonably large Terraform code base is to handle a couple of bugs in the AWS provider. – ydaetskcoR Jun 13 '19 at 17:43
  • 1
    If you deal with `desired capacity` in autoscaling group, you definiately need ignore on the change to it. There are several other use cases as well. – BMW Jun 14 '19 at 02:14