Skip to content

【Terraform】targetオプション指定時のplanとapply

はじめに

社内で Terraform に関する質問がありました。

  1. terraform plan 実行時に target オプションに module.A を指定しているにもかかわらず、その module と関係ない部分が plan として表示される
  2. terraform apply 実行時に target オプションをつけて実行したあと、再度 plan を実行すると apply 前と同じ plan が表示される

私自身どのような条件でこの事象が発生するのか気になったので調べてみました。

環境

バージョン
MacVentura 13.2.1
Terraform1.8.2

成果物

https://github.com/kntks/blog-code/tree/main/2024/04/terraform-plan-diff-with-target

状況

事象が発生したときの状況を一度整理します。

  • module.A が定義されており、 その module は module.B.output_value に依存している。
  • terraform plan、apply はともに依存元である module.A を target に指定している。

検証

この検証では、AWS VPC と Security Group を作成する module(以下:VPC module, SG module)を設定し、SG module が VPC module の output に依存するよう設定します。module.B を VPC module、module.A を SG module と想定しています。

このセクションでは、質問にあった事象が発生する状況を調べます。

環境構築

ディレクトリ構成

Terminal window
$ tree
.
├── backend.tf
├── main.tf
├── providers.tf
├── terraform.tfstate
└── terraform.tfstate.backup
providers.tf
terraform {
required_version = "~> 1.8"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.46"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
backend.tf
terraform {
backend "local" {
path = "./terraform.tfstate"
}
}
main.tf
locals {
cidr = "10.0.0.0/16"
private_subnets = []
public_subnets = [
cidrsubnet(local.cidr, 8, 101),
]
}
data "aws_availability_zones" "available" {
state = "available"
}
# ===============
# VPC
# ===============
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.8"
name = "my-vpc"
cidr = local.cidr
azs = data.aws_availability_zones.available.names
private_subnets = local.private_subnets
public_subnets = local.public_subnets
manage_default_network_acl = false
manage_default_route_table = false
manage_default_security_group = false
manage_default_vpc = false
enable_nat_gateway = false
enable_vpn_gateway = false
}
# ===============
# Security Group
# ===============
module "example_sg" {
source = "terraform-aws-modules/security-group/aws"
version = "~> 5.1"
name = "example-sg"
description = "example security group"
# VPC moduleのoutputを参照する
vpc_id = module.vpc.vpc_id
ingress_cidr_blocks = [local.cidr]
ingress_rules = ["https-443-tcp"]
ingress_with_cidr_blocks = []
use_name_prefix = false
}

まず AWS のリソースを作成します。

Terminal window
terraform init
terraform plan
terraofrm apply -auto-approve

検証1: Terraform で VPC に tag をつける

Terraform の VPC module に tag を追記します。

main.tf
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.8"
name = "my-vpc"
cidr = local.cidr
azs = data.aws_availability_zones.available.names
private_subnets = local.private_subnets
public_subnets = local.public_subnets
manage_default_network_acl = false
manage_default_route_table = false
manage_default_security_group = false
manage_default_vpc = false
enable_nat_gateway = false
enable_vpn_gateway = false
tags = {
Terraform = "true"
}
}

先にオプションなしの plan を実行してみます。VPC module 内部のリソース4つに tag をつける変更が表示されました。

Terminal window
Plan: 0 to add, 4 to change, 0 to destroy.
plan全文
Terminal window
$ terraform plan
data.aws_availability_zones.available: Reading...
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
data.aws_availability_zones.available: Read complete after 0s [id=ap-northeast-1]
module.vpc.aws_subnet.public[0]: Refreshing state... [id=subnet-0d1742f93d3371e15]
module.vpc.aws_internet_gateway.this[0]: Refreshing state... [id=igw-081a83b00a08bab8d]
module.vpc.aws_route_table.public[0]: Refreshing state... [id=rtb-069564d690385c37f]
module.example_sg.aws_security_group.this_name_prefix[0]: Refreshing state... [id=sg-0af7db8f0a8f4ed11]
module.vpc.aws_route_table_association.public[0]: Refreshing state... [id=rtbassoc-0cc7d2eee0ed43270]
module.vpc.aws_route.public_internet_gateway[0]: Refreshing state... [id=r-rtb-069564d690385c37f1080289494]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-1049769209]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_internet_gateway.this[0] will be updated in-place
~ resource "aws_internet_gateway" "this" {
id = "igw-081a83b00a08bab8d"
~ tags = {
"Name" = "my-vpc"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (3 unchanged attributes hidden)
}
# module.vpc.aws_route_table.public[0] will be updated in-place
~ resource "aws_route_table" "public" {
id = "rtb-069564d690385c37f"
~ tags = {
"Name" = "my-vpc-public"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (5 unchanged attributes hidden)
}
# module.vpc.aws_subnet.public[0] will be updated in-place
~ resource "aws_subnet" "public" {
id = "subnet-0d1742f93d3371e15"
~ tags = {
"Name" = "my-vpc-public-ap-northeast-1a"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (19 unchanged attributes hidden)
}
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 4 to change, 0 to destroy.

次に VPC module に tag をつけましたが、plan を実行するときに SG module を指定します。すると plan は aws_vpc リソースのみ表示されました。

Terminal window
$ terraform plan -target module.example_sg
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
module.example_sg.aws_security_group.this_name_prefix[0]: Refreshing state... [id=sg-0af7db8f0a8f4ed11]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-1049769209]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.

targetオプションを指定してapplyを実行してみます。

Terminal window
$ terraform apply -target module.example_sg -auto-approve
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
apply全文
Terminal window
$ terraform apply -target module.example_sg -auto-approve
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
module.example_sg.aws_security_group.this[0]: Refreshing state... [id=sg-074c36b58780c7c15]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-3270750140]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Warning: Resource targeting is in effect
You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.
Warning: Applied changes may be incomplete
The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the following command to verify that no other changes
are pending:
terraform plan
Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error
message.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

apply によって変更は適用されず、再度 plan を実行すると apply 前の plan と同じ結果になりました。

Terminal window
$ terraform plan -target module.example_sg
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
module.example_sg.aws_security_group.this[0]: Refreshing state... [id=sg-074c36b58780c7c15]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-3270750140]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
+ "Terraform" = "true"
}
~ tags_all = {
+ "Terraform" = "true"
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.

つまりこの検証から Terraorm のコード自体は変更されているが、依存元である VPC module が apply されていない場合に質問の事象が発生することがわかりました。

change-module-vpc

なぜ aws_vpc のみ plan に表示される?

target オプションを使用せずに terraform plan を実行すると、VPC module 内の4つのリソースについてのプランが表示されました。しかし、target オプションに module.example_sg を指定すると4つのリソースのうちの1つである aws_vpc のみに変更が表示されました。

SG module が参照している module.vpc.vpc_id の設定を確認すると、VPC module の output である vpc_idaws_vpc.this.id を参照しています。

output "vpc_id" {
description = "The ID of the VPC"
value = try(aws_vpc.this[0].id, null)
}

引用:https://github.com/terraform-aws-modules/terraform-aws-vpc/blob/v5.8.0/outputs.tf#L11-L14

以下の引用を読むと、 aws_vpc と SG module のリソースの間に暗黙の依存関係があることを推測できます。

For example, an expression in a resource argument that refers to another managed resource creates an implicit dependency between the two resources.

(訳)例えば、リソース引数で別の管理リソースを参照する式は、2つのリソース間に暗黙の依存関係を作ります。

引用:Named Values and Dependencies

state ファイルから SG module で作成されるリソースの依存を確認します。すると作成された2つのリソースがともに "module.vpc.aws_vpc.this" に依存していることを確認できました。このことから plan に aws_vpc のみ表示されたと推測できます。

Terminal window
$ cat terraform.tfstate | jq -M '.resources[] | select(.module=="module.example_sg") | { type: .type, dependencies:.instances[].dependencies }'
{
"type": "aws_security_group",
"dependencies": [
"module.vpc.aws_vpc.this"
]
}
{
"type": "aws_security_group_rule",
"dependencies": [
"module.example_sg.aws_security_group.this",
"module.example_sg.aws_security_group.this_name_prefix",
"module.vpc.aws_vpc.this"
]
}

module-implicit-dependency

ちなみに module 全体に対して依存させるには、 depends_on を入れることで明示的な依存関係を作ることができます。

main.tf
module "example_sg" {
source = "terraform-aws-modules/security-group/aws"
version = "~> 5.1"
name = "example-sg"
description = "example security group"
vpc_id = module.vpc.vpc_id
ingress_cidr_blocks = [local.cidr]
ingress_rules = ["https-443-tcp"]
ingress_with_cidr_blocks = []
use_name_prefix = false
depends_on = [ module.vpc ]
}

参考:The depends_on Meta-Argument

plan 結果は、target 指定なしで plan した結果と同じです。

Terminal window
$ terraform plan -target module.example_sg
# targetオプションなしの場合とplan結果が同じため省略
Plan: 0 to add, 4 to change, 0 to destroy.

検証2: AWS CLIでVPCにtagをつける

検証1では、Terraform の VPC module に tag を設定することで質問にあった事象が再現するか確認しました。しかし、それはリソース変更前の話です。

次は AWS CLI で tag をつけることで、Terraform の管理外ですでにリソースへの変更があった場合を確認してみます。

検証1で設定した VPC module の tag は外しておきます。

main.tf
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.8"
name = "my-vpc"
cidr = local.cidr
azs = data.aws_availability_zones.available.names
private_subnets = local.private_subnets
public_subnets = local.public_subnets
manage_default_network_acl = false
manage_default_route_table = false
manage_default_security_group = false
manage_default_vpc = false
enable_nat_gateway = false
enable_vpn_gateway = false
tags = {
Terraform = "true"
}
}

事前準備で用意した環境に戻しておきます。

Terminal window
$ terraform apply -auto-approve
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

以下の AWS CLI コマンドを実行して VPC、Subnet、Route table、Internet Gateway に対して tag をつけます。

Terminal window
VPC_ID=vpc-028b17b12099cb202
SUBNET_ID=subnet-0d1742f93d3371e15
ROUTE_TABLE_ID=rtb-069564d690385c37f
INTERNET_GATEWAY_ID=igw-081a83b00a08bab8d
aws ec2 create-tags --resources $VPC_ID $SUBNET_ID $ROUTE_TABLE_ID $INTERNET_GATEWAY_ID --tags Key=Terraform,Value=true

まず target オプションなしで plan を実行します。するとタグを付けた4つのリソースに対して変更が出力されました。

Terminal window
$ terraform plan
Plan: 0 to add, 4 to change, 0 to destroy.
plan全文
Terminal window
$ terraform plan
data.aws_availability_zones.available: Reading...
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
data.aws_availability_zones.available: Read complete after 0s [id=ap-northeast-1]
module.vpc.aws_internet_gateway.this[0]: Refreshing state... [id=igw-081a83b00a08bab8d]
module.vpc.aws_route_table.public[0]: Refreshing state... [id=rtb-069564d690385c37f]
module.example_sg.aws_security_group.this[0]: Refreshing state... [id=sg-074c36b58780c7c15]
module.vpc.aws_subnet.public[0]: Refreshing state... [id=subnet-0d1742f93d3371e15]
module.vpc.aws_route.public_internet_gateway[0]: Refreshing state... [id=r-rtb-069564d690385c37f1080289494]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-3270750140]
module.vpc.aws_route_table_association.public[0]: Refreshing state... [id=rtbassoc-0cc7d2eee0ed43270]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_internet_gateway.this[0] will be updated in-place
~ resource "aws_internet_gateway" "this" {
id = "igw-081a83b00a08bab8d"
~ tags = {
"Name" = "my-vpc"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (3 unchanged attributes hidden)
}
# module.vpc.aws_route_table.public[0] will be updated in-place
~ resource "aws_route_table" "public" {
id = "rtb-069564d690385c37f"
~ tags = {
"Name" = "my-vpc-public"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (5 unchanged attributes hidden)
}
# module.vpc.aws_subnet.public[0] will be updated in-place
~ resource "aws_subnet" "public" {
id = "subnet-0d1742f93d3371e15"
~ tags = {
"Name" = "my-vpc-public-ap-northeast-1a"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (19 unchanged attributes hidden)
}
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 4 to change, 0 to destroy.

続いて target オプションを付けて plan を実行します。module.example_sg のリソースが aws_vpc に依存しているため target オプションを付けても plan が表示されます。

Terminal window
$ terraform plan -target module.example_sg
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
module.example_sg.aws_security_group.this[0]: Refreshing state... [id=sg-074c36b58780c7c15]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-3270750140]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.

target オプションを付けて apply を実行します。

Terminal window
$ terraform apply -target module.example_sg -auto-approve
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
apply全文
Terminal window
$ terraform apply -target module.example_sg -auto-approve
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
module.example_sg.aws_security_group.this[0]: Refreshing state... [id=sg-074c36b58780c7c15]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-3270750140]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Warning: Resource targeting is in effect
You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by
the current configuration.
The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or
when Terraform specifically suggests to use it as part of an error message.
Warning: Applied changes may be incomplete
The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output
values may not be fully updated. Run the following command to verify that no other changes are pending:
terraform plan
Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors
or mistakes, or when Terraform specifically suggests to use it as part of an error message.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

apply によって変更は適用されず、再度 plan を実行すると apply 前の plan と同じ結果になりました。

Terminal window
$ terraform plan -target module.example_sg
module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-028b17b12099cb202]
module.example_sg.aws_security_group.this[0]: Refreshing state... [id=sg-074c36b58780c7c15]
module.example_sg.aws_security_group_rule.ingress_rules[0]: Refreshing state... [id=sgrule-3270750140]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.vpc.aws_vpc.this[0] will be updated in-place
~ resource "aws_vpc" "this" {
id = "vpc-028b17b12099cb202"
~ tags = {
"Name" = "my-vpc"
- "Terraform" = "true" -> null
}
~ tags_all = {
- "Terraform" = "true" -> null
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.

質問にあった状況と同じ事象を発生させることができました。

つまりこの検証からすでに実環境側(ここではAWS)で依存元の設定が変更された状態で、依存先のリソースを target に指定して plan を実行した場合に質問の事象が発生することがわかりました。

change-resource-by-cli

ドキュメントとissueを調べる

再度質問を確認します。

  1. terraform plan 実行時に target オプションに module.A を指定しているにもかかわらず、その module と関係ない部分が plan として表示される
  2. terraform apply 実行時に target オプションをつけて実行したあと、再度 plan を実行すると apply 前と同じ plan が表示される

これらについてドキュメントと GitHub の issue を探してみます。

まず、1つ目の質問に対する回答は、検証で推測したように、target で指定したリソースの依存するリソースも plan として表示されるからです。

-target=ADDRESS - Instructs Terraform to focus its planning efforts only on resource instances which match the given address and on any objects that those instances depend on.

(訳)指定されたアドレスにマッチするリソースインスタンスと、それらのインスタンスが依存するオブジェクトのみに計画を集中させるように指示します。

引用:Planning Options

Once Terraform has selected one or more resource instances that you’ve directly targeted, it will also then extend the selection to include all other objects that those selections depend on either directly or indirectly.

(訳)Terraformは、あなたが直接ターゲットとした1つまたは複数のリソースインスタンスを選択すると、その選択範囲が直接または間接的に依存している他のすべてのオブジェクトにも拡張されます。

引用:Resource Targeting

次に2つ目の質問ですが、以下に同じ事象についてissueが上がっています。

Hashicorp 社のメンバーの方が以下のように発言しています。

We generally expect plan and apply with the same arguments to behave the same, so this does seem like a bug somewhere in the upstream Terraform core handling of this situation.

(訳)私たちは一般的に、同じ引数を持つplanとapplyは同じ動作をすると考えているので、この状況はアップストリームのTerraformコアの処理のどこかにバグがあるように思えます。

引用:https://github.com/hashicorp/terraform-provider-aws/issues/5172#issuecomment-404590059

そして、バグについては hashicorp/terraform#18439 を引き続き確認するようコメントされています。
しかし、hashicorp/terraform#18439 のコメントは2018年を最後に更新されていません。そのため2つ目の質問に対する回答として、バグだと思われます。

まとめ

今回の Terraform に関する質問は、Terraform の仕様と(おそらく)バグによって発生した事象です。

ドキュメントに書いてあるように、target オプションは例外的な状況のために用意されたオプションであるため、普段からそのオプションを使用するのは避けたほうが良いと思います。

target オプションを使用しなければ発生しない事象であるため、チーム内での使用が常態化している場合はリファクタリングの合図なのかもしれません。

Resource Targeting is intended for exceptional circumstances only and should not be used routinely.

(例)リソース・ターゲティングは例外的な状況のみを想定しており、日常的に使用されるべきではない。

引用:Targeted Plan and Apply

This targeting capability is provided for exceptional circumstances, such as recovering from mistakes or working around Terraform limitations. It is not recommended to use -target for routine operations

(訳)このターゲティング機能は、ミスからの回復やTerraformの制限を回避するような例外的な状況のために提供されています。日常的な操作に -target を使うことは推奨されません。

引用:Resource Targeting

さいごに

この issue コメントで知ったのですが、terraform_data リソースでも事象を再現できます。

main.tf
terraform {
required_version = "~> 1.8"
backend "local" {
path = "./terraform.tfstate"
}
}
variable "example" {}
resource "terraform_data" "resource1" {
triggers_replace = [
var.example
]
}
resource "terraform_data" "resource2" {
depends_on = [ terraform_data.resource1 ]
}
Terminal window
terraform init
terraform apply -var example=a -auto-approve
terraform plan -var example=b
terraform apply -var example=b -target terraform_data.resource2 -auto-approve
terraform plan -var example=b