Infrastructure as Code を Terraform/OpenTofu GitLabで
(トップページはこちら) - (インフラ管理を始める)
1. はじめに:なぜGitLabでTerraform/OpenTofuなのか
従来のTerraform運用では、以下のような課題に直面します。
- S3バケット、DynamoDB、IAMロールなど、ステートバックエンドの複雑な初期設定
- チーム間でのステートファイル共有とロック管理の煩雑さ
- インフラ変更のレビュープロセスが、コードレビューと分離されている
- Terraformモジュールの社内共有に外部サービスが必要
GitLabのTerraform/OpenTofu統合は、これらの課題を追加のインフラなしで解決します。すべての機能は、GitLab.com、Self-Managed、Dedicatedの全エディション(Free、Premium、Ultimate)で利用可能です。
1.1 重要:Terraformライセンス変更への対応
2023年、HashiCorpはTerraformのライセンスをMPLからBSL(Business Source License)に変更しました。これにより、GitLabは公式にTerraformを配布できなくなりましたが、以下の選択肢を提供しています。
- OpenTofuへの移行(推奨):Terraformのオープンソースフォーク、完全互換
- セルフホスティング:Terraform Imagesプロジェクトを使用した独自ビルド
本記事では主にOpenTofuを使用した説明を行いますが、Terraformでも同様に動作します。
2. GitLab管理のステート保存
2.1 ステート管理の仕組み
GitLab管理のステートは、以下の特徴を持ちます。
-
暗号化: Lockbox Ruby gemによる保存時の自動暗号化(
db_key_baseから派生した鍵を使用) - バージョン管理: すべてのステート変更を自動的に記録
- アクセス制御: GitLabの権限モデルと統合
- ロック機構: 同時実行による競合を防止
2.2 権限モデル
| 操作 | 必要な役割 | 説明 |
|---|---|---|
| ステート読み取り | Developer以上 |
tofu plan -lock=falseの実行 |
| ステート書き込み | Maintainer以上 |
tofu applyの実行、ロック操作 |
| ステート削除 | Maintainer以上 | ステートファイルの完全削除 |
| バージョン管理 | Developer以上 | 特定バージョンの取得 |
2.3 CI/CDでの基本設定
2.3.1 OpenTofu CI/CDコンポーネントの使用(推奨)
include:
- component: gitlab.com/components/opentofu/validate-plan-apply@1.0.0
inputs:
version: 1.0.0
opentofu_version: 1.6.0
root_dir: terraform/
state_name: production
stages: [validate, build, deploy]
2.3.2 バックエンド設定
プロジェクトの.tfファイルでHTTPバックエンドを定義します。
terraform {
backend "http" {
}
}
環境変数は自動的に設定されますが、カスタマイズも可能です。
| 環境変数 | デフォルト値 | 説明 |
|---|---|---|
TF_ADDRESS |
${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/default |
ステートのHTTPエンドポイント |
TF_USERNAME |
gitlab-ci-token |
CI/CD実行時の認証ユーザー |
TF_PASSWORD |
${CI_JOB_TOKEN} |
CI/CD実行時の認証トークン |
TF_PLAN_CACHE |
plan.cache |
プランファイルの保存名 |
2.3.3 複数環境の管理
環境ごとに異なるステート名を使用します。
variables:
STATE_NAME: "default"
.tofu_base:
image: registry.gitlab.com/gitlab-org/terraform-images/releases/1.5:v1.0.0
before_script:
- export TF_ADDRESS="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${STATE_NAME}"
staging:
extends: .tofu_base
variables:
STATE_NAME: "staging"
script:
- gitlab-tofu apply
environment:
name: staging
production:
extends: .tofu_base
variables:
STATE_NAME: "production"
script:
- gitlab-tofu apply
environment:
name: production
when: manual
2.4 ローカル環境からのアクセス
GitLab CLI(glab)1.66以降を使用します。
2.4.1 初期設定
# GitLab CLIのインストール確認
glab version
# ステートの初期化
glab opentofu init production
2.4.2 ステート操作
# 最新ステートのダウンロード
glab opentofu state download production
# 特定バージョンのダウンロード
glab opentofu state download production 5
# ステートのロック(メンテナンス時など)
glab opentofu state lock production
# ステートのアンロック
glab opentofu state unlock production
# ステートバージョンの削除
glab opentofu state delete production 3
2.4.3 手動設定(GitLab CLI未使用の場合)
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/production"
tofu init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
2.5 既存ステートの移行
2.5.1 S3バックエンドからの移行例
# 1. 既存のS3バックエンドで初期化
tofu init
# 2. GitLabバックエンドへの移行
glab opentofu init production -- -migrate-state
# 確認プロンプトで "yes" を入力
2.5.2 ステート名の変更
# 旧ステート名で初期化
glab opentofu init old-state-name
# 新ステート名へ移行
glab opentofu init new-state-name -- -migrate-state
2.6 リモートステートのデータソース活用
他のプロジェクトのステートを参照できます。
2.6.1 変数定義
variable "network_state_address" {
type = string
description = "ネットワークプロジェクトのステートアドレス"
}
variable "network_username" {
type = string
description = "認証ユーザー名"
}
variable "network_access_token" {
type = string
description = "アクセストークン(API scope必須)"
sensitive = true
}
2.6.2 データソース設定
data "terraform_remote_state" "network" {
backend = "http"
config = {
address = var.network_state_address
username = var.network_username
password = var.network_access_token
}
}
# 他プロジェクトのアウトプットを参照
resource "aws_instance" "app" {
subnet_id = data.terraform_remote_state.network.outputs.subnet_id
vpc_id = data.terraform_remote_state.network.outputs.vpc_id
}
2.6.3 変数ファイル(バージョン管理外)
network.auto.tfvarsファイルを作成します(.gitignoreに追加)。
network_state_address = "https://gitlab.com/api/v4/projects/456/terraform/state/production"
network_username = "tanaka_taro"
network_access_token = "glpat-xxxxxxxxxxxxxxxxxxxx"
2.7 災害復旧の考慮事項
重要な制限事項:ステートファイルはdb_key_baseで暗号化されているため、GitLabが利用不可能な場合、ステートファイルの復号化ができません。
2.7.1 推奨される対策
- 定期的なステートバックアップ
backup_state:
stage: backup
script:
- glab opentofu state download production > backup-$(date +%Y%m%d).tfstate
- # バックアップストレージへアップロード
only:
- schedules
-
重要な依存関係の分離:GitLab自体のインフラをGitLabで管理しない
-
別インスタンスでのミラーリング:異なる障害ドメインにGitLabインスタンスを配置
3. マージリクエストでのインフラ変更可視化
3.1 Terraform Reportの仕組み
tofu planの実行結果をJSON形式で出力し、GitLabがマージリクエストウィジェットに統計情報を表示します。
3.2 自動設定(OpenTofu CI/CDコンポーネント使用時)
OpenTofu CI/CDコンポーネントを使用すると、Terraformレポートが自動的に設定されます。追加の設定は不要です。
3.3 手動設定
カスタムパイプラインでの設定例です。
variables:
PLAN: plan.cache
PLAN_JSON: plan.json
before_script:
- apk --no-cache add jq
# Bashを使用する場合はalias展開を有効化
- shopt -s expand_aliases
- alias convert_report="jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'"
plan:
stage: build
script:
- gitlab-tofu plan -out=$PLAN
- gitlab-tofu show -json $PLAN | convert_report > $PLAN_JSON
artifacts:
name: plan
paths:
- $PLAN
reports:
terraform: $PLAN_JSON
access: developer # Developer以上のみアクセス可能
only:
- merge_requests
3.4 ウィジェットの表示内容
マージリクエストには以下の情報が表示されます。
- 作成されるリソース数(緑色)
- 更新されるリソース数(オレンジ色)
- 削除されるリソース数(赤色)
- View Full Logリンク:パイプラインログへの直接アクセス
表示制限:各アクションの最大表示数は999,999です。これは表示上の制限であり、実際の適用には影響しません。
4. セキュリティ考慮事項
4.1 プランファイルの機密情報
Terraformプランファイルには、以下のような機密情報が含まれる可能性があります。
- データベースパスワード
- APIキー、アクセストークン
- TLS証明書、秘密鍵
- 環境変数の値
4.2 推奨されるセキュリティ対策
4.2.1 アーティファクトのアクセス制御
artifacts:
access: developer # Developer以上のみアクセス可能
reports:
terraform: $PLAN_JSON
4.2.2 パブリックパイプラインの無効化
プロジェクト設定で以下を無効化します。
- 設定 > CI/CD > 全般パイプライン
- Public pipelinesを無効化
4.2.3 プランファイルの暗号化
機密性の高い環境では、プランファイルを暗号化します。
plan:
stage: build
script:
- gitlab-tofu plan -out=$PLAN
- gitlab-tofu show -json $PLAN | convert_report > $PLAN_JSON
# プランファイルを暗号化
- gpg --symmetric --cipher-algo AES256 --output $PLAN.gpg $PLAN
artifacts:
paths:
- $PLAN.gpg # 暗号化されたファイルのみ保存
reports:
terraform: $PLAN_JSON
apply:
stage: deploy
script:
# プランファイルを復号化
- gpg --decrypt --output $PLAN $PLAN.gpg
- gitlab-tofu apply $PLAN
4.3 ステートファイルのセキュリティ
- ステートファイルは自動的に暗号化されます
- アクセス制御はGitLabの権限モデルに従います
- APIトークンは最小限のスコープ(
read_apiまたはapi)を使用
5. Terraformモジュールレジストリ
5.1 モジュールレジストリの利点
GitLabプロジェクトをTerraformモジュールのプライベートレジストリとして使用することで、以下が実現できます。
- 組織内でのモジュール共有と再利用
- バージョン管理とセマンティックバージョニング
- CI/CDによる自動テストとセキュリティスキャン
- アクセス制御の統合管理
5.2 モジュールの公開
5.2.1 CI/CDテンプレートを使用した公開(推奨)
include:
template: Terraform-Module.gitlab-ci.yml
variables:
TERRAFORM_MODULE_DIR: ${CI_PROJECT_DIR}
TERRAFORM_MODULE_NAME: terraform-aws-vpc
TERRAFORM_MODULE_SYSTEM: aws
# TERRAFORM_MODULE_VERSIONはCI_COMMIT_TAGから自動取得
このテンプレートには以下のジョブが含まれます。
| ジョブ名 | 実行タイミング | 説明 |
|---|---|---|
fmt |
すべてのパイプライン |
terraform fmt -checkによる検証 |
kics-iac-sast |
すべてのパイプライン | セキュリティ脆弱性のスキャン |
deploy |
タグパイプラインのみ | モジュールレジストリへのアップロード |
5.2.2 セマンティックバージョニング
モジュールバージョンは、セマンティックバージョニング(SemVer)に従います。
# パッチバージョン(バグ修正)
git tag v1.0.1
git push origin v1.0.1
# マイナーバージョン(後方互換性のある機能追加)
git tag v1.1.0
git push origin v1.1.0
# メジャーバージョン(破壊的変更)
git tag v2.0.0
git push origin v2.0.0
5.2.3 手動設定
stages:
- validate
- deploy
fmt:
stage: validate
image: hashicorp/terraform:latest
script:
- terraform fmt -check -recursive
only:
- merge_requests
- tags
upload:
stage: deploy
image: curlimages/curl:latest
variables:
TERRAFORM_MODULE_DIR: ${CI_PROJECT_DIR}
TERRAFORM_MODULE_NAME: ${CI_PROJECT_NAME}
TERRAFORM_MODULE_SYSTEM: aws
TERRAFORM_MODULE_VERSION: ${CI_COMMIT_TAG}
script:
- TERRAFORM_MODULE_NAME=$(echo "${TERRAFORM_MODULE_NAME}" | tr " _" -)
- tar -vczf /tmp/${TERRAFORM_MODULE_NAME}-${TERRAFORM_MODULE_SYSTEM}-${TERRAFORM_MODULE_VERSION}.tgz -C ${TERRAFORM_MODULE_DIR} --exclude=./.git .
- 'curl --fail-with-body --location --header "JOB-TOKEN: ${CI_JOB_TOKEN}"
--upload-file /tmp/${TERRAFORM_MODULE_NAME}-${TERRAFORM_MODULE_SYSTEM}-${TERRAFORM_MODULE_VERSION}.tgz
${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/terraform/modules/${TERRAFORM_MODULE_NAME}/${TERRAFORM_MODULE_SYSTEM}/${TERRAFORM_MODULE_VERSION}/file'
only:
- tags
5.3 モジュールの参照
5.3.1 名前空間からの参照(推奨)
環境変数で認証を設定します。
# 環境変数の設定
export TF_TOKEN_gitlab_com='glpat-xxxxxxxxxxxxxxxxxxxx'
# または ~/.terraformrc ファイルで設定
cat > ~/.terraformrc << EOF
credentials "gitlab.com" {
token = "glpat-xxxxxxxxxxxxxxxxxxxx"
}
EOF
Terraformコードでモジュールを参照します。
module "vpc" {
source = "gitlab.com/my-org/terraform-aws-vpc/aws"
version = "1.2.3" # 特定バージョンを指定(推奨)
cidr_block = "10.0.0.0/16"
name = "production-vpc"
}
module "subnet" {
source = "gitlab.com/my-org/terraform-aws-subnet/aws"
version = "~> 1.0" # マイナーバージョンの範囲指定
vpc_id = module.vpc.vpc_id
cidr_block = "10.0.1.0/24"
}
5.3.2 プロジェクトからの参照
HTTPアーカイブフェッチを使用します。
module "vpc" {
source = "https://gitlab.com/api/v4/projects/12345/packages/terraform/modules/terraform-aws-vpc/aws/1.2.3"
cidr_block = "10.0.0.0/16"
name = "production-vpc"
}
認証は~/.netrcファイルで設定します。
machine gitlab.com
login tanaka_taro
password glpat-xxxxxxxxxxxxxxxxxxxx
5.3.3 最新バージョンの参照(非推奨)
# バージョン指定なし(最新版を自動取得)
module "vpc" {
source = "gitlab.com/my-org/terraform-aws-vpc/aws"
# 本番環境では非推奨:予期しない変更が適用される可能性
}
5.4 モジュール名の重複管理
GitLab 16.8以降、名前空間内でのモジュール名の重複を制御できます。
5.4.1 重複の許可設定
- グループの設定 > パッケージとレジストリに移動
- Duplicate packagesテーブルのTerraform module行を確認
- Allow duplicatesトグルを設定
- Exceptionsフィールドで正規表現による例外を設定可能
5.4.2 重複時の解決ルール
重複が許可されている場合:最新公開されたモジュールが使用されます。
重複が許可されていない場合:同一名前空間内で同じモジュール名は使用できません。
エラー例:
{"message":"A module with the same name already exists in the namespace."}
5.4.3 重複モジュールの特定バージョン参照
プロジェクトレベルのソースを使用します。
# 名前空間レベル(最新の重複モジュールが使用される)
module "vpc_latest" {
source = "gitlab.com/my-org/terraform-aws-vpc/aws"
}
# プロジェクトレベル(特定プロジェクトのモジュールを明示)
module "vpc_specific" {
source = "https://gitlab.com/api/v4/projects/12345/packages/terraform/modules/terraform-aws-vpc/aws/1.2.3"
}
5.5 モジュールのREADME表示
GitLab 17.2以降、モジュールのREADMEファイルがUIに表示されます。
5.5.1 README作成のベストプラクティス
# Terraform AWS VPC Module
## 概要
AWSのVPCを作成するTerraformモジュールです。
## 使用方法
```hcl
module "vpc" {
source = "gitlab.com/my-org/terraform-aws-vpc/aws"
version = "1.2.3"
cidr_block = "10.0.0.0/16"
name = "my-vpc"
}
入力変数
| 変数名 | 型 | デフォルト値 | 説明 |
|---|---|---|---|
cidr_block |
string | - | VPCのCIDRブロック(必須) |
name |
string | - | VPCの名前(必須) |
enable_dns_hostnames |
bool | true | DNSホスト名の有効化 |
出力値
| 出力名 | 説明 |
|---|---|
vpc_id |
作成されたVPCのID |
vpc_arn |
作成されたVPCのARN |
要件
- Terraform >= 1.0
- AWS Provider >= 4.0
## 6. OpenTofuへの移行とTerraform Imagesプロジェクト
### 6.1 ライセンス変更の影響
2023年8月、HashiCorpはTerraform 1.5.5以降のライセンスをMPL 2.0からBSL 1.1に変更しました。これにより、GitLabは以下の対応を行いました。
- Terraform 1.5.5以降のバージョンを含むイメージの配布停止
- OpenTofuへの移行推奨
- Terraform Imagesプロジェクトによるセルフホスティングサポート
### 6.2 OpenTofu CI/CDコンポーネント(推奨)
OpenTofuは、Terraformのオープンソースフォークであり、完全な互換性を持ちます。
```yaml
include:
- component: gitlab.com/components/opentofu/validate-plan-apply@1.0.0
inputs:
version: 1.0.0
opentofu_version: 1.6.0
root_dir: terraform/
state_name: production
stages: [validate, build, deploy]
6.2.1 コンポーネントの機能
| ステージ | ジョブ | 説明 |
|---|---|---|
| validate | validate |
tofu validateとtofu fmt -checkの実行 |
| build | plan |
tofu planの実行とレポート生成 |
| deploy | apply |
tofu applyの実行(手動トリガー) |
6.3 Terraform Imagesプロジェクトによるセルフホスティング
最新のTerraformバージョンを使用したい場合、独自にイメージをビルドできます。
6.3.1 セルフホスティングの手順
ステップ1:プロジェクトのミラーリング
- 自社GitLabインスタンスで新規プロジェクトを作成
- 設定 > リポジトリ > ミラーリングリポジトリ
- Git repository URL:
https://gitlab.com/gitlab-org/terraform-images.git - ミラー方向: Pull
- ミラーリポジトリをクリック
ステップ2:Terraformバージョンの指定
.gitlab-ci.ymlの.terraform-versionsを編集します。
.terraform-versions:
parallel:
matrix:
- TERRAFORM_VERSION: ["1.9.0", "1.8.5", "1.7.5"]
ステップ3:リリースパイプラインの実行
git tag v1.0.0
git push origin v1.0.0
ステップ4:プロジェクトでの使用
include:
- project: "my-org/terraform-images"
file: "/templates/Terraform.gitlab-ci.yml"
default:
image:
name: ${CI_REGISTRY}/my-org/terraform-images/releases/1.9.0:v1.0.0
variables:
TF_ROOT: ${CI_PROJECT_DIR}/terraform
TF_STATE_NAME: production
6.4 gitlab-terraformスクリプトの機能
gitlab-terraformは、terraformバイナリのラッパーであり、以下を自動化します。
- GitLab HTTPバックエンドの設定
- CI/CD環境変数の
TF_VARへの変換 - プランファイルの標準化された管理
6.4.1 自動公開されるCI/CD変数
以下の変数がTF_VAR_プレフィックス付きで自動的に利用可能になります。
| GitLab変数 | Terraform変数 | 説明 |
|---|---|---|
CI_JOB_ID |
TF_VAR_CI_JOB_ID |
ジョブID |
CI_COMMIT_SHA |
TF_VAR_CI_COMMIT_SHA |
コミットSHA |
CI_JOB_STAGE |
TF_VAR_CI_JOB_STAGE |
ステージ名 |
CI_PROJECT_ID |
TF_VAR_CI_PROJECT_ID |
プロジェクトID |
CI_PROJECT_NAME |
TF_VAR_CI_PROJECT_NAME |
プロジェクト名 |
CI_PROJECT_NAMESPACE |
TF_VAR_CI_PROJECT_NAMESPACE |
名前空間 |
CI_PROJECT_PATH |
TF_VAR_CI_PROJECT_PATH |
プロジェクトパス |
CI_PROJECT_URL |
TF_VAR_CI_PROJECT_URL |
プロジェクトURL |
6.4.2 Terraformでの使用例
variable "CI_PROJECT_NAME" {
type = string
description = "GitLabプロジェクト名(CI/CDから自動注入)"
}
variable "CI_COMMIT_SHA" {
type = string
description = "コミットSHA(CI/CDから自動注入)"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "${var.CI_PROJECT_NAME}-terraform-state"
tags = {
Project = var.CI_PROJECT_NAME
CommitSHA = var.CI_COMMIT_SHA
ManagedBy = "Terraform"
}
}
6.4.3 ロックファイルの取り扱い
.terraform.lock.hclをリポジトリにコミットする場合の推奨設定です。
variables:
TF_INIT_FLAGS: "-lockfile=readonly"
plan:
script:
- gitlab-terraform init ${TF_INIT_FLAGS}
- gitlab-terraform plan
理由:-backend-configオプションを使用すると、設定がプランファイルにキャッシュされ、apply時に問題が発生する可能性があります。環境変数を使用することで、この問題を回避できます。
6.5 TerraformとOpenTofuの互換性
以下の機能は、TerraformとOpenTofuの両方で完全に互換性があります。
| 機能 | Terraform | OpenTofu | 備考 |
|---|---|---|---|
| GitLab管理ステート | ✓ | ✓ | HTTPバックエンド使用 |
| マージリクエスト統合 | ✓ | ✓ | レポート形式は同一 |
| モジュールレジストリ | ✓ | ✓ | プロトコル互換 |
| CI/CDコンポーネント | - | ✓ | OpenTofu専用 |
| gitlab-terraformスクリプト | ✓ | ✓ | 両方で動作 |
7. 実践的なワークフロー
7.1 開発からデプロイまでの完全なフロー
7.2 環境別の管理戦略
7.2.1 ディレクトリ構造
terraform/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── rds/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── environments/
│ ├── staging/
│ │ ├── main.tf
│ │ ├── backend.tf
│ │ ├── terraform.tfvars
│ │ └── .terraform.lock.hcl
│ └── production/
│ ├── main.tf
│ ├── backend.tf
│ ├── terraform.tfvars
│ └── .terraform.lock.hcl
└── .gitlab-ci.yml
7.2.2 環境別のCI/CD設定
include:
- component: gitlab.com/components/opentofu/validate-plan-apply@1.0.0
inputs:
version: 1.0.0
opentofu_version: 1.6.0
root_dir: terraform/environments/staging
state_name: staging
- component: gitlab.com/components/opentofu/validate-plan-apply@1.0.0
inputs:
version: 1.0.0
opentofu_version: 1.6.0
root_dir: terraform/environments/production
state_name: production
stages: [validate, build, deploy]
# Staging環境は自動デプロイ
staging_apply:
extends: .apply
variables:
TF_ROOT: terraform/environments/staging
TF_STATE_NAME: staging
environment:
name: staging
only:
- main
# Production環境は手動デプロイ
production_apply:
extends: .apply
variables:
TF_ROOT: terraform/environments/production
TF_STATE_NAME: production
environment:
name: production
when: manual
only:
- main
7.3 ベストプラクティス
7.3.1 ステート管理
推奨事項:
- 環境ごとに異なるステート名を使用
variables:
TF_STATE_NAME: "${CI_ENVIRONMENT_NAME}"
- 定期的なステートバックアップ
backup_state:
stage: backup
script:
- |
for env in staging production; do
glab opentofu state download ${env} > backup-${env}-$(date +%Y%m%d).tfstate
# S3などにアップロード
done
only:
- schedules
- ステートロックのタイムアウト設定
terraform {
backend "http" {
retry_wait_min = 5
retry_wait_max = 30
}
}
7.3.2 セキュリティ
推奨事項:
- 機密情報の外部化
# 環境変数から取得
variable "db_password" {
type = string
sensitive = true
}
# GitLab CI/CD変数で設定
# TF_VAR_db_password = "secret_password"
- プランファイルのアクセス制御
artifacts:
access: developer
expire_in: 1 week # 保持期間を制限
- SAST(Static Application Security Testing)の有効化
include:
- template: Security/SAST.gitlab-ci.yml
kics-iac-sast:
variables:
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
7.3.3 モジュール管理
推奨事項:
- セマンティックバージョニングの厳守
# バグ修正
git tag v1.0.1
# 新機能(後方互換)
git tag v1.1.0
# 破壊的変更
git tag v2.0.0
- モジュールのバージョン固定
module "vpc" {
source = "gitlab.com/my-org/terraform-aws-vpc/aws"
version = "1.2.3" # 完全一致
}
module "subnet" {
source = "gitlab.com/my-org/terraform-aws-subnet/aws"
version = "~> 1.2" # 1.2.x の最新
}
- CHANGELOG.mdの維持
# Changelog
## [1.2.3] - 2024-01-15
### Fixed
- サブネットのタグ設定バグを修正
## [1.2.0] - 2024-01-10
### Added
- IPv6サポートを追加
## [1.1.0] - 2024-01-05
### Added
- VPCフローログ機能を追加
7.3.4 CI/CD
推奨事項:
- 環境変数の適切な管理
variables:
TF_INIT_FLAGS: "-lockfile=readonly"
TF_CLI_ARGS_plan: "-parallelism=10"
TF_CLI_ARGS_apply: "-parallelism=10"
- 段階的なロールアウト
production_apply:
stage: deploy
script:
- gitlab-tofu apply -auto-approve
environment:
name: production
deployment_tier: production
when: manual
needs:
- staging_apply # Stagingの成功を前提
- 失敗時の通知
.notify_on_failure:
after_script:
- |
if [ "$CI_JOB_STATUS" == "failed" ]; then
curl -X POST $SLACK_WEBHOOK_URL \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Terraform apply failed in ${CI_ENVIRONMENT_NAME}\"}"
fi
7.4 トラブルシューティング
7.4.1 ステートロックの解除
問題:パイプラインが異常終了し、ステートがロックされたまま
解決方法:
# UIから解除
# Operate > Terraform states > Actions > Unlock
# CLIから解除
glab opentofu state unlock production
# 強制解除(最終手段)
curl --request DELETE --header "PRIVATE-TOKEN: <token>" \
"https://gitlab.com/api/v4/projects/<project-id>/terraform/state/production/lock"
7.4.2 プランとアプライの不一致
問題:Can't lock Terraform state files in CI jobs
原因:-backend-configオプションの使用によるキャッシュ問題
解決方法:環境変数を使用
# 悪い例
script:
- terraform init -backend-config="address=$TF_ADDRESS"
# 良い例
variables:
TF_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/production"
script:
- gitlab-terraform init
7.4.3 モジュールの認証エラー
問題:Error: Failed to download module
解決方法:
# 環境変数の確認
echo $TF_TOKEN_gitlab_com
# 再設定
export TF_TOKEN_gitlab_com='glpat-xxxxxxxxxxxxxxxxxxxx'
# または ~/.terraformrc の確認
cat ~/.terraformrc
8. まとめ
GitLabのTerraform/OpenTofu統合は、以下の価値を提供します。
8.1 主要な利点
-
統合されたワークフロー
- コード、ステート、レビュープロセスが単一プラットフォームに集約
- 追加のインフラ設定が不要
-
セキュアな管理
- ステートファイルの自動暗号化
- GitLab権限モデルとの統合
- バージョン管理による変更追跡
-
チームコラボレーション
- マージリクエストでのインフラ変更可視化
- レビュープロセスの標準化
- 変更履歴の一元管理
-
モジュール再利用
- プライベートレジストリによる組織内共有
- セマンティックバージョニングのサポート
- CI/CDによる自動テストとセキュリティスキャン
-
柔軟な選択肢
- TerraformとOpenTofuの両方をサポート
- セルフホスティングによる完全なコントロール
- 段階的な移行パス
8.2 導入ロードマップ
フェーズ1:基本的なステート管理(1-2週間)
- GitLab管理ステートへの移行
- CI/CDパイプラインの基本設定
- チームメンバーへのトレーニング
フェーズ2:マージリクエスト統合(1週間)
- Terraformレポートの有効化
- レビュープロセスの確立
- セキュリティ対策の実装
フェーズ3:モジュール化(2-4週間)
- 共通パターンのモジュール化
- モジュールレジストリの構築
- ドキュメント整備
フェーズ4:最適化(継続的)
- パイプラインの最適化
- セキュリティスキャンの強化
- ベストプラクティスの確立
8.3 今後の展望
HashiCorpのライセンス変更により、Terraformの配布方法は変化しましたが、GitLabは以下を通じて継続的なサポートを提供します。
- OpenTofuへの完全な移行サポート
- Terraform Imagesプロジェクトによるセルフホスティング
- コミュニティベースのサポート体制
GitLabのIaC機能を活用することで、インフラストラクチャ管理の効率化、品質向上、そしてチーム全体の生産性向上を実現できます。