Terraform AWS Provider Version 3 Upgrade Guide
Version 3.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 2.X to version 3.0.0. See the Version 2 Upgrade Guide for information about upgrading from 1.X 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.
\~> NOTE: Version 3.0.0 and later of the AWS Provider can only be automatically installed on Terraform 0.12 and later.
Upgrade topics:
- Provider Version Configuration
- Provider Authentication Updates
- Provider Custom Service Endpoint Updates
- Data Source: aws_availability_zones
- Data Source: aws_lambda_invocation
- Data Source: aws_launch_template
- Data Source: aws_route53_resolver_rule
- Data Source: aws_route53_zone
- Resource: aws_acm_certificate
- Resource: aws_api_gateway_method_settings
- Resource: aws_autoscaling_group
- Resource: aws_cloudfront_distribution
- Resource: aws_cloudwatch_log_group
- Resource: aws_codepipeline
- Resource: aws_cognito_user_pool
- Resource: aws_dx_gateway
- Resource: aws_dx_gateway_association
- Resource: aws_dx_gateway_association_proposal
- Resource: aws_ebs_volume
- Resource: aws_elastic_transcoder_preset
- Resource: aws_emr_cluster
- Resource: aws_glue_job
- Resource: aws_iam_access_key
- Resource: aws_iam_instance_profile
- Resource: aws_iam_server_certificate
- Resource: aws_instance
- Resource: aws_lambda_alias
- Resource: aws_launch_template
- Resource: aws_lb_listener_rule
- Resource: aws_msk_cluster
- Resource: aws_rds_cluster
- Resource: aws_route53_resolver_rule
- Resource: aws_route53_zone
- Resource: aws_s3_bucket
- Resource: aws_s3_bucket_metric
- Resource: aws_security_group
- Resource: aws_sns_platform_application
- Resource: aws_spot_fleet_request
Provider Version Configuration
-> Before upgrading to version 3.0.0, it is recommended to upgrade to the most recent 2.X version of the provider and ensure that your environment successfully runs terraformPlan
without unexpected changes or deprecation notices.
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 terraformInit
to download the new version.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.provider.AwsProvider(this, "aws", {});
Update to latest 3.X version:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.provider.AwsProvider(this, "aws", {});
Provider Authentication Updates
Authentication Ordering
Previously, the provider preferred credentials in the following order:
- Static credentials (those defined in the Terraform configuration)
- Environment variables (e.g.,
awsAccessKeyId
orawsProfile
) - Shared credentials file (e.g.,
~/Aws/credentials
) - EC2 Instance Metadata Service
- Default AWS Go SDK handling (shared configuration, CodeBuild/ECS/EKS)
The provider now prefers the following credential ordering:
- Static credentials (those defined in the Terraform configuration)
- Environment variables (e.g.,
awsAccessKeyId
orawsProfile
) - Shared credentials and/or configuration file (e.g.,
~/Aws/credentials
and~/Aws/config
) - Default AWS Go SDK handling (shared configuration, CodeBuild/ECS/EKS, EC2 Instance Metadata Service)
This means workarounds of disabling the EC2 Instance Metadata Service handling to enable CodeBuild/ECS/EKS credentials or to enable other credential methods such as credentialProcess
in the AWS shared configuration are no longer necessary.
Shared Configuration File Automatically Enabled
The awsSdkLoadConfig
environment variable is no longer necessary for the provider to automatically load the AWS shared configuration file (e.g., ~/Aws/config
).
Removal of AWS_METADATA_TIMEOUT Environment Variable Usage
The provider now relies on the default AWS Go SDK timeouts for interacting with the EC2 Instance Metadata Service.
Provider Custom Service Endpoint Updates
Removal of kinesis_analytics and r53 Arguments
The custom service endpoints for Kinesis Analytics and Route 53 now use the kinesisanalytics
and route53
argument names in the provider configuration.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.provider.AwsProvider(this, "aws", {
endpoints: [
{
kinesisAnalytics: "https://example.com",
r53: "https://example.com",
},
],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.provider.AwsProvider(this, "aws", {
endpoints: [
{
kinesisanalytics: "https://example.com",
route53: "https://example.com",
},
],
});
Data Source: aws_availability_zones
blacklisted_names Attribute Removal
Switch your Terraform configuration to the excludeNames
attribute instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dataAwsAvailabilityZones.DataAwsAvailabilityZones(this, "example", {
blacklisted_names: ["us-west-2d"],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dataAwsAvailabilityZones.DataAwsAvailabilityZones(this, "example", {
excludeNames: ["us-west-2d"],
});
blacklisted_zone_ids Attribute Removal
Switch your Terraform configuration to the excludeZoneIds
attribute instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dataAwsAvailabilityZones.DataAwsAvailabilityZones(this, "example", {
blacklisted_zone_ids: ["usw2-az4"],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dataAwsAvailabilityZones.DataAwsAvailabilityZones(this, "example", {
excludeZoneIds: ["usw2-az4"],
});
Data Source: aws_lambda_invocation
result_map Attribute Removal
Switch your Terraform configuration to the result
attribute with the jsondecode()
function instead.
For example, given this previous configuration:
import * as cdktf from "cdktf";
new cdktf.TerraformOutput(this, "lambda_result", {
value: '${data.aws_lambda_invocation.example.result_map["key1"]}',
});
An updated configuration:
import * as cdktf from "cdktf";
new cdktf.TerraformOutput(this, "lambda_result", {
value: '${jsondecode(data.aws_lambda_invocation.example.result)["key1"]}',
});
Data Source: aws_launch_template
Error raised if no matching launch template is found
Previously, when a launch template matching the criteria was not found the data source would have been null
. Now this could produce errors similar to the below:
data.aws_launch_template.current: Refreshing state...
Error: error reading launch template: empty output
Configuration that depend on the previous behavior will need to be updated.
Data Source: aws_route53_resolver_rule
Removal of trailing period in domain_name argument
Previously the data-source returned the Resolver Rule Domain Name directly from the API, which included a .
suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g., ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Resolver Rule Domain Name such as exampleCom
, the attribute now will be returned as exampleCom
. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted.
Data Source: aws_route53_zone
Removal of trailing period in name argument
Previously the data-source returned the Hosted Zone Domain Name directly from the API, which included a .
suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g., ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Hosted Zone Domain Name such as exampleCom
, the attribute now will be returned as exampleCom
. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted.
Resource: aws_acm_certificate
domain_validation_options Changed from List to Set
Previously, the domainValidationOptions
attribute was a list type and completely unknown until after an initial terraformApply
. This generally required complicated configuration workarounds to properly create DNS validation records since referencing this attribute directly could produce errors similar to the below:
Error: Invalid for_each argument
on main.tf line 16, in resource "aws_route53_record" "existing":
16: for_each = aws_acm_certificate.existing.domain_validation_options
The `for_each` value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the for_each depends on.
The domainValidationOptions
attribute is now a set type and the resource will attempt to populate the information necessary during the planning phase to handle the above situation in most environments without workarounds. This change also prevents Terraform from showing unexpected differences if the API returns the results in varying order.
Configuration references to this attribute will likely require updates since sets cannot be indexed (e.g., domainValidationOptions[0]
or the older domainValidationOptions0
syntax will return errors). If the domainValidationOptions
list previously contained only a single element like the two examples just shown, it may be possible to wrap these references using the tolist()
function
(e.g., tolist(awsAcmCertificateExampleDomainValidationOptions)[0]
) as a quick configuration update. However given the complexity and workarounds required with the previous domainValidationOptions
attribute implementation, different environments will require different configuration updates and migration steps. Below is a more advanced example. Further questions on potential update steps can be submitted to the community forums.
For example, given this previous configuration using a count
based resource approach that may have been used in certain environments:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsAcmCertificateExisting = new aws.acmCertificate.AcmCertificate(
this,
"existing",
{
domainName: "existing.${var.public_root_domain}",
subjectAlternativeNames: [
"existing1.${var.public_root_domain}",
"existing2.${var.public_root_domain}",
"existing3.${var.public_root_domain}",
],
validationMethod: "DNS",
}
);
const dataAwsRoute53ZonePublicRootDomain =
new aws.dataAwsRoute53Zone.DataAwsRoute53Zone(this, "public_root_domain", {
name: "${var.public_root_domain}",
});
const awsRoute53RecordExisting = new aws.route53Record.Route53Record(
this,
"existing_2",
{
allowOverwrite: true,
name: `\${${awsAcmCertificateExisting.domainValidationOptions.fqn}[count.index].resource_record_name}`,
records: [
`\${${awsAcmCertificateExisting.domainValidationOptions.fqn}[count.index].resource_record_value}`,
],
ttl: 60,
type: `\${${awsAcmCertificateExisting.domainValidationOptions.fqn}[count.index].resource_record_type}`,
zoneId: dataAwsRoute53ZonePublicRootDomain.zoneId,
}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsRoute53RecordExisting.overrideLogicalId("existing");
/*In most cases loops should be handled in the programming language context and
not inside of the Terraform context. If you are looping over something external, e.g. a variable or a file input
you should consider using a for loop. If you are looping over something only known to Terraform, e.g. a result of a data source
you need to keep this like it is.*/
awsRoute53RecordExisting.addOverride(
"count",
`\${length(${awsAcmCertificateExisting.subjectAlternativeNames}) + 1}`
);
const awsAcmCertificateValidationExisting =
new aws.acmCertificateValidation.AcmCertificateValidation(
this,
"existing_3",
{
certificateArn: awsAcmCertificateExisting.arn,
validationRecordFqdns: `\${${awsRoute53RecordExisting.fqn}[*].fqdn}`,
}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsAcmCertificateValidationExisting.overrideLogicalId("existing");
It will receive errors like the below after upgrading:
Error: Invalid index
on main.tf line 14, in resource "aws_route53_record" "existing":
14: name = aws_acm_certificate.existing.domain_validation_options[count.index].resource_record_name
|----------------
| aws_acm_certificate.existing.domain_validation_options is set of object with 4 elements
| count.index is 1
This value does not have any indices.
Since the domainValidationOptions
attribute changed from a list to a set and sets cannot be indexed in Terraform, the recommendation is to update the configuration to use the more stable resource forEach
support instead of count
. Note the slight change in the validationRecordFqdns
syntax as well.
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsRoute53RecordExisting = new aws.route53Record.Route53Record(
this,
"existing",
{
allowOverwrite: true,
name: "${each.value.name}",
records: ["${each.value.record}"],
ttl: 60,
type: "${each.value.type}",
zoneId: "${data.aws_route53_zone.public_root_domain.zone_id}",
}
);
/*In most cases loops should be handled in the programming language context and
not inside of the Terraform context. If you are looping over something external, e.g. a variable or a file input
you should consider using a for loop. If you are looping over something only known to Terraform, e.g. a result of a data source
you need to keep this like it is.*/
awsRoute53RecordExisting.addOverride(
"for_each",
"${{\n for dvo in aws_acm_certificate.existing.domain_validation_options : dvo.domain_name => {\n name = dvo.resource_record_name\n record = dvo.resource_record_value\n type = dvo.resource_record_type\n }\n }}"
);
const awsAcmCertificateValidationExisting =
new aws.acmCertificateValidation.AcmCertificateValidation(
this,
"existing_1",
{
certificateArn: "${aws_acm_certificate.existing.arn}",
validationRecordFqdns: [
`\${[for record in ${awsRoute53RecordExisting.fqn} : record.fqdn]}`,
],
}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsAcmCertificateValidationExisting.overrideLogicalId("existing");
After the configuration has been updated, a plan should no longer error and may look like the following:
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
- destroy
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_acm_certificate_validation.existing must be replaced
-/+ resource "aws_acm_certificate_validation" "existing" {
certificate_arn = "arn:aws:acm:us-east-2:123456789012:certificate/ccbc58e8-061d-4443-9035-d3af0512e863"
~ id = "2020-07-16 00:01:19 +0000 UTC" -> (known after apply)
~ validation_record_fqdns = [
- "_40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com",
- "_812ddf11b781af1eec1643ec58f102d2.existing.example.com",
- "_8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com",
- "_d7112da809a40e848207c04399babcec.existing1.example.com",
] -> (known after apply) # forces replacement
}
# aws_route53_record.existing will be destroyed
- resource "aws_route53_record" "existing" {
- fqdn = "_812ddf11b781af1eec1643ec58f102d2.existing.example.com" -> null
- id = "Z123456789012__812ddf11b781af1eec1643ec58f102d2.existing.example.com._CNAME" -> null
- name = "_812ddf11b781af1eec1643ec58f102d2.existing.example.com" -> null
- records = [
- "_bdeba72164eec216c55a32374bcceafd.jfrzftwwjs.acm-validations.aws.",
] -> null
- ttl = 60 -> null
- type = "CNAME" -> null
- zone_id = "Z123456789012" -> null
}
# aws_route53_record.existing[1] will be destroyed
- resource "aws_route53_record" "existing" {
- fqdn = "_40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com" -> null
- id = "Z123456789012__40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com._CNAME" -> null
- name = "_40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com" -> null
- records = [
- "_638532db1fa6a1b71aaf063c8ea29d52.jfrzftwwjs.acm-validations.aws.",
] -> null
- ttl = 60 -> null
- type = "CNAME" -> null
- zone_id = "Z123456789012" -> null
}
# aws_route53_record.existing[2] will be destroyed
- resource "aws_route53_record" "existing" {
- fqdn = "_d7112da809a40e848207c04399babcec.existing1.example.com" -> null
- id = "Z123456789012__d7112da809a40e848207c04399babcec.existing1.example.com._CNAME" -> null
- name = "_d7112da809a40e848207c04399babcec.existing1.example.com" -> null
- records = [
- "_6e1da5574ab46a6c782ed73438274181.jfrzftwwjs.acm-validations.aws.",
] -> null
- ttl = 60 -> null
- type = "CNAME" -> null
- zone_id = "Z123456789012" -> null
}
# aws_route53_record.existing[3] will be destroyed
- resource "aws_route53_record" "existing" {
- fqdn = "_8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com" -> null
- id = "Z123456789012__8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com._CNAME" -> null
- name = "_8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com" -> null
- records = [
- "_a419f8410d2e0720528a96c3506f3841.jfrzftwwjs.acm-validations.aws.",
] -> null
- ttl = 60 -> null
- type = "CNAME" -> null
- zone_id = "Z123456789012" -> null
}
# aws_route53_record.existing["existing.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_812ddf11b781af1eec1643ec58f102d2.existing.example.com"
+ records = [
+ "_bdeba72164eec216c55a32374bcceafd.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
# aws_route53_record.existing["existing1.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_d7112da809a40e848207c04399babcec.existing1.example.com"
+ records = [
+ "_6e1da5574ab46a6c782ed73438274181.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
# aws_route53_record.existing["existing2.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com"
+ records = [
+ "_638532db1fa6a1b71aaf063c8ea29d52.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
# aws_route53_record.existing["existing3.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com"
+ records = [
+ "_a419f8410d2e0720528a96c3506f3841.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
Plan: 5 to add, 0 to change, 5 to destroy.
Due to the type of configuration change, Terraform does not know that the previous awsRoute53Record
resources (indexed by number in the existing state) and the new resources (indexed by domain names in the updated configuration) are equivalent. Typically in this situation, the terraformStateMv
command can be used to reduce the plan to show no changes. This is done by associating the count index (e.g., [1]
) with the equivalent domain name index (e.g., ["existing2ExampleCom"]
), making one of the four commands to fix the above example: terraformStateMv 'awsRoute53RecordExisting[1]' 'awsRoute53RecordExisting["existing2ExampleCom"]'
. We recommend using this terraformStateMv
update process where possible to reduce chances of unexpected behaviors or changes in an environment.
If using terraformStateMv
to reduce the plan to show no changes, no additional steps are required.
In larger or more complex environments though, this process can be tedius to match the old resource address to the new resource address and run all the necessary terraformStateMv
commands. Instead, since the awsRoute53Record
resource implements the allowOverwrite =True
argument, it is possible to just remove the old awsRoute53Record
resources from the Terraform state using the terraformStateRm
command. In this case, Terraform will leave the existing records in Route 53 and plan to just overwrite the existing validation records with the same exact (previous) values.
-> This guide is showing the simpler terraformStateRm
option below as a potential shortcut in this specific situation, however in most other cases terraformStateMv
is required to change from count
based resources to forEach
based resources and properly match the existing Terraform state to the updated Terraform configuration.
$ terraform state rm aws_route53_record.existing
Removed aws_route53_record.existing[0]
Removed aws_route53_record.existing[1]
Removed aws_route53_record.existing[2]
Removed aws_route53_record.existing[3]
Successfully removed 4 resource instance(s).
Now the Terraform plan will show only the additions of new Route 53 records (which are exactly the same as before the upgrade) and the proposed recreation of the awsAcmCertificateValidation
resource. The awsAcmCertificateValidation
resource recreation will have no effect as the certificate is already validated and issued.
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_acm_certificate_validation.existing must be replaced
-/+ resource "aws_acm_certificate_validation" "existing" {
certificate_arn = "arn:aws:acm:us-east-2:123456789012:certificate/ccbc58e8-061d-4443-9035-d3af0512e863"
~ id = "2020-07-16 00:01:19 +0000 UTC" -> (known after apply)
~ validation_record_fqdns = [
- "_40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com",
- "_812ddf11b781af1eec1643ec58f102d2.existing.example.com",
- "_8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com",
- "_d7112da809a40e848207c04399babcec.existing1.example.com",
] -> (known after apply) # forces replacement
}
# aws_route53_record.existing["existing.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_812ddf11b781af1eec1643ec58f102d2.existing.example.com"
+ records = [
+ "_bdeba72164eec216c55a32374bcceafd.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
# aws_route53_record.existing["existing1.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_d7112da809a40e848207c04399babcec.existing1.example.com"
+ records = [
+ "_6e1da5574ab46a6c782ed73438274181.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
# aws_route53_record.existing["existing2.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_40b71647a8d88eb82d53fe988e8a3cc1.existing2.example.com"
+ records = [
+ "_638532db1fa6a1b71aaf063c8ea29d52.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
# aws_route53_record.existing["existing3.example.com"] will be created
+ resource "aws_route53_record" "existing" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = "_8dc56b6e35f699b8754afcdd79e9748d.existing3.example.com"
+ records = [
+ "_a419f8410d2e0720528a96c3506f3841.jfrzftwwjs.acm-validations.aws.",
]
+ ttl = 60
+ type = "CNAME"
+ zone_id = "Z123456789012"
}
Plan: 5 to add, 0 to change, 1 to destroy.
Once applied, no differences should be shown and no additional steps should be necessary.
Alternatively, if you are referencing a subset of domainValidationOptions
, there is another method of upgrading from v2 to v3 without having to move state. Given the scenario below...
data "aws_route53_zone" "public_root_domain" {
name = var.public_root_domain
}
resource "aws_acm_certificate" "existing" {
domain_name = "existing.${var.public_root_domain}"
subject_alternative_names = [
"existing1.${var.public_root_domain}",
"existing2.${var.public_root_domain}",
"existing3.${var.public_root_domain}",
]
validation_method = "DNS"
}
resource "aws_route53_record" "existing_1" {
allow_overwrite = true
name = aws_acm_certificate.existing.domain_validation_options[0].resource_record_name
records = [aws_acm_certificate.existing.domain_validation_options[0].resource_record_value]
ttl = 60
type = aws_acm_certificate.existing.domain_validation_options[0].resource_record_type
zone_id = data.aws_route53_zone.public_root_domain.zone_id
}
resource "aws_acm_certificate_validation" "existing_1" {
certificate_arn = aws_acm_certificate.existing.arn
validation_record_fqdns = aws_route53_record.existing_1.fqdn
}
resource "aws_route53_record" "existing_3" {
allow_overwrite = true
name = aws_acm_certificate.existing.domain_validation_options[2].resource_record_name
records = [aws_acm_certificate.existing.domain_validation_options[2].resource_record_value]
ttl = 60
type = aws_acm_certificate.existing.domain_validation_options[2].resource_record_type
zone_id = data.aws_route53_zone.public_root_domain.zone_id
}
resource "aws_acm_certificate_validation" "existing_3" {
certificate_arn = aws_acm_certificate.existing.arn
validation_record_fqdns = aws_route53_record.existing_3.fqdn
}
You can perform a conversion of the new domainValidationOptions
object into a map, to allow you to perform a lookup by the domain name in place of an index number.
locals {
existing_domain_validation_options = {
for dvo in aws_acm_certificate.cloudfront_cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
}
resource "aws_route53_record" "existing_1" {
allow_overwrite = true
name = local.existing_domain_validation_options["existing1.${var.public_root_domain}"].name
records = [local.existing_domain_validation_options["existing1.${var.public_root_domain}"].record]
ttl = 60
type = local.existing_domain_validation_options["existing1.${var.public_root_domain}"].type
zone_id = data.aws_route53_zone.public_root_domain.zone_id
}
resource "aws_acm_certificate_validation" "existing_1" {
certificate_arn = aws_acm_certificate.existing.arn
validation_record_fqdns = aws_route53_record.existing_1.fqdn
}
resource "aws_route53_record" "existing_3" {
allow_overwrite = true
name = local.existing_domain_validation_options["existing3.${var.public_root_domain}"].name
records = [local.existing_domain_validation_options["existing3.${var.public_root_domain}"].record]
ttl = 60
type = local.existing_domain_validation_options["existing3.${var.public_root_domain}"].type
zone_id = data.aws_route53_zone.public_root_domain.zone_id
}
resource "aws_acm_certificate_validation" "existing_3" {
certificate_arn = aws_acm_certificate.existing.arn
validation_record_fqdns = aws_route53_record.existing_3.fqdn
}
Performing a plan against these resources will not cause any change in state, since underlying resources have not changed.
subject_alternative_names Changed from List to Set
Previously the subjectAlternativeNames
argument was stored in the Terraform state as an ordered list while the API returned information in an unordered manner. The attribute is now configured as a set instead of a list. Certain Terraform configuration language features distinguish between these two attribute types such as not being able to index a set (e.g., awsAcmCertificateExampleSubjectAlternativeNames[0]
is no longer a valid reference). Depending on the implementation details of a particular configuration using subjectAlternativeNames
as a reference, possible solutions include changing references to using for
/forEach
or using the tolist()
function as a temporary workaround to keep the previous behavior until an appropriate configuration (properly using the unordered set) can be determined. Usage questions can be submitted to the community forums.
certificate_body, certificate_chain, and private_key Arguments No Longer Stored as Hash
Previously when the certificateBody
, certificateChain
, and privateKey
arguments were stored in state, they were stored as a hash of the actual value. This prevented Terraform from properly updating the resource when necessary and the hashing has been removed. The Terraform AWS Provider will show an update to these arguments on the first apply after upgrading to version 3.0.0, which is fixing the Terraform state to remove the hash. Since the privateKey
attribute is marked as sensitive, the values in the update will not be visible in the Terraform output. If the non-hashed values have not changed, then no update is occurring other than the Terraform state update. If these arguments are the only updates and they all match the hash removal, the apply will occur without submitting API calls.
Resource: aws_api_gateway_method_settings
throttling_burst_limit and throttling_rate_limit Arguments Now Default to -1
Previously when the throttlingBurstLimit
or throttlingRateLimit
argument was not configured, the resource would enable throttling and set the limit value to the AWS API Gateway default. In addition, as these arguments were marked as computed
, Terraform ignored any subsequent changes made to these arguments in the resource. These behaviors have been removed and, by default, the throttlingBurstLimit
and throttlingRateLimit
arguments will be disabled in the resource with a value of 1
.
Resource: aws_autoscaling_group
availability_zones and vpc_zone_identifier Arguments Now Report Plan-Time Conflict
Specifying both the availabilityZones
and vpcZoneIdentifier
arguments previously led to confusing behavior and errors. Now this issue is reported at plan-time. Use the null
value instead of []
(empty list) in conditionals to ensure this validation does not unexpectedly trigger.
Drift detection enabled for loadBalancers
and targetGroupArns
arguments
If you previously set one of these arguments to an empty list to enable drift detection (e.g., when migrating an ASG from ELB to ALB), this can be updated as follows.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.autoscalingGroup.AutoscalingGroup(this, "example", {
loadBalancers: [],
targetGroupArns: ["${aws_lb_target_group.example.arn}"],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.autoscalingGroup.AutoscalingGroup(this, "example", {
targetGroupArns: ["${aws_lb_target_group.example.arn}"],
});
If awsAutoscalingAttachment
resources reference your ASG configurations, you will need to add the lifecycle
configuration block with an ignoreChanges
argument to prevent Terraform non-empty plans (i.e., forcing resource update) during the next state refresh.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsAutoscalingGroupExample = new aws.autoscalingGroup.AutoscalingGroup(
this,
"example",
{}
);
const awsAutoscalingAttachmentExample =
new aws.autoscalingAttachment.AutoscalingAttachment(this, "example_1", {
autoscalingGroupName: awsAutoscalingGroupExample.id,
elb: "${aws_elb.example.id}",
});
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsAutoscalingAttachmentExample.overrideLogicalId("example");
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsAutoscalingGroupExample = new aws.autoscalingGroup.AutoscalingGroup(
this,
"example",
{}
);
awsAutoscalingGroupExample.addOverride("lifecycle", [
{
ignore_changes: ["${load_balancers}", "${target_group_arns}"],
},
]);
const awsAutoscalingAttachmentExample =
new aws.autoscalingAttachment.AutoscalingAttachment(this, "example_1", {
autoscalingGroupName: awsAutoscalingGroupExample.id,
elb: "${aws_elb.example.id}",
});
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsAutoscalingAttachmentExample.overrideLogicalId("example");
Resource: aws_cloudfront_distribution
active_trusted_signers Attribute Name and Type Change
Previously, the activeTrustedSigners
computed attribute was implemented with a Map that did not support accessing its computed items
attribute in Terraform 0.12 correctly. To address this, the activeTrustedSigners
attribute has been renamed to trustedSigners
and is now implemented as a List with a computed items
List attribute and computed enabled
boolean attribute. The nested items
attribute includes computed awsAccountNumber
and keyPairIds
sub-fields, with the latter implemented as a List. Thus, user configurations referencing the activeTrustedSigners
attribute and its sub-fields will need to be changed as follows.
Given these previous references:
aws_cloudfront_distribution.example.active_trusted_signers.enabled
aws_cloudfront_distribution.example.active_trusted_signers.items
Updated references:
aws_cloudfront_distribution.example.trusted_signers[0].enabled
aws_cloudfront_distribution.example.trusted_signers[0].items
Resource: aws_cloudwatch_log_group
Removal of arn Wildcard Suffix
Previously, the resource returned the ARN directly from the API, which included a :*
suffix to denote all CloudWatch Log Streams under the CloudWatch Log Group. Most other AWS resources that return ARNs and many other AWS services do not use the :*
suffix. The suffix is now automatically removed. For example, the resource previously returned an ARN such as arn:aws:logs:usEast1:123456789012:logGroup:/example:*
but will now return arn:aws:logs:usEast1:123456789012:logGroup:/example
.
Workarounds, such as using replace()
as shown below, should be removed:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsCloudwatchLogGroupExample =
new aws.cloudwatchLogGroup.CloudwatchLogGroup(this, "example", {
name: "example",
});
const awsDatasyncTaskExample = new aws.datasyncTask.DatasyncTask(
this,
"example_1",
{
cloudwatchLogGroupArn: `\${replace(${awsCloudwatchLogGroupExample.arn}, ":*", "")}`,
}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsDatasyncTaskExample.overrideLogicalId("example");
Removing the :*
suffix is a breaking change for some configurations. Fix these configurations using string interpolations as demonstrated below. For example, this configuration is now broken:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dataAwsIamPolicyDocument.DataAwsIamPolicyDocument(
this,
"ad-log-policy",
{
statement: [
{
actions: ["logs:CreateLogStream", "logs:PutLogEvents"],
effect: "Allow",
principals: [
{
identifiers: ["ds.amazonaws.com"],
type: "Service",
},
],
resources: ["${aws_cloudwatch_log_group.example.arn}"],
},
],
}
);
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dataAwsIamPolicyDocument.DataAwsIamPolicyDocument(
this,
"ad-log-policy",
{
statement: [
{
actions: ["logs:CreateLogStream", "logs:PutLogEvents"],
effect: "Allow",
principals: [
{
identifiers: ["ds.amazonaws.com"],
type: "Service",
},
],
resources: ["${aws_cloudwatch_log_group.example.arn}:*"],
},
],
}
);
Resource: aws_codepipeline
GITHUB_TOKEN environment variable removal
Switch your Terraform configuration to the oAuthToken
element in the action
configuration
map instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.codepipeline.Codepipeline(this, "example", {
stage: [
{
action: [
{
category: "Source",
configuration: [
{
branch: "main",
owner: "lifesum-terraform",
repo: "example",
},
],
name: "Source",
outputArtifacts: ["example"],
owner: "ThirdParty",
provider: "GitHub",
version: "1",
},
],
name: "Source",
},
],
});
The configuration could be updated as follows:
import * as cdktf from "cdktf";
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
/*Terraform Variables are not always the best fit for getting inputs in the context of Terraform CDK.
You can read more about this at https://cdk.tf/variables*/
const githubToken = new cdktf.TerraformVariable(this, "github_token", {});
new aws.codepipeline.Codepipeline(this, "example", {
stage: [
{
action: [
{
category: "Source",
configuration: [
{
branch: "main",
oAuthToken: githubToken.value,
owner: "lifesum-terraform",
repo: "example",
},
],
name: "Source",
outputArtifacts: ["example"],
owner: "ThirdParty",
provider: "GitHub",
version: "1",
},
],
name: "Source",
},
],
});
Resource: aws_cognito_user_pool
Removal of admin_create_user_config.unused_account_validity_days Argument
The Cognito API previously deprecated the adminCreateUserConfig
configuration block unusedAccountValidityDays
argument in preference of the passwordPolicy
configuration block temporaryPasswordValidityDays
argument. Configurations will need to be updated to use the API supported configuration.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.cognitoUserPool.CognitoUserPool(this, "example", {
adminCreateUserConfig: {
unusedAccountValidityDays: 7,
},
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.cognitoUserPool.CognitoUserPool(this, "example", {
passwordPolicy: {
temporaryPasswordValidityDays: 7,
},
});
Resource: aws_dx_gateway
Removal of Automatic aws_dx_gateway_association Import
Previously when importing the awsDxGateway
resource with the terraformImport
command, the Terraform AWS Provider would automatically attempt to import an associated awsDxGatewayAssociation
resource(s) as well. This automatic resource import has been removed. Use the awsDxGatewayAssociation
resource import to import those resources separately.
Resource: aws_dx_gateway_association
vpn_gateway_id Argument Removal
Switch your Terraform configuration to the associatedGatewayId
argument instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dxGatewayAssociation.DxGatewayAssociation(this, "example", {
vpnGatewayId: "${aws_vpn_gateway.example.id}",
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dxGatewayAssociation.DxGatewayAssociation(this, "example", {
associatedGatewayId: "${aws_vpn_gateway.example.id}",
});
Resource: aws_dx_gateway_association_proposal
vpn_gateway_id Argument Removal
Switch your Terraform configuration to the associatedGatewayId
argument instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dxGatewayAssociationProposal.DxGatewayAssociationProposal(
this,
"example",
{
vpn_gateway_id: "${aws_vpn_gateway.example.id}",
}
);
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.dxGatewayAssociationProposal.DxGatewayAssociationProposal(
this,
"example",
{
associatedGatewayId: "${aws_vpn_gateway.example.id}",
}
);
Resource: aws_ebs_volume
iops Argument Apply-Time Validation
Previously when the iops
argument was configured with a type
other than io1
(either explicitly or omitted, indicating the default type gp2
), the Terraform AWS Provider would automatically disregard the value provided to iops
as it is only configurable for the io1
volume type per the AWS EC2 API. This behavior has changed such that the Terraform AWS Provider will instead return an error at apply time indicating an iops
value is invalid for types other than io1
. Exceptions to this are in cases where iops
is set to null
or 0
such that the Terraform AWS Provider will continue to accept the value regardless of type
.
Resource: aws_elastic_transcoder_preset
video Configuration Block max_frame_rate Argument No Longer Uses 30 Default
Previously when the maxFrameRate
argument was not configured, the resource would default to 30. This behavior has been removed and allows for auto frame rate presets to automatically set the appropriate value.
Resource: aws_emr_cluster
core_instance_count Argument Removal
Switch your Terraform configuration to the coreInstanceGroup
configuration block instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
core_instance_count: 2,
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
coreInstanceGroup: {
instanceCount: 2,
},
});
core_instance_type Argument Removal
Switch your Terraform configuration to the coreInstanceGroup
configuration block instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
core_instance_type: "m4.large",
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
coreInstanceGroup: {
instanceType: "m4.large",
},
});
instance_group Configuration Block Removal
Switch your Terraform configuration to the masterInstanceGroup
and coreInstanceGroup
configuration blocks instead. For any task instance groups, use the awsEmrInstanceGroup
resource.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
instance_group: [
{
instance_role: "MASTER",
instance_type: "m4.large",
},
{
instance_count: 1,
instance_role: "CORE",
instance_type: "c4.large",
},
{
instance_count: 2,
instance_role: "TASK",
instance_type: "c4.xlarge",
},
],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsEmrClusterExample = new aws.emrCluster.EmrCluster(this, "example", {
coreInstanceGroup: {
instanceCount: 1,
instanceType: "c4.large",
},
masterInstanceGroup: {
instanceType: "m4.large",
},
});
const awsEmrInstanceGroupExample = new aws.emrInstanceGroup.EmrInstanceGroup(
this,
"example_1",
{
clusterId: awsEmrClusterExample.id,
instanceCount: 2,
instanceType: "c4.xlarge",
}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsEmrInstanceGroupExample.overrideLogicalId("example");
master_instance_type Argument Removal
Switch your Terraform configuration to the masterInstanceGroup
configuration block instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
master_instance_type: "m4.large",
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.emrCluster.EmrCluster(this, "example", {
masterInstanceGroup: {
instanceType: "m4.large",
},
});
Resource: aws_glue_job
allocated_capacity Argument Removal
The Glue API has deprecated the allocatedCapacity
argument. Switch your Terraform configuration to the maxCapacity
argument instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.glueJob.GlueJob(this, "example", {
allocated_capacity: 2,
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.glueJob.GlueJob(this, "example", {
maxCapacity: 2,
});
Resource: aws_iam_access_key
ses_smtp_password Attribute Removal
In many regions today and in all regions after October 1, 2020, the SES API will only accept version 4 signatures. If referencing the sesSmtpPassword
attribute, switch your Terraform configuration to the sesSmtpPasswordV4
attribute instead. Please note that this signature is based on the region of the Terraform AWS Provider. If you need the SES v4 password in multiple regions, it may require using multiple provider instances.
Depending on when the awsIamAccessKey
resource was created, it may not have a sesSmtpPasswordV4
attribute for you to use. If this is the case you will need to taint the resource so that it can be recreated with the new value.
Alternatively, you can stage the change by creating a new awsIamAccessKey
resource and change any downstream dependencies to use the new sesSmtpPasswordV4
attribute. Once dependents have been updated with the new resource you can remove the old one.
Resource: aws_iam_instance_profile
roles Argument Removal
Switch your Terraform configuration to the role
argument instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.iamInstanceProfile.IamInstanceProfile(this, "example", {
roles: ["${aws_iam_role.example.id}"],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.iamInstanceProfile.IamInstanceProfile(this, "example", {
role: "${aws_iam_role.example.id}",
});
Resource: aws_iam_server_certificate
certificate_body, certificate_chain, and private_key Arguments No Longer Stored as Hash
Previously when the certificateBody
, certificateChain
, and privateKey
arguments were stored in state, they were stored as a hash of the actual value. This hashing has been removed for new or recreated resources to prevent lifecycle issues.
Resource: aws_instance
ebs_block_device.iops and root_block_device.iops Argument Apply-Time Validations
Previously when the iops
argument was configured in either the ebsBlockDevice
or rootBlockDevice
configuration block, the Terraform AWS Provider would automatically disregard the value provided to iops
if the type
argument was also configured with a value other than io1
(either explicitly or omitted, indicating the default type gp2
) as iops
are only configurable for the io1
volume type per the AWS EC2 API. This behavior has changed such that the Terraform AWS Provider will instead return an error at apply time indicating an iops
value is invalid for volume types other than io1
. Exceptions to this are in cases where iops
is set to null
or 0
such that the Terraform AWS Provider will continue to accept the value regardless of type
.
Resource: aws_lambda_alias
Import No Longer Converts Function Name to ARN
Previously the resource import would always convert the functionName
portion of the import identifier into the ARN format. Configurations using the Lambda Function name would show this as an unexpected difference after import. Now this will passthrough the given value on import whether its a Lambda Function name or ARN.
Resource: aws_launch_template
network_interfaces.delete_on_termination Argument type change
The networkInterfacesDeleteOnTermination
argument is now of type string
, allowing an unspecified value for the argument since the previous bool
type only allowed for true/false
and defaulted to false
when no value was set. Now to enforce deleteOnTermination
to false
, the string "false"
or bare false
value must be used.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.launchTemplate.LaunchTemplate(this, "example", {
networkInterfaces: [
{
deleteOnTermination: [null],
},
],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.launchTemplate.LaunchTemplate(this, "example", {
networkInterfaces: [
{
deleteOnTermination: false,
},
],
});
Resource: aws_lb_listener_rule
condition.field and condition.values Arguments Removal
Switch your Terraform configuration to use the hostHeader
or pathPattern
configuration block instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.lbListenerRule.LbListenerRule(this, "example", {
condition: [
{
field: "path-pattern",
values: ["/static/*"],
},
],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.lbListenerRule.LbListenerRule(this, "example", {
condition: [
{
pathPattern: {
values: ["/static/*"],
},
},
],
});
Resource: aws_msk_cluster
encryption_info.encryption_in_transit.client_broker Default Updated to Match API
A few weeks after general availability launch and initial release of the awsMskCluster
resource, the MSK API default for client broker encryption switched from tlsPlaintext
to tls
. The attribute default has now been updated to match the more secure API default, however existing Terraform configurations may show a difference if this setting is not configured.
To continue using the old default when it was previously not configured, add or modify this configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.mskCluster.MskCluster(this, "example", {
encryptionInfo: {
encryptionInTransit: {
clientBroker: "TLS_PLAINTEXT",
},
},
});
Resource: aws_rds_cluster
scaling_configuration.min_capacity Now Defaults to 1
Previously when the minCapacity
argument in a scalingConfiguration
block was not configured, the resource would default to 2. This behavior has been updated to align with the AWS RDS Cluster API default of 1.
Resource: aws_route53_resolver_rule
Removal of trailing period in domain_name argument
Previously the resource returned the Resolver Rule Domain Name directly from the API, which included a .
suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g., ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Resolver Rule Domain Name such as exampleCom
, the attribute now will be returned as exampleCom
. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted.
Resource: aws_route53_zone
Removal of trailing period in name argument
Previously the resource returned the Hosted Zone Domain Name directly from the API, which included a .
suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g., ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Hosted Zone Domain Name such as exampleCom
, the attribute now will be returned as exampleCom
. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted.
Resource: aws_s3_bucket
Removal of Automatic aws_s3_bucket_policy Import
Previously when importing the awsS3Bucket
resource with the terraformImport
command, the Terraform AWS Provider would automatically attempt to import an associated awsS3BucketPolicy
resource as well. This automatic resource import has been removed. Use the awsS3BucketPolicy
resource import to import that resource separately.
region Attribute Is Now Read-Only
The region
attribute is no longer configurable, but it remains as a read-only attribute. The region of the awsS3Bucket
resource is determined by the region of the Terraform AWS Provider, similar to all other resources.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.s3Bucket.S3Bucket(this, "example", {
region: "us-west-2",
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.s3Bucket.S3Bucket(this, "example", {});
Resource: aws_s3_bucket_metric
filter configuration block Plan-Time Validation Change
The filter
configuration block no longer supports the empty block {}
and requires at least one of the prefix
or tags
attributes to be specified.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.s3BucketMetric.S3BucketMetric(this, "example", {
filter: {},
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.s3BucketMetric.S3BucketMetric(this, "example", {});
Resource: aws_security_group
Removal of Automatic aws_security_group_rule Import
Previously when importing the awsSecurityGroup
resource with the terraformImport
command, the Terraform AWS Provider would automatically attempt to import an associated awsSecurityGroupRule
resource(s) as well. This automatic resource import has been removed. Use the awsSecurityGroupRule
resource import to import those resources separately.
Resource: aws_sns_platform_application
platform_credential and platform_principal Arguments No Longer Stored as SHA256 Hash
Previously when the platformCredential
and platformPrincipal
arguments were stored in state, they were stored as a SHA256 hash of the actual value. This prevented Terraform from properly updating the resource when necessary and the hashing has been removed. The Terraform AWS Provider will show an update to these arguments on the first apply after upgrading to version 3.0.0, which is fixing the Terraform state to remove the hash. Since the attributes are marked as sensitive, the values in the update will not be visible in the Terraform output. If the non-hashed values have not changed, then no update is occurring other than the Terraform state update. If these arguments are the only two updates and they both match the SHA256 removal, the apply will occur without submitting an actual setPlatformApplicationAttributes
API call.
Resource: aws_spot_fleet_request
valid_until Argument No Longer Uses 24 Hour Default
Previously when the validUntil
argument was not configured, the resource would default to a 24 hour request. This behavior has been removed and allows for non-expiring requests. To recreate the old behavior, the timeOffset
resource can potentially be used.
Resource: aws_ssm_maintenance_window_task
logging_info Configuration Block Removal
Switch your Terraform configuration to the taskInvocationParameters
configuration block runCommandParameters
configuration block outputS3Bucket
and outputS3KeyPrefix
arguments instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.ssmMaintenanceWindowTask.SsmMaintenanceWindowTask(this, "example", {
logging_info: [
{
s3_bucket_key_prefix: "example",
s3_bucket_name: "${aws_s3_bucket.example.id}",
},
],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.ssmMaintenanceWindowTask.SsmMaintenanceWindowTask(this, "example", {
taskInvocationParameters: {
runCommandParameters: {
outputS3Bucket: "${aws_s3_bucket.example.id}",
outputS3KeyPrefix: "example",
},
},
});
task_parameters Configuration Block Removal
Switch your Terraform configuration to the taskInvocationParameters
configuration block runCommandParameters
configuration block parameter
configuration blocks instead.
For example, given this previous configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.ssmMaintenanceWindowTask.SsmMaintenanceWindowTask(this, "example", {
task_parameters: [
{
name: "commands",
values: ["date"],
},
],
});
An updated configuration:
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.ssmMaintenanceWindowTask.SsmMaintenanceWindowTask(this, "example", {
taskInvocationParameters: {
runCommandParameters: {
parameter: [
{
name: "commands",
values: ["date"],
},
],
},
},
});