Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_ssm_parameter: Remove overwrite parameter #25636

Open
gdavison opened this issue Jun 30, 2022 · 22 comments
Open

resource/aws_ssm_parameter: Remove overwrite parameter #25636

gdavison opened this issue Jun 30, 2022 · 22 comments
Labels
breaking-change Introduces a breaking change in current functionality; usually deferred to the next major release. enhancement Requests to existing resources that expand the functionality or scope. service/ssm Issues and PRs that pertain to the ssm service.
Milestone

Comments

@gdavison
Copy link
Contributor

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Description

The AWS API uses a PUT operation to create or modify SSM Parameters. By default it will return an error on modify, but setting Overwrite = true allows the modification.

The aws_ssm_parameter resource exposes this as the parameter overwrite. This is redundant for Update operations, since the provider always sets it to true. When creating an aws_ssm_parameter, setting overwrite = true allows the Create operation to act as an Import. This does not match the standard Terraform resource model, so should be removed.

This will be a breaking change.

@gdavison gdavison added enhancement Requests to existing resources that expand the functionality or scope. breaking-change Introduces a breaking change in current functionality; usually deferred to the next major release. labels Jun 30, 2022
@gdavison gdavison added this to the v5.0.0 milestone Jun 30, 2022
@mjburling
Copy link

When creating an aws_ssm_parameter, setting overwrite = true allows the Create operation to act as an Import. This does not match the standard Terraform resource model, so should be removed.

Hi, @gdavison. I agree that it doesn't match the Terraform resource model, but I'm struggling with this a bit: should the provider be more faithful to the API or more faithful to the Terraform resource model?

I'm currently building something where I was expecting AWS SSM Parameter Store's Overwrite Request Parameter to be exposed in terraform. I have a subset of parameters that users find easier to work with if they use some of Parameter Store's built-in features: the TUI (awscli) or GUI (AWS Console) frontends. Developers can quickly adjust parameters and even add new ones on the fly to be consumed in their ephemeral environments, and they aren't forced to go back to update terraform/yaml, commit their changes, and wait for the CI process. However, when that automation is run (for further updates or destruction) terraform is supportive and captures their changes in tfstate. The process is lightweight and helps us keep the hierarchies tidy–no dangling hierarchies upon destruction.

It's more strictly (statefully) controlled for production environments. I'll admit, this is an edge case and maybe I'm doing it wrong. I'm torn.

@jar-b jar-b added the service/ssm Issues and PRs that pertain to the ssm service. label May 24, 2023
@johnsonaj johnsonaj modified the milestones: v5.0.0, v6.0.0 May 24, 2023
@orlovmyk
Copy link

orlovmyk commented Jun 9, 2023

And how do I need to handle situations where I want to create new version by Terraform rather than recreate parameter each time? For example I need to have versioning for Canary deployments.

@orlovmyk
Copy link

@gdavison Any comment on this? This change is breaking and you haven't give any alternative...?

@orlovmyk
Copy link

@gdavison From terraform docs
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter.html#overwrite

overwrite - (Optional, Deprecated) 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).

Can you give me an example how to use lifecycle meta-argument to achieve same behaviour? I tried almost everything, but have no clue what you meant by that note.

@briceburg
Copy link

briceburg commented Jun 21, 2023

I too am in the same boat as @orlovmyk ^^^ and would benefit to see an example of lifecycle rules in the documentation.

For context:
We manage ssm parameters in terraform, and previously had the overwrite = true attribute set. This (I thought) allowed the value to change. The parameters were never imported and always managed by terraform.

In trying to move to the 5.0 version of AWS provider, I removed the overwrite attribute as it's marked deprecated and am now getting ParameterAlreadyExists errors.

│ Error: updating SSM Parameter (/discovery/v1/namespaces/...): ParameterAlreadyExists: The parameter already exists. To overwrite this value, set the overwrite option in the request to true.

edit isn't it strange to see the error message recommending to set a deprecated parameter?

The terraform looks something like:

locals {
  discovery_path = "/discovery/v1/namespaces/${var.config.id}"
  discovery_params = {
    account_name         = "foo"
    account_tier         = "bar"
    ...
  }
}

resource "aws_ssm_parameter" "discovery" {
  for_each = local.discovery_params
  name     = "${local.discovery_path}/${each.key}"
  type     = "String"
  value    = jsonencode(each.value)

  tags = {
    Namespace = var.config.id
  }
}

Any ideas on managing these paramters whose values perodically change? /cc @jar-b

Thanks!

@briceburg
Copy link

To followup on ^^^, following the migration guide for aws_ssm_parameter I tried importing these resources and am getting "Resource already managed by terraform" error...

module.namespace.aws_ssm_parameter.discovery["lb"]: Importing from ID "/discovery/v1/namespaces/pe-app-dev/lb"...
module.namespace.aws_ssm_parameter.discovery["lb"]: Import prepared!
  Prepared aws_ssm_parameter for import
╷
│ Error: Resource already managed by Terraform
│
│ Terraform is already managing a remote object for
│ module.namespace.aws_ssm_parameter.discovery["lb"]. To import to this address
│ you must first remove the existing object from the state.

so kind of at a loss of what to do. We have a many params across many configurations and the removing from state <-> re-importing is not a trivial thing.

to sumarize,

  • we previously managed SSM parameters with v4 of the provider and overwrite = true set.
  • upgrading to v5 of the provider sends a deprecation notice, so we remove overwrite = true.
    • removing overwrite = true results in ParameterAlreadyExists errors when applying the configuration, and suggests adding overwrite = true which is deprecated?
    • importing the resource results in "Resource already managed by Terraform" error and is tedious

@ChrisMcKee
Copy link
Contributor

Not sure why this was marked as depreciated before feeling it out.
The parameter is useful, by all means feel free to have the plan output warn that the keys already exist but removing it when it's available in the api seems backwards.

@phyber
Copy link
Contributor

phyber commented Jul 3, 2023

I believe this will break at least one workflow in an environment I work with.

There is a base set of Terraform that creates initial resources in an account, including setting some SSM Parameters. This Terraform uses lifecycling to ignore changes to the SSM Parameter value that it sets.

Later, in another set of Terraform managing other resources for the same account, these SSM Parameters are referenced via a data lookup.

Some resources are created (in Kubernetes) based on that SSM Parameter before the SSM Parameter is finally overwritten with a new value. That resource in Kubernetes does its thing and then ceases to exist. We do not want Terraform to create the resource on every terraform apply, so it's controlled via an SSM Parameter.

Because this manipulation of the same SSM Parameter happens in different Terraform workspaces (and separate state files), I believe that the overwriting of the SSM Parameter that we do here would cause an error if the overwrite parameter is removed.

The parameter wouldn't exist in the 2nd state file, which I believe means that Terraform wouldn't know to set the overwrite parameter to true internally, and the API would throw an error since the SSM Parameter already exists in AWS.

@jar-b
Copy link
Member

jar-b commented Jul 6, 2023

Hi everyone - first off, we apologize for the confusion deprecation of this argument and the entry in the V5 upgrade guide have caused. Given the number of questions, a more detailed explanation of the propsed changes is in order.

Ultimately the goal is to align the SSM parameter resource with the standard Terraform resource model. Specifically, the overwrite attribute enables adoption of existing resources on create ("import-on-create"), and the ability to skip update operations without a lifecycle rule. Both of these are anti-patterns, and removal of the overwrite argument will encourage the use of explicit imports and the lifecycle rules to control update flows, respectively.

The sections below cover each of these issues in more depth, and provide descriptions of how the same behavior can be achieved once this attribute is removed in v6.0.0.


Import on create

Current behavior

Setting overwrite to true currently allows the resource to inherit existing parameters created outside of Terraform.

Future behavior

In v6.0.0 this will no longer be possible, as overwrite will be removed and the provider will set the value to false internally on all create operations. To begin managing an existing resourece, first import it with either the CLI or an import block.

import {
  to = aws_ssm_parameter.example
  id = "/some/param"
}

resource "aws_ssm_parameter" "example" {
  name = "/some/param"
  # (other resource arguments...)
}

Skipping updates without a lifecycle rule

Current behavior

Setting overwrite to false currently allows resource updates to be skipped without specifying a lifecycle rule.

Future behavior

In v6.0.0 this will no longer be possible, as overwrite will be removed and the provider will set the value to true internally on all update operations. To skip updating a resource when certain arguments change, the ignore_changes lifecycle rule can be used.

resource "aws_ssm_parameter" "example" {
  name = "/some/param"
  type  = "String"
  value = "foo"

  lifecycle {
    ignore_changes = [value]
  }
}

What changed in v5.0.0?

The deprecation note added in v5.0.0 was part of our normal process for argument removals. Before making the breaking changes outlined above in v6.0.0, we provide notice that this argument is set to be removed in the future.

To prepare for v6.0.0, configurations where overwrite is used to adopt ownership of existing resources can add an import block to make the operation explicit. Configurations where overwrite is set to false to prevent updates can change to an ignore_changes lifecycle block. Lastly, and unfortunately, configurations expecting the standard update flow will need to keep overwrite = true set until this becomes the default behavior in v6.0.0. Removing it in v5.X will result in the default value of false, preventing the parameter value from being updated, causing persistent differences.

@briceburg
Copy link

@jar-b thanks for the update and clear explanation. is there a workaround for 5.0 currently to avoid the deprecation notice? in my situation I am;

  • unable to import the resource (Resource already managed by Terraform error).
  • unable to update the resource without setting overwrite to true (ParameterAlreadyExists)

thus I have to set overwrite to true and see the deprecation notice. I think my use-case is that I always have managed the ssm parameter via the terraform configuration (in v4 of the aws provider), but decided to set overwrite to true (it wasn't deprecated) in case the parameter got updated outside of terraform and thus terrafrom would revert the external change (kind of like crossplane).

@jar-b
Copy link
Member

jar-b commented Jul 21, 2023

Hey @briceburg - Based on your description is sounds like you're expecting the standard Terraform workflow, mentioned above here:

Lastly, and unfortunately, configurations expecting the standard update flow will need to keep overwrite = true set until this becomes the default behavior in v6.0.0. Removing it in v5.X will result in the default value of false, preventing the parameter value from being updated.

There isn't currently a workaround to avoid the deprecation notice in v5.X, but when this becomes the default behavior in v6.0.0 you can simply remove the overwrite parameter and retain the same behavior.

@briceburg
Copy link

Ok great! We can live with it =) I wanted to doubly make sure our terraforms were not deviating too far towards exotic...

So in a post v6+ world, where we have an SSM parameter created by an "upstream" terraform configuration and potentially updated by a "downstream" one, could we use the following pattern?

upstream terraform

# create addon discovery params
resource "aws_ssm_parameter" "addons" {
  for_each = toset(["foo", "bar"])
  name     = "/disovery/v1/addons/${each.key}"
  type     = "String"
  value    = jsonencode({ enabled : false })

  # ignore subsequent 'downstream' changes
  lifecycle {
    ignore_changes = [value, tags]
  }
}

downstream terraform

import {
  id = "/disovery/v1/addons/foo"
  to = aws_ssm_parameter.discovery
}

# enable the 'foo' addon
resource "aws_ssm_parameter" "discovery" {
  name = "/disovery/v1/addons/foo"
  type = "String"
  value = jsonencode({
    enabled = true
    hello   = "world"
  })
} 

@jar-b
Copy link
Member

jar-b commented Jul 21, 2023

Yes, the import block would be the new pattern to achieve the "import-on-create" behavior overwrite = true previously enabled for the "downstream" resource.

The import docs also mention leaving the block permanently as a record of the resource origin, so I don't think this approach deviates too far from the intended use of the feature.

The import block records that Terraform imported the resource and did not create it. After importing, you can optionally remove import blocks from your configuration or leave them as a record of the resource's origin.

@sirocode
Copy link

Hi, the overwrite feature has been working for years and it's a crucial part for a tons of deployments in my company now. We store docker tags (as well as other deployment-wide params) of the images in SSM param store and using "terraform apply -var image_ver=1234" to deploy new image to AWS ECS.

In case when image_ver var is not specified the image version gets collected using terraform data. It's a bullet proof schema that has been working like a charm for years.

@arnvid
Copy link

arnvid commented Aug 17, 2023

In our case we use a variable to set part of the ssm path - and the new import block does not support this.

import {
  to = aws_ssm_parameter.bootstrap_complete
  id = "${local.tlz_prefix}/bootstrap_complete"
}

resource "aws_ssm_parameter" "bootstrap_complete" {
  name           = "${local.tlz_prefix}/bootstrap_complete"
  type           = "String"
  insecure_value = var.tlz_bootstrap_complete
}

Error: Variables not allowed

│ on ssm.tf line 18, in import:
│ 18: id = "${local.tlz_prefix}/bootstrap_complete"

│ Variables may not be used here.


│ Error: Unsuitable value type

│ on ssm.tf line 18, in import:
│ 18: id = "${local.tlz_prefix}/bootstrap_complete"

│ Unsuitable value: value must be known

@dmajano
Copy link

dmajano commented Sep 18, 2023

In our case, we have the creation of every ssm parameter store with a "null" value first, and after, in another terraform stack, we define the value of these parameters.

The creation part with ignore_changes is covered:

resource "aws_ssm_parameter" "app" {
  for_each = toset(local.app_parameters)
  name  = "${local.app_path}/${each.key}"
  type  = "String"
  value = "null"

  lifecycle {
    ignore_changes        = all
  }
}

The second part, update the parameter's value without overwrite is very painful because we have all our terraform projects developed with nested modules and the import block only can be used at root level:

│ Error: Invalid import configuration
│ 
│   on ../../globals/app/main.tf line 5:
│    5: import {
│ 
│ An import block was detected in "module.globals_app". Import blocks are only allowed in the root module.
╵
╷
│ Error: Variables not allowed
│ 
│   on ../../globals/app/main.tf line 7, in import:
│    7:   id = "${local.path}/example"
│ 
│ Variables may not be used here.

While with overwrite = true everything is completely simplified

@jbonnier
Copy link

jbonnier commented Oct 4, 2023

Kinda weird that there is no in the middle workaround.

Usually, when something is deprecated. The future configuration is implemented in a non-breaking way with a deprecation warning. And in the next major release, the deprecated functionality is removed.

If I understood this thread correctly, there is no way to implement the new configuration before moving to v6.0.0 which is kinda weird.

@pvilasra
Copy link

pvilasra commented Oct 8, 2023

I am using terraform v1.1.2 version If I want to use import block instead of overrite = "true" , The import blocks are only available in Terraform v1.5.0 and later. If I use terraform import command its says resource already managed by terraform. If I remove overrrite parameter it says resource already created. So I need to upgrade terraform version to latest v1.6.0 for this change ? or is there any other workaround for this?

@kovaacs
Copy link

kovaacs commented Dec 8, 2023

I agree that it's very strange to get a deprecation warning without any action possible until the actual breaking change.

Either there should be

  • no warning now and this should be considered a breaking change in 6.0, or
  • warning now with a clear way to accommodate the change coming in 6.0.

What we have now is the worst of both worlds. Correct me if I'm wrong.

@faust64
Copy link

faust64 commented Dec 11, 2023

Hi,

I'm a little confused as well ... I did attempt to remove that "overwrite" from my code, at which point terraform is unable to write values, when rotating some secret.

Can't share exact code here, sorry, ... imagine I have an iam_access_key. its value written as an SSM parameter. And a time_rotating.
My access key is rotating on an interval. When it does, Terraform plan show my SSM param should be re-created. Omitting that "overwrite=true", Terraform apply fails to write new value. Tells me param already exists.

Would make sense for replacement to first delete old value, and only then write new copy.
Would be nice being able to test that code change, before deprecation turns into full removal.

Thanks!

@queglay
Copy link

queglay commented Dec 20, 2023

I am very confused after coming across this deprecation warning, so I disabled the overwrite value.
but then when I try to import the resource it says I cannot as its already managed by terraform. and then if I apply I get:

Error: updating SSM Parameter (/firehawk/resourcetier/dev/vault_kms_unseal_key_id): ParameterAlreadyExists: The parameter already exists. To overwrite this value, set the overwrite option in the request to true.

What should I do to adhere to the deprecation warning and deprecate the parameter while still allowing me to set parameter values?

@tjstansell
Copy link

In some cases, we use the overwrite flag to ensure that terraform takes over any existing parameter store entries that might have been manually added in the past. they don't necessarily exist. if we try to use an import block, it will fail if it doesn't exist. There's no way to say "import if it exists, otherwise create it", which the current overwrite=true attribute gives us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Introduces a breaking change in current functionality; usually deferred to the next major release. enhancement Requests to existing resources that expand the functionality or scope. service/ssm Issues and PRs that pertain to the ssm service.
Projects
None yet
Development

No branches or pull requests