TerraformのDependencyViolationを修正:リソース削除のスタックを解消する

intermediate🏗️ Terraform2026-07-15| Terraform CLI (全バージョン), AWS/Azure/GCP クラウドプロバイダー

Error Message

Error: Error deleting Security Group: DependencyViolation: The security group 'sg-0a1b2c3d4e5f6g7h8' has dependencies and cannot be deleted.
#terraform#aws#devops#トラブルシューティング

午前2時の本番環境の停滞

ステージング環境を廃止しようとしており、すぐに終わるだろうと考えています。しかし、Terraformは180秒間ハングした後に DependencyViolation エラーでクラッシュします。ターミナルの出力は最悪の事態を告げています。何かがまだ使用しているため、Security Group または Subnet が削除できず停止しています。

Error: Error deleting Security Group: DependencyViolation: The security group 'sg-0a1b2c3d4e5f6g7h8' has dependencies and cannot be deleted.
    status code: 400, request id: 12345678-90ab-cdef-1234-567890abcdef

この問題は、Terraformの状態ファイル(state file)とクラウドコンソールの実態との間の乖離に起因します。Terraformは自身がリソースのライフサイクルを管理していると考えています。しかし、手動でアタッチされたNetwork Interface (ENI)、残存しているLambda関数、あるいはLoad Balancerといった外部エンティティが、まだそのリソースに固執しています。クラウドのAPIは、ネットワークの切断を防ぐために削除リクエストを拒否します。

ステップ1:ゴースト依存関係の特定

Terraformは何を削除できないかは教えてくれますが、その「理由」については驚くほど口を閉ざします。AWSのSecurity Groupが削除できない場合、ほとんどの原因は隠れたNetwork Interface (ENI)にあります。これは、すぐにはスケールダウンしないElastic Load Balancer (ELB)やEKSノードで頻繁に発生します。

リソースを「人質」に取っている具体的なアタッチメントを見つけるために、AWS CLIを使用します:

# 削除できないSecurity GroupにリンクされているENIを検索
aws ec2 describe-network-interfaces \
    --filters Name=group-id,Values=sg-0a1b2c3d4e5f6g7h8 \
    --query 'NetworkInterfaces[*].{ID:NetworkInterfaceId,Description:Description,Status:Status}'

このコマンドがアクティブなIDを返した場合、ゴーストが見つかったことになります。AWS LambdaのENIは、この問題の常連です。関数が削除された後でも、VPCが回収するまでネットワークインターフェースが数分間残ることがあります。Terraformは、これらの手動またはシステム管理のアタッチメントが .tfstate ファイルに含まれていないため、検知することができません。

ステップ2:実践的な解決策

方法A:ライフサイクルによる修正(予防的)

apply の際、Terraformはしばしば新しいリソースを作成する前に古いリソースを削除しようとします。他のリソースがまだ古いIDを参照している場合、このプロセスは失敗します。lifecycle ブロックを使用して、このロジックを逆にすることができます。

resource "aws_security_group" "web_server" {
  name = "web-sg-v2"

  lifecycle {
    create_before_destroy = true
  }
}

このブロックは、Terraformにまず新しいSecurity Groupをプロビジョニングさせます。その後、依存するすべてのリソースを更新して新しいIDを指すようにします。古いリソースが完全に「孤立」した後にのみ、Terraformは削除を試みます。これは、ネットワーキングコードにおける依存関係のループを防ぐ最も効果的な方法です。

方法B:手動による介入(対症療法)

時には、手動で道を切り開く必要があります。これは、Terraformが追跡していないLoad BalancerをKubernetesクラスター (EKS) が作成した場合によく見られます。

  • 特定とデタッチ: ステップ1で得たIDを使用して、AWSコンソールでリソースを見つけます。手動でENIまたはLoad Balancerを削除します。
  • 状態の同期: 障害物がなくなったら、terraform plan -refresh-only を実行してローカルの状態を更新します。
  • 作業の完了: 再度 terraform destroy を実行します。今度は即座に完了するはずです。

方法C:状態から強制的に削除する

クラウドコンソール経由ですでにリソースを削除したにもかかわらず、Terraformが削除を試み続ける場合は、状態ファイルに「開頭手術」を行う必要があります。state rm コマンドを使用します。

terraform state rm aws_security_group.web_server

注意: これは追跡記録を削除するだけで、実際のインフラストラクチャを削除するわけではありません。物理的なリソースがすでに存在しない場合、または手動で管理するつもりの場合にのみ使用してください。

ステップ3:検証

planを実行して修正を確認します。create_before_destroy を実装した場合、出力は以下のようになるはずです:

# aws_security_group.web_server must be replaced
# +/- create replacement and then destroy

成功すると、Destroy complete! Resources: 1 destroyed. という満足のいくメッセージで終了します。

今後のための教訓

  • 「ClickOps」を避ける: コンソールでSecurity GroupをEC2インスタンスに手動でアタッチすることは、次回のTerraform実行を確実に失敗させる方法です。
  • Lambdaの遅延を考慮する: VPC対応のLambdaは、まれにENIを完全に解放するまで最大20分かかることがあります。これが頻繁に発生する場合は、CI/CDパイプラインにリトライロジックを組み込んでください。
  • ライフサイクルルールを標準化する: SubnetやVPC Peering接続などの基礎的なコンポーネントには、デフォルトで create_before_destroy を適用します。
  • サイレントキラーに注意する: NAT GatewayやVPC Endpointは、親VPCの削除を妨げる長いクリーンアップ時間を要することがよくあります。

Related Error Notes