はじめに
GuardDuty を Terraform で有効化しようとしたところ以下のエラーが発生しました。
╷
│ Error: creating GuardDuty Detector: operation error GuardDuty: CreateDetector, https response error StatusCode: 400, RequestID: ********-****-****-****-************, BadRequestException: The request is rejected because a detector already exists for the current account.
│
│ with module.guardduty.aws_guardduty_detector.this,
│ on ../../modules/aws/guardduty/main.tf line 1, in resource "aws_guardduty_detector" "this":
│ 1: resource "aws_guardduty_detector" "this" {
│
╵
エラーは見ての通り、すでに作成されているという内容です。
どうやら、SecurityHub で GuardDuty 連携を行う設定を入れたために GuardDuty が有効化され、すでに存在するという事態が発生したようです。
以下が SecurityHub 側で追加した terraform コードになります。
resource "aws_guardduty_detector" "main" {
enable = true
}
resource "aws_securityhub_product_subscription" "guardduty" {
product_arn = "arn:aws:securityhub:${var.region}::product/aws/guardduty"
}
このままだと GuardDuty がデフォルト設定の状態で有効になっているだけで機能を有効化できないため対応方法について調べて実際に実施した内容を今回記載しました。
対応方法
以下の方法が考えられそうです。
- 既存の Detector を Terraform にインポート
- 手動で削除して Terraform で再作成
今まで利用したことがなかったのですが、Terraform のインポート機能が有効な感じだったため実施したいと思います。
Detector ID を確認
まずはインポートを行うために Detector ID を確認します。
% aws guardduty list-detectors
{
"DetectorIds": [
"********************************"
]
}
Terraform インポート
今回の場合、GuardDuty を有効にするための terraform コードがあるため、terraform import
で Detector ID を指定するだけインポートが完了です。
% terraform import module.guardduty.aws_guardduty_detector.this ********************************
module.guardduty.aws_guardduty_detector.this: Import prepared!
Prepared aws_guardduty_detector for import
module.guardduty_notification.data.aws_iam_policy_document.sns_policy: Reading...
module.guardduty_notification.data.aws_iam_policy_document.sns_policy: Read complete after 0s [id=*********]
module.guardduty.aws_guardduty_detector.this: Refreshing state... [id=********************************]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
Import successful! と表示されれば成功です。
terraform import で何が行われているか?
terraform import は、既存のクラウドリソースを Terraform の管理下に置く操作になります。
- 指定したリソースの状態を取得
- 状態ファイル(.tfstate または backend)に登録
ただし、インフラ自体の変更は行わず、.tf ファイルと整合もしないです。
そのため plan を実施すると差分が発生する場合があります。
Terraform プラン
インポートするだけだと実際の環境で有効になっている設定とコードに書かれている設定との差分が発生しています。
まずは terraform plan
で差分を確認します。
% terraform plan
module.guardduty_notification.data.aws_iam_policy_document.sns_policy: Reading...
module.guardduty_notification.data.aws_iam_policy_document.sns_policy: Read complete after 0s [id=*********]
module.guardduty_notification.aws_cloudwatch_event_target.sns_target: Refreshing state... [id=guardduty-findings]
module.guardduty_notification.aws_sns_topic_policy.sns_policy: Refreshing state... [id=arn:aws:sns:ap-northeast-1:************:guardduty-alerts]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
~ update in-place
Terraform will perform the following actions:
# module.guardduty.aws_guardduty_detector_feature.ebs_volume_scan will be created
+ resource "aws_guardduty_detector_feature" "ebs_volume_scan" {
+ detector_id = "********************************"
+ id = (known after apply)
+ name = "EBS_MALWARE_PROTECTION"
+ region = "ap-northeast-1"
+ status = "ENABLED"
}
# module.guardduty.aws_guardduty_detector_feature.kubernetes_audit_logs will be created
+ resource "aws_guardduty_detector_feature" "kubernetes_audit_logs" {
+ detector_id = "********************************"
+ id = (known after apply)
+ name = "EKS_AUDIT_LOGS"
+ region = "ap-northeast-1"
+ status = "DISABLED"
}
# module.guardduty.aws_guardduty_detector_feature.s3_protection will be created
+ resource "aws_guardduty_detector_feature" "s3_protection" {
+ detector_id = "********************************"
+ id = (known after apply)
+ name = "S3_DATA_EVENTS"
+ region = "ap-northeast-1"
+ status = "ENABLED"
}
Plan: 3 to add, 0 to change, 0 to destroy.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
今回は EBS_MALWARE_PROTECTION, EKS_AUDIT_LOGS, S3_DATA_EVENTS の3つが既存では有効になっていないため terraform apply
するとこれらが有効になります。
Terraform コード適用
差分内容に問題ないので terraform apply
でコード内容を適用します。
% terraform apply
module.guardduty_notification.aws_cloudwatch_event_rule.guardduty_findings: Refreshing state... [id=guardduty-findings]
module.guardduty.aws_guardduty_detector.this: Refreshing state... [id=********************************]
module.guardduty_notification.aws_sns_topic.guardduty_alerts: Refreshing state... [id=arn:aws:sns:ap-northeast-1:************:guardduty-alerts]
module.guardduty_notification.aws_cloudwatch_event_target.sns_target: Refreshing state... [id=guardduty-findings-SendToSNS]
module.guardduty_notification.data.aws_iam_policy_document.sns_policy: Reading...
module.guardduty_notification.data.aws_iam_policy_document.sns_policy: Read complete after 0s [id=*********]
module.guardduty_notification.aws_sns_topic_policy.sns_policy: Refreshing state... [id=arn:aws:sns:ap-northeast-1::************:guardduty-alerts]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
~ update in-place
Terraform will perform the following actions:
# module.guardduty.aws_guardduty_detector_feature.ebs_volume_scan will be created
+ resource "aws_guardduty_detector_feature" "ebs_volume_scan" {
+ detector_id = "********************************"
+ id = (known after apply)
+ name = "EBS_MALWARE_PROTECTION"
+ region = "ap-northeast-1"
+ status = "ENABLED"
}
# module.guardduty.aws_guardduty_detector_feature.kubernetes_audit_logs will be created
+ resource "aws_guardduty_detector_feature" "kubernetes_audit_logs" {
+ detector_id = "********************************"
+ id = (known after apply)
+ name = "EKS_AUDIT_LOGS"
+ region = "ap-northeast-1"
+ status = "DISABLED"
}
# module.guardduty.aws_guardduty_detector_feature.s3_protection will be created
+ resource "aws_guardduty_detector_feature" "s3_protection" {
+ detector_id = "********************************"
+ id = (known after apply)
+ name = "S3_DATA_EVENTS"
+ region = "ap-northeast-1"
+ status = "ENABLED"
}
Plan: 3 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
module.guardduty.aws_guardduty_detector.this: Modifying... [id=********************************]
module.guardduty.aws_guardduty_detector.this: Modifications complete after 1s [id=********************************]
module.guardduty.aws_guardduty_detector_feature.kubernetes_audit_logs: Creating...
module.guardduty.aws_guardduty_detector_feature.ebs_volume_scan: Creating...
module.guardduty.aws_guardduty_detector_feature.s3_protection: Creating...
module.guardduty.aws_guardduty_detector_feature.ebs_volume_scan: Creation complete after 0s [id=********************************/EBS_MALWARE_PROTECTION]
module.guardduty.aws_guardduty_detector_feature.s3_protection: Creation complete after 0s [id=********************************/S3_DATA_EVENTS]
module.guardduty.aws_guardduty_detector_feature.kubernetes_audit_logs: Creation complete after 3s [id=********************************/EKS_AUDIT_LOGS]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
以上で既存の GuardDuty を terraform のコードに取り込み、さらに必要な設定を有効化することができました。
おわりに
今まで既存環境を terraform import
してコード化したことがなかったのですが思った以上にスムーズに行うことができました。
とても便利な機能なので今後も活用していきたいと思います。