なにもしてないのにEC2インスタンスが壊れた


この記事について

DMMグループ Advent Calendar 2020 の 17日目の投稿記事となります
https://qiita.com/advent-calendar/2020/dmm

また、発表に向けた記事のため、スライドモードでの回覧を推奨しています。


自己紹介

名前 : 松田 弘樹
入社 : 2015年5月入社の6年目
担当 : バックエンド、インフラ担当
趣味 : 乗馬🐎 全乗協の5級ライセンス取得しました。  


想定読者

  • IaC (Terraformなど)の概要を理解している人
  • CI/CDによる、自動デプロイの概要を理解している人
  • AWSのEC2インスタンスを構築したことがある人

発端

通常の運用で

ある日、Terraformにて構築済みのEC2インスタンスから、作業のために mysqlコマンドで接続をしてみると
mysql: command not found
というエラーコードが返却された


発端

!?

数日前まで、使えていたコマンドが使えなくなっていること示すをエラーが返却された。
histroyを確認してみると、実行したコマンド履歴が一切無い。つまり、EC2インスタンスが初期化されている。

自分「(構築後にインフラので変更していないはずなのに)何もしていないのに壊れた」


発端

というわけで

本記事では私が遭遇した なにもしてないのにEC2インスタンスが壊れた について、ストーリ仕立てでお話をしていきます。

最後にまとめがあるので、忙しい人はそちらへどうぞ


状況整理

まずは事象と影響範囲の確認から

事象

Terraformのtfstateで管理さている、EC2インスタンスが初期化された。

影響範囲

他のTerraform管理のインフラ要素に影響はなし。


環境について

概要をざっくり説明

インフラ構成管理

基本と、Terraformを利用し、インフラ構成をコードで管理している


環境について

Terraformコードを管理するリポジトリは2種類

  • inf: VPC、サブネット、ネットワーク定義など管理。デプロイは手動適用。
  • app: アプリ特有の定義管理。WEBサーバ、RDB定義など。EC2もここで管理。デプロイはCI/CDに組み込まれ自動適用。

環境について

CI/CDフロー

利用しているツール類は次の通り。

  • GithubEnterprise (ソースコードのリポジトリ管理)
  • CircleCI (Docker Build、コンテナ上での単体テスト、Terraformのapply、Docker ImageのPUSH)
  • AWS ECR (Docker Image用リポジトリ)
  • AWS ECS (コンテナの実行環境)

上から順番に連携するフローとなっている


調査

ここからは調査です。
可能性のありそうな仮設をたてながら、検証を繰り返していきました。


調査

仮設1 手動で、メンバーか削除した可能性

一番わかり易いのは、誰かが手動でEC2を作り直したことです。
しかし、メンバーに確認をとってみましたが、該当者がいないため、この説否定されました


調査

仮設2 tfstateの状態が破損し、作り直した可能性

何かの理由でstateファイルが破損したことでEC2インスタンスがterraform管理から外れ、
新しくTerraform管理とするため作り直された可能性を考えました。

tfstateファイルの状態確認のため、手動で Terraform plan を実行しました。
結果、エラーなく正常に動作し、tfstateファイルは正しく機能しているため、この説は否定されました


調査

仮設3 TerraformのEC2の記述が修正されて、EC2が再構築した可能性

EC2インスタンスを管理しているtfファイルの直近の修正履歴を確認しましたが、直近ではtfファイルは修正されていませんでした。
症状発生時には編集されていないため、この説は否定されました


調査

他にどんな原因が考えられるかと仮設をかんがえていたなかで、調査をお願いしていたメンバーから新たな情報をいただく

新く判明した情報

CloudTrail上のイベントにおいて、Terraform実行ユーザが、EC2インスタンス対して Terminateinstance を複数回、実行していることが判明。


同様に。EC2インスタンスが作成されているイベントも確認。


調査

上記の情報より、原因がTerraformが怪しいとの絞り込みができたので新たな仮設が浮かぶ。

仮設4 Terraformにおいて、意図せずEC2が再構築した可能性

EC2の何かしらのリソースが動的取得しており、その部分が更新されるたびにEC2インスタンスが再構築されるのではないか。


調査

というわけで、EC2関連の記載について細かく見ていきました。

当時のソース

AMI情報をaws_amifilter で絞り込んだあと、aws_instanceに指定する流れとなっています。

# AMI情報を取得
data "aws_ami" "amazon_linux" { 
  most_recent = true    
  owners      = ["amazon"]  

  filter {
    name   = "architecture" 
    values = ["x86_64"] 
  }

  filter {
    name   = "root-device-type" 
    values = ["ebs"]
  }

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  filter {
    name   = "block-device-mapping.volume-type"
    values = ["gp2"]
  } 
}

# AMIのIDを指定して構築
resource "aws_instance" "rds_access_ec2" {
  ami = data.aws_ami.amazon_linux.id
  instance_type = "t2.micro" 
}

調査

aws_ami のパラメータをひとつづつ確認していると、怪しい記述を発見しました。

怪しい部分

most_recent - (Optional) If more than one result is returned, use the most recent AMI. 
most_recent-(オプション)複数の結果が返される場合は、最新のAMIを使用します。

これだ!!!!!!!!!!!!!!!
原因が特定できました。


原因

CDCDの自動デプロイフローにおいて、EC2のAMIを動的に取得しており、デプロイのたびに最新版のAMIを取得して、更新がある場合はEC2再構築を行うため。

発生時のフロー

  1. GithubEnterpirseに、コードをpushする。
  2. 連携しているCircleCIで、push検知してCI/CDが起動する。
  3. デプロイ処理のなかで、毎回最新のAMIイメージを取得する。
  4. AMIイメージが更新されている場合、古いEC2インスタンスを削除し、新しいAMIイメージでEC2インスタンスを作成する。

このため、直接のEC2の定義部分のtfファイルの修正なくとも、EC2インスタンスが新しいものに差し替わってしまったのです。


対応

原因がわかったので対応をしていきましょう。

案1

EC2インスタンスの再作成を許容する。
EC2インスタンスの更新のたびに、コマンドが消失しないように、aws_instanceuser_dataに必要なインストールコマンドを定義しておく。

resource "aws_instance" "rds_access_ec2" {
  user_data = <<EOF
    #!/bin/bash
    sudo yum install -y mysql-community-client
  EOF
}

欠点は、ローカルにおいたファイルなどが消えてしまうことです。


対応

案2

AMIの値を固定値に変更する。
更新したい場合は、AMIの値を修正する運用とする。

resource "aws_instance" "rds_access_ec2" {
  # 固定値に修正
  ami = "ami-00f045aed21a55240"
}

欠点は、手動運用の手間が増えることとなります。


対応

どちらの案も欠点があるので、要件などと照らし合わせて判断すればいいかなと思います。


まとめ

次の環境の場合は、意図せずにリソースが更新されることがあるので注意しましょう。

  • インフラの構成を、Terraformなどでコード管理している
  • デプロイが、手動ではなく自動でデプロイする
  • リソースを動的に取得している部分がある

Special Thanks

調査に協力してくれた @moroishisan


宣伝

弊社ではエンジニアを積極募集中です!
https://dmm-corp.com/recruit/

個人あてに、カジュアルにお話が聞きたいかたもどうぞ!


引用

Data Source: aws_ami
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami


ご視聴ありがとうございました