新しくAWSアカウントを作ったら、すぐにアプリケーションのリソースを作り始めたくなります。しかし、操作の記録や不正な挙動の検知といったセキュリティの土台は、問題が起きてから入れても、起きる前の記録は残っていません。
この記事では、新しいAWSアカウントで最初に入れておきたいセキュリティ設定を5つ選び、Terraformでまとめて設定する方法を紹介します。
入れる設定
- CloudTrail:誰が、いつ、どのAPIを呼んだかを長期間記録する
- GuardDuty:不正なアクセスや不審な通信を自動で検知する
- IAM Access Analyzer:外部に公開されているリソースを見つける
- S3のパブリックアクセスのブロック(アカウント全体):バケットの公開をアカウント単位で禁止する
- EBSのデフォルト暗号化:新しく作るEBSボリュームを自動で暗号化する
どれも数行のコードで設定でき、アカウントを作った直後から効果があります。
1. CloudTrail:操作の記録を長期間残す
AWSのコンソールでは、過去90日分の操作履歴を見られます。ただし90日を過ぎると消えてしまい、検索の機能も限られます。証跡(トレイル)を作ってS3に保存しておけば、期間の制限なく記録を残せます。
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "cloudtrail" {
bucket = "cloudtrail-logs-${data.aws_caller_identity.current.account_id}"
}
resource "aws_s3_bucket_public_access_block" "cloudtrail" {
bucket = aws_s3_bucket.cloudtrail.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
data "aws_iam_policy_document" "cloudtrail" {
statement {
actions = ["s3:GetBucketAcl"]
resources = [aws_s3_bucket.cloudtrail.arn]
principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}
}
statement {
actions = ["s3:PutObject"]
resources = ["${aws_s3_bucket.cloudtrail.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"]
principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "s3:x-amz-acl"
values = ["bucket-owner-full-control"]
}
}
}
resource "aws_s3_bucket_policy" "cloudtrail" {
bucket = aws_s3_bucket.cloudtrail.id
policy = data.aws_iam_policy_document.cloudtrail.json
}
resource "aws_cloudtrail" "main" {
name = "main-trail"
s3_bucket_name = aws_s3_bucket.cloudtrail.id
is_multi_region_trail = true
include_global_service_events = true
enable_log_file_validation = true
depends_on = [aws_s3_bucket_policy.cloudtrail]
}
- is_multi_region_trail = true:すべてのリージョンの操作を記録する。普段使わないリージョンでリソースを勝手に作られても気づける
- enable_log_file_validation = true:ログファイルが改ざんされていないかを後から検証できるようにする
- depends_on:バケットポリシーができる前にトレイルを作ると、書き込み権限がなくエラーになる
2. GuardDuty:不審な挙動を自動で検知する
GuardDutyは、CloudTrailやVPCフローログ、DNSのログを分析し、不正アクセスや不審な通信を検知します。設定は有効にするだけです。
resource "aws_guardduty_detector" "main" {
enable = true
}
注意点は、GuardDutyはリージョンごとのサービスだということです。東京リージョンで有効にしても、他のリージョンは監視されません。使っていないリージョンでの不正な利用も検知したい場合は、リージョンごとにプロバイダーを用意して有効にするか、AWS Organizationsで一括して有効にします。
検知結果は、EventBridgeでSNSに通知できます。重要度の高いものだけに絞ると、通知が多すぎて見なくなる事態を避けられます。
variable "alert_topic_arn" {
type = string
}
resource "aws_cloudwatch_event_rule" "guardduty" {
name = "guardduty-high-severity"
event_pattern = jsonencode({
source = ["aws.guardduty"]
"detail-type" = ["GuardDuty Finding"]
detail = {
severity = [{ numeric = [">=", 7] }]
}
})
}
resource "aws_cloudwatch_event_target" "guardduty_sns" {
rule = aws_cloudwatch_event_rule.guardduty.name
arn = var.alert_topic_arn
}
通知先のSNSトピックには、events.amazonaws.comからの発行を許可するポリシーが必要です。
3. IAM Access Analyzer:外部に公開されたリソースを見つける
S3バケットやIAMロール、KMSキーなどが、アカウントの外から使える状態になっていないかを継続的にチェックします。
resource "aws_accessanalyzer_analyzer" "account" {
analyzer_name = "account-analyzer"
type = "ACCOUNT"
}
外部からのアクセスを調べる機能は、追加の料金なしで使えます。意図しない公開を見つけたら、検出結果から該当のリソースを確認できます。
4. S3のパブリックアクセスをアカウント全体でブロックする
バケットごとの設定とは別に、アカウント全体でS3の公開を禁止できます。
resource "aws_s3_account_public_access_block" "this" {
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
これを設定しておけば、**個別のバケットの設定を誤っても、バケットは公開されません。**静的サイトの配信などでS3を公開したい場合も、CloudFrontのOAC経由にすれば、この設定のまま配信できます。
5. EBSのデフォルト暗号化
新しく作るEBSボリュームとスナップショットを、自動で暗号化します。
resource "aws_ebs_encryption_by_default" "this" {
enabled = true
}
この設定もリージョンごとです。一度有効にしておけば、EC2を作るたびに暗号化を指定し忘れる心配がなくなります。
料金について
- CloudTrail:管理イベントを記録する最初の1つのトレイルは、トレイル自体の料金はかからない。ログを保存するS3の料金はかかる
- GuardDuty:最初の30日間は無料で試せる。その後は分析するログの量に応じて課金される
- IAM Access Analyzer:外部アクセスの分析は無料
- S3のパブリックアクセスのブロック、EBSのデフォルト暗号化:設定自体は無料
GuardDutyの料金はログの量で変わるため、無料期間中にコンソールで表示される見積もり額を確認しておくと安心です。最新の料金は、各サービスの料金ページで確認してください。
まとめ
- 記録や検知の仕組みは、問題が起きる前に入れておかないと意味がない
- CloudTrailは全リージョンを対象にし、ログの改ざん検知も有効にする
- GuardDutyとEBSのデフォルト暗号化はリージョンごとの設定なので、対象のリージョンを意識する
- S3のパブリックアクセスはアカウント全体でブロックし、設定ミスによる公開を防ぐ
5つとも数行のコードで済みます。モジュールにしておけば、新しいアカウントを作るたびに同じ設定をすぐに適用できます。