📝

Terraformでiamとcloudwatchを作成する

2023/06/09に公開

背景

某AWSオンライン学習サイトのAWSの環境構築を進める際、ふとterraformで書いたらどうなるのか?
と興味が湧き、学習教材の環境構築で作成するAWSリソースをterraformで記述した。

要件

  • Administrator権限を持ったIAMユーザーの作成。初回ログイン後にパスワードを再設定する。MFAの設定をする
  • 請求アラート用のcloudwatchの作成しする。もし10USDを超えた場合、指定したメールアドレスに送信する

要件を満たすために作成するAWSリソースまたは設定

  • IAM
    • ユーザーの作成
    • ユーザー作成後の初回ログイン時の設定
    • MFAの設定
  • ポリシー
    • Administrator
  • CloudWatch
    • アラームの起動条件
      • 閾値:10USD
      • 条件:閾値を超えた場合
  • SNS
    • 配信形式:メール
    • 通知先:指定したメールアドレス

構成図

リポジトリ

IAMユーザーの実装

resource "aws_iam_user" "admin" {
  name          = "Administrator"
  force_destroy = true
  tags = {
    environment = "development"
  }
}

resource "aws_iam_user_login_profile" "admin" {
  user                    = aws_iam_user.admin.name
  password_reset_required = true
}

resource "aws_iam_user_policy_attachment" "admin" {
  user       = aws_iam_user.admin.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

resource "local_file" "user_info" {
  depends_on = [aws_iam_user.admin, aws_iam_user_login_profile.admin]
  filename   = "${pathexpand("../")}/user_info.txt"
  content    = "IAM User Name: ${aws_iam_user.admin.name}\nPassword: ${aws_iam_user_login_profile.admin.password}"
}

PR: https://github.com/beginerbeginer/cloudtech-Issue1-1/pull/3/files
ISSUE: https://github.com/beginerbeginer/cloudtech-Issue1-1/issues/1

工夫した箇所

  • デフォルトだとiamユーザー作成時のデフォルトパスワードが取得できないため、パスワードが取得されるよう設定
  • iamユーザーを作成した場合、アイパスの情報をuser_info.txtで出力
  • user_info.txtは間違ってgitに含めないよう親ディレクトリを指定

clouwatchの実装

resource "aws_sns_topic" "billing" {
  name = "Billing"
}

resource "aws_sns_topic_subscription" "user_subscription" {
  topic_arn = aws_sns_topic.billing.arn
  protocol  = "email"
  endpoint  = "test@gmail.com"
}

resource "aws_cloudwatch_metric_alarm" "alarm" {
  alarm_name          = "Billing-Alarm"
  alarm_description   = "テストアラーム詳細"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "1"
  metric_name         = "EstimatedCharges"
  namespace           = "AWS/Billing"
  period              = "21600"
  statistic           = "Maximum"
  threshold           = "10"
  alarm_actions       = [aws_sns_topic.billing.arn]
}

CloudWatchとSNS(Simple Notification Service)の解説

よく混同されがちだが怖くない。下記を想像してみよう!

イメージ:新聞が新聞配達員によって毎日朝8時に家にポストに届けられる。

新聞
配達員

上記をそれぞれAWSリソースで例えた場合、下記の通りである。

  • aws_sns_topic:新聞
  • aws_sns_topic_subscription:新聞配達員
  • aws_cloudwatch_metric_alarm:新聞が配達される条件

aws_sns_topicは新聞社(AWS)が発行する新聞で、aws_sns_topic_subscriptionは配達員としてaws_sns_topicという新聞を届けます。aws_cloudwatch_metric_alarmは"毎日朝8時"という配達条件です。

しかし、aws_cloudwatch_metric_alarmは特殊です。通常の新聞配達は毎日同じ時間に新聞が届くのが普通ですが、CloudWatchは特定の「条件」を監視し、その「条件」が満たされたときにSNSトピックにアラーム(通知)を発行します。このアラームはSNSトピックからサブスクリプション(ここでは「新聞配達員」)によって所定のエンドポイント(この例では"test@gmail.com"というメールアドレス)に配達されます。

この3つのリソースを一緒に使うことで、「AWSの料金が一定値を超えたら、"Billing"というトピックで通知を作り、それをメールで送信する」という要件を満たすことができます。
上記によって請求額が10ドルを超えたという重要な情報をリアルタイムで受け取ることができるようになるのです。

MFAの設定について

今回はMFAの設定は見送った。設定方法は作成したIAMユーザでログインした後、マネジメントコンソールから登録する従来の手順にした。
見送った理由

  • 技術的な課題:terraformで送られてきたデータをQRコードに変換する方法がわからなかった
  • リソース:時間が足りなかった

セキュリティの観点で見たのコードの問題

今回のコードをレビューいただいた際、以下のレビューをいただいた。

ユーザー名やパスワードをlocal_fileリソースを使用してテキストファイルに出力することについては、セキュリティの観点から見ると問題があるように見えます。これらの情報は秘密情報として扱うべきであり、引き続き対策を検討してみると良いかと思います。

上記についての問題点と対策を自分になりに考えてみた。

問題点

情報の露出: local_file リソースを使って情報をテキストファイルに出力した場合、そのファイルはコンピュータ上のどこからでもアクセスできる。IAMユーザーのパスワードやMFAのシード値などの機密情報が含まれている場合、誤って他人がその情報を見ることが可能になる

不適切な保存: この方法では、パスワードが平文(暗号化されていない状態)で保存されてしまう。

対策

terraformを使わない: 理由:パスワードの露出が最小限で済む

terraformでiamを作成する場合パスワードを何らかの方法(ファイル、ターミナル)で平文で出力する必要がある。
そのため下記セキュリティの観点でリスクがある。

  • 第3者にみられるリスク
  • 誤ってファイルを共有してしまうリスク

TerraformでAWSリソース作成をする中で学んだこと

  • Terraformでコードを書くことによって各AWSリソースの関係、役割の違いがわかりよりサービスの理解につながった
  • Terraformのドキュメントを読むことでAWSサービスで何が設定できるのかわかるり、何ができるか理解できるようになった
  • セキュリティの面からterraformを使わずにAWSマネジメントコンソールから作成するべきケースもある

参考記事

GitHubで編集を提案

Discussion