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.