1.はじめに
こんにちは。
今回はAWS SecurityHubをTerraformを利用して展開する方法について記事にしていきたいと思います。
SecurityHubとは、AWS Configと連携して、セキュリティ業界標準およびベストプラクティスに照らしたAWS環境評価を行うのに有効なサービスです。
参考:AWS Security Hubとは?
SecurityHubの使用を開始すると、ベストプラクティスに沿ったConfigルールが自動的に作成されますが、不要なルールがあった場合は一つずつルールを無効化させる必要があり、かなり手間になってしまいます。
そこでSecurityHubの使用の開始、不要ルールの無効化などを一度に展開できるTerraformコードを作成しましたので共有します。
2.構成
前回の記事でConfigルールをデプロイする構成について紹介しましたので、
今回はSecurityHubを加えた構成で実装していきたいと思います。
3.実装
3.1 フォルダ構成
以下のようなフォルダ構成で実装していきます。
リソース名などは変数管理としたいため、Local Valuesを利用します。
参考:Local Values
Terraform/
└─ dev
├─ s3.tf
├─ locals.tf
├─ security.tf
└─ terraform.tf
3.2 terraform.tf
以下の内容でterraform.tfを設定します。
アカウントIDとリージョンをコード内で取得できるようにしたいので、aws_caller_identity
とaws_region
のdata source設定を記載しておきます。
# providerの定義
provider "aws" {
region = "ap-northeast-1"
}
terraform {
required_version = ">=1.0"
required_providers {
awscc = {
source = "hashicorp/awscc"
version = "0.45.0"
}
}
}
# 実行するAWSアカウント情報取得用
data "aws_caller_identity" "self" {}
# 実行するリージョン情報取得用
data "aws_region" "self" {}
3.3 s3.tf
S3のバケット名は後述するlocals.tfに記載するため、以下のコード内ではlocalsを参照するようにしています。
ConfigとS3の連携にはS3バケットポリシーの設定が必要となるため、それも記載します。
# S3 Bucket
resource "aws_s3_bucket" "this" {
for_each = toset(local.s3_bucket)
force_destroy = true
bucket = "${local.env}-${each.value}"
tags = {
Name = "${local.env}-${each.value}"
}
}
resource "aws_s3_bucket_policy" "config-service" {
bucket = aws_s3_bucket.this["awsconfig-${data.aws_caller_identity.self.account_id}"].bucket
policy = data.aws_iam_policy_document.config-service.json
}
data "aws_iam_policy_document" "config-service" {
version = "2012-10-17"
statement {
sid = "AWSConfigBucketPermissionsCheck"
effect = "Allow"
principals {
type = "Service"
identifiers = ["config.amazonaws.com"]
}
actions = [
"s3:GetBucketAcl"
]
resources = [
"${aws_s3_bucket.this["awsconfig-${data.aws_caller_identity.self.account_id}"].arn}"
]
condition {
test = "StringEquals"
variable = "AWS:SourceAccount"
values = ["${data.aws_caller_identity.self.account_id}"]
}
}
statement {
sid = "AWSConfigBucketExistenceCheck"
effect = "Allow"
principals {
type = "Service"
identifiers = ["config.amazonaws.com"]
}
actions = [
"s3:ListBucket"
]
resources = [
"${aws_s3_bucket.this["awsconfig-${data.aws_caller_identity.self.account_id}"].arn}"
]
condition {
test = "StringEquals"
variable = "AWS:SourceAccount"
values = ["${data.aws_caller_identity.self.account_id}"]
}
}
statement {
sid = "AWSConfigBucketDelivery"
effect = "Allow"
principals {
type = "Service"
identifiers = ["config.amazonaws.com"]
}
actions = [
"s3:PutObject"
]
resources = [
"${aws_s3_bucket.this["awsconfig-${data.aws_caller_identity.self.account_id}"].arn}/AWSLogs/${data.aws_caller_identity.self.account_id}/Config/*"
]
condition {
test = "StringEquals"
variable = "s3:x-amz-acl"
values = ["bucket-owner-full-control"]
}
condition {
test = "StringEquals"
variable = "AWS:SourceAccount"
values = ["${data.aws_caller_identity.self.account_id}"]
}
}
}
resource "aws_s3_bucket_public_access_block" "config-service" {
bucket = aws_s3_bucket.this["awsconfig-${data.aws_caller_identity.self.account_id}"].id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
3.4 security.tf
Configに関連するリソースの説明については前回の記事をご参考ください。
SecurityHubのデプロイのために、以下のリソースを利用します。
- aws_securityhub_account
- AWSアカウントでSecurityHubを有効化します。
- aws_securityhub_standards_subscription
- SecurityHubで有効化させるセキュリティ基準を指定します。現在セキュリティ基準は以下がサポートされているので、ここから必要なものだけ選択します。
- aws_securityhub_standards_control
- 自動で有効化されたルールの中から、不要なルールを無効化させるために利用します。
# IAM
# AWSConfigサービスロールの作成
resource "aws_iam_service_linked_role" "config-service" {
aws_service_name = "config.amazonaws.com"
}
# Config
# Configレコーダーの有効化
resource "aws_config_configuration_recorder_status" "config-service" {
name = aws_config_configuration_recorder.config-service.name
is_enabled = true
depends_on = [aws_config_delivery_channel.config-service]
}
# Configレコーダーの作成
resource "aws_config_configuration_recorder" "config-service" {
name = "${local.env}-awsconfig"
role_arn = aws_iam_service_linked_role.config-service.arn
recording_group {
all_supported = "true"
include_global_resource_types = "true"
}
}
# Config配信チャネルの作成
resource "aws_config_delivery_channel" "config-service" {
name = "${local.env}-awsconfig"
s3_bucket_name = aws_s3_bucket.this["awsconfig-${data.aws_caller_identity.self.account_id}"].id
depends_on = [aws_config_configuration_recorder.config-service]
}
# SecurityHub
resource "aws_securityhub_account" "securityhub" {
depends_on = [
aws_config_configuration_recorder.config-service,
aws_config_configuration_recorder_status.config-service,
aws_config_delivery_channel.config-service
]
}
# セキュリティ基準の有効化
resource "aws_securityhub_standards_subscription" "securityhub_standards" {
depends_on = [aws_securityhub_account.securityhub]
for_each = local.securityhub_standards
standards_arn = each.value.standards_arn
}
# 不要なコントロールを無効化
resource "aws_securityhub_standards_control" "securityhub_disabled_controls" {
for_each = local.securityhub_disabled_controls
standards_control_arn = each.value.standards_control_arn
control_status = "DISABLED"
disabled_reason = each.value.disabled_reason
depends_on = [aws_securityhub_standards_subscription.securityhub_standards]
}
3.5 locals.tf
locals.tf
では以下の設定が行えるようにコードに記載します。
- 環境名:dev
- S3バケット名:awsconfig-{AWSアカウントID}
- 有効化するセキュリティ基準:
- AWS 基礎セキュリティのベストプラクティス v1.0.0
- CIS AWS Foundations Benchmark v1.2.0
- 無効化するルール:
# ##########
# Environment Parameters
# ##########
locals {
env = "dev"
}
# ##########
# S3
# ##########
locals {
s3_bucket = [
"awsconfig-${data.aws_caller_identity.self.account_id}"
]
}
# ##########
# SecurityHub
# ##########
# SecurityHubセキュリティ標準の有効化
locals {
securityhub_standards = {
aws-best-practices = {
standards_arn = "arn:aws:securityhub:${data.aws_region.self.name}::standards/aws-foundational-security-best-practices/v/1.0.0"
}
cis = {
standards_arn = "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0"
}
}
}
# SecuritHub個別のコントロールの無効化
locals {
securityhub_disabled_controls = {
access-keys-rotated-cis-1-4 = {
standards_control_arn = "arn:aws:securityhub:${data.aws_region.self.name}:${data.aws_caller_identity.self.account_id}:control/cis-aws-foundations-benchmark/v/1.2.0/1.4"
disabled_reason = "No access key rotation required."
}
acm-certificate-expiration-check-acm-1 = {
standards_control_arn = "arn:aws:securityhub:${data.aws_region.self.name}:${data.aws_caller_identity.self.account_id}:control/aws-foundational-security-best-practices/v/1.0.0/ACM.1"
disabled_reason = "ACM is automatically updated."
}
alb-http-drop-invalid-header-enabled-elb-4 = {
standards_control_arn = "arn:aws:securityhub:${data.aws_region.self.name}:${data.aws_caller_identity.self.account_id}:control/aws-foundational-security-best-practices/v/1.0.0/ELB.4"
disabled_reason = "No setting required."
}
}
}
4.デプロイ
まずterraform plan
を実行してエラーがないことを確認してからterraform apply
を実行して、AWS環境にデプロイします。
ログにApply complete!と出力されたらデプロイ完了です。
5.実機確認
AWSマネジメントコンソールにアクセスし、実際にリソースが作成されているか確認します。
前回の記事でConfig、S3バケット、IAMロールの作成ができることは確認済みのため、今回はSecurityHubに関連するリソースのみ見ていきます。
Terraformコードで記載した通りの設定が反映されていることが確認できました。
6.おわりに
今回はSecurityHubの有効化の設定と、周辺環境の構築をTerraformを利用して展開する方法について記事にしてみました。
SecurityHubのルールを無効化にする作業は、手作業でやろうとするとかなり手間のかかるものなので、デプロイが容易にできるようにこちらの記事が参考になれば幸いです。
7.参考