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