github.com/hugorut/terraform@v1.1.3/website/docs/language/upgrade-guides/0-15.mdx (about) 1 --- 2 page_title: Upgrading to Terraform v0.15 3 description: Upgrading to Terraform v0.15 4 --- 5 6 # Upgrading to Terraform v0.15 7 8 Terraform v0.15 is a major release and so it includes some small changes in 9 behavior that you may need to consider when upgrading. This guide is intended 10 to help with that process. 11 12 The goal of this guide is to cover the most common upgrade concerns and 13 issues that would benefit from more explanation and background. The exhaustive 14 list of changes will always be 15 [the Terraform Changelog](https://github.com/hugorut/terraform/blob/v0.15/CHANGELOG.md). 16 After reviewing this guide, we recommend reviewing the Changelog to check for 17 specific notes about less-commonly-used features. 18 19 This guide is also not intended as an overview of the new features in 20 Terraform v0.15. This release includes other enhancements that don't need any 21 special attention during upgrade, but those are described in the changelog and 22 elsewhere in the Terraform documentation. 23 24 This guide focuses on changes from v0.14 to v0.15. Terraform supports upgrade 25 tools and features only for one major release upgrade at a time, so if you are 26 currently using a version of Terraform prior to v0.14 please upgrade through 27 the latest minor releases of all of the intermediate versions first, reviewing 28 the previous upgrade guides for any considerations that may be relevant to you. 29 30 Unlike the previous few Terraform major releases, v0.15's upgrade concerns are 31 largely conclusions of deprecation cycles left over from previous releases, 32 many of which already had deprecation warnings in v0.14. If you previously 33 responded to those while using Terraform v0.14 then you hopefully won't need 34 to make any special changes to upgrade, although we still recommend reviewing 35 the content below to confirm, particularly if you see new errors or unexpected 36 behavior after upgrading from Terraform v0.14. 37 38 -> If you run into any problems during upgrading that are not addressed by the 39 information in this guide, please feel free to start a topic in 40 [The Terraform community forum](https://discuss.hashicorp.com/c/terraform-core), 41 describing the problem you've encountered in enough detail that other readers 42 may be able to reproduce it and offer advice. 43 44 Upgrade guide sections: 45 46 * [Sensitive Output Values](#sensitive-output-values) 47 * [Legacy Configuration Language Features](#legacy-configuration-language-features) 48 * [Alternative (Aliased) Provider Configurations Within Modules](#alternative-provider-configurations-within-modules) 49 * [Commands Accepting a Configuration Directory Argument](#commands-accepting-a-configuration-directory-argument) 50 * [Microsoft Windows Terminal Support](#microsoft-windows-terminal-support) 51 * [Other Minor Command Line Behavior Changes](#other-minor-command-line-behavior-changes) 52 * [Azure Backend `arm_`-prefixed Arguments](#azure-backend-removed-arguments) 53 54 ## Sensitive Output Values 55 56 Terraform v0.14 previously introduced the ability for Terraform to track and 57 propagate the "sensitivity" of values through expressions that include 58 references to sensitive input variables and output values. For example: 59 60 ```hcl 61 variable "example" { 62 type = string 63 sensitive = true 64 } 65 66 resource "example" "example" { 67 # The following value is also treated as sensitive, because it's derived 68 # from var.example. 69 name = "foo-${var.example}" 70 } 71 ``` 72 73 As part of that feature, Terraform also began requiring you to mark an output 74 value as sensitive if its definition includes any sensitive values itself: 75 76 ```hcl 77 output "example" { 78 value = "foo-${var.example}" 79 80 # Must mark this output value as sensitive, because it's derived from 81 # var.example that is declared as sensitive. 82 sensitive = true 83 } 84 ``` 85 86 Terraform v0.15 extends this mechanism to also work for values derived from 87 resource attributes that the provider has declared as being sensitive. 88 Provider developers will typically mark an attribute as sensitive if the 89 remote system has documented the corresponding field as being sensitive, such 90 as if the attribute always contains a password or a private key. 91 92 As a result of that, after upgrading to Terraform v0.15 you may find that 93 Terraform now reports some of your output values as invalid, if they were 94 derived from sensitive attributes without also being marked as sensitive: 95 96 ``` 97 ╷ 98 │ Error: Output refers to sensitive values 99 │ 100 │ on sensitive-resource-attr.tf line 5: 101 │ 5: output "private_key" { 102 │ 103 │ Expressions used in outputs can only refer to sensitive values if the 104 │ sensitive attribute is true. 105 ╵ 106 ``` 107 108 If you were intentionally exporting a sensitive value, you can address the 109 error by adding an explicit declaration `sensitive = true` to the output 110 value declaration: 111 112 ```hcl 113 output "private_key" { 114 value = tls_private_key.example.private_key_pem 115 sensitive = true 116 } 117 ``` 118 119 With that addition, if this output value was a root module output value then 120 Terraform will hide its value in the `terraform plan` and `terraform apply` 121 output: 122 123 ``` 124 Changes to Outputs: 125 + private_key = (sensitive value) 126 ``` 127 128 -> **Note:** The declaration of an output value as sensitive must be made 129 within the module that declares the output, so if you depend on a third-party 130 module that has a sensitive output value that is lacking this declaration then 131 you will need to wait for a new version of that module before you can upgrade 132 to Terraform v0.15. 133 134 The value is only hidden in the main UI, and so the sensitive value 135 will still be recorded in the state. If you declared this output value in order 136 to use it as part of integration with other software, you can still retrieve 137 the cleartext value using commands intended for machine rather than human 138 consumption, such as `terraform output -json` or `terraform output -raw`: 139 140 ```shellsession 141 $ terraform output -raw private_key 142 -----BEGIN RSA PRIVATE KEY----- 143 MIIEowIBAAKCAQEAoahsvJ1rIxTIOOmJZ7yErs5eOq/Kv9+5l3h0LbxW78K8//Kb 144 OMU3v8F3h8jp+AB/1zGr5UBYfnYp5ncJm/OTCXLFAHxGibEbRnf1m2A3o0hEaWsw 145 # (etc...) 146 ``` 147 148 If you consider Terraform's treatment of a sensitive value to be too 149 conservative and you'd like to force Terraform to treat a sensitive value as 150 non-sensitive, you can use 151 [the `nonsensitive` function](/language/functions/nonsensitive) to 152 override Terraform's automatic detection: 153 154 ```hcl 155 output "private_key" { 156 # WARNING: Terraform will display this result as cleartext 157 value = nonsensitive(tls_private_key.example.private_key_pem) 158 } 159 ``` 160 161 For more information on the various situations where sensitive values can 162 originate in Terraform, refer to the following sections: 163 164 * [Sensitive Input Variables](/language/values/variables#suppressing-values-in-cli-output) 165 * [Sensitive Resource Attributes](/language/expressions/references#sensitive-resource-attributes) 166 * [Sensitive Output Values](/language/values/outputs#sensitive) 167 168 -> **Note:** The new behavior described in this section was previously 169 available in Terraform v0.14 as the 170 [language experiment](/language/settings/#experimental-language-features) 171 `provider_sensitive_attrs`. That experiment has now concluded, so if you were 172 participating in that experiment then you'll now need to remove the experiment 173 opt-in from your module as part of upgrading to Terraform v0.15. 174 175 ## Legacy Configuration Language Features 176 177 Terraform v0.12 introduced new syntax for a variety of existing Terraform 178 language features that were intended to make the language easier to read and 179 write and, in some cases, to better allow for future changes to the language. 180 181 Many of the old forms remained available but deprecated from v0.12 through to 182 v0.14, with these deprecations finally concluding in the v0.15 release. Those 183 who used the `terraform 0.12upgrade` command when upgrading from Terraform v0.11 184 to v0.12 will have had these updated automatically, but we've summarized the 185 changes below to help with any remaining legacy forms you might encounter while 186 upgrading to Terraform v0.15: 187 188 * The built-in functions `list` and `map` were replaced with first-class syntax 189 `[ ... ]` and `{ ... }` in Terraform v0.12, and we've now removed the 190 deprecated functions in order to resolve the ambiguity with the syntax used 191 to declare list and map type constraints inside `variable` blocks. 192 193 If you need to update a module which was using the `list` function, you 194 can get the same result by replacing `list(...)` with `tolist([...])`. 195 For example: 196 197 ```diff 198 - list("a", "b", "c") 199 + tolist(["a", "b", "c"]) 200 ``` 201 202 If you need to update a module which was using the `map` function, you 203 can get the same result by replacing `map(...)` with `tomap({...})`. 204 For example: 205 206 ```diff 207 - map("a", 1, "b", 2) 208 + tomap({ a = 1, b = 2 }) 209 ``` 210 211 The above examples include the type conversion functions `tolist` and 212 `tomap` to ensure that the result will always be of the same type as 213 before. However, in most situations those explicit type conversions won't 214 be necessary because Terraform can infer the necessary type conversions 215 automatically from context. In those cases, you can just use the 216 `[ ... ]` or `{ ... }` syntax directly, without a conversion function. 217 218 * In `variable` declaration blocks, the `type` argument previously accepted 219 v0.11-style type constraints given as quoted strings. This legacy syntax 220 is removed in Terraform v0.15. 221 222 To update an old-style type constraint to the modern syntax, start by 223 removing the quotes so that the argument is a bare keyword rather than 224 a string: 225 226 ```hcl 227 variable "example" { 228 type = string 229 } 230 ``` 231 232 Additionally, if the previous type constraint was either `"list"` or 233 `"map`", add a type argument to specify the element type of the collection. 234 Terraform v0.11 typically supported only collections of strings, so in 235 most cases you can set the element type to `string`: 236 237 ```hcl 238 variable "example" { 239 type = list(string) 240 } 241 242 variable "example" { 243 type = map(string) 244 } 245 ``` 246 247 * In `lifecycle` blocks nested inside `resource` blocks, Terraform previously 248 supported a legacy value `["*"]` for the `ignore_changes` argument, which 249 is removed in Terraform v0.15. 250 251 Instead, use the `all` keyword to indicate that you wish to ignore changes 252 to all of the resource arguments: 253 254 ```hcl 255 lifecycle { 256 ignore_changes = all 257 } 258 ``` 259 260 * Finally, Terraform v0.11 and earlier required all non-constant expressions 261 to be written using string interpolation syntax, even if the result was 262 not a string. Terraform v0.12 introduced a less confusing syntax where 263 arguments can accept any sort of expression without any special wrapping, 264 and so the interpolation-style syntax has been redundant and deprecated 265 in recent Terraform versions. 266 267 For this particular change we have not made the older syntax invalid, but 268 we do still recommend updating interpolation-only expressions to bare 269 expressions to improve readability: 270 271 ```diff 272 - example = "${var.foo}" 273 + example = var.foo 274 ``` 275 276 This only applies to arguments where the value is a single expression without 277 any string concatenation. You must continue to use the `${ ... }` syntax for 278 situations where you are combining string values together into a larger 279 string. 280 281 The `terraform fmt` command can detect and repair simple examples of the 282 legacy interpolation-only syntax, and so we'd recommend running 283 `terraform fmt` on your modules once you've addressed any of the other 284 situations above that could block configuration parsing in order to update 285 your configurations to the typical Terraform language style conventions. 286 287 ## Alternative Provider Configurations Within Modules 288 289 Terraform's provider configuration scheme includes the idea of a "default" 290 (unaliased) provider configuration along with zero or more alternative 291 (aliased) provider configurations. 292 293 The `required_providers` block now has a new field for providers to indicate 294 aliased configuration names, replacing the need for an empty "proxy 295 configuration block" as a placeholder. In order to declare 296 [configuration aliases](/language/modules/develop/providers#provider-aliases-within-modules), 297 add the desired names to the `configuration_aliases` argument for the provider 298 requirements. 299 300 ```hcl 301 terraform { 302 required_providers { 303 aws = { 304 source = "hashicorp/aws" 305 version = ">= 2.7.0" 306 configuration_aliases = [ aws.alternate ] 307 } 308 } 309 } 310 ``` 311 312 Warnings will be emitted now where empty configuration blocks are present but 313 no longer required, though they continue to work unchanged in the 0.15 release. 314 There are a few cases where existing configurations may return new errors: 315 316 * The `providers` map in a module call cannot override a provider configured 317 within the module. This is not a supported configuration, but was previously 318 missed in validation and now returns an error. 319 320 * A provider alias within a module that has no configuration _requires_ a 321 provider configuration be supplied in the module `providers` map. 322 323 * All entries in the `providers` map in a module call must correspond to a 324 provider name within the module. Passing in a configuration to an undeclared 325 provider is now an error. 326 327 ## Commands Accepting a Configuration Directory Argument 328 329 A subset of Terraform's CLI commands have historically accepted a final 330 positional argument to specify which directory contains the root module of 331 the configuration, overriding the default behavior of expecting to find it 332 in the current working directory. 333 334 However, the design of that argument was flawed in a number of ways due to 335 it being handled at the wrong level of abstraction: it only changed where 336 Terraform looks for configuration and not any of the other files that Terraform 337 might search for, and that could therefore violate assumptions that Terraform 338 configurations might make about the locations of different files, leading 339 to confusing error messages. It was also not possible to support this usage 340 pattern across all commands due to those commands using positional arguments 341 in other ways. 342 343 To address these design flaws, Terraform v0.14 introduced a new global option 344 `-chdir` which you can use before the subcommand name, causing Terraform to 345 run the subcommand as if the given directory had been the current working 346 directory: 347 348 ```shellsession 349 $ terraform -chdir=example init 350 ``` 351 352 This command causes the Terraform process to actually change its current 353 working directory to the given directory before launching the subcommand, and 354 so now any relative paths accessed by the subcommand will be treated as 355 relative to that directory, including (but not limited to) the following key 356 directory conventions: 357 358 * As with the positional arguments that `-chdir` replaces, Terraform will look 359 for the root module's `.tf` and `.tf.json` files in the given directory. 360 361 * The `.tfvars` and `.tfvars.json` files that Terraform automatically searches 362 for, and any relative paths given in `-var-file` options, will be searched 363 in the given directory. 364 365 * The `.terraform` directory which Terraform creates to retain the working 366 directory internal state will appear in the given directory, rather than 367 the current working directory. 368 369 After treating the v0.14 releases as a migration period for this new behavior, 370 Terraform CLI v0.15 no longer accepts configuration directories on any 371 command except `terraform fmt`. (`terraform fmt` is special compared to the 372 others because it primarily deals with configuration files in isolation, 373 rather than modules or configurations as a whole.) 374 375 If you built automation which previously relied on overriding the configuration 376 directory alone, you will need to transition to using the `-chdir` command line 377 option before upgrading to Terraform v0.15. 378 379 Since the `-chdir` argument behavior is more comprehensive than the positional 380 arguments it has replaced, you may need to make some further changes in the 381 event that your automation was relying on the limitations of the old mechanism: 382 383 * If your system depends on the `.terraform` directory being created in the 384 _real_ current working directory while using a root module defined elsewhere, 385 you can use the `TF_DATA_DIR` environment variable to specify the absolute 386 path where Terraform should store its working directory internal state: 387 388 ```bash 389 TF_DATA_DIR="$PWD/.terraform" 390 ``` 391 392 * If your system uses `.tfvars` or `.tfvars.json` files either implicitly found 393 or explicitly selected in the current working directory, you must either 394 move those variables files into the root module directory or specify your 395 files from elsewhere explicitly using the `-var-file` command line option: 396 397 ```bash 398 terraform plan -var-file="$PWD/example.tfvars" 399 ``` 400 401 As a special case for backward compatibility, Terraform ensures that the 402 language expression `path.cwd` will return the _original_ working directory, 403 before overriding with `-chdir`, so that existing configurations referring to 404 files in that directory can still work. If you want to refer to files in the 405 directory given in `-chdir` then you can use `path.root`, which returns the 406 directory containing the configuration's root module. 407 408 ## Microsoft Windows Terminal Support 409 410 Until the first Windows 10 update, Microsoft Windows had a console window 411 implementation with an API incompatible with the virtual terminal approach 412 taken on all other platforms that Terraform supports. 413 414 Previous versions of Terraform accommodated this by using an API translation 415 layer which could convert a subset of typical virtual terminal sequences into 416 corresponding Windows Console API function calls, but as a result this has 417 prevented Terraform from using more complex terminal features such as progress 418 indicators that update in place, menu prompts, etc. 419 420 Over the course of several updates to Windows 10, Microsoft has introduced 421 virtual terminal support similar to other platforms and 422 [now recommends the virtual terminal approach for console application developers](https://docs.microsoft.com/en-us/windows/console/classic-vs-vt). 423 In response to that recommendation, Terraform v0.15 no longer includes the 424 terminal API translation layer and consequently it will, by default, produce 425 incorrectly-formatted output on Windows 8 and earlier, and on non-updated 426 original retail Windows 10 systems. 427 428 If you need to keep using Terraform on an older version of Windows, there are 429 two possible workarounds available in the v0.15.0 release: 430 431 * Run Terraform commands using the `-no-color` command line option to disable 432 the terminal formatting sequences. 433 434 This will cause the output to be unformatted plain text, but as a result 435 will avoid the output being interspersed with uninterpreted terminal 436 control sequences. 437 438 * Alternatively, you can use Terraform v0.15.0 in various third-party 439 virtual terminal implementations for older Windows versions, including 440 [ConEmu](https://conemu.github.io/), [Cmder](https://cmder.net/), 441 and [mintty](https://mintty.github.io/). 442 443 Although we have no immediate plans to actively block running Terraform on 444 older versions of Windows, we will not be able to test future versions of 445 Terraform on those older versions and so later releases may contain 446 unintended regressions. We recommend planning an upgrade to a modern Windows 447 release on any system where you expect to continue using Terraform CLI. 448 449 ## Other Minor Command Line Behavior Changes 450 451 Finally, Terraform v0.15 includes a small number of minor changes to the 452 details of some commands and command line arguments, as part of a general 453 cleanup of obsolete features and improved consistency: 454 455 * Interrupting Terraform commands with your operating system's interrupt 456 signal (`SIGINT` on Unix systems) will now cause Terraform to exit with 457 a non-successful exit code. Previously it would, in some cases, exit with 458 a success code. 459 460 This signal is typically sent to Terraform when you press 461 Ctrl+C or similar interrupt keyboard shortcuts in an interactive terminal, 462 but might also be used by automation in order to gracefully cancel a 463 long-running Terraform operation. 464 465 * The `-lock` and `-lock-timeout` options are no longer available for the 466 `terraform init` command. Locking applies to operations that can potentially 467 change remote objects, to help ensure that two concurrent Terraform processes 468 don't try to run conflicting operations, but `terraform init` does not 469 interact with any providers in order to possibly effect such changes. 470 471 These options didn't do anything in the `terraform init` command before, 472 and so you can remove them from any automated calls with no change 473 in behavior. 474 475 * The `-verify-plugins` and `-get-plugins` options to `terraform init` are 476 no longer available. These have been non-functional since Terraform v0.13, 477 with the introduction of the new Terraform Registry-based provider installer, 478 because in practice there are very few operations Terraform can perform which 479 both require a `terraform init` but can also run without valid provider 480 plugins installed. 481 482 If you were using these options in automated calls to `terraform init`, 483 remove them from the command line for compatibility with Terraform v0.15. 484 There is no longer an option to initialize without installing the 485 required provider plugins. 486 487 * The `terraform destroy` command no longer accepts the option `-force`. This 488 was a previous name for the option in earlier Terraform versions, but we've 489 since adopted `-auto-approve` for consistency with the `terraform apply` 490 command. 491 492 If you are using `-force` in an automated call to `terraform destroy`, 493 change to using `-auto-approve` instead. 494 495 ## Azure Backend Removed Arguments 496 497 In an earlier release the `azure` backend changed to remove the `arm_` prefix 498 from a number of the configuration arguments: 499 500 | Old Name | New Name | 501 | --------------------- | ----------------- | 502 | `arm_client_id` | `client_id` | 503 | `arm_client_secret` | `client_secret` | 504 | `arm_subscription_id` | `subscription_id` | 505 | `arm_tenant_id` | `tenant_id` | 506 507 The old names were previously deprecated, but we've removed them altogether 508 in Terraform v0.15 in order to conclude that deprecation cycle. 509 510 If you have a backend configuration using the old names then you may see 511 errors like the following when upgrading to Terraform v0.15: 512 513 ``` 514 ╷ 515 │ Error: Invalid backend configuration argument 516 │ 517 │ The backend configuration argument "arm_client_id" given on 518 │ the command line is not expected for the selected backend type. 519 ╵ 520 ``` 521 522 If you see errors like this, rename the arguments in your backend configuration 523 as shown in the table above and then run the following to re-initialize your 524 backend configuration: 525 526 ``` 527 terraform init -reconfigure 528 ``` 529 530 The `-reconfigure` argument instructs Terraform to just replace the old 531 configuration with the new configuration directly, rather than offering to 532 migrate the latest state snapshots from the old to the new configuration. 533 Migration would not be appropriate in this case because the old and new 534 configurations are equivalent and refer to the same remote objects.