これは、なにをしたくて書いたもの?
GitLabにはTerraformのProviderがあるようなので、こちらを試してみたいなということで。
GitLab Provider
GitLab Providerのドキュメントはこちら。
ProviderがサポートするGitLabのバージョンは、直近3つのパッチリリースのようです。
Latest 3 patch releases within a major release. For example, if current is 17.8, we support 17.6-17.8. Or if current is 18.1, we support 18.0-18.1.
現時点のProviderのバージョンは17.10なので、ProviderはGitLab 17.8、17.9、17.10でテストされていることになります。
というか、バージョン体型がGitLabと同じに見えますね。
見てみると、3.20.0から15.7.0にジャンプしていて、ここからGitLabとバージョンを揃えるようになったみたいです。
ただ、テストされているだけであって、ProviderとGitLabに完全に互換性があるかどうかは推測できない(機能が異なる
可能性がある)ということには注意が必要みたいですね。
Note, that the compatibility between a provider release and GitLab itself cannot be inferred from the release version. New features added to GitLab may not be added to the provider until later versions. Equally, features removed or deprecated in GitLab may not be removed or deprecated from the provider until later versions.
最低限必要なTerraformのバージョンは1.0で、1.4.0以上が推奨とされています。
This provider requires at least Terraform 1.0. A minimum of Terraform 1.4.0 is recommended.
リソースへのアクセスにはアクセストークンが必要になるようです。サービスアカウントの作成を勧められていますね。
Using a Project or Group access token may cause issues with some resources, as those token types don't have full access to every API. This is also true when using a CI_JOB_TOKEN. Consider using a dedicated Personal Access Token or Service Account if you are experiencing permission errors when adding resources.
Providerにはアクセストークンを設定することになります。
# Configure the GitLab Provider provider "gitlab" { token = var.gitlab_token }
ですが、gitlab.com版であってもGitLab Self-Hosted版であっても有償プランでなければサービスアカウントは
作成できなさそうです…。
GitLab Providerの使い方をざっくりと把握するには、こちらのユースケースに関するドキュメントを見るとよさそうです。
Use Cases / A Tech Lead Bootstrapping a Small Team
以下について書かれているので、基本的なことはできるようになると思います。
- Configure GitLab provider
- Create a group and projects
- Configure CI/CD runner
今回は手元にインストールGitLabインスタンスに対して、GitLab Providerを使ってみましょう。
環境
今回の環境はこちら。
$ 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.0 Revision: d8c1ba94b65 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.0 - default Git Version: 2.48.1.gl1
GitLabは192.168.0.6で動作しているものとします。またアカウントはインストール直後のrootのみがあるものとします。
Terraform。
$ terraform version Terraform v1.11.2 on linux_amd64
GitLab Providerで、GitLabグループ、プロジェクト、ユーザーを作成する
それでは、GitLab Providerを使ってGitLabのリソースをTerraformで構築してみましょう。
TerraformとGitLab Providerのバージョン指定。
terraform.tf
terraform { required_version = "1.11.2" required_providers { gitlab = { source = "gitlabhq/gitlab" version = "17.10.0" } } }
Providerとリソース定義。今回はまとめて書きました。
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" "my_group" { name = "my group" path = "my-group" } resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.my_group.id } resource "gitlab_project" "standalone_app" { name = "standalone-app" namespace_id = gitlab_user.standalone_user1.id } resource "gitlab_user" "my_group_admin1" { name = "my-group-admin1" username = "my-group-admin1" password = "P@ssw0rd" email = "my-group-admin1@example.com" namespace_id = gitlab_group.my_group.id } resource "gitlab_group_membership" "my_group_admin1" { group_id = gitlab_group.my_group.id user_id = gitlab_user.my_group_admin1.id access_level = "owner" } resource "gitlab_user" "my_group_user1" { name = "my-group-user1" username = "my-group-user1" password = "P@ssw0rd" email = "my-group-user1@example.com" namespace_id = gitlab_group.my_group.id } resource "gitlab_group_membership" "my_group_user1" { group_id = gitlab_group.my_group.id user_id = gitlab_user.my_group_user1.id access_level = "developer" } resource "gitlab_user" "standalone_user1" { name = "standalone-user1" username = "standalone-user1" password = "P@ssw0rd" email = "standalone-user1@example.com" } kazuhira@ikaruga:~/study/terraform/clover/gitlab-examples/gitlab-getting-started$ cat 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" "my_group" { name = "my group" path = "my-group" } resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.my_group.id } resource "gitlab_project" "standalone_app" { name = "standalone-app" namespace_id = gitlab_user.standalone_user1.id } resource "gitlab_user" "my_group_admin1" { name = "my-group-admin1" username = "my-group-admin1" password = "P@ssw0rd" email = "my-group-admin1@example.com" } resource "gitlab_group_membership" "my_group_admin1" { group_id = gitlab_group.my_group.id user_id = gitlab_user.my_group_admin1.id access_level = "owner" } resource "gitlab_user" "my_group_user1" { name = "my-group-user1" username = "my-group-user1" password = "P@ssw0rd" email = "my-group-user1@example.com" } resource "gitlab_group_membership" "my_group_user1" { group_id = gitlab_group.my_group.id user_id = gitlab_user.my_group_user1.id access_level = "developer" } resource "gitlab_user" "standalone_user1" { name = "standalone-user1" username = "standalone-user1" password = "P@ssw0rd" email = "standalone-user1@example.com" }
GitLab Providerの定義はこちらで、rootアカウントのアクセストークンは変数として定義しました。
variable "root_access_token" { type = string ephemeral = true } provider "gitlab" { token = var.root_access_token base_url = "http://192.168.0.6/" }
$ export TF_VAR_root_access_token=...
グループとプロジェクトを定義。
resource "gitlab_group" "my_group" { name = "my group" path = "my-group" } resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.my_group.id } resource "gitlab_project" "standalone_app" { name = "standalone-app" namespace_id = gitlab_user.standalone_user1.namespace_id }
namespace_id
は、プロジェクトがどのグループまたはユーザーに属するかを指定します。
省略すると、GitLab Providerを実行しているユーザーに属するプロジェクト(今回の場合はrootアカウント)になるようなので、
事実上必須で指定することになるのかなと思います。
ユーザーに属させる場合は、ユーザーのnamespace_id
を指定します。
グループに属するユーザーと、そうでないユーザーの定義。
resource "gitlab_user" "my_group_admin1" { name = "my-group-admin1" username = "my-group-admin1" password = "P@ssw0rd" email = "my-group-admin1@example.com" } resource "gitlab_group_membership" "my_group_admin1" { group_id = gitlab_group.my_group.id user_id = gitlab_user.my_group_admin1.id access_level = "owner" } resource "gitlab_user" "my_group_user1" { name = "my-group-user1" username = "my-group-user1" password = "P@ssw0rd" email = "my-group-user1@example.com" } resource "gitlab_group_membership" "my_group_user1" { group_id = gitlab_group.my_group.id user_id = gitlab_user.my_group_user1.id access_level = "developer" } resource "gitlab_user" "standalone_user1" { name = "standalone-user1" username = "standalone-user1" password = "P@ssw0rd" email = "standalone-user1@example.com" }
グループに属するユーザーとして定義する場合は、gitlab_group_membership
で設定します。またグループ内の役割は
access_level
で指定します。
gitlab_group_membership (Resource)
こんな感じで、あとはterraform init
してapply
してみます。
$ terraform init $ terraform apply
結果を見てみましょう。
rootアカウントで、GitLabのトップページからProjectsを見てみます。
グループ。
グループ内のユーザー。
なんか、rootアカウントがグループ内のユーザーに入っていますね…。作成した人が入ってしまうのか、管理者だから入って
しまうのか、どちらなんでしょう…。
グループから外すことはできそうですけどね。
それから、グループに属していないユーザーとプロジェクトはどこに行ったんでしょうか?
「Admin area」から見つけることができます。
グループに属しているユーザーでログインして確認。
グループに属していないユーザーでログインして確認。
こんなところでしょうか。
オマケ:サービスアカウントについて
今回は使えませんでしたが、サービスアカウントについてメモしておきます。
サービスアカウントというのは、個人に関連付けられていないタイプのマシンユーザーです。
A service account is a type of machine user that is not tied to an individual human user.
Service accounts | GitLab Docs
グループのメンバーとしても扱われますが、UIでログインすることができません。また、有効なメールアドレスを設定されて
いない限り、通知メールを受信することもないとされています。
つまり今回のTerraformによる構成管理のように、特定のユーザーがGitLabを管理していることを前提にせず、資格情報を
維持したい場合はサービスアカウントを使った方がよいということになります。
You should use service accounts in pipelines or integrations where credentials must be set up and maintained without being impacted by changes in human user membership.
ちなみに、個人のアクセストークンを使用するとそれはそれでサービスアカウントとして使えることにはなるようです。
You can authenticate as a service account with a personal access token. Service account users with a personal access token have the same abilities as a standard user. This includes interacting with registries and using the personal access token for Git operations.
サービスアカウントを作成するには、トップレベルのグループの管理者または(GitLab Self-Managedの場合は)インスタンスの
管理者である必要があります。
Service accounts / Create a service account
なのですが、それ以前にPremiumまたはUltimateプランである必要があるようです。
- On GitLab Free, service accounts are not available.
- On GitLab Premium, you can create one service account for every paid seat you have.
- On GitLab Ultimate, you can create an unlimited number of service accounts.
これに最初に気づかなくてTerraformでサービスアカウントを作ろうとして、以下のように404になって「???」となりました。
gitlab_instance_service_account.admin_service_account: Creating... ╷ │ Error: GitLab API error occurred │ │ with gitlab_instance_service_account.admin_service_account, │ on main.tf line 11, in resource "gitlab_instance_service_account" "admin_service_account": │ 11: resource "gitlab_instance_service_account" "admin_service_account" { │ │ Unable to create service account: 404 Not Found ╵
というわけで、自分の環境で扱う場合は個人ユーザーのアクセストークンを使うことになりますね。
おわりに
GitLabのリソースをTerraformで作成してみました。
ちょっと癖がある気はしますが、ソースコードとして定義できるのは便利なので使っていこうと思います。