はじめに
先日ニュースサイトを見ていたところ、Terraform actionsといった機能がHashiCorpから発表されたとの記事を見つけました。
- HashiCorp、TerraformとAnsibleを連携する第一歩「Terraform actions」を発表
- Terraform & Ansible: Unifying infrastructure provisioning and configuration management
- Invoke an action
名前からTerraformとGitHub Actionsか何かを組み合わせてCI的なことをするものかとも思いましたが、どうやらTerraformでLambdaやStep Functions等のリソースを実行したりできる機能のようです。
執筆時の2025年10月時点でTerraform actionsはパブリックベータとのことなのでまだこれからのサービスですが、今後のために試してみようと思います。
Terraform actionsとは
今までのTerraformは、各種リソースを作成・管理することを目的としているため、Terraformで作成・管理しているLambdaやStep Functions等のリソースを実行するようなことは、local-execやremote-execで、他のシェルやコマンド等を呼び出して実行することしかできませんでした。
しかし、Terraform Version 1.14から、actionブロックが実装されたことで、トリガー設定に従って、LambdaやStep Functionsを実行するようなことができるようになりました。
使用するためには、Terraformとプロバイダ両方の対応が必要となりますが、対応しているプロバイダ・バージョンであれば、リソースの作成からリソースの実行までTerraformだけで完結することも可能です。
数としてはまだ少ないですが、執筆時最新となるAWSプロバイダのVersion6.16.0では以下のアクションブロックが使えるようになっているようです。
| アクションブロック名 | 内容 |
|---|---|
| aws_cloudfront_create_invalidation | CloudFrontキャッシュ無効化 |
| aws_codebuild_start_build | CodeBuildの実行 |
| aws_ec2_stop_instance | EC2の停止 |
| aws_events_put_events | EventBridgeへのカスタムイベント送信 |
| aws_lambda_invoke | Lambdaの実行 |
| aws_ses_send_email | メール送信 |
| aws_sfn_start_execution | Step Functionsの実行 |
| aws_sns_publish | SNSトピックへのメッセージ発行 |
| aws_transcribe_start_transcription_job | Amazon Transcribeの実行 |
以下、今回参考とさせて頂いたサイト、ドキュメントとなります。
Terraform actionsの使い方
上述の通り、Terraform&プロバイダバージョンを対応しているバージョンまで引き上げる必要がありますが、対応済みであれば、作成や更新が行われた際にTerraform actionsを実行したいリソースに対して、以下のようなlifecycle設定を付与することで、actionsで指定したアクションを実行することができます。
resource "xxx" "yyy" {
(略)
lifecycle {
action_trigger {
events = [before_create, after_create, before_update, after_update]
actions = [action.aws_sfn_start_execution.example]
}
}
}
eventsは以下のような種類があり、actionsで指定した処理を実行するタイミングを指定できます。
| events種類 | 内容 |
|---|---|
| before_create | Terraformがリソースを作成する前にactionsの処理を実行する |
| after_create | Terraformがリソースを作成した後にactionsの処理を実行する |
| before_update | Terraformがリソースを更新する前にactionsの処理を実行する |
| after_update | Terraformがリソースを更新した後にactionsの処理を実行する |
なお、before/after_updateが動作するのはupdate in-placeの場合であり、リソースがすでに存在していたとしてもforces replacementの場合は動作しないため、その場合はbefore/after_createで指定する必要があるようですのでご注意ください。
Terraform actionsを実行するための環境の構築
Terraform actionsを試すための環境を構築して実際にTerraformを流してみようと思います。
とりあえず試すのが目的のため、ユースケースなどは無視して、サッと簡単に以下のようなコードを書いてみました。
1ファイルにまとめているので、terraform applyしてAWS環境にデプロイしておいてください。
#----------------------------------------------------------------------------------------------------------------------
# Terraform基本設定
#----------------------------------------------------------------------------------------------------------------------
provider "aws" {
region = "ap-northeast-1"
}
terraform {
required_version = ">= 1.14.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.15.0"
}
}
}
#----------------------------------------------------------------------------------------------------------------------
# Data Resource設定
#----------------------------------------------------------------------------------------------------------------------
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
#----------------------------------------------------------------------------------------------------------------------
# IAM設定
#----------------------------------------------------------------------------------------------------------------------
# Assume Role
data "aws_iam_policy_document" "sfn_assume_role_policy" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["states.amazonaws.com"]
}
}
}
# IAM Role
resource "aws_iam_role" "sfn_iam_role" {
name = "terraform-actions-test-sfn-role"
assume_role_policy = data.aws_iam_policy_document.sfn_assume_role_policy.json
}
# Policy Attachment
resource "aws_iam_role_policy_attachment" "sfn_policy_attachment" {
role = aws_iam_role.sfn_iam_role.name
policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
#----------------------------------------------------------------------------------------------------------------------
# IAM User設定
#----------------------------------------------------------------------------------------------------------------------
# Terraform actionsテスト用ユーザー
resource "aws_iam_user" "test_user" {
lifecycle {
action_trigger {
events = [before_update, after_update]
actions = [action.aws_sfn_start_execution.test]
}
}
name = "terraform-actions-test-user"
path = "/"
tags = {
Environment = "production"
}
}
#----------------------------------------------------------------------------------------------------------------------
# Step Functions State Machine
#----------------------------------------------------------------------------------------------------------------------
# Step Functions State Machine
resource "aws_sfn_state_machine" "test" {
name = "terraform-actions-test"
role_arn = aws_iam_role.sfn_iam_role.arn
definition = jsonencode({
Comment = "Terraform actionsテスト"
StartAt = "ListUserTags"
States = {
ListUserTags = {
Type = "Task"
Parameters = {
UserName = aws_iam_user.test_user.name
}
Resource = "arn:aws:states:::aws-sdk:iam:listUserTags"
End = true
}
}
})
}
#----------------------------------------------------------------------------------------------------------------------
# 特定ファイルの追跡
#----------------------------------------------------------------------------------------------------------------------
# Terraform actionsテスト用ファイル
resource "terraform_data" "testfile" {
input = filesha256("./testfile")
lifecycle {
action_trigger {
events = [before_update]
actions = [action.aws_sfn_start_execution.test]
}
}
}
#----------------------------------------------------------------------------------------------------------------------
# Terraform Actions
#----------------------------------------------------------------------------------------------------------------------
# Terraform actionsリソース
action "aws_sfn_start_execution" "test" {
config {
state_machine_arn = "arn:aws:states:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:stateMachine:terraform-actions-test"
input = jsonencode({
user_id = "12345"
action = "process"
})
}
}
なお、actionブロックで他のリソースを直接参照させたり、データリソースで参照させたりすると、更新時に以下のような循環参照のエラーとなってしまったので、Step FunctionsのARNを無理やり作成して参照させています。
╷
│ Error: Cycle: action.aws_sfn_start_execution.test (instance),
│ aws_iam_user.test_user, aws_sfn_state_machine.test (expand),
│ action.aws_sfn_start_execution.test (expand)
│
│
╵
作成した環境を使って、以下2点について試してみようと思います。
IAMユーザが更新された場合にStep Functionsを実行
まずはIAMユーザの設定がTerraformによって更新された前後でStep Functionsを実行してみようと思います。
上記のコードより、aws_iam_userリソースにlifecycle設定で以下のように記載されているため、更新前後でStep Functionsのactionsが実行されるようにトリガーされています。
lifecycle {
action_trigger {
events = [before_update, after_update]
actions = [action.aws_sfn_start_execution.test]
}
}
実際に実行される定義は以下のactionブロックで定義している箇所となり、ここで指定した内容に従って指定したStep Functionsが実行されるようになっています。
action "aws_sfn_start_execution" "test" {
config {
state_machine_arn = aws_sfn_state_machine.test.arn
input = jsonencode({
user_id = "12345"
action = "process"
})
}
}
設定更新時に実行されるか確認するため、aws_iam_userリソースに設定しているタグを変更して、applyしてみます。
tags = {
Environment = "production" ← "develop"に変更
}
ちなみにタグを変更後にterraform planを実行した結果は以下となりました。
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_iam_user.test_user will be updated in-place
~ resource "aws_iam_user" "test_user" {
id = "terraform-actions-test-user"
name = "terraform-actions-test-user"
~ tags = {
~ "Environment" = "production" -> "develop"
}
~ tags_all = {
~ "Environment" = "production" -> "develop"
}
# (5 unchanged attributes hidden)
}
# Actions to be invoked before this change in order:
action "aws_sfn_start_execution" "test" {
config {
input = jsonencode(
{
action = "process"
user_id = "12345"
}
)
state_machine_arn = "arn:aws:states:ap-northeast-1:123456789012:stateMachine:terraform-actions-test"
}
}
# Actions to be invoked after this change in order:
action "aws_sfn_start_execution" "test" {
config {
input = jsonencode(
{
action = "process"
user_id = "12345"
}
)
state_machine_arn = "arn:aws:states:ap-northeast-1:123456789012:stateMachine:terraform-actions-test"
}
}
Plan: 0 to add, 1 to change, 0 to destroy. Actions: 2 to invoke.
terraform apply後、Step Functionsの実行結果を見ると、以下のように2回実行されていることが確認できました。
想定通り、1回目はTerraformによる更新前となるので、タグの値がproductionとなっており、2回目はTerraformによる更新後となるので、タグの値がdevelopになっていることが確認できました。
- 1回目実行結果
- 2回目実行結果
特定ファイルが更新された場合にStep Functionsを実行
特定のファイルが更新されていたりする際にTerraform actionsを実行する方法について紹介します。
例えばLambdaのソースコードが更新された場合にterraform applyするには、terraform_dataリソース(旧null_resource)でファイルのハッシュ値をTerraformで管理することにより実現できますが、terraform_dataに、先ほどと同じ用にlifecycle設定を行うことで、ファイルが更新されたらTerraform actionsを実行させることができます。
resource "terraform_data" "testfile" {
input = filesha256("./testfile")
lifecycle {
action_trigger {
events = [before_update]
actions = [action.aws_sfn_start_execution.test]
}
}
}
ちなみにtestfileの中身を編集後、terraform planを実行した結果は以下となりました。
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# terraform_data.testfile will be updated in-place
~ resource "terraform_data" "testfile" {
id = "8982fd69-906d-d81a-bba1-86dd53b67296"
~ input = "2ac8479caead590f7f9d483b00b01a02c97dbb8c92cf200ca8dde34bb3d9b312" -> "a5d4217c0fe15c46c10ec56a3fefbeb8c26b8b8885e61cc5b68ac5024fe98641"
~ output = "2ac8479caead590f7f9d483b00b01a02c97dbb8c92cf200ca8dde34bb3d9b312" -> (known after apply)
}
# Actions to be invoked before this change in order:
action "aws_sfn_start_execution" "test" {
config {
input = jsonencode(
{
action = "process"
user_id = "12345"
}
)
state_machine_arn = "arn:aws:states:ap-northeast-1:123456789012:stateMachine:terraform-actions-test"
}
}
Plan: 0 to add, 1 to change, 0 to destroy. Actions: 1 to invoke.
terraform apply後、Step Functionsの実行結果を見ると、1回実行されていることが確認できました。
おわりに
まだベータ版のため、実環境で使い始めるのはまだまだ先になると思いますが、リソース更新後に追加で行ったりする作業は実際に運用していると結構あるので、一連の運用手順をTerraformでまとめて管理できるのは、かなり有用だなと感じました。
EC2等のセットアップでよく使用するAnsibleについても、Ansible公式のプロバイダでactionブロックに対応するよう開発が進められており、また、Ansible統合管理のAnsible Automation Platformではすでにactionブロックに対応している処理もあるようなので、Ansible Automation PlatformやAnsible AWXを使用している方は試してみるのも良いかと思います。
正式リリース版となったら、今まで手作業やAnsible等を使って処理していた運用周りの作業をまとめてTerraformで管理するのもありかなと感じました。


