Version 2.0.0 of the AWS provider for Terraform is a major release and includes some changes that you will need to consider when upgrading. This guide is intended to help with that process and focuses only on changes from version 1.60.0 to version 2.0.0.
Most of the changes outlined in this guide have been previously marked as deprecated in the Terraform plan/apply output throughout previous provider releases. These changes, such as deprecation notices, can always be found in the Terraform AWS Provider CHANGELOG.
Upgrade topics:
We recommend using version constraints when configuring Terraform providers. If you are following that recommendation, update the version constraints in your Terraform configuration and run terraform init
to download the new version.
Update to latest 1.X version:
provider "aws" {
# ... other configuration ...
version = "~> 1.60"
}
Update to latest 2.X version:
provider "aws" {
# ... other configuration ...
version = "~> 2.0"
}
If the provider is unable to determine the AWS account ID from a provider assume role configuration or the STS GetCallerIdentity call used to verify the credentials (if skip_credentials_validation = false
), it will attempt to lookup the AWS account ID via EC2 metadata, IAM GetUser, IAM ListRoles, and STS GetCallerIdentity. Previously, the provider would silently allow the failure of all the above methods.
The provider will now return an error to ensure operators understand the implications of the missing AWS account ID in the provider.
If necessary, the AWS account ID lookup logic can be skipped via:
provider "aws" {
# ... other configuration ...
skip_requesting_account_id = true
}
The owners
argument is now required. Specifying owner-id
or owner-alias
under filter
does not satisfy this requirement.
The owners
argument is now required. Specifying owner-id
or owner-alias
under filter
does not satisfy this requirement.
Switch your attribute references to the assume_role_policy
attribute instead.
Switch your attribute references to the unique_id
attribute instead.
Switch your Terraform configuration to the name
argument instead.
The implementation of the aws_kms_secret
data source, prior to Terraform AWS provider version 2.0.0, used dynamic attribute behavior which is not supported with Terraform 0.12 and beyond (full details available in this GitHub issue).
Terraform configuration migration steps:
aws_kms_secret
to aws_kms_secrets
"${data.aws_kms_secret.example.ATTRIBUTE}"
) from .ATTRIBUTE
to .plaintext["ATTRIBUTE"]
As an example, lets take the below sample configuration and migrate it.
# Below example configuration will not be supported in Terraform AWS provider version 2.0.0
data "aws_kms_secret" "example" {
secret {
# ... potentially other configuration ...
name = "master_password"
payload = "AQEC..."
}
secret {
# ... potentially other configuration ...
name = "master_username"
payload = "AQEC..."
}
}
resource "aws_rds_cluster" "example" {
# ... other configuration ...
master_password = "${data.aws_kms_secret.example.master_password}"
master_username = "${data.aws_kms_secret.example.master_username}"
}
Notice that the aws_kms_secret
data source previously was taking the two secret
configuration block name
arguments and generating those as attribute names (master_password
and master_username
in this case). To remove the incompatible behavior, this updated version of the data source provides the decrypted value of each of those secret
configuration block name
arguments within a map attribute named plaintext
.
Updating the sample configuration from above:
data "aws_kms_secrets" "example" {
secret {
# ... potentially other configuration ...
name = "master_password"
payload = "AQEC..."
}
secret {
# ... potentially other configuration ...
name = "master_username"
payload = "AQEC..."
}
}
resource "aws_rds_cluster" "example" {
# ... other configuration ...
master_password = "${data.aws_kms_secrets.example.plaintext["master_password"]}"
master_username = "${data.aws_kms_secrets.example.plaintext["master_username"]}"
}
The arn
attribute now always returns the unqualified (no :QUALIFIER
or :VERSION
suffix) ARN value and the qualified_arn
attribute now always returns the qualified (includes :QUALIFIER
or :VERSION
suffix) ARN value. Previously by default, the arn
attribute included :$LATEST
suffix when not setting the optional qualifier
argument, which was not compatible with many other resources. To restore the previous default behavior, set the qualifier
argument to $LATEST
and reference the qualified_arn
attribute.
Simply remove current = true
from your Terraform configuration. The data source defaults to the current provider region if no other filtering is enabled.
Since the API Gateway usage plans feature was launched on August 11, 2016, usage plans are now required to associate an API key with an API stage. To migrate your Terraform configuration, the AWS provider implements support for usage plans with the following resources:
For example, given this previous configuration:
resource "aws_api_gateway_rest_api" "example" {
name = "example"
}
resource "aws_api_gateway_deployment" "example" {
rest_api_id = "${aws_api_gateway_rest_api.example.id}"
stage_name = "example"
}
resource "aws_api_gateway_api_key" "example" {
name = "example"
stage_key {
rest_api_id = "${aws_api_gateway_rest_api.example.id}"
stage_name = "${aws_api_gateway_deployment.example.stage_name}"
}
}
An updated configuration:
resource "aws_api_gateway_rest_api" "example" {
name = "example"
}
resource "aws_api_gateway_deployment" "example" {
rest_api_id = "${aws_api_gateway_rest_api.example.id}"
stage_name = "example"
}
resource "aws_api_gateway_api_key" "example" {
name = "example"
}
resource "aws_api_gateway_usage_plan" "example" {
name = "example"
api_stages {
api_id = "${aws_api_gateway_rest_api.example.id}"
stage = "${aws_api_gateway_deployment.example.stage_name}"
}
}
resource "aws_api_gateway_usage_plan_key" "example" {
key_id = "${aws_api_gateway_api_key.example.id}"
key_type = "API_KEY"
usage_plan_id = "${aws_api_gateway_usage_plan.example.id}"
}
Switch your Terraform configuration to the request_parameters
argument instead.
For example, given this previous configuration:
resource "aws_api_gateway_integration" "example" {
# ... other configuration ...
request_parameters_in_json = <<PARAMS
{
"integration.request.header.X-Authorization": "'static'"
}
PARAMS
}
An updated configuration:
resource "aws_api_gateway_integration" "example" {
# ... other configuration ...
request_parameters = {
"integration.request.header.X-Authorization" = "'static'"
}
}
Switch your Terraform configuration to the response_parameters
argument instead.
For example, given this previous configuration:
resource "aws_api_gateway_integration_response" "example" {
# ... other configuration ...
response_parameters_in_json = <<PARAMS
{
"method.response.header.Content-Type": "integration.response.body.type"
}
PARAMS
}
An updated configuration:
resource "aws_api_gateway_integration_response" "example" {
# ... other configuration ...
response_parameters = {
"method.response.header.Content-Type" = "integration.response.body.type"
}
}
Switch your Terraform configuration to the request_parameters
argument instead.
For example, given this previous configuration:
resource "aws_api_gateway_method" "example" {
# ... other configuration ...
request_parameters_in_json = <<PARAMS
{
"method.request.header.Content-Type": false,
"method.request.querystring.page": true
}
PARAMS
}
An updated configuration:
resource "aws_api_gateway_method" "example" {
# ... other configuration ...
request_parameters = {
"method.request.header.Content-Type" = false
"method.request.querystring.page" = true
}
}
Switch your Terraform configuration to the response_parameters
argument instead.
For example, given this previous configuration:
resource "aws_api_gateway_method_response" "example" {
# ... other configuration ...
response_parameters_in_json = <<PARAMS
{
"method.response.header.Content-Type": true
}
PARAMS
}
An updated configuration:
resource "aws_api_gateway_method_response" "example" {
# ... other configuration ...
response_parameters = {
"method.response.header.Content-Type" = true
}
}
The following arguments have been moved into a nested argument named step_scaling_policy_configuration
:
adjustment_type
cooldown
metric_aggregation_type
min_adjustment_magnitude
step_adjustment
For example, given this previous configuration:
resource "aws_appautoscaling_policy" "example" {
# ... other configuration ...
adjustment_type = "ChangeInCapacity"
cooldown = 60
metric_aggregation_type = "Maximum"
step_adjustment {
metric_interval_upper_bound = 0
scaling_adjustment = -1
}
}
An updated configuration:
resource "aws_appautoscaling_policy" "example" {
# ... other configuration ...
step_scaling_policy_configuration {
adjustment_type = "ChangeInCapacity"
cooldown = 60
metric_aggregation_type = "Maximum"
step_adjustment {
metric_interval_upper_bound = 0
scaling_adjustment = -1
}
}
}
Switch your Terraform configuration to the min_adjustment_magnitude
argument instead.
For example, given this previous configuration:
resource "aws_autoscaling_policy" "example" {
# ... other configuration ...
min_adjustment_step = 2
}
An updated configuration:
resource "aws_autoscaling_policy" "example" {
# ... other configuration ...
min_adjustment_magnitude = 2
}
Switch your attribute references to the ecs_cluster_arn
attribute instead.
Switch your Terraform configuration to the ordered_cache_behavior
argument instead. It behaves similar to the previous cache_behavior
argument, however the ordering of the configurations in Terraform is now reflected in the distribution where previously it was indeterminate.
For example, given this previous configuration:
resource "aws_cloudfront_distribution" "example" {
# ... other configuration ...
cache_behavior {
# ... other configuration ...
}
cache_behavior {
# ... other configuration ...
}
}
An updated configuration:
resource "aws_cloudfront_distribution" "example" {
# ... other configuration ...
ordered_cache_behavior {
# ... other configuration ...
}
ordered_cache_behavior {
# ... other configuration ...
}
}
Choose one argument or the other. These arguments update the same underlying information in Cognito and the selection is indeterminate if differing values are provided.
Choose one argument or the other. These arguments update the same underlying information in Cognito and the selection is indeterminate if differing values are provided.
Choose one argument or the other. These arguments update the same underlying information in Cognito and the selection is indeterminate if differing values are provided.
Default connections have been removed as part of LAG creation. To migrate your Terraform configuration, the AWS provider implements the following resources:
For example, given this previous configuration:
resource "aws_dx_lag" "example" {
name = "example"
connections_bandwidth = "1Gbps"
location = "EqSe2-EQ"
number_of_connections = 1
}
An updated configuration:
resource "aws_dx_connection" "example" {
name = "example"
bandwidth = "1Gbps"
location = "EqSe2-EQ"
}
resource "aws_dx_lag" "example" {
name = "example"
connections_bandwidth = "1Gbps"
location = "EqSe2-EQ"
}
resource "aws_dx_connection_association" "example" {
connection_id = "${aws_dx_connection.example.id}"
lag_id = "${aws_dx_lag.example.id}"
}
Switch your Terraform configuration to the ordered_placement_strategy
argument instead. It behaves similar to the previous placement_strategy
argument, however the ordering of the configurations in Terraform is now reflected in the distribution where previously it was indeterminate.
For example, given this previous configuration:
resource "aws_ecs_service" "example" {
# ... other configuration ...
placement_strategy {
# ... other configuration ...
}
placement_strategy {
# ... other configuration ...
}
}
An updated configuration:
resource "aws_ecs_service" "example" {
# ... other configuration ...
ordered_placement_strategy {
# ... other configuration ...
}
ordered_placement_strategy {
# ... other configuration ...
}
}
Switch your Terraform configuration to the creation_token
argument instead.
For example, given this previous configuration:
resource "aws_efs_file_system" "example" {
# ... other configuration ...
reference_name = "example"
}
An updated configuration:
resource "aws_efs_file_system" "example" {
# ... other configuration ...
creation_token = "example"
}
Switch your Terraform configuration to the preferred_availability_zones
argument instead. The argument is still optional and the API will continue to automatically choose Availability Zones for nodes if not specified. The new argument will also continue to match the APIs required behavior that the length of the list must be the same as num_cache_nodes
.
For example, given this previous configuration:
resource "aws_elasticache_cluster" "example" {
# ... other configuration ...
availability_zones = ["us-west-2a", "us-west-2b"]
}
An updated configuration:
resource "aws_elasticache_cluster" "example" {
# ... other configuration ...
preferred_availability_zones = ["us-west-2a", "us-west-2b"]
}
When attempting to bring existing IAM User Login Profiles under Terraform management, terraform import
is now required. See the aws_iam_user_login_profile
resource documentation for more information.
Switch your attribute references to the primary_network_interface_id
attribute instead.
Setting reserved_concurrent_executions
to 0
will now disable Lambda Function invocations, causing downtime for the Lambda Function.
Previously reserved_concurrent_executions
accepted 0
and below for unreserved concurrency, which means it was not previously possible to disable invocations. The argument now differentiates between a new value for unreserved concurrency (-1
) and disabling Lambda invocations (0
). If previously configuring this value to 0
for unreserved concurrency, update the configured value to -1
or the resource will disable Lambda Function invocations on update. If previously unconfigured, the argument does not require any changes.
See the Lambda User Guide for more information about concurrency.
Switch your arn
attribute references to the layer_arn
attribute instead and vice-versa.
Switch your Terraform configuration to the subnet_ids
argument instead.
For example, given this previous configuration:
resource "aws_network_acl" "example" {
# ... other configuration ...
subnet_id = "subnet-12345678"
}
An updated configuration:
resource "aws_network_acl" "example" {
# ... other configuration ...
subnet_ids = ["subnet-12345678"]
}
The following arguments have been moved into a nested argument named logging
:
bucket_name
enable_logging
(also renamed to just enable
)s3_key_prefix
For example, given this previous configuration:
resource "aws_redshift_cluster" "example" {
# ... other configuration ...
bucket_name = "example"
enable_logging = true
s3_key_prefix = "example"
}
An updated configuration:
resource "aws_redshift_cluster" "example" {
# ... other configuration ...
logging {
bucket_name = "example"
enable = true
s3_key_prefix = "example"
}
}
Previously, importing this resource resulted in an aws_route
resource for each route, in
addition to the aws_route_table
, in the Terraform state. Support for importing aws_route
resources has been added and importing this resource only adds the aws_route_table
resource, with in-line routes, to the state.
The resource now requires existing Route 53 Records to be imported into the Terraform state for management unless the allow_overwrite
argument is enabled.
For example, if the www.example.com
Route 53 Record in the example.com
Route 53 Hosted Zone existed previously and this new Terraform configuration was introduced:
resource "aws_route53_record" "www" {
# ... other configuration ...
name = "www.example.com"
}
During resource creation in version 1.X and prior, it would silently perform an UPSERT
changeset to the existing Route 53 Record and not report back an error. In version 2.0.0 of the Terraform AWS Provider, the resource now performs a CREATE
changeset, which will error for existing Route 53 Records.
The allow_overwrite
argument provides a workaround to keep the old behavior, but most existing workflows should be updated to perform a terraform import
command like the following instead:
$ terraform import aws_route53_record.www ZONEID_www.example.com_TYPE
More information can be found in the aws_route53_record
resource documentation.
Switch your Terraform configuration to vpc
configuration block(s) instead.
For example, given this previous configuration:
resource "aws_route53_zone" "example" {
# ... other configuration ...
vpc_id = "..."
}
An updated configuration:
resource "aws_route53_zone" "example" {
# ... other configuration ...
vpc {
vpc_id = "..."
}
}
Switch your Terraform configuration to the byte_match_tuples
argument instead.
For example, given this previous configuration:
resource "aws_wafregional_byte_match_set" "example" {
# ... other configuration ...
byte_match_tuple {
# ... other configuration ...
}
byte_match_tuple {
# ... other configuration ...
}
}
An updated configuration:
resource "aws_wafregional_byte_match_set" "example" {
# ... other configuration ...
byte_match_tuples {
# ... other configuration ...
}
byte_match_tuples {
# ... other configuration ...
}
}