これは、なにをしたくて書いたもの?
GitLabのDefault branchとProtected branchesを、Terraformで設定してみましょう、ということで。
Default branch
Default branchはこちらの話です。
新しいプロジェクトを作成した時に作成されるブランチで、以下のように特別扱いされます。
- 削除不可
- デフォルトではforce push不可
- Merge Requestでissueをクローズすると、Default branchにマージされる
GitLab Terraform Providerではgitlab_projectで設定します。
Protected branches
Protected branchesはこちらの話です。
Protected branches | GitLab Docs
このようなブランチのことです。
- コードの変更をmergeおよびpushできるユーザーを制限できる
- 削除保護を設定できる
- コードレビューを承認プロセスを設定できる(PremiumまたはUltimateのみ)
- コード所有者の承認とファイルの制限を管理できる
- force pushを制限できる
- UIおよびAPIの両方でアクセス制御ができる
GitLab Terraform Providerではこちらで設定します。
gitlab_branch_protection (Resource)
環境
今回の環境はこちら。GitLabはすでに構築済みで、192.168.0.6で動作しているものとします。
$ sudo gitlab-rake gitlab:env:info System information System: Ubuntu 24.04 Current User: git Using RVM: no Ruby Version: 3.2.5 Gem Version: 3.6.5 Bundler Version:2.6.5 Rake Version: 13.0.6 Redis Version: 7.0.15 Sidekiq Version:7.2.4 Go Version: unknown GitLab information Version: 17.10.4 Revision: 17c5705edda Directory: /opt/gitlab/embedded/service/gitlab-rails DB Adapter: PostgreSQL DB Version: 14.17 URL: http://192.168.0.6 HTTP Clone URL: http://192.168.0.6/some-group/some-project.git SSH Clone URL: git@192.168.0.6:some-group/some-project.git Using LDAP: no Using Omniauth: yes Omniauth Providers: GitLab Shell Version: 14.41.0 Repository storages: - default: unix:/var/opt/gitlab/gitaly/gitaly.socket GitLab Shell path: /opt/gitlab/embedded/service/gitlab-shell Gitaly - default Address: unix:/var/opt/gitlab/gitaly/gitaly.socket - default Version: 17.10.4 - default Git Version: 2.48.1.gl1
Terraform。
$ terraform version Terraform v1.11.4 on linux_amd64
Default branchとProtected branchesを設定したGitLabプロジェクトをTerraformで構築する
それでは、Default branchとProtected branchesを設定したGitLabプロジェクトをTerraformで構築してみます。
Terraformでのリソース定義。
terraform.tf
terraform { required_version = "1.11.4" required_providers { gitlab = { source = "gitlabhq/gitlab" version = "17.10.0" } } }
main.tf
variable "root_access_token" { type = string ephemeral = true } provider "gitlab" { token = var.root_access_token base_url = "http://192.168.0.6/" } resource "gitlab_group" "sample_group" { name = "sample group" path = "sample-group" } resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.sample_group.id default_branch = "main" visibility_level = "private" auto_devops_enabled = false ## 今回はGitLab CI/CDを使わないのでオフ only_allow_merge_if_pipeline_succeeds = false ## 今回はGitLab CI/CDを使わないのでオフ only_allow_merge_if_all_discussions_are_resolved = true } resource "gitlab_branch_protection" "main_branch" { project = gitlab_project.sample_app.id branch = "main" allow_force_push = false merge_access_level = "maintainer" push_access_level = "no one" unprotect_access_level = "maintainer" } resource "gitlab_group_membership" "sample_owner" { group_id = gitlab_group.sample_group.id user_id = gitlab_user.sample_owner.id access_level = "owner" } resource "gitlab_user" "sample_owner" { name = "sample-owner" username = "sample-owner" password = "P@ssw0rd" email = "sample-owner@example.com" } resource "gitlab_group_membership" "sample_developer" { group_id = gitlab_group.sample_group.id user_id = gitlab_user.sample_developer.id access_level = "developer" } resource "gitlab_user" "sample_developer" { name = "sample-developer" username = "sample-developer" password = "P@ssw0rd" email = "sample-developer@example.com" }
Defaut branchはgitlab_projectのdefault_branchで設定します。ひとまずmainにしておきました。
resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.sample_group.id default_branch = "main" visibility_level = "private" auto_devops_enabled = false ## 今回はGitLab CI/CDを使わないのでオフ only_allow_merge_if_pipeline_succeeds = false ## 今回はGitLab CI/CDを使わないのでオフ only_allow_merge_if_all_discussions_are_resolved = true }
今回は簡単のためにCI/CDを使わないので、Auto DevOpsとマージの条件にパイプラインが成功していることの
2つを無効にしています。
Protected branchの設定はこちら。
resource "gitlab_branch_protection" "main_branch" { project = gitlab_project.sample_app.id branch = "main" allow_force_push = false merge_access_level = "maintainer" push_access_level = "no one" unprotect_access_level = "maintainer" }
force push無効、mergeはmaintainerのみ、pushは許可しない、unprotectはmaintainerのみが可能という設定です。
ユーザーはownerとdeveloperの2人を用意しました。
$ export TF_VAR_root_access_token=...
リソース構築。
$ terraform init $ terraform apply
できあがったプロジェクトのSettings → Repositoryで現在のブランチ設定を確認。

mainブランチがprotectedになっているのみですね。Default branchは設定が見えません。ブランチがないので。
Protected branchに関しては、存在していないブランチに対しても追加ができます。
ソースコードを登録する
では、このプロジェクトにソースコードを登録します。
登録する内容はあまり関係がないので、今回はGitLabの新規プロジェクト作成に表示されている手順にそのまま
習うことにします。
$ git init --initial-branch=main $ git remote add origin http://192.168.0.6/sample-group/sample-app.git $ git add . $ git config --local user.name 'sample-owner' $ git config --local user.email 'sample-owner@example.com' $ git commit -m 'Initial commit' $ git push --set-upstream origin main
push後、Default branchがmainになりました。

Terraformの設定が反映されているかに見えますが、最初にpushされたブランチがデフォルトになっているだけな
気もします…。
Protected branchを追加して、Default branchを変更する
ではここにdevelopブランチを追加してみます。
$ git switch -c develop $ git push --set-upstream origin develop
そしてTerraformもリソース定義でDefault branchをdevelopに変更し
resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.sample_group.id default_branch = "develop" visibility_level = "private" auto_devops_enabled = false ## 今回はGitLab CI/CDを使わないのでオフ only_allow_merge_if_pipeline_succeeds = false ## 今回はGitLab CI/CDを使わないのでオフ only_allow_merge_if_all_discussions_are_resolved = true }
Protected branchとしても設定します。
resource "gitlab_branch_protection" "develop_branch" { project = gitlab_project.sample_app.id branch = "develop" allow_force_push = false merge_access_level = "maintainer" push_access_level = "no one" unprotect_access_level = "maintainer" }
反映。
$ terraform apply
Default branchがdevelopになり、Protected branchesにも追加されました。

確認
少しコードを変更して、developブランチにpushしてみます。
$ git commit -m 'edit' $ git commit -m 'edit' [develop 0ac9ac3] edit 1 file changed, 1 insertion(+) ubuntu@60e0d4fad550:/host$ git push origin HEAD Username for 'http://192.168.0.6': sample-owner Password for 'http://sample-owner@192.168.0.6': Enumerating objects: 17, done. Counting objects: 100% (17/17), done. Delta compression using up to 16 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (9/9), 536 bytes | 536.00 KiB/s, done. Total 9 (delta 2), reused 0 (delta 0), pack-reused 0 remote: GitLab: You are not allowed to push code to protected branches on this project. To http://192.168.0.6/sample-group/sample-app.git ! [remote rejected] HEAD -> develop (pre-receive hook declined) error: failed to push some refs to 'http://192.168.0.6/sample-group/sample-app.git'
Protected branchなのでNGです。
では、別ブランチにしてMerge Requestにしてみましょう。
$ git switch -c feature1 $ git push origin HEAD
Merge Requestを作ってdeveloperで見てみると、マージができません。

ownerで見ると、マージができるようになっています。

そして、実際マージが可能です。

こんなところでしょうか。
おわりに
TerraformでGitLabのDefault branchとProtected branchesを設定してみました。
UIで操作すると簡単に終わる内容なのですが、Terraformでいざやろうとするとまあまあハマりました…。
まあ、今後いろいろ確認するのに慣れておいた方がいいと思うので、これはこれで押さえておいた方がいいと
思うことにしておきましょう。