Amazon OpenSearch Service のモニターとアラートを Terraform で管理する

## はじめに

OpenSearch ではシステムの状態を監視し、問題が発生した際に通知するためのモニターとアラート機能が提供されています。
しかし、多数のモニターを手動で作成・管理していくと、以下のような課題が発生します：

- 設定の一貫性を保つことが難しい
- 環境間（開発・ステージング・本番）での再現が煩雑
- 変更履歴の管理が困難
- 大量のモニター設定の更新作業が手間

これらの課題を解決するため、Terraform を使って OpenSearch のモニターとアラートを管理するようにしてみました。


## 実装方法

### 1. プロジェクト構成

基本的なプロジェクト構成は以下の通りです：

```
.
├── main.tf           # OpenSearch モニターリソースの定義
├── variables.tf      # 変数の定義
├── terraform.tfvars  # 実際の変数値の設定
├── provider.tf       # AWS と OpenSearch プロバイダーの設定
├── outputs.tf        # 出力値の定義
└── versions.tf       # Terraform とプロバイダーのバージョン要件
```

### 2. プロバイダーの設定

provider.tfで、AWS と OpenSearch のプロバイダーを設定します：

```provider.tf
provider "aws" {
  region = var.aws_region
}

provider "opensearch" {
  url         = var.opensearch_endpoint
  aws_region  = var.aws_region
  
  # IAM認証を使用
  sign_aws_requests = true
  
  # ヘルスチェックを無効化
  healthcheck = false
  
  # スナップショット設定
  sniff = false
  
  # TLS設定
  insecure = true  # 自己署名証明書を使用している場合はtrueに設定
}
```

### 3. 変数の定義

variables.tf で、必要な変数を定義します：

```variables.tf
variable "aws_region" {
  description = "AWS region where the OpenSearch domain is located"
  type        = string
  default     = "ap-northeast-1"
}

variable "opensearch_domain_name" {
  description = "Name of the existing OpenSearch domain"
  type        = string
}

variable "opensearch_endpoint" {
  description = "OpenSearch domain endpoint URL"
  type        = string
}

# 複数のモニターとアラートを定義するための変数
variable "monitors" {
  description = "Map of monitors to create with their configurations"
  type = map(object({
    monitor_name     = string
    monitor_schedule = string
    monitor_indices  = list(string)
    aggregation_name = string
    aggregation_type = string
    aggregation_field = string
    alert_name       = string
    alert_threshold  = number
    condition        = string
    subject_template = string
    message_template = string
    destination_key  = string
  }))
  default = {}
}
```

### 4. モニターの定義

main.tf で、OpenSearch モニターリソースを定義します：

```main.tf
# モニターの作成
resource "opensearch_monitor" "monitors" {
  for_each = var.monitors
  
  body = jsonencode({
    name     = each.value.monitor_name
    enabled  = true
    schedule = {
      cron = {
        expression = each.value.monitor_schedule
        timezone   = "Asia/Tokyo"
      }
    }
    inputs = [
      {
        search = {
          indices = each.value.monitor_indices
          query = {
            aggregations = {
              "${each.value.aggregation_name}" = {
                "${each.value.aggregation_type}" = {
                  field = each.value.aggregation_field
                }
              }
            }
          }
        }
      }
    ]
    triggers = [
      {
        name      = each.value.alert_name
        severity  = "1"
        condition = {
          script = {
            source = "return ${each.value.aggregation_name}.value ${each.value.condition == "GREATER_THAN" ? ">" : each.value.condition == "LESS_THAN" ? "<" : "=="} ${each.value.alert_threshold}"
            lang   = "painless"
          }
        }
        actions = [
          {
            name             = "send_notification"
            destination_id   = each.value.destination_key
            message_template = {
              source = each.value.message_template
            }
            subject_template = {
              source = each.value.subject_template
            }
          }
        ]
      }
    ]
  })
}
```

### 5. モニター設定の定義

terraform.tfvars で、実際のモニター設定を定義します：

```terraform.tfvars
aws_region = "ap-northeast-1"
opensearch_domain_name = "mydomain"
opensearch_endpoint = "https://search-mydomain-xxxxxxxxxxxx.ap-northeast-1.es.amazonaws.com"

# モニターとアラートの設定
monitors = {
  monitor_001 = {
    monitor_name     = "monitor_001"
    monitor_schedule = "0 0/15 * * *"  # 15分ごと
    monitor_indices  = ["opensearch_dashboards_sample_data_logs"]
    aggregation_name = "response_503"
    aggregation_type = "value_count"
    aggregation_field = "response.keyword"
    alert_name       = "alert_001"
    alert_threshold  = 1
    condition        = "GREATER_THAN"
    subject_template = "OpenSearch Alert: alert_001"
    message_template = "This is alert_001."
    destination_key  = "channel-sns"  # OpenSearch Dashboardsで作成した送信先の名前
  },
  # 必要に応じて複数のモニターを追加できます
  monitor_002 = {
    monitor_name     = "cpu-usage-monitor"
    monitor_schedule = "0 0/5 * * *"  # 5分ごと
    monitor_indices  = ["metrics-*"]
    aggregation_name = "avg_cpu"
    aggregation_type = "avg"
    aggregation_field = "cpu.usage"
    alert_name       = "high-cpu-alert"
    alert_threshold  = 80
    condition        = "GREATER_THAN"
    subject_template = "OpenSearch Alert: High CPU Usage"
    message_template = "The average CPU usage has exceeded 80%."
    destination_key  = "channel-sns"
  }
}
```

### 6. 出力の定義

outputs.tf で、作成されたモニターの情報を出力するための設定を行います：

```outputs.tf
output "monitor_ids" {
  description = "IDs of the created OpenSearch monitors"
  value       = { for k, v in opensearch_monitor.monitors : k => v.id }
}

output "monitor_count" {
  description = "Number of monitors created"
  value       = length(opensearch_monitor.monitors)
}
```

## デプロイ手順

### 1. 前提条件

- Terraform がインストールされていること
- AWS CLI が設定されていること
- OpenSearch ドメインへのアクセス権限があること
- OpenSearch Dashboards でアラート送信先が作成されていること

### 2. 初期化

```bash
terraform init
```   

### 3. 実行計画の確認

```bash
terraform plan
```   

### 4. デプロイ

```bash
terraform apply
```   

### 5. 確認

OpenSearch Dashboards にアクセスして、モニターが正常に作成されていることを確認します。

![スクリーンショット 2025-05-31 20.17.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/81881cf6-90c3-4c04-a038-9f72864c4ee1.png)

## まとめ

Terraform を使用して OpenSearch のモニターとアラートを管理することで、以下のメリットが得られます：

- 設定の一貫性と再現性の確保
- バージョン管理による変更履歴の追跡
- 複数環境への簡単なデプロイ
- 大量のモニター設定の効率的な管理

今回の実装では、OpenSearch のモニターとアラートを Terraform で管理する基本的な方法を紹介しました。