TECHSTEP

ITインフラ関連の記事を公開してます。

GitLab Wikiの紹介

今回はGitLab Wikiを紹介します。

docs.gitlab.com

背景

GitLab WIkiはGItLab Projectで利用できるWikiページを提供する機能です。GitLab WikiMarkdown / AsciiDoc / Rdoc / Orgをサポートしているほか、Wikiのページはサイドバーに表示され、サイドバーは利用者がカスタマイズ可能です。またGitLab WikiはGitLab Webページ上で編集できるほか、Gitを使ってローカルから編集もできます。

GitLabドキュメントでは、Wikiを使うケースとして ドキュメントをリポジトリに置きたくないがProjectに置きたい場合 を挙げています。具体的なケースとしては、以下のようなものがあるかと思います。

  • README.md には書ききれない、長文にわたるコンテンツ( Projectの利用方法や設計など) を記載する
  • 開発中のコードの変更履歴とは分けて管理したドキュメント (運用・開発ルールなど) を記載する
  • OSSの場合は、製品の目的や解決する課題などを紹介する。

また、GItLab 16.10で Wiki Template というテンプレート機能が導入されました。これにより、特定のテーマに沿ったWikiページをテンプレートから作成し、一貫したフォーマットでドキュメントを作成することができます。

検証

Wikiページの作成

ここからWikiを簡単に試してみます。GitLabの画面では 計画 からWikiのメニューに移動します。

Wikiのページを初めて作成するときは以下のような画面が表示され、 最初のページを作成 を選択します。

Wikiページの作成画面は以下の通りです。タイトルやフォーマット、内容を入力します。またWikiはGitリポジトリとして扱われるので、コミットメッセージを指定する必要があります。

Home画面を作成すると、以下のように表示されます。新しいページの作成は 新しいページ を選択します。

ここでは Home 配下に test というページを追加します。

右側のサイドバーを見ると、 Home/test という階層構造でページを作成したのを確認できます。

また各ページは、ページの履歴の確認、PDF形式でのエクスポートができます。

ページの履歴 を押すと、以下のように履歴が表示されます。

古い履歴を選択すれば、その時のページが表示されます。なお見た限りですが、古い履歴の内容をリストアすることはできなさそうでした。

Wiki templateの利用

docs.gitlab.com

Wiki templateは、Wikiページの右サイドバーにある テンプレート から操作できます。

新しいテンプレートを New template から作成します。

テンプレート作成画面は以下の通りです。通常のWikiページを作成するのとほぼ同じ内容です。

ここでは適当に template01 というテンプレートを作成します。

テンプレート作成後にWikiページの作成・編集画面に移動すると、用意したテンプレートを指定することができます。

作成済みのページ上でテンプレートを使って上書きするときは、以下のようにメッセージが表示されます。

その他

GitLab WikiにはGroup WIkiという機能があります。これはGitLab Groupで利用できる機能で、Group内のProjectが作成したWIkiをProjectをまたいで閲覧・エクスポートできるものです。

なおGroup WikiはPremium以上のプランで利用できます。

GitLab Description templateでIssue/Merge requestのテンプレートを用意する

今回はGitLabのDescription templateの紹介です。

docs.gitlab.com

背景

GitLabには、あらかじめ用意したテンプレートを使い、GitLab上での作業をらくにする機能がいくつか提供されています。今回は Description template という、Issue template / Merge request template を提供する機能を紹介します。

Issue template / Merge request templateは、名前の通りIssue / Merge requestそれぞれのテンプレートを作成・利用する機能です。IssueやMerge requestに何を書くべきかをProjectやGroupレベルで定義することで、それぞれのコメントの粒度を揃え、品質の向上をもたらすことをサポートします。

なお、Description templateはFreeプランから利用できますが、一部機能はPremiumプラン以上でのみ利用可能です。

検証

Issue templateの作成と利用

Issue templateを用意するには、 .gitlab/issue_template 配下にMarkdown形式のテキストファイルを配置すれば利用できます。

ここでは .gitlab/issue_template/test.md というファイルを配置してみます。

ファイルを作成後にIssueの作成画面から新しいIssueを作成します。

ここで テンプレートを選択してください という項目を選択すると、Issue templateで用意したテンプレートの一覧が表示され、使いたいテンプレートを選ぶことができます。また、表示されるテンプレートの名称は、作成したMarkdownのファイル名と一致します。

先ほど作成した test というテンプレートを選択すると、 test.md に記載したものが出力されます。

後からIssue templateを追加すると、Issue作成時に表示されるテンプレートも追加されます。実際に利用する場合は、用途に応じてファイル名を変更し、適切なものを選択できるようにするのが良いでしょう。

Merge request templateの作成と利用

Merge request templateを用意するには、 .gitlab/merge_request_template 配下にMarkdown形式のテキストファイルを配置すれば利用できます。

先ほどのIssue templateと同様、 .gitlab/merge_request_template/test.md というファイルを作成します。

Merge request画面から新しいMerge requestを作成すると、 test というテンプレートを選択できます。

また、Issue / Merge request templateはデフォルトのテンプレートを用意することもできます。 .gitlab/merge_request_template/Default.md というファイルを作成すると、Merge request作成画面で Default.md に定義した内容が表示されます (別のテンプレートを選んで上書きすることもできます) 。

Default.md にはいくつか組み込みの変数を利用できます。変数を利用すると、Merge requestメッセージにコミットメッセージやソースブランチなどを埋め込むことができます。

docs.gitlab.com

ここでは以下のような Default.md を用意します。

作成後にMerge requestを作成すると、 Default.md で定義した内容が表示されます。また表示されたMerge requestには、コミットメッセージ、ソースブランチ、ターゲットブランチが表示されているのを確認できます。

その他

Description templateはPremium/Ultimateプランで以下の機能を利用できます。

  • Instance/Group-level description template: GitLabインスタンス、またはGroup共通のDescription templateを利用できます。
  • Default template: Default.md の設定とは別に、GitLabの設定からDefault templateを設定できます。

GitLabとActive Directoryを連携する

今回はGitLabとActive Directoryとを連携したユーザー管理の紹介です。

docs.gitlab.com

背景

以前GitLabのユーザーについて紹介しましたが、GitLabはLDAPと統合したユーザー認証機能を提供しています。GitLabとActive Directoryの連携はLDAPによるユーザー認証の1つです。Active Directoryと連携することで、組織に導入済みの認証基盤を利用しつつGitLabも利用できます。

検証

ここから実際にGitLabとADとの連携を行います。検証時の条件は以下の通りです。

  • GitLab: Self-managed版をAmazon EC2に構築
    • OS: Amazon Linux 2
    • サイズ: t3.xlarge
    • Session Managerでアクセスできるよう設定
  • Active DIrectory: Amazon EC2に構築
    • OS: Windows Server 2019
    • サイズ: t3.xlarge
    • ドメイン名: gitlab.domain.example.com
    • ユーザー: test01 test02 を作成
  • その他
    • GitLab / ADは同じサブネット上に作成

GitLabの設定変更

GitLabとLDAPを統合するには /etc/gitlab/gitlab.rb を修正し設定変更を行う必要があります。

# バックアップ用にコピーを作成
$ sudo cp /etc/gitlab/gitlab.rb /etc/gitlab/gitlab.rb_20240218

$ sudo vi /etc/gitlab/gitlab.rb

(以下のように修正)

### LDAP Settings
###! Docs: https://docs.gitlab.com/ee/administration/auth/ldap/index.html
###! **Be careful not to break the indentation in the ldap_servers block. It is
###!   in yaml format and the spaces must be retained. Using tabs will not work.**

gitlab_rails['ldap_enabled'] = true
gitlab_rails['prevent_ldap_sign_in'] = false

###! **remember to close this block with 'EOS' below**
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
  main: # 'main' is the GitLab 'provider ID' of this LDAP server
    label: 'LDAP'
    host: '<ADサーバーのIPアドレスを指定>'
    port: 389
    uid: 'sAMAccountName'
    bind_dn: 'CN=test01,CN=Users,DC=gitlab,DC=domain,DC=example,DC=com'
    password: '<bind_dnのユーザーのパスワードを指定>'
    encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
    verify_certificates: false
    smartcard_auth: false
    active_directory: true
    allow_username_or_email_login: true
    lowercase_usernames: false
    block_auto_created_users: false
    base: 'DC=gitlab,DC=domain,DC=example,DC=com'
    user_filter: ''
    ## EE only
    group_base: ''
    admin_group: ''
    sync_ssh_keys: false
#
#   secondary: # 'secondary' is the GitLab 'provider ID' of second LDAP server
#     label: 'LDAP'
#     host: '_your_ldap_server'
#     port: 389
#     uid: 'sAMAccountName'
#     bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
#     password: '_the_password_of_the_bind_user'
#     encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
#     verify_certificates: true
#     smartcard_auth: false
#     active_directory: true
#     allow_username_or_email_login: false
#     lowercase_usernames: false
#     block_auto_created_users: false
#     base: ''
#     user_filter: ''
#     ## EE only
#     group_base: ''
#     admin_group: ''
#     sync_ssh_keys: false
EOS

修正箇所を抜粋します。

  • host: ADのIPアドレス / ドメイン名を指定
  • bind_dn: BindするユーザーのDNを指定
  • password: bind_dnで指定したユーザーのパスワードを指定
  • verify_certificates: encryption が "start_tls" or "simple_tls"の場合はtrueに設定
  • allow_username_or_email_login: ログイン時にユーザーが送信したLDAPユーザー名の@以降を無視する
  • base: ベースとなるDNを指定

docs.gitlab.com

上記修正後、GitLabに反映します。

$ sudo gitlab-ctl reconfigure

(割愛)

gitlab Reconfigured!

GitLabへの反映を完了後にログイン画面を見ると、LDAPという項目が追加されています。

試しに test01 のログインを試すと、問題なくログインできます。

Authentication Logを見るとLDAPでの認証が行われた様子も記録されています。

rootユーザーで Admin Area からユーザーを確認すると、ログインした test01 が表示されます。

指定したLDAPの情報なども確認できます。

GitLabコンテナレジストリへのアクセス権限

今回はGitLabコンテナレジストリの権限周りについて整理しました。

docs.gitlab.com

背景

GitLabはProject/Groupごとにコンテナレジストリを提供する機能があります。GitLabはProject/Groupごとに、どのユーザーにどんな権限を付与するかをRoleで制御しますが、この制御にはコンテナレジストリに対する権限も含まれます。

一方、コンテナレジストリはRoleだけですべての権限が決まるわけではなく、どの設定が関係しているかが分かりにくいと感じることがありました。

今回は、GitLabのコンテナレジストリの権限に関連する設定を整理し、理解を深めていきたいと思います。

検証

今回は以下の3つについて整理しました。

GitLab Projectで設定するVisibility

まず、コンテナレジストリへのVisibilityはGitLab Projectの設定でコントロールしています。GitLab Projectは Public / Internal / Private の3種類の公開設定ができます。デフォルトではProjectにアクセスできるユーザー全員が閲覧可能 (Visible) ですが、設定によってProjectメンバーのみに制限することもできます。

Visibilityの設定は、GitLab画面から 設定一般 に移動し、可視性、プロジェクトの機能、権限 から変更します。変更は以下の2種類から選択できます。

  • Everyone with Access: Projectにアクセスできる全員が閲覧できます。
  • Only Project members: Projectに所属するメンバーであり、かつ Reporter 以上の権限を持つ人が閲覧できます。

以下がProjectのVisibilityの対応表です。最も広い公開設定は、Projectが PublicEveryone with Access の場合です。これはGitLabユーザー以外も含めたすべての人が閲覧可能です。

Project Registry Visibility Anonymous Guest Reporter/Developer/Maintainer/Owner
Public Everyone with Access
Only Project members
Internal Everyone with Access
Only Project members
Private Everyone with Access
Only Project members

Role

docs.gitlab.com

以前GitLabのRoleについて簡単にまとめましたが、GitLabはRoleに応じて各機能をどこまで利用できるかが決まります (Custom Roleを使えば、利用者が定義したRoleを作成できます) 。

コンテナレジストリに対するRoleは以下のような表にまとめられます。大まかにいえば、コンテナイメージの取得 (Pull) は誰でもできて、Push/DeleteはDeveloper以上、Cleanup policyのような管理系の機能はMaintainer以上のみ、という分類です。なおCleanup Policyとは、コンテナレジストリ上のイメージを、あるポリシーに従って定期的に削除する機能のことです。

Guest Reporter Developer Maintainer Owner
Pull image
Push image
Remove image
Create/Edit/Delete cleanup policy

アクセストーク

docs.gitlab.com

GitLabのコンテナレジストリに対し、イメージをPull / Pushするには、何かしらのトークンを使う必要があります。GitLabは以下の4種類のトークンを利用できます。

  • Personal access token : アカウント単位で発行・管理できるトーク
  • Deploy token : デプロイタスク専用のトーク
  • Project access token : 発行したProject専用のトーク
  • Group access token : 発行したGroup専用のトーク

いずれのトークンも、コンテナレジストリに対しては以下の権限を付与します。

  • イメージのPull: read_registry
  • イメージのPush: read_registry / write_registry

GitLab CLI (glab) を使ってみる

今回はGitLabが提供する glab というCLIツールを紹介します。

gitlab.com

背景

glabコマンドラインからGitLabの各種APIにアクセスすることで、Webブラウザを開くことなくGitLabの情報を確認する手段を提供します。例えばIssueを確認してタスクを確認したり、git push後にパイプラインが実行されたかチェックしたり、といった作業を実現できます。

glabはGitLab SaaS版 / Self-managed版のどちらでも利用可能です。また複数のGitLabインスタンスへの認証もサポートしています。

glabでは幅広いコマンドを利用できますが、こちらのドキュメントでCore commandとしているのは以下の18個です。

  • glab alias
  • glab api
  • glab auth
  • glab check-update
  • glab ci
  • glab completion
  • glab config
  • glab incident
  • glab issue
  • glab label
  • glab mr
  • glab release
  • glab repo
  • glab schedule
  • glab snippet
  • glab ssh-key
  • glab user
  • glab variable

検証

ここから検証ですが、glabを操作する場合、GitLabにログインするためPersonal Access Tokenの発行が必要です。

今回は glab-test というProjectを検証用に用意しました。また事前にIssueの登録と .gitlab-ci.yml の配置を完了しています。

インストール

まずは glab をインストールします。インストール方法は複数用意されていますが、ここではバイナリを取得する方法にしました。

gitlab.com

$ wget https://gitlab.com/gitlab-org/cli/-/releases/v1.36.0/downloads/glab_1.36.0_Linux_x86_64.tar.gz
$ tar -zxvf glab_1.36.0_Linux_x86_64.tar.gz 
LICENSE
README.md
bin/glab

$ sudo cp -p bin/glab /usr/local/bin/glab
$ glab version
glab version 1.36.0

インストールを完了したので、glabからGitLabにログインします。 glab auth login コマンドを実行すると、対話形式でログイン処理を進められます。

#対話形式でのログイン
#GitLab SaaSかSelf-managedか選択
$ glab auth login
? What GitLab instance do you want to log into?  [Use arrows to move, type to filter]
> gitlab.com
  GitLab Self-hosted Instance

#ログインをTokenかWebか選択
$ glab auth login
? What GitLab instance do you want to log into? gitlab.com
- Logging into gitlab.com
? How would you like to login?  [Use arrows to move, type to filter]
> Token
  Web

#Tokenの場合はここで入力
$ glab auth login
? What GitLab instance do you want to log into? gitlab.com
- Logging into gitlab.com
? How would you like to login? Token


Tip: you can generate a Personal Access Token here https://gitlab.com/-/profile/personal_access_tokens?scopes=api,write_repository
The minimum required scopes are 'api' and 'write_repository'.
? Paste your authentication token: 


#Gitプロトコルを選択
$ glab auth login
? What GitLab instance do you want to log into? gitlab.com
- Logging into gitlab.com
? How would you like to login? Token


Tip: you can generate a Personal Access Token here https://gitlab.com/-/profile/personal_access_tokens?scopes=api,write_repository
The minimum required scopes are 'api' and 'write_repository'.
? Paste your authentication token: **************************
? Choose default git protocol  [Use arrows to move, type to filter]
  SSH
> HTTPS
  HTTP


#GitLab credentialでのGit認証を許可
$ glab auth login
? What GitLab instance do you want to log into? gitlab.com
- Logging into gitlab.com
? How would you like to login? Token

Tip: you can generate a Personal Access Token here https://gitlab.com/-/profile/personal_access_tokens?scopes=api,write_repository
The minimum required scopes are 'api' and 'write_repository'.
? Paste your authentication token: **************************
? Choose default git protocol HTTPS
? Authenticate Git with your GitLab credentials? (Y/n) 


#ログイン完了
$ glab auth login
? What GitLab instance do you want to log into? gitlab.com
- Logging into gitlab.com
? How would you like to login? Token

Tip: you can generate a Personal Access Token here https://gitlab.com/-/profile/personal_access_tokens?scopes=api,write_repository
The minimum required scopes are 'api' and 'write_repository'.
? Paste your authentication token: **************************
? Choose default git protocol HTTPS
? Authenticate Git with your GitLab credentials? Yes
- glab config set -h gitlab.com git_protocol https
✓ Configured git protocol
- glab config set -h gitlab.com api_protocol https
✓ Configured API protocol
✓ Logged in as fy0323

GitLabにログインしたので、試しに glab repo list コマンドを実行し、リポジトリの一覧を出力してみます。

$ glab repo list
Showing 24 of 24 projects (Page 1 of 1)

fy0323/glab-test                      git@gitlab.com:fy0323/glab-test.git                      

(以降割愛)

glab repo view コマンドを実行すると、各リポジトリのREADME.mdの内容が確認できます。

$ glab repo view glab-test
Futa Yamaji / glab-test
(No description provided)


   glab-test                                                                  
                                                                              
  ## Getting started                                                          
                                                                              
  To make it easy for you to get started with GitLab, here's a list of        
  recommended next steps.                                                     

~~~

View this project on GitLab: https://gitlab.com/fy0323/glab-test

Issueの操作

続いてIssueのチェックをしてみます。作成済みのIssueの一覧を確認するには glab issue list コマンドを実行します。対象のIssueの詳細を見るには glab issue view コマンドを使用します。

$ glab issue list -R fy0323/glab-test
Showing 1 open issue in fy0323/glab-test that match your search (Page 1)

#1  fy0323/glab-test#1  test issue    about 6 minutes ago

$ glab issue view 1 -R fy0323/glab-test
open • opened by fy0323 about 6 minutes ago
test issue #1

  テスト用の文章                                                              



0 upvotes • 0 downvotes • 0 comments

View this issue on GitLab: https://gitlab.com/fy0323/glab-test/-/issues/1

次に新しいIssueの作成を行います。 glab issue create コマンドを実行すると、対話形式でIssueの作成を実施できます。

#templateがある場合は選択できるようですが、ここでは空のIssueのみ選択できます
$ glab issue create 
? Choose a template  [Use arrows to move, type to filter]
> Open a blank Issue

#Issueのタイトルを入力
$ glab issue create 
? Choose a template Open a blank Issue
? Title 

#Descriptionを追加
$ glab issue create 
? Choose a template Open a blank Issue
? Title test from glab
? Description [(e) or Enter to launch nano, (s) or Esc to skip] 

#そのまま提出するか、ブラウザに移動して操作を続けるか、などを選択
$ glab issue create 
? Choose a template Open a blank Issue
? Title test from glab
? Description <Received>
? What’s next?  [Use arrows to move, type to filter]
> Submit
  Continue in browser
  Add metadata
  Cancel

#作成完了
$ glab issue create 
? Choose a template Open a blank Issue
? Title test from glab
? Description <Received>
? What’s next? Submit
- Creating issue in fy0323/glab-test
#2 test from glab (less than a minute ago)
 https://gitlab.com/fy0323/glab-test/-/issues/2

#Issueの確認
$ glab issue list
Showing 2 open issues in fy0323/glab-test that match your search (Page 1)

#2  fy0323/glab-test#2  test from glab    less than a minute ago
#1  fy0323/glab-test#1  test issue        about 39 minutes ago  

Pipelineの操作

次にPipelineの操作を試します。

glabには glab ci lint というコマンドがあり、これを使うと .gitlab-ci.yml に対して構文チェックを実行できます。

$ glab ci lint
Validating...
✓ CI/CD YAML is valid!


#適当に修正してエラーを発生させる
$ glab ci lint
Validating...
.gitlab-ci.yml is invalid
1 jobs:lint-test-job configcontains unknown keys: stages

glabはPipelineの実行も可能です。 glab ci run コマンドでPipelineを起動後、 glab ci status コマンドで進行状況をリアルタイムにチェックすることもできます。

$ glab ci run
Created pipeline (id: 1163246103 ), status: created , ref: main , weburl:  https://gitlab.com/fy0323/glab-test/-/pipelines/1163246103 )
$ glab ci status --live
(created) • not started deploy          deploy-job
(created) • not started test            lint-test-job
(created) • not started test            unit-test-job
(running) • 00m 16s     build           build-job

https://gitlab.com/fy0323/glab-test/-/pipelines/1163246103
SHA: 82784a89350e52a26c2458ffae998a04b69db4e7
Pipeline State: running


#build Jobが成功
$ glab ci status --live
(created) • not started deploy          deploy-job
(running) • 00m 09s     test            lint-test-job
(running) • 00m 09s     test            unit-test-job
(success) • 00m 26s     build           build-job

https://gitlab.com/fy0323/glab-test/-/pipelines/1163246103
SHA: 82784a89350e52a26c2458ffae998a04b69db4e7
Pipeline State: running


#全てのJobが成功し、Pipelineが終了
$ glab ci status --live
(success) • 00m 27s     deploy          deploy-job
(success) • 00m 37s     test            lint-test-job
(success) • 01m 27s     test            unit-test-job
(success) • 00m 27s     deploy          deploy-job
(success) • 00m 37s     test            lint-test-job
(success) • 01m 27s     test            unit-test-job
(success) • 00m 26s     build           build-job

https://gitlab.com/fy0323/glab-test/-/pipelines/1163246103
SHA: 82784a89350e52a26c2458ffae998a04b69db4e7
Pipeline State: success

> Exit

終了後のPipeline情報も確認できます。

$ glab ci get
# Pipeline:
id:           1163246103                              
status:       success                                 
source:       api                                     
ref:          main                                    
sha:          82784a89350e52a26c2458ffae998a04b69db4e7
tag:          false                                   
yaml Errors:                                          
user:         fy0323                                  
created:      2024-02-03 09:04:58.737 +0000 UTC       
started:      2024-02-03 09:04:59.275 +0000 UTC       
updated:      2024-02-03 09:07:20.748 +0000 UTC       

# Jobs:
deploy-job:     success
lint-test-job:  success
unit-test-job:  success
build-job:      success

また glab ci view コマンドを使うと、CUIのような形式でPipeline/Jobの実行結果、実行時間、Jobのログなどを確認できます。

$ glab ci view


╔════════════════════════════════════════════════ Pipeline #1163246103 triggered about 9 minutes ago by Futa Yamaji ═════════════════════════════════════════════════╗
║  ╔════✔ build-job═════╗                               ┌──✔ unit-test-job───┐                               ┌────✔ deploy-job────┐                                  ║
║  ║                    ║                               │                    │                               │                    │                                  ║
║  ║             00m 26s║════════════════════════════╦══│             01m 27s│══╦════════════════════════════│             00m 27s│                                  ║
║  ╚════════════════════╝                            ║  └────────────────────┘  ║                            └────────────────────┘                                  ║
║                                                    ║                          ║                                                                                    ║
║                                                    ║  ┌──✔ lint-test-job───┐  ║                                                                                    ║
║                                                    ║  │                    │  ║                                                                                    ║
║                                                    ╚══│             00m 37s│══╝                                                                                    ║
║                                                       └────────────────────┘                                                                                       ║
║                                                                                                                                                                    ║
║                                                                                                                                                                    ║
║                                                                                                                                                                    ║
║                                                                                                                                                                    ║
╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

╔════════════════════════════════════════════════ Pipeline #1163246103 triggered about 9 minutes ago by Futa Yamaji ═════════════════════════════════════════════════╗
║                                                                                                                                                                    ║
║  ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗  ║
║  ║ Using docker image sha256:5cd1ffe2802975362ac267390dbf21810460e86b2e7ce5cb4b4870db9f579e6c for ruby:3.1 with digest ruby@sha256:e921f98b3211fee6789927e55f6c ║  ║
║  ║ cfcba583bb26565dbf3efb9c58ad072bc3a6 ...                                                                                                                     ║  ║
║  ║ $ echo "Compiling the code..."                                                                                                                               ║  ║
║  ║ Compiling the code...                                                                                                                                        ║  ║
║  ║ $ echo "Compile complete."                                                                                                                                   ║  ║
║  ║ Compile complete.                                                                                                                                            ║  ║
║  ║ Cleaning up project directory and file based variables                                                                                                       ║  ║
║  ║ Job succeeded                                                                                                                                                ║  ║
║  ║                                                                                                                                                              ║  ║
║  ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝  ║
║                                                                                                                                                                    ║
╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝

番外編: GitLab Duoとの連携

glabはGitLab Duoとも連携しており、 glab ask コマンドで自然言語によるサジェストを受けることができるようです。私はGitLab Duoを使える環境になかったため以下のようにエラーとなりましたが、良ければ試してみてください。

$ glab ask git list last 10 commit titles
x Error: API is unreachable error=POST https://gitlab.com/api/v4/ai/llm/git_command: 400 {message: 400 Bad request - AI features are not enabled or resource is not permitted to be sent.}

GitLab Container Scanningを実施する

今回はGitLabの提供するコンテナイメージのスキャン機能を検証します。

docs.gitlab.com

背景

GitLabのコンテナスキャン機能は、GitLab CI/CDでコンテナイメージスキャンのJobを実行し、レジストリに配置したイメージを検査して結果を出力します。

GitLabのコンテナスキャン機能は Trivy / Grype と統合しており、どちらかを利用、あるいはその他のツールを統合することも可能です。

※GrypeのサポートはGitLab 17.0で廃止されます

本機能を利用する方法は2通りあります。今回は1つ目の方法を検証します。

  • .gitlab-ci.ymlinclude:template を追加し、Jobを呼び出す
  • Auto DevOpsの提供するコンテナスキャンを使用する

コンテナスキャン機能を利用するには、いくつかの前提条件があります。

  • GitLab CI/CD上で実行する場合は test ステージで実行するため、 test ステージを含める必要があります。
  • GitLab Runnerは Docker / Kubernetes (Linux/amd64) のいずれかに対応しています。
  • Dockerは 18.09.03 以上のバージョンが必要です。Shared runnerを利用する場合は考慮不要です。
  • スキャン対象のコンテナは、サポートするディストリビューションとマッチしている必要があります。
  • スキャン対象はコンテナレジストリに配置されたものなので、CI/CDの中でBuild / Pushをする必要があります。
  • GitLabのコンテナレジストリ以外の外部レジストリを利用する場合、アクセスするための認証情報が必要となります。

検証

ここからコンテナスキャン機能を検証します。検証はGitLab SaaS版 (Freeプラン) で行っています。

GitLab Registryに配置したイメージをスキャン

まずはGitLab Registryに配置するイメージに対するスキャンを検証します。ここでは簡単なプログラムを含んだイメージをビルドし、それに対するスキャンを実行します。

利用する .gitlab-ci.yml は以下の通りです。

stages:
  - build
  - test

build:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

include:
  - template: Security/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

パイプラインを実行すると、 test ステージで container_scanning というJobが実行されます。

Jobの結果を見ると、スキャン結果を確認できます。

このJobの実行結果はアーティファクトとして保存されます。ここでは以下のファイルが格納されます。

  • artifacts.zip
  • metadata.gz
  • job.log

ファイルの中身の一部を載せておきます。

gl-container-scanning-report.json

{
    "vulnerabilities": [
                ...
        {
            "id": "cc2bfb8e198e16ce133e23745de34a762c89263e",
            "severity": "High",
            "location": {
                "dependency": {
                    "package": {
                        "name": "libcrypto1.1"
                    },
                    "version": "1.1.1q-r0"
                },
                "operating_system": "alpine 3.16.2",
                "image": "registry.gitlab.com/fy0323/container-scan-test:faa4979e"
            },
            "identifiers": [
                {
                    "type": "cve",
                    "name": "CVE-2023-0286",
                    "value": "CVE-2023-0286",
                    "url": "https://access.redhat.com/errata/RHSA-2023:2165"
                }
            ],
            "links": [
                {
                    "url": "https://access.redhat.com/errata/RHSA-2023:2165"
                },
                                ...
            ],
            "details": {
                "vulnerable_package": {
                    "name": "Vulnerable Package",
                    "type": "text",
                    "value": "libcrypto1.1:1.1.1q-r0"
                }
            },
            "description": "There is a type confusion vulnerability relating to X.400 address processing\ninside an X.509 GeneralName. X.400 addresses were parsed as an ASN1_STRING but\nthe public structure definition for GENERAL_NAME incorrectly specified the type\nof the x400Address field as ASN1_TYPE. This field is subsequently interpreted by\nthe OpenSSL function GENERAL_NAME_cmp as an ASN1_TYPE rather than an\nASN1_STRING.\n\nWhen CRL checking is enabled (i.e. the application sets the\nX509_V_FLAG_CRL_CHECK flag), this vulnerability may allow an attacker to pass\narbitrary pointers to a memcmp call, enabling them to read memory contents or\nenact a denial of service. In most cases, the attack requires the attacker to\nprovide both the certificate chain and CRL, neither of which need to have a\nvalid signature. If the attacker only controls one of these inputs, the other\ninput must already contain an X.400 address as a CRL distribution point, which\nis uncommon. As such, this vulnerability is most likely to only affect\napplications which have implemented their own functionality for retrieving CRLs\nover a network.\n\n",
            "solution": "Upgrade libcrypto1.1 to 1.1.1t-r0"
        },
                ...

外部レジストリに配置したイメージをスキャン

docs.gitlab.com

次は、Amazon ECRに格納したイメージをスキャンする例を実施します。今回は .gitlab-ci.ecr.yml という別の定義ファイルを用意し、CI/CDの設定を修正します。以前のAmazon ECSサービスを更新する記事の設定を流用しています。

.gitlab-ci.ecr.yml

stages:
  - build
  - test

build:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  before_script:
    - apk add --no-cache aws-cli
    - >
      export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
      $(aws sts assume-role-with-web-identity
      --role-arn ${AWS_IAM_ROLE}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token ${GITLAB_OIDC_TOKEN}
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
  script:
    - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ECR_LOGIN_URL
    - docker build -t $AWS_ECR_REPOSITORY:$CI_COMMIT_SHORT_SHA .
    - docker push $AWS_ECR_REPOSITORY:$CI_COMMIT_SHORT_SHA

include:
  - template: Security/Container-Scanning.gitlab-ci.yml

container_scanning:
  before_script:
    - ruby -r open-uri -e "IO.copy_stream(URI.open('https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip'), 'awscliv2.zip')"
    - unzip -q awscliv2.zip
    - sudo ./aws/install
    - aws --version
    - >
      export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
      $(aws sts assume-role-with-web-identity
      --role-arn ${AWS_IAM_ROLE}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token ${GITLAB_OIDC_TOKEN}
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
    - export AWS_ECR_PASSWORD=$(aws ecr get-login-password --region $AWS_DEFAULT_REGION)
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  variables:
    CS_IMAGE: $AWS_ECR_REPOSITORY:$CI_COMMIT_SHORT_SHA
    CS_REGISTRY_USER: AWS
    CS_REGISTRY_PASSWORD: $AWS_ECR_PASSWORD
    AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION

ただし、GitLabから外部レジストリ上のイメージをスキャンするために、IAMロールに権限を追加する必要があります。今回は以下の2つの権限を追加しています。

  • ecr:BatchGetImage
  • ecr:GetDownloadUrlForLayer

また、 .gitlab-ci.ecr.yml で使用する変数も追加しておきます。

設定が正しければ、パイプラインも問題なく実行されます。スキャン結果は先ほどと同様なので割愛します。

開発言語向けスキャンの有効化

docs.gitlab.com

GitLabのコンテナスキャンは、デフォルトではOSのパッケージに関する脆弱性のみを報告します。 CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN というCI/CD変数を false にセットすることで、開発言語に関する脆弱性も報告します。

ここでは .gitlab-ci.language.yml という定義ファイルを用意します。

.gitlab-ci.language.yml

stages:
  - build
  - test

build:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

include:
  - template: Security/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN: "false"

また、ここでは脆弱性を検知するため、こちらの記事にあるDockerfileを使用しました。

Dockerfileを修正してパイプラインを実行します。

スキャン結果を確認すると、確かにGo言語に関する脆弱性が報告されています。

Grypeの利用

docs.gitlab.com

GitLabのコンテナスキャンは、デフォルトではTrivyを利用します。 CS_ANALYZER_IMAGE で利用するイメージを指定すると、Grypeも利用できます。

ここでは .gitlab-ci.grype.yml に定義します。

stages:
  - build
  - test

build:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

include:
  - template: Security/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    CS_ANALYZER_IMAGE: registry.gitlab.com/security-products/container-scanning/grype:6

修正後にパイプラインを実行した結果を見ると、確かにTrivyとは異なる結果が表示されました。

その他

GitLab Ultimateプランを利用すると、以下の機能を利用できます。

  • 脆弱性レポートの表示先が増える: Merge Request や CI/CDパイプラインJobの Security タブから、脆弱性レポートを確認できます。
  • 脆弱性に対する自動修復: 脆弱性に対する修復案をGitLabが提案し、それを利用して修復できます。
  • 脆弱性の許可リスト: 脆弱性を許容するCVE IDをリストに登録し、検知を抑制できます。
  • セキュリティダッシュボード: 脆弱性チェックの結果を評価するためのダッシュボードが利用できます。
  • 依存関係のページ: プロジェクト・グループ間やSBoMによる依存関係のリストを利用できます。

GitLab roleを整理する

今回はGitLabで利用できるロールを簡単に整理します。

docs.gitlab.com

背景

GitLabユーザーをProject/Groupに追加するとき、ユーザーに対して何らかのRoleを付与します。Roleは、あらかじめ用意されたDefault Roleと、ユーザーが作成したCustomr Roleがあります。Custom RoleはUltimateプランでのみ利用できます。

docs.gitlab.com

Default Roleは以下の5種類です。簡単に言えば Guest が最も権限が弱く、 Owner が最も強い権限を持ちます。

  • Guest
  • Reporter
  • Developer
  • Maintainer
  • Owner

Roleは主にProject / Group / CI/CD設定という3つのリソースに対して割り当て、権限を付与します。Default roleが各リソースにどんな権限を付与するかは、以降で簡単に紹介します。

Projectメンバーの権限

Project内のユーザーに振り当てられるRoleは、Project上の操作権限をコントロールします。Owner roleは全ての権限を付与しますが、Owner roleは以下の場合にのみ付与されます。

  • Administratorの場合
  • Group/ProjectのOwnerの場合

また、Personal namespaceのOwnerは、GitLab 14.9より以前のバージョンの場合、該当のNamespaceではMaintainerと表示されますが、実際はOwner roleを持つユーザーと同じ権限を有します。

各Default roleにどんな権限が付与されるかですが、基本的に Guest / Reporter はView権限のみが付与され、Developer はProject管理関連の機能以外 (policy/ruleなど) はCreate権限も付与されています。Ownerは各種リソースのDelete権限も含め、すべての権限を所持します。

いくつかのリソースに対する権限を載せておきます。

リソース 操作 Guest Reporter Developer Maintainer Owner
Merge request View
Approve
Assign
Create
Delete
Project Download
Export
Rename
Archive
Delete
Container Registry Pull image
Push image
Remove image

全ての権限は以下のページに記載されています。

docs.gitlab.com

Groupメンバーの権限

Group内のユーザーに振り当てられるRoleは、Groupに対する操作権限をコントロールします。そのGroupの最後のOwnerでない限り、全てのユーザーは自身をGroupから削除することができます。

また、Subgroupにユーザーを追加すると、親Groupから権限レベルを受け継ぎます。また、いずれかの親Groupに属していれば、その配下のNested groupにアクセスできます。

いくつかのリソースに対する権限を載せておきます。

リソース 操作 Guest Reporter Developer Maintainer Owner
Group epic View
Create
Edit
Delete
Group View
Delete
Migrate
Subgroup Create

docs.gitlab.com

GitLab CI/CD権限

GitLab CI/CDの権限は、そのパイプラインを実行したユーザーの権限が反映されます。またCI/CDの権限は、いくつかのRoleについては以下の設定から修正できます。

  • Public pipelineに設定した場合、Guest Projectメンバーに一部機能へのアクセス許可を与えます。
  • Pipeline visibilityを Everyone with Access に設定した場合、Project外のメンバーにも一部CI/CDの View権限を付与します。

いくつかのリソースに対する権限を載せておきます。

リソース 操作 Guest Reporter Developer Maintainer Owner
Environment View
Create
Stop
Job View
Retry
Cancel

docs.gitlab.com

その他

Premium/Ultimateプランでは、以下の機能も利用できます。

  • Custom role : 利用者が使用したい権限を組み合わせてカスタマイズしたroleを作成・適用できます。Ultimateプランでのみ利用可能です。
  • Users with Minimal access : SAML SSOを使用する場合、Owner はユーザーに Minimal Access というRoleを付与できます。このRoleはユーザーにGroupのList権限を付与しますが、リソースやProjectなどの詳細は確認できません。

docs.gitlab.com

docs.gitlab.com

about.gitlab.com