概要
AWSリソースのセキュリティ監視、解析環境をterraformで構築する方法をまとめています。
Security Hubの設定
SecurityHubはAWSのセキュリティイベントを集約し、セキュリティの状態を監視するサービスです。例えばAWS ConfigやGuardDutyなどのセキュリティサービスの結果を集約し、それらの結果を一元的に確認することができます。
また、「セキュリティ基準」と呼ばれるセキュリティのベストプラクティスに基づいて、リソースの設定をチェックすることができます。このチェックはAWS Configと連携して行われます。
以下のように記述することで、Security Hubを有効化することができます。デフォルトで有効化されているセキュリティ基準を無効化している点に注意してください。
セキュリティ基準の有効化は、AWS Configの設定の後に行います。
resource "aws_securityhub_account" "default" {
#デフォルトで有効化されているセキュリティ基準を無効化
enable_default_standards = false
}
AWS Configの設定
AWS ConfigはAWSリソースの設定変更を監視するサービスです。Config Rulesと呼ばれるリソースの設定のルールを定義することで、そのルールから逸脱したリソースがあれば、それを検知することができます。
AWS Configはリソースの設定履歴をS3に保存することができます。この情報は、リソースの設定変更の履歴を確認する際に利用します。
S3のアクセスログを保管するために、別途S3バケットを作成していますが、これは設定履歴を保管しているバケットが誤ってpublicになった時にその影響範囲を調査するために利用されます。
保管用のS3バケットを作成する
AWS Configの設定履歴を保存するためのS3バケットを作成します。
resource "aws_s3_bucket" "config_log_bucket" {
bucket = "${var.name_prefix}-config-log-bucket"
tags = {
Name = "${var.tag_name}-config-log-bucket"
group = "${var.tag_group}"
}
}
resource "aws_s3_bucket_public_access_block" "config_log_bucket_public_access_block" {
bucket = aws_s3_bucket.config_log_bucket.id
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
data "aws_iam_policy_document" "config_log_bucket_policy_document" {
statement {
actions = [
"s3:PutObject"
]
resources = [
"${aws_s3_bucket.config_log_bucket.arn}/*",
]
principals {
type = "Service"
identifiers = ["config.amazonaws.com"]
}
}
statement {
actions = [
"s3:GetBucketAcl",
"s3:ListBucket"
]
resources = [
aws_s3_bucket.config_log_bucket.arn
]
principals {
type = "Service"
identifiers = ["config.amazonaws.com"]
}
}
}
resource "aws_s3_bucket_policy" "config_log_bucket_policy" {
bucket = aws_s3_bucket.config_log_bucket.id
policy = data.aws_iam_policy_document.config_log_bucket_policy_document.json
}
resource "aws_s3_bucket_lifecycle_configuration" "config_log_bucket_lifecycle_configuration" {
bucket = aws_s3_bucket.config_log_bucket.id
rule {
id = "transfer to glacier"
status = "Enabled"
transition {
days = 30
storage_class = "GLACIER"
}
}
}
# アクセスログの送信先を定義
resource "aws_s3_bucket_logging" "config_log_bucket_logging" {
bucket = aws_s3_bucket.config_log_bucket.id
target_bucket = aws_s3_bucket.config_log_bucket_bclg.id
target_prefix = "config-log-bclg"
}
S3バケットのアクセスログを保管するためのバケットを作成する
resource "aws_s3_bucket" "config_log_bucket_bclg" {
bucket = "${var.name_prefix}-config-log-bucket-bclg"
tags = {
Name = "${var.tag_name}-config-log-bucket-bclg"
group = "${var.tag_group}"
}
}
resource "aws_s3_bucket_public_access_block" "config_log_bucket_bclg_public_access_block" {
bucket = aws_s3_bucket.config_log_bucket_bclg.id
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
data "aws_iam_policy_document" "config_log_bucket_bclg_policy_document" {
statement {
actions = [
"s3:PutObject",
]
resources = [
"${aws_s3_bucket.config_log_bucket_bclg.arn}/*",
]
principals {
type = "Service"
identifiers = ["logging.s3.amazonaws.com"]
}
}
statement {
actions = [
"s3:GetBucketAcl"
]
resources = [
aws_s3_bucket.config_log_bucket_bclg.arn
]
principals {
type = "Service"
identifiers = ["logging.s3.amazonaws.com"]
}
}
}
resource "aws_s3_bucket_policy" "config_log_bucket_bclg_policy" {
bucket = aws_s3_bucket.config_log_bucket_bclg.id
policy = data.aws_iam_policy_document.config_log_bucket_bclg_policy_document.json
}
resource "aws_s3_bucket_lifecycle_configuration" "config_log_bucket_bclg_lifecycle_configuration" {
bucket = aws_s3_bucket.config_log_bucket_bclg.id
rule {
id = "transfer to glacier"
status = "Enabled"
transition {
days = 1
storage_class = "GLACIER"
}
}
}
AWS ConfigのIAMロールを作成する
AWS ConfigはAWSリソースを調査するためのサービスであるため、他リソースへ横断的にアクセスする必要があります。そのため、AWS Configには対応するポリシーを持ったIAMロールを作成する必要があります。
IAMポリシーにはConfig用に用意されたマネージドポリシーが存在するので、それを利用しています。
#ConfigのIAMロールを作成
resource "aws_iam_role" "config-role" {
name = "${var.name_prefix}-config-role"
assume_role_policy = jsonencode({
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
})
}
#Configのマネージドポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "config-role-policy" {
role = aws_iam_role.config-role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"
}
AWS Configの設定を行う
AWS Configの設定を行います。以下のように記述することで、AWS Configを有効化することができます。
resource "aws_config_configuration_recorder_status" "default" {
name = "default"
is_enabled = true
depends_on = [aws_config_delivery_channel.default]
}
#調査対象のリソースを設定、ここでは全てのリソースを調査対象にしています
resource "aws_config_configuration_recorder" "default" {
#上記で作成したIAMロールを指定
role_arn = "${var.config_role_arn}"
#全てのリソースを記録する
recording_group {
all_supported = true
include_global_resource_types = true
resource_types = []
}
}
#設定履歴を保存するS3バケットを指定
resource "aws_config_delivery_channel" "default" {
name = "default"
#保存先のS3バケットを指定
s3_bucket_name = "${var.config_log_bucket_name}"
}
上記の設定でAWS Configが有効化されますが、Config Rulesが設定されていない状態であるため、リソースのチェックは実行されません。今回の記事ではConfigサービスを主体としたルールを設定せず、Security Hubと連携して生成されるConfig Rulesを利用するに留めます。
運用の方針によって、個別のマネージドルールやカスタムルールを設定してください。
SecurityHubと連携してConfig Rulesを設定する
SecurityHubのセキュリティ基準を有効化することで、その基準のチェックに必要なConfigRulesが自動的に作成されます。
今回は「AWS 基礎セキュリティのベストプラクティス」を有効化しています。
resource "aws_securityhub_standards_subscription" "aws_foundational_security_best_practices" {
#上記で有効化したSecurityHubを指定
depends_on = [aws_securityhub_account.default]
#セキュリティ基準のARNを指定
standards_arn = "arn:aws:securityhub:ap-northeast-1::standards/aws-foundational-security-best-practices/v/1.0.0"
}
「AWS 基礎セキュリティのベストプラクティス」を有効化すると以下のようにConfig Rulesが追加され、リソースのチェックが実行されます。
Config Rulesのチェックの結果をSecurity Hubで確認する
Config Rulesのチェックの結果はSecurity Hubで確認することができます。
この結果から、リソースの設定を修正するか、または無視してそのチェック自体を無効化することを判断していくことになります。
Macieの設定
MacieはS3バケットに保存されているデータのセキュリティを監視するサービスです。有効化すれば、S3バケットに保存されているデータの中から、個人情報や機密情報などの特定のデータを検出することができます。
また検出結果はSecurity Hubに連携されます。
resource "aws_macie2_account" "default" {
status = "ENABLED"
}
有効化すると以下のようにS3バケットに対するチェックが実行されます。
IAM Access Analyzerの設定
IAM Access Analyzerは、IAMポリシーによるリソースへのアクセス権限を分析するサービスです。有効化すれば、リソースに対するアクセス権限の分析が実行されます。
また検出結果はSecurity Hubに連携されます。
resource "aws_accessanalyzer_analyzer" "default" {
analyzer_name = "${var.name_prefix}-iam-access-analyzer"
}
Inspectorの設定
InspectorはEC2やECRのイメージに対してアプリの観点から脆弱性のスキャンを実行するサービスです。有効化すれば、リソースに対する脆弱性のスキャンが実行されます。
また検出結果はSecurity Hubに連携されます。
今回はECRのイメージに対してスキャンを実行するため、以下のように記述しています。
resource "aws_inspector2_enabler" "ecr" {
#アカウントIDとリソースタイプを指定
account_ids = ["${var.account_id}"]
resource_types = ["ECR"]
}
有効化すると以下のようにECRのイメージに対するスキャンが実行されます。
GuardDutyの設定
GuardDutyはAWSリソースのログを監視し、不正なアクセスを検知するサービスです。有効化すれば、リソースに対する不正なアクセスの検知が実行されます。
GuardDutyはCloudTrail、VPC Flow Logs、DNSログなどのログの情報をもとにセキュリティイベントを検知します。そのため、これらのログを有効化しておく必要があります。また、検知された際の調査のためにログを保存するS3バケットを作成しておく必要があります。
CloudTrailの設定
CloudTrailはAWSリソースの操作ログを記録するサービスです。
CloudTrailはアカウント設定時からログの出力が有効化されていますが、そのログの保存期間は90日間となっています。そのためログの長期保存を考慮してS3バケットにログが転送されるように設定します。
バケットポリシーにはCloudTrailからのログの取得と保存を許可するポリシーを設定している点に注意してください。
resource "aws_s3_bucket" "log_bucket_cloud_trail" {
bucket = "${var.name_prefix}-log-bucket-cloud-trail"
tags = {
Name = "${var.tag_name}-log-bucket-cloud-trail"
group = "${var.tag_group}"
}
}
resource "aws_s3_bucket_public_access_block" "log_bucket_cloud_trail_public_access_block" {
bucket = aws_s3_bucket.log_bucket_cloud_trail.id
#外部からの読み込みを許可しない
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
#CloudWatch LogsからS3へのログ出力を許可する
data "aws_iam_policy_document" "log_bucket_cloud_trail_policy_document" {
statement {
actions = [
"s3:PutObject",
]
resources = [
"${aws_s3_bucket.log_bucket_cloud_trail.arn}/*"
]
principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}
}
statement {
actions = [
"s3:GetBucketAcl"
]
resources = [
aws_s3_bucket.log_bucket_cloud_trail.arn
]
principals {
type = "Service"
identifiers = ["cloudtrail.amazonaws.com"]
}
}
}
resource "aws_s3_bucket_policy" "log_bucket_cloud_trail_policy" {
bucket = aws_s3_bucket.log_bucket_cloud_trail.id
policy = data.aws_iam_policy_document.log_bucket_cloud_trail_policy_document.json
}
CloudTrailのログをS3へ転送するために以下のように設定します。
resource "aws_cloudtrail" "default" {
name = "default"
s3_bucket_name = "${var.s3_bucket_log_cloud_trail_id}"
s3_key_prefix = "${var.name_prefix}/cloudtrail/"
include_global_service_events = false
}
VPC Flow Logsの設定
VPC Flow LogsはVPC内のリソースの通信ログを記録するサービスです。
VPC Flow Logsのログを保存するためのS3バケットを作成します。
resource "aws_s3_bucket" "log_bucket_vpc_flow" {
bucket = "${var.name_prefix}-log-bucket-vpc-flow"
tags = {
Name = "${var.tag_name}-log-bucket-vpc-flow"
group = "${var.tag_group}"
}
}
resource "aws_s3_bucket_public_access_block" "log_bucket_vpc_flow_public_access_block" {
bucket = aws_s3_bucket.log_bucket_vpc_flow.id
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
data "aws_iam_policy_document" "log_bucket_vpc_flow_policy_document" {
statement {
actions = [
"s3:PutObject",
]
resources = [
"${aws_s3_bucket.log_bucket_vpc_flow.arn}/*"
]
principals {
type = "Service"
identifiers = ["delivery.logs.amazonaws.com"]
}
}
statement {
actions = [
"s3:GetBucketAcl"
]
resources = [
aws_s3_bucket.log_bucket_vpc_flow.arn
]
principals {
type = "Service"
identifiers = ["delivery.logs.amazonaws.com"]
}
}
}
resource "aws_s3_bucket_policy" "log_bucket_vpc_flow_policy" {
bucket = aws_s3_bucket.log_bucket_vpc_flow.id
policy = data.aws_iam_policy_document.log_bucket_vpc_flow_policy_document.json
}
VPC Flow Logsのログを有効化するとともに、S3へ転送するように設定します。
resource "aws_flow_log" "default" {
log_destination = "${var.s3_bucket_log_vpc_flow_arn}"
log_destination_type = "s3"
traffic_type = "ALL"
vpc_id = "${var.vpc_id}"
}
DNSクエリログの設定
クエリログに関してはterraformでの設定ができないため、AWSコンソールから設定します。
以下の記事などを参照に、設定を行ってください。
GuardDutyの有効化
GuardDutyは初期設定では無効化されているため、有効化します。
resource "aws_guardduty_detector" "default" {
enable = true
}
有効化すると以下のようにセキュリティイベントの検知が実行されます。
AWS Healthについて
AWS HealthはAWSのサービスの障害情報を提供するサービスです。
セキュリティに関する通知はSecurity Hubに連携されるようにデフォルトで設定されています。
Detectiveの設定
DetectiveはGuiardDutyで検知されたセキュリティイベントを解析するためのサービスです。
resource "aws_detective_graph" "default" {}
Athenaの設定
CloudTrailのログやConfig構成情報を解析する際は、Athenaを利用します。Athenaの利用方法についてはここでは説明しません。
セキュリティイベントの通知の設定
セキュリティイベントはSecurityHubに集約されるように設定されていますが、即座にセキュリティイベントに対応できるようにするために、運用者へメールで新規のセキュリティイベントが通知されるように設定します。
以下の図のように、EventBridgeルールを利用して、SecurityHubに新規のセキュリティイベントが届いたことを検知して、それを起点としてSNSトピックからメールを送信するように設定します。
まずはSNSトピックを作成します。送信先には運用者のメールアドレスを指定します。また、EventBridgeからメッセージを受け取るためにSNSトピックポリシーを設定します。
#セキュリティイベントを通知するためのSNSトピックを作成
resource "aws_sns_topic" "security_alart_topic" {
name = "${var.name_prefix}-security-alart-topic"
}
#送信先に運用者のメールアドレスを指定
resource "aws_sns_topic_subscription" "security_alart_topic_subscription" {
topic_arn = aws_sns_topic.security_alart_topic.arn
protocol = "email"
endpoint = "${var.email}"
}
# EventBridgeからの操作を受け付けるために、SNSトピックポリシーを設定
resource "aws_sns_topic_policy" "default" {
arn = aws_sns_topic.security_alart_topic.arn
policy = data.aws_iam_policy_document.sns_topic_policy.json
}
data "aws_iam_policy_document" "sns_topic_policy" {
statement {
effect = "Allow"
actions = ["SNS:Publish"]
principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}
resources = [aws_sns_topic.security_alart_topic.arn]
}
}
次にEventBridgeルールを作成します。以下のように記述することで、SecurityHubに新規のセキュリティイベントが届いたことを検知して、それを起点としてSNSトピックにメッセージを送信するように設定します。
resource "aws_cloudwatch_event_rule" "security_hub" {
name = "security_hub_event"
description = "security_hub_event"
event_pattern = jsonencode({
"source": [
"aws.securityhub"
],
#新規のセキュリティイベントが届いたことを検知
"detail-type": [
"Security Hub Findings - Imported"
]
})
}
resource "aws_cloudwatch_event_target" "security_hub_to_sns" {
rule = aws_cloudwatch_event_rule.security_hub.name
#SNSトピックを指定
target_id = "SendToSNS"
arn = "${var.sns_arn}"
}
以上でAWSリソースのセキュリティ監視環境の構築は完了です。
参考文献
本記事は以下の書籍、記事を参考にさせていただきました。