Snowflake × Terraform のマルチアカウント環境をGitHub ActionsでCI/CD化してみた
はじめに
データ事業本部のkasamaです。
今回は、開発環境と本番環境でアカウントが分かれているSnowflake × Terraform環境を、GitHub ActionsでCI/CD化してみました。
前提
前提として、オープンソース版のTerraformの話であり、HCP Terraform(クラウド版)は考慮していません。
以下ブログの構成を参考にし、自分なりにカスタマイズして使用します。OIDC設定や一連の流れは大体同じですが、マルチアカウント構成箇所が少し異なるため、その辺りを中心に記載します。
以下の構成を元に検討していきたいと思います。moduleをaccess role + リソース単位で作成し、dev/prdごとのmain.tfで呼び出す実装です。terraformのinitやplan,applyコマンドの実行はGitHub Actions経由で行います。
snowflake-terraform-sample % tree
.
├── .github/
│ └── workflows/
│ ├── dev-snowflake-terraform-cicd.yml
│ └── prd-snowflake-terraform-cicd.yml
├── cfn
│ └── create_state_gha_resources.yml
├── environments
│ ├── dev
│ │ ├── backend.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ └── prd
│ ├── backend.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── modules
│ ├── access_role_and_database
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── access_role_and_file_format
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── access_role_and_schema
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── access_role_and_stage
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── access_role_and_storage_integration
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── access_role_and_warehouse
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── aws_storage_integration
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── functional_role
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
└── README.md
GitHub Actions 処理フロー
今回のプロジェクト構成ではGit Flow戦略を採用しています。Git Flowは、mainブランチ(本番環境)とdevelopブランチ(開発環境)を中心とした、環境ごとにブランチを分離する戦略です。featureブランチで開発を行い、developブランチで統合・検証した後、mainブランチへマージして本番リリースを行います。各ブランチが特定の環境に対応し、ブランチへのマージをトリガーに自動デプロイが実行されます。
- 開発環境 (feature → develop): featureブランチからdevelopブランチへのPRマージ時に開発環境へ自動デプロイ
- 本番環境 (develop → main): 開発環境での検証完了後、developブランチからmainブランチへのPRマージ時に本番環境へ自動デプロイ
各環境で、PR作成時にterraform plan
でプレビュー、PRマージ時にterraform apply
で実際にデプロイが実行されます。
開発環境デプロイフロー (feature → develop)
-
PR作成時(terraform plan)
- 開発者がfeatureブランチからdevelopブランチへPRを作成
- GitHub Actionsワークフローが自動トリガー
- AWSにOIDC認証し、S3からstateを取得してterraform init
- コード品質チェック(fmt/validate/TFLint/Trivy)を実行
- Snowflake環境にKey-pair認証でterraform planを実行
- Plan結果をPRにコメント投稿
-
PRマージ時(terraform apply)
- PRが承認されdevelopブランチへマージ
- pushイベントでワークフローが再トリガー
- AWSにOIDC認証し、terraform initを実行
- コード品質チェックを再実行
- terraform apply -auto-approveで開発環境Snowflakeへ自動デプロイ
本番環境デプロイフロー (develop → main)
-
PR作成時(terraform plan)
- 開発環境での検証完了後、developブランチからmainブランチへPRを作成
- GitHub Actionsワークフローが自動トリガー
- AWSにOIDC認証し、S3からstateを取得してterraform init
- コード品質チェック(fmt/validate/TFLint/Trivy)を実行
- 本番Snowflake環境にKey-pair認証でterraform planを実行
- Plan結果をPRにコメント投稿
-
PRマージ時(terraform apply)
- レビュー・承認を経てmainブランチへマージ
- pushイベントでワークフローが再トリガー
- AWSにOIDC認証し、terraform initを実行
- コード品質チェックを再実行
- terraform apply -auto-approveで本番環境Snowflakeへ自動デプロイ
本番環境の処理フローは開発環境と同様ですが、ブランチ保護の設定で違いを持たせることができます。
一般的には、本番環境へのデプロイとなるmainブランチへのPRマージには、最低1人以上の承認を必須とします。一方、開発環境となるdevelopブランチへのマージは、プロジェクトの方針により柔軟に設定します。例えば、TerraformのState Lockを考慮してローカルからのデプロイを禁止している場合、developブランチへのマージ承認を任意にすることで、CI/CD経由での検証サイクルを高速化できます。または、コード品質を重視してdevelopブランチは承認者1人、mainブランチは管理者と承認者の2人必須、といった段階的な承認体制も選択できます。
GitHubのRulesetsでマージ承認などのbranch保護設定が可能です。以下の記事が参考になりました。
試してみましたが、作成はできるもののFree PlanのPrivateリポジトリへ適用できないようでした。
実装
name: "Snowflake Terraform CI/CD - DEV"
on:
push:
branches:
- develop
paths:
- "environments/dev/**"
- "modules/**"
- ".github/workflows/dev-snowflake-terraform-cicd.yml"
pull_request:
branches:
- develop
paths:
- "environments/dev/**"
- "modules/**"
- ".github/workflows/dev-snowflake-terraform-cicd.yml"
jobs:
plan-dev:
runs-on: ubuntu-latest
timeout-minutes: 30
environment: dev
env:
# Terraform
TF_VERSION: "1.11.0"
# Snowflake - TF_VAR_プレフィックスでTerraform変数にマッピング
TF_VAR_snowflake_organization_name: ${{ secrets.SNOWFLAKE_ORG_NAME }}
TF_VAR_snowflake_account_name: ${{ secrets.SNOWFLAKE_ACCOUNT_NAME }}
TF_VAR_snowflake_private_key: ${{ secrets.SNOWFLAKE_PRIVATE_KEY }}
permissions:
id-token: write # OIDCを利用する際に必須
contents: read # actions/checkout のために必要
pull-requests: write # PRコメント投稿用
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Set up AWS credentials
uses: aws-actions/configure-aws-credentials@a03048d87541d1d9fcf2ecf528a4a65ba9bd7838 # v5.0.0
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
audience: sts.amazonaws.com
- name: Terraform format
run: terraform fmt -check -recursive
working-directory: environments/dev
- name: Terraform Init
run: terraform init -upgrade -no-color
working-directory: environments/dev
- name: Terraform validate
run: terraform validate -no-color
working-directory: environments/dev
- name: Setup TFLint
uses: terraform-linters/setup-tflint@ae78205cfffec9e8d93fd2b3115c7e9d3166d4b6 # v5.0.0
with:
tflint_version: v0.58.0
- name: Run TFLint
run: tflint --init && tflint -f compact --minimum-failure-severity=error
working-directory: environments/dev
- name: Run Trivy Security Scan
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
with:
scan-type: "config"
scan-ref: "environments/dev"
format: "table"
exit-code: 1
severity: CRITICAL,HIGH
ignore-unfixed: true
- name: Terraform Plan
id: plan
if: github.event_name == 'pull_request'
run: |
terraform plan -no-color -out=tfplan.binary
terraform show -no-color tfplan.binary > tfplan.txt
working-directory: environments/dev
- name: Post Plan to PR
if: github.event_name == 'pull_request' && steps.plan.outcome == 'success'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
const plan = fs.readFileSync('environments/dev/tfplan.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### Terraform Plan - Dev
<details>
<summary>Show Plan</summary>
\`\`\`terraform
${plan.substring(0, 65000)}
\`\`\`
</details>`
});
- name: Terraform Apply
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
run: terraform apply -auto-approve
working-directory: environments/dev
開発環境用のGitHub Actionsワークフロー設定です。
on
: トリガーをdevelopブランチに限定し、paths
フィルタで関連ファイル変更時のみ実行しますenv
: 事前に設定したGitHub Secretsの値をTF_VAR_
プレフィックスで参照し、Terraform変数へ自動マッピングしますpermissions
: 最小権限の原則に基づき、id-token: write
(OIDC認証)、contents: read
(チェックアウト)、pull-requests: write
(PRコメント)のみ指定します- サードパーティAction:
actions/checkout@08c6903...
のようにコミットSHAで固定し、タグ改ざん攻撃を防止します - AWS認証: OIDCで一時的な認証情報を取得し、長期アクセスキーの漏洩リスクを削減します
- コード品質チェック: terraform fmt/validate、TFLint、Trivyを順次実行し、問題があればワークフローを停止します
terraform plan
:github.event_name == 'pull_request'
の条件でPR作成時のみ実行します- Plan結果のPR投稿:
steps.plan.outcome == 'success'
の条件でplanが成功した場合のみ、actions/github-script
でPRにコメントを投稿します terraform apply
:github.ref == 'refs/heads/develop' && github.event_name == 'push'
の条件でdevelopブランチへのマージ時のみ実行します
セキュリティ面で気をつけているポイントがあります。permissions
では、デフォルトのwrite
権限を付与せず、id-token: write
、contents: read
、pull-requests: write
のみを明示的に指定することで、必要最小限の権限のみ付与し、攻撃対象領域を最小化しています。サードパーティActionは、バージョンタグ(v5.0.0
)ではなく、コミットSHA(actions/checkout@08c6..
)で固定しています。タグは後から書き換え可能なため、悪意のあるコードに置き換えられるリスクがありますが、コミットSHAは不変なのでこのリスクを防止できます。秘密情報の管理では、Snowflakeの秘密鍵などの機密情報をGitHub Secretsで管理し、ワークフローログに出力されないようにしています。GitHub Actionsは自動的にSecretsの値をマスキングするため、ログに秘密情報が露出するリスクを低減できます。また、今回は設定していないですが、サードパーティActionのバージョン更新を自動化するため、Dependabotの導入をしてもい良いと思います。
これらの内容は以下の記事を参考にしています。
name: "Snowflake Terraform CI/CD - PRD"
on:
push:
branches:
- main
paths:
- "environments/prd/**"
- "modules/**"
- ".github/workflows/prd-snowflake-terraform-cicd.yml"
pull_request:
branches:
- main
paths:
- "environments/prd/**"
- "modules/**"
- ".github/workflows/prd-snowflake-terraform-cicd.yml"
jobs:
plan-prd:
runs-on: ubuntu-latest
timeout-minutes: 30
environment: prd
env:
# Terraform
TF_VERSION: "1.11.0"
# Snowflake - TF_VAR_プレフィックスでTerraform変数にマッピング
TF_VAR_snowflake_organization_name: ${{ secrets.SNOWFLAKE_ORG_NAME }}
TF_VAR_snowflake_account_name: ${{ secrets.SNOWFLAKE_ACCOUNT_NAME }}
TF_VAR_snowflake_private_key: ${{ secrets.SNOWFLAKE_PRIVATE_KEY }}
permissions:
id-token: write # OIDCを利用する際に必須
contents: read # actions/checkout のために必要
pull-requests: write # PRコメント投稿用
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Set up AWS credentials
uses: aws-actions/configure-aws-credentials@a03048d87541d1d9fcf2ecf528a4a65ba9bd7838 # v5.0.0
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
audience: sts.amazonaws.com
- name: Terraform format
run: terraform fmt -check -recursive
working-directory: environments/prd
- name: Terraform Init
run: terraform init -upgrade -no-color
working-directory: environments/prd
- name: Terraform validate
run: terraform validate -no-color
working-directory: environments/prd
- name: Setup TFLint
uses: terraform-linters/setup-tflint@ae78205cfffec9e8d93fd2b3115c7e9d3166d4b6 # v5.0.0
with:
tflint_version: v0.58.0
- name: Run TFLint
run: tflint --init && tflint -f compact --minimum-failure-severity=error
working-directory: environments/prd
- name: Run Trivy Security Scan
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
with:
scan-type: "config"
scan-ref: "environments/prd"
format: "table"
exit-code: 1
severity: CRITICAL,HIGH
ignore-unfixed: true
- name: Terraform Plan
id: plan
if: github.event_name == 'pull_request'
run: |
terraform plan -no-color -out=tfplan.binary
terraform show -no-color tfplan.binary > tfplan.txt
working-directory: environments/prd
- name: Post Plan to PR
if: github.event_name == 'pull_request' && steps.plan.outcome == 'success'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
const plan = fs.readFileSync('environments/prd/tfplan.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### Terraform Plan - Production
<details>
<summary>Show Plan</summary>
\`\`\`terraform
${plan.substring(0, 65000)}
\`\`\`
</details>`
});
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve
working-directory: environments/prd
本番環境用のGitHub Actionsワークフロー設定です。
開発環境と同様の構成ですが、トリガーブランチがmain、作業ディレクトリがenvironments/prd、Apply条件がgithub.ref == 'refs/heads/main'
となります。
事前準備
Snowflakeデプロイ用ユーザー作成
2025年10月現在、Snowflake CLIはOIDCに対応していますが、Snowflake Terraformは未対応ですので、Snowflakeデプロイ用ユーザーでのキーペア認証で接続します。
ローカルもしくはAWS CloudShell上などで以下のコマンドを実行しkey-pairを作成します。GitHub Secretsは後から値の参照ができないため、AWS SSM Parameterに値を格納しています。
# RSA鍵ペア生成
openssl genrsa -out snowflake_private_key.pem 2048
openssl rsa -in snowflake_private_key.pem -pubout -out snowflake_public_key.pem
# 公開鍵を整形(改行を削除して1行にする)
PUBLIC_KEY=$(cat snowflake_public_key.pem | grep -v "BEGIN PUBLIC KEY" | grep -v "END PUBLIC KEY" | tr -d '\n')
echo $PUBLIC_KEY
# 秘密鍵をAWS SSM Parameter Storeに保存
aws ssm put-parameter \
--name "/<your-unique-name>/dev/snowflake/terraform-user/private-key" \
--value "$(cat snowflake_private_key.pem)" \
--type "SecureString" \
--overwrite
# 公開鍵(整形済み)を保存
aws ssm put-parameter \
--name "/<your-unique-name>/dev/snowflake/terraform-user/public-key" \
--value "$PUBLIC_KEY" \
--type "String" \
--overwrite
Snowflakeアカウントで以下のSQLを実行し、デプロイ用ユーザー等を作成します。
USE ROLE SECURITYADMIN;
CREATE USER TERRAFORM_BLOG_USER
TYPE = SERVICE
RSA_PUBLIC_KEY='<YOUR_RSA_PUBLIC_KEY>' -- 上記で整形した公開鍵を貼り付け
DEFAULT_ROLE=PUBLIC;
CREATE ROLE TERRAFORM;
GRANT ROLE TERRAFORM TO USER TERRAFORM_BLOG_USER;
GRANT ROLE SECURITYADMIN TO ROLE TERRAFORM;
GRANT ROLE SYSADMIN TO ROLE TERRAFORM;
GRANT ROLE TERRAFORM TO ROLE ACCOUNTADMIN;
-- INTEGRATION作成権限の付与(ACCOUNTADMINで実行)
USE ROLE ACCOUNTADMIN;
GRANT CREATE INTEGRATION ON ACCOUNT TO ROLE TERRAFORM;
USE ROLE SYSADMIN;
CREATE OR REPLACE WAREHOUSE TERRAFORM_BLOG_WH
WAREHOUSE_SIZE=XSMALL
AUTO_RESUME=TRUE
AUTO_SUSPEND=60
INITIALLY_SUSPENDED=TRUE
STATEMENT_TIMEOUT_IN_SECONDS=300 -- 5min
COMMENT='For terraform.';
-- SECURITYADMINにもウェアハウスの操作権限を付与(Terraform実行に必要)
GRANT USAGE ON WAREHOUSE TERRAFORM_BLOG_WH TO ROLE SECURITYADMIN;
-- MANAGE GRANTS権限をSYSADMINに付与(future grant実行に必要)
USE ROLE SECURITYADMIN;
GRANT MANAGE GRANTS ON ACCOUNT TO ROLE SYSADMIN;
AWS GitHub Actions用リソースデプロイ
以下は、Terraformデプロイに使用するIAM RoleやS3の一例です。リソース名等はプロジェクトによって変更いただければと思います。こちらをCloudFormationでデプロイしました。
cfn/create_state_gha_resources.yml
AWSTemplateFormatVersion: 2010-09-09
Description: |-
Snowflake-Terraform S3 & GitHub Actions Setup - Creates S3 bucket for Terraform state
and IAM role for GitHub Actions with comprehensive configuration
Mappings:
# AWS AccountIdによって値を切り替える
EnvMapping:
"123456789012":
EnvName: dev
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "GitHub Configuration"
Parameters:
- GitHubAccountName
- GitHubRemoteRepoName
- GitHubOIDCProviderArn
Parameters:
GitHubAccountName:
Type: String
Default: your-github-account
Description: GitHub account name of the repository
GitHubRemoteRepoName:
Type: String
Default: "terraform-snowflake-sample"
GitHubOIDCProviderArn:
Type: String
Description: ARN of the existing GitHub OIDC Provider
Resources:
# S3 Bucket for Terraform state
TerraformStateBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub
- "your-project-${EnvName}-s3-snf-state"
- EnvName: !FindInMap
- EnvMapping
- !Ref "AWS::AccountId"
- EnvName
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
Tags:
- Key: service-id
Value: your-project
- Key: module
Value: terraform-state
- Key: project
Value: integrated-analysis-env
# IAM Role for GitHub Actions
GitHubActionsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub
- "your-project-${EnvName}-iamrole-snf-gha"
- EnvName: !FindInMap
- EnvMapping
- !Ref "AWS::AccountId"
- EnvName
Path: /
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: TrustGitHubActionsOIDCProvider
Effect: Allow
Principal:
Federated: !Ref GitHubOIDCProviderArn
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringLike:
token.actions.githubusercontent.com:sub:
- !Sub "repo:${GitHubAccountName}/${GitHubRemoteRepoName}:*"
Policies:
- PolicyName: !Sub
- "your-project-${EnvName}-iampolicy-snf-gha"
- EnvName: !FindInMap
- EnvMapping
- !Ref "AWS::AccountId"
- EnvName
PolicyDocument:
Version: 2012-10-17
Statement:
# Terraform state S3 bucket permissions
- Sid: TerraformS3StateBucketPolicy
Effect: Allow
Action:
- s3:ListBucket
- s3:GetBucketLocation
- s3:ListBucketMultipartUploads
- s3:ListBucketVersions
- s3:GetObject
- s3:GetObjectVersion
- s3:PutObject
- s3:DeleteObject
Resource:
- !Sub "arn:aws:s3:::${TerraformStateBucket}"
- !Sub "arn:aws:s3:::${TerraformStateBucket}/*"
# Permissions to create and configure S3 buckets used by Terraform modules
- Sid: ModuleS3BucketManagement
Effect: Allow
Action:
- s3:CreateBucket
- s3:DeleteBucket
- s3:PutBucketVersioning
- s3:GetBucketTagging
- s3:PutEncryptionConfiguration
- s3:GetEncryptionConfiguration
- s3:PutBucketTagging
- s3:PutBucketPolicy
- s3:GetBucketPolicy
- s3:DeleteBucketPolicy
- s3:GetBucketLocation
- s3:GetBucketAcl
- s3:GetBucketCORS
- s3:ListBucket
- s3:GetBucketWebsite
- s3:GetBucketVersioning
- s3:GetAccelerateConfiguration
- s3:GetBucketRequestPayment
- s3:GetBucketLogging
- s3:GetLifecycleConfiguration
- s3:GetReplicationConfiguration
- s3:GetBucketObjectLockConfiguration
Resource:
- !Sub
- "arn:aws:s3:::your-project-${EnvName}-s3-*"
- EnvName: !FindInMap
- EnvMapping
- !Ref "AWS::AccountId"
- EnvName
- "arn:aws:s3:::your-project-snowflake-*"
# IAM permissions to create roles and attach inline policies for modules
- Sid: ModuleIamRoleManagement
Effect: Allow
Action:
- iam:CreateRole
- iam:DeleteRole
- iam:GetRole
- iam:TagRole
- iam:PutRolePolicy
- iam:GetRolePolicy
- iam:DeleteRolePolicy
- iam:ListRolePolicies
- iam:ListAttachedRolePolicies
- iam:ListInstanceProfilesForRole
- iam:UpdateAssumeRolePolicy
- iam:UntagRole
Resource:
- !Sub
- "arn:aws:iam::${AWS::AccountId}:role/your-project-${EnvName}-iamrole-*"
- EnvName: !FindInMap
- EnvMapping
- !Ref "AWS::AccountId"
- EnvName
- !Sub "arn:aws:iam::${AWS::AccountId}:role/your-project-snowflake-*"
# SSM Parameter Store permissions
- Sid: SSMParameterStorePolicy
Effect: Allow
Action:
- ssm:GetParameter
- ssm:GetParameters
Resource:
- !Sub "arn:aws:ssm:ap-northeast-1:${AWS::AccountId}:parameter/your-project/snowflake/*"
Outputs:
TerraformStateBucketName:
Description: Terraform state bucket name
Value: !Ref TerraformStateBucket
GitHubActionsRoleArn:
Description: IAM Role ARN for GitHub Actions
Value: !GetAtt GitHubActionsRole.Arn
GitHub Secrets設定
GitHubリポジトリのSecretsを手動で設定します。
GitHubリポジトリのSettings > Environmentsを開き、New environment
からdev
,prd
を作成します。作成したEnvironment内でPRIVATE_KEYなどのSecretsを定義することでGitHub Actions内で参照します。
デプロイ
それでは実際にSnowflake Terraformをデプロイしてみます。Snowflake Terraformの実際の実装については、以下のブログの内容と同様のため、省略します。main.tfで設定値を定義してmoduleを呼び出す構成です。
実装した内容をローカルのfeatureブランチからpushします。
@ snowflake-terraform-sample % git add .
@ snowflake-terraform-sample % git commit -m "feat(dev): Enable all Snowflake infrastructure modules"
@ snowflake-terraform-sample % git push origin
GitHub上でfeatureブランチ → developブランチに対するPull Requestを作成します。
developブランチへのPull Requestが作成されるとGitHub Actionsが起動します。
Actionsログを確認すると正常に終了していることが確認できました。terraform applyは想定通りskipされています。
Pull Requestに再度戻るとbotからterraform planコマンドの結果が出力されていることが確認できます。ClaudeのAIレビューを導入しているプロジェクトの場合は、terraform planの結果を要約させてみても良いですね。
問題ないと判断しmergeしました。GitHub Actionsが動き、今度はterraform planコマンドをskipし、terraform applyコマンドを実行しています。
処理は正常終了し、Snowflakeアカウント上でリソースが存在することを確認できました。
最後に
GitHub Actionsの設定は色々と考慮すべき内容が多いですので一つの参考になれば幸いです。