EC2 ユーザーデータ内の AWS 認証情報の確認

EC2 のユーザーデータから長期 AWS 認証情報を取り除き、インスタンスロールの一時的な認証情報を使用してください。

説明

EC2 の user_data に AWS 認証情報を埋め込むと、ソースリポジトリ、Terraform の状態、初期化ログ、インスタンスメタデータから漏えいする可能性があります。アクセスキー ID だけでは AWS API を呼び出せませんが、対応するシークレットアクセスキーも漏えいすると、その認証情報に付与された権限が悪用されるおそれがあります。

インスタンスプロファイルを介して IAM ロールを関連付け、アプリケーションが固定キーではなく一時的な認証情報を使うようにしてください。

想定される影響

  • 有効な認証情報が別の環境で再利用され、許可された AWS 操作を実行される可能性があります。
  • スクリプトやデプロイ資料に複製されたシークレットは、回収や交換が難しくなります。
  • 認証情報の交換により、それを利用する初期化処理やアプリケーションが停止する可能性があります。

対処方法

  • ユーザーデータとそこから呼び出すスクリプトから、アクセスキー ID とシークレットアクセスキーを取り除いてください。
  • EC2 ロールには必要な操作とリソースだけを許可し、AWS SDK がロールの一時的な認証情報を使うようにしてください。外部サービスのシークレットは、Secrets Manager などからアクセスを制限して取得してください。
  • 実際の認証情報が漏えいした場合は、利用先を確認して交換・失効し、関連する API 操作を調査してください。ソース、状態ファイル、初期化ログへのアクセスも制限してください。

例

以下は部分的な例です。環境に適した ami_id と subnet_id を指定し、IAM インスタンスプロファイルは別途設定してください。

変更前

hcl
module "ec2_instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "~> 3.0"

  name      = "single-instance"
  ami       = var.ami_id
  subnet_id = var.subnet_id
  user_data = "1234567890123456789012345678901234567890$"
}

user_data に文字列を直接指定しています。この例の値が発行済みの AWS 認証情報であることを示すものではありませんが、実際のシークレットアクセスキーをここに保存しないでください。

変更後

hcl
module "ec2_instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "~> 3.0"

  name      = "single-instance"
  ami       = var.ami_id
  subnet_id = var.subnet_id
  user_data = file("scripts/first-boot-http.sh")
}

file() はスクリプトの内容を読み込み、ユーザーデータとして渡します。ファイルに移すだけではシークレットを保護できないため、スクリプトにも認証情報を含めず、ロールによるアクセスを設定してください。

参考資料