0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プロジェクトアクセストークン、デプロイキー、デプロイトークンの使い分け

Posted at

プロジェクトアクセストークン、デプロイキー、デプロイトークンの使い分け

(トップページはこちら) - (プロジェクトで作業を整理する)

CI/CDパイプラインでコンテナイメージをプッシュしたい。外部サーバーからリポジトリをクローンしたい。APIを使ってIssueを自動作成したい。これらの自動化を実現する際、「どの認証方式を使えばいいのか」迷ったことはありませんか。

GitLab.comには3つの認証方式があり、それぞれ異なる目的に最適化されています。本記事では、プロジェクトアクセストークン、デプロイキー、デプロイトークンの特性を理解し、適切に使い分けるための実践的なガイドを提供します。

1. 3つの認証方式の基本

1.1 プロジェクトアクセストークン

プロジェクトアクセストークンは、GitLab APIとHTTP経由のGit操作に対応した、最も汎用性の高い認証方式です。

基本特性:

  • 提供形式: GitLabが生成するトークン文字列(作成時のみ表示)
  • プロトコル: HTTP/HTTPS
  • 利用可能ティア: Premium/Ultimate(トライアルでは1つのみ)
  • 有効期限: 必須(デフォルト30日、最大365日、GitLab 17.6以降は400日)
  • スコープ: プロジェクト単位

技術的な仕組み:

トークン作成時、GitLabは自動的にボットユーザーを生成します。このボットユーザーは以下の特徴を持ちます。

  • ユーザー名: project_{project_id}_bot_{random_string}
  • メールアドレス: project_{project_id}_bot_{random_string}@noreply.gitlab.com
  • 課金対象外(ライセンス数にカウントされない)
  • プロジェクトメンバーとして表示される

利用可能なスコープ:

スコープ 用途
api GitLab API全般(Issue、MR、設定変更など)
read_api GitLab APIの読み取り専用操作
read_repository Gitリポジトリのクローン、プル
write_repository Gitリポジトリへのプッシュ
read_registry コンテナイメージのプル
write_registry コンテナイメージのプッシュ
read_package_registry パッケージのダウンロード
write_package_registry パッケージの公開
create_runner ランナーの作成
manage_runner ランナーの管理
ai_features GitLab Duo機能の利用
k8s_proxy Kubernetes Agent経由のAPI呼び出し
self_rotate トークン自身のローテーション(GitLab 17.9以降)

1.2 デプロイキー

デプロイキーは、SSH経由でGitリポジトリにアクセスするための公開鍵認証方式です。

基本特性:

  • 提供形式: ユーザーが生成したSSH公開鍵をGitLabに登録
  • プロトコル: SSH
  • 利用可能ティア: 全ティア(Free、Premium、Ultimate)
  • 有効期限: オプション
  • スコープ: プロジェクト単位、または複数プロジェクト共有

2種類のデプロイキー:

権限レベル:

  • 読み取り専用: git clonegit pullのみ
  • 読み書き: git clonegit pullgit push

重要な注意点:

デプロイキーは作成者のユーザーアカウントに紐付きます。作成者がプロジェクトから削除されたり、ブロックされたりすると、デプロイキーの動作に影響が出る可能性があります。

1.3 デプロイトークン

デプロイトークンは、個人アカウントに依存せず、HTTP経由で複数のリソースにアクセスできる認証方式です。

基本特性:

  • 提供形式: GitLabが生成するユーザー名とトークンのペア(作成時のみ表示)
  • プロトコル: HTTP/HTTPS
  • 利用可能ティア: 全ティア(Free、Premium、Ultimate)
  • 有効期限: オプション(デフォルトなし)
  • スコープ: プロジェクト単位、またはグループ単位

デフォルトのユーザー名形式:

gitlab+deploy-token-{n}(カスタマイズ可能)

利用可能なスコープ:

スコープ 用途
read_repository Gitリポジトリのクローン
read_registry コンテナイメージのプル
write_registry コンテナイメージのプッシュ
read_package_registry パッケージのダウンロード
write_package_registry パッケージの公開
read_virtual_registry 依存関係プロキシ経由のイメージプル
write_virtual_registry 依存関係プロキシ経由のイメージプッシュ

特別な機能:gitlab-deploy-token

gitlab-deploy-tokenという名前でデプロイトークンを作成すると、CI/CDジョブで自動的に以下の環境変数として利用可能になります。

  • CI_DEPLOY_USER
  • CI_DEPLOY_PASSWORD

これにより、CI/CD設定ファイルに認証情報を記述する必要がなくなります。

2. 比較と選択基準

2.1 機能比較表

項目 プロジェクトアクセストークン デプロイキー デプロイトークン
プロトコル HTTP/HTTPS SSH HTTP/HTTPS
GitLab API × ×
Git操作
コンテナレジストリ ×
パッケージレジストリ ×
複数プロジェクト共有 × ○(公開キーのみ) ○(グループレベル)
ユーザー依存 ボットユーザー 作成者に依存 非依存
利用可能ティア Premium/Ultimate 全ティア 全ティア
有効期限 必須 オプション オプション
CI/CD自動変数 × × ○(特定名のみ)

2.2 選択フローチャート

2.3 ティア別の利用可能性

Freeティア:

  • デプロイキー: ○
  • デプロイトークン: ○
  • プロジェクトアクセストークン: ×

Premium/Ultimateティア:

  • デプロイキー: ○
  • デプロイトークン: ○
  • プロジェクトアクセストークン: ○

トライアルライセンス:

  • プロジェクトアクセストークン: 1つのみ作成可能

3. 実践的な使い分け

3.1 判断基準マトリクス

やりたいこと 推奨方式 理由
GitLab APIでIssue/MRを操作 プロジェクトアクセストークン API操作に対応しているのはこれのみ
CI/CDでコンテナイメージをプッシュ デプロイトークン(gitlab-deploy-token) CI/CD変数として自動利用可能
外部サーバーからSSHでクローン デプロイキー SSHプロトコルに対応
Kubernetesからイメージをプル デプロイトークン 長期的に安定、ユーザー非依存
複数プロジェクトに同じ鍵でアクセス 公開デプロイキー 一元管理が可能
グループ全体のパッケージにアクセス グループデプロイトークン グループスコープで効率的
ランナーの作成・管理 プロジェクトアクセストークン 専用スコープあり
読み取り専用のミラーリング デプロイキー(読み取り専用) 最小権限の原則

3.2 アクセス範囲による選択

4. 具体的なユースケース

4.1 CI/CDパイプラインでのコンテナイメージ管理

シナリオ:

マイクロサービスアーキテクチャで、各サービスのDockerイメージをビルドし、GitLabコンテナレジストリにプッシュします。

要件:

  • ソースコードの取得
  • Dockerイメージのビルド
  • コンテナレジストリへのプッシュ
  • CI/CD設定の簡素化

推奨方式: デプロイトークン(gitlab-deploy-token

実装:

# .gitlab-ci.yml
stages:
  - build
  - push

variables:
  DOCKER_DRIVER: overlay2
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build_image:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - echo "$CI_DEPLOY_PASSWORD" | docker login $CI_REGISTRY -u $CI_DEPLOY_USER --password-stdin
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
  only:
    - main
    - develop

メリット:

  • 認証情報をCI/CD変数に手動設定する必要がない
  • チームメンバーの変更に影響されない
  • トークンの管理が一元化される

4.2 外部ビルドサーバーからの継続的デプロイ

シナリオ:

社内のビルドサーバー(Jenkins、TeamCityなど)から、複数のGitLabプロジェクトのソースコードを取得してビルドします。

要件:

  • SSH経由でのアクセス
  • 複数プロジェクトへのアクセス
  • 読み取り専用で十分
  • セキュリティの確保

推奨方式: 公開デプロイキー(読み取り専用)

実装手順:

# 1. ビルドサーバー上でSSHキーペアを生成
ssh-keygen -t ed25519 -C "ビルドサーバー用デプロイキー" -f ~/.ssh/gitlab_deploy_key

# 2. 公開鍵の内容を確認
cat ~/.ssh/gitlab_deploy_key.pub

# 3. GitLab管理者が公開デプロイキーとして登録
# Admin Area > Deploy Keys > New deploy key

# 4. 各プロジェクトのMaintainerが有効化
# Project Settings > Repository > Deploy keys > Publicly accessible deploy keys > Enable

# 5. ビルドスクリプト
#!/bin/bash
export GIT_SSH_COMMAND="ssh -i ~/.ssh/gitlab_deploy_key -o StrictHostKeyChecking=no"

# プロジェクトAのビルド
git clone git@gitlab.com:組織名/プロジェクトA.git
cd プロジェクトA
make build
cd ..

# プロジェクトBのビルド
git clone git@gitlab.com:組織名/プロジェクトB.git
cd プロジェクトB
make build

メリット:

  • 1つのSSHキーで複数プロジェクトにアクセス
  • 読み取り専用で最小権限を実現
  • プロジェクトごとに個別に有効化/無効化可能

4.3 自動化スクリプトによるプロジェクト管理

シナリオ:

定期的に実行されるスクリプトで、Issueの自動作成、ラベルの整理、マイルストーンの管理を行います。

要件:

  • GitLab APIへのアクセス
  • Issue/MRの作成・更新
  • プロジェクト設定の読み取り
  • 定期実行(cron)

推奨方式: プロジェクトアクセストークン(apiスコープ)

実装:

#!/usr/bin/env python3
import requests
from datetime import datetime, timedelta

GITLAB_URL = "https://gitlab.com"
PROJECT_ID = "12345"
TOKEN = "glpat-xxxxxxxxxxxxxxxxxxxx"

headers = {"PRIVATE-TOKEN": TOKEN}

def create_weekly_maintenance_issue():
    """週次メンテナンスIssueを自動作成"""
    next_week = datetime.now() + timedelta(days=7)
    due_date = next_week.strftime("%Y-%m-%d")
    
    issue_data = {
        "title": f"週次メンテナンス {next_week.strftime('%Y年%m月%d日')}",
        "description": """
## 実施項目
- [ ] 依存パッケージの更新確認
- [ ] セキュリティスキャン結果の確認
- [ ] ログの確認
- [ ] パフォーマンスメトリクスの確認
        """,
        "labels": "メンテナンス,定期作業",
        "due_date": due_date,
        "assignee_ids": [123]  # 担当者ID
    }
    
    response = requests.post(
        f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/issues",
        headers=headers,
        json=issue_data
    )
    
    if response.status_code == 201:
        issue = response.json()
        print(f"Issue作成成功: {issue['web_url']}")
        return issue
    else:
        print(f"エラー: {response.status_code} - {response.text}")
        return None

def close_old_issues():
    """30日以上更新されていないIssueを自動クローズ"""
    thirty_days_ago = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%dT%H:%M:%SZ")
    
    # 古いIssueを検索
    params = {
        "state": "opened",
        "updated_before": thirty_days_ago,
        "labels": "自動クローズ対象"
    }
    
    response = requests.get(
        f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/issues",
        headers=headers,
        params=params
    )
    
    if response.status_code == 200:
        issues = response.json()
        for issue in issues:
            # Issueをクローズ
            close_response = requests.put(
                f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/issues/{issue['iid']}",
                headers=headers,
                json={"state_event": "close"}
            )
            
            if close_response.status_code == 200:
                print(f"Issue #{issue['iid']} をクローズしました")
            
            # クローズコメントを追加
            comment_data = {
                "body": "30日間更新がなかったため、自動的にクローズしました。"
            }
            requests.post(
                f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/issues/{issue['iid']}/notes",
                headers=headers,
                json=comment_data
            )

if __name__ == "__main__":
    create_weekly_maintenance_issue()
    close_old_issues()

cron設定:

# 毎週月曜日の9時に実行
0 9 * * 1 /usr/local/bin/python3 /path/to/gitlab_automation.py

メリット:

  • API操作に必要な権限を細かく制御
  • ボットユーザーとして動作するため、人間のアクションと区別可能
  • 有効期限があるため、定期的な見直しが促される

4.4 Kubernetesクラスタでのプライベートイメージ利用

シナリオ:

複数のKubernetes Namespaceで、GitLabコンテナレジストリのプライベートイメージを使用します。グループ内の複数プロジェクトのイメージにアクセスする必要があります。

要件:

  • プライベートコンテナレジストリからのイメージpull
  • 複数Namespaceでの利用
  • グループ内の複数プロジェクトのイメージにアクセス
  • 長期的に安定した認証

推奨方式: グループレベルのデプロイトークン(read_registryスコープ)

実装手順:

# 1. GitLab UIでグループレベルのデプロイトークンを作成
# Group Settings > Repository > Deploy tokens
# Name: k8s-image-pull
# Scopes: read_registry

# 2. トークン情報を環境変数に設定
DEPLOY_TOKEN_USERNAME="gitlab+deploy-token-123"
DEPLOY_TOKEN="xxxxxxxxxxxxxxxxxxxx"

# 3. 各Namespaceにdocker-registry Secretを作成
for namespace in production staging development; do
  kubectl create secret docker-registry gitlab-registry \
    --docker-server=registry.gitlab.com \
    --docker-username=$DEPLOY_TOKEN_USERNAME \
    --docker-password=$DEPLOY_TOKEN \
    --namespace=$namespace
done

# 4. ServiceAccountにImagePullSecretを設定(オプション)
kubectl patch serviceaccount default \
  -p '{"imagePullSecrets": [{"name": "gitlab-registry"}]}' \
  --namespace=production

Deployment例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ウェブアプリ
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ウェブアプリ
  template:
    metadata:
      labels:
        app: ウェブアプリ
    spec:
      # 方法1: Deployment内で明示的に指定
      imagePullSecrets:
        - name: gitlab-registry
      containers:
        - name: アプリ
          image: registry.gitlab.com/組織名/プロジェクトA/ウェブアプリ:v1.2.3
          ports:
            - containerPort: 8080
        - name: サイドカー
          image: registry.gitlab.com/組織名/プロジェクトB/監視エージェント:latest
          ports:
            - containerPort: 9090

メリット:

  • グループ内の全プロジェクトのイメージにアクセス可能
  • ユーザーアカウントに依存しない
  • 有効期限なしで長期運用可能(必要に応じて設定も可能)
  • 複数Namespaceで同じSecretを再利用

4.5 パッケージレジストリへの自動公開

シナリオ:

CI/CDパイプラインで、NuGetパッケージをビルドし、GitLabパッケージレジストリに公開します。

要件:

  • パッケージのビルド
  • パッケージレジストリへの公開
  • バージョン管理
  • CI/CD統合

推奨方式: デプロイトークン(write_package_registryスコープ)

実装:

# .gitlab-ci.yml
stages:
  - build
  - publish

variables:
  PACKAGE_VERSION: "1.0.$CI_PIPELINE_IID"
  NUGET_SOURCE: "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json"

build_package:
  stage: build
  image: mcr.microsoft.com/dotnet/sdk:8.0
  script:
    - dotnet restore
    - dotnet build --configuration Release
    - dotnet pack --configuration Release -p:PackageVersion=$PACKAGE_VERSION --output ./packages
  artifacts:
    paths:
      - packages/*.nupkg
    expire_in: 1 week

publish_package:
  stage: publish
  image: mcr.microsoft.com/dotnet/sdk:8.0
  dependencies:
    - build_package
  script:
    # デプロイトークンを使用してNuGetソースを追加
    - dotnet nuget add source $NUGET_SOURCE 
        --name GitLab 
        --username $DEPLOY_TOKEN_USER 
        --password $DEPLOY_TOKEN 
        --store-password-in-clear-text
    # パッケージを公開
    - dotnet nuget push "packages/*.nupkg" --source GitLab
  only:
    - tags
    - main

CI/CD変数設定:

DEPLOY_TOKEN_USER: gitlab+deploy-token-456
DEPLOY_TOKEN: xxxxxxxxxxxxxxxxxxxx (Masked)

パッケージの利用側:

# 開発者のローカル環境でパッケージを利用
dotnet nuget add source https://gitlab.com/api/v4/projects/12345/packages/nuget/index.json \
  --name GitLab \
  --username gitlab+deploy-token-456 \
  --password xxxxxxxxxxxxxxxxxxxx

dotnet add package MyCompany.MyPackage --version 1.0.42

メリット:

  • パッケージの公開と取得に同じトークンを使用可能
  • CI/CD変数として管理しやすい
  • グループレベルで作成すれば、複数プロジェクトで共有可能

5. セキュリティベストプラクティス

5.1 共通の原則

5.1.1 最小権限の原則

必要最小限のスコープのみを付与します。

悪い例:

# すべての権限を持つトークン
スコープ: api, read_repository, write_repository, read_registry, write_registry

良い例:

# コンテナイメージのプルのみ
スコープ: read_registry

# パッケージの公開のみ
スコープ: write_package_registry

5.1.2 有効期限の設定

可能な限り有効期限を設定し、定期的にローテーションします。

推奨設定:

  • 開発環境: 30日
  • ステージング環境: 90日
  • 本番環境: 180日(最大365日)

5.1.3 命名規則の統一

トークンの用途が一目でわかる名前を付けます。

推奨命名パターン:

{環境}_{用途}_{作成日}

例:
- prod_container_push_2024-01
- staging_api_automation_2024-01
- dev_package_publish_2024-01

5.2 プロジェクトアクセストークン固有の注意点

5.2.1 内部プロジェクトへのアクセス

内部ユーザーが作成したプロジェクトアクセストークンは、可視性レベルが「Internal」のすべてのプロジェクトにアクセス可能です。

対策:

  • プロジェクトの可視性レベルを適切に設定
  • 必要に応じてPrivateに変更
  • トークンのスコープを厳密に制限

5.2.2 ボットユーザーの管理

ボットユーザーはプロジェクトメンバーとして表示されます。

確認方法:

Project Settings > Members

ボットユーザーは以下の形式で表示されます。

project_12345_bot_a1b2c3d4 (Bot)

5.2.3 有効期限通知の活用

GitLab 17.6以降、以下のタイミングでメール通知が送信されます。

  • 60日前
  • 30日前
  • 7日前

通知先:

  • プロジェクトのMaintainer以上のロール
  • GitLab 17.7以降、継承されたOwner/Maintainerも対象(設定による)

5.3 デプロイキー固有の注意点

5.3.1 サービスアカウントの使用

個人アカウントではなく、サービスアカウントでデプロイキーを作成します。

理由:

  • 個人の退職や異動による影響を回避
  • 権限管理の明確化
  • 監査ログの追跡が容易

実装手順:

API実行例:

# 1. グループサービスアカウントの作成
curl --request POST \
  --header "PRIVATE-TOKEN: <管理者トークン>" \
  --data "name=デプロイ用サービスアカウント&username=deploy_service" \
  "https://gitlab.com/api/v4/groups/456/service_accounts"

# レスポンス例:
# {
#   "id": 789,
#   "username": "deploy_service",
#   "name": "デプロイ用サービスアカウント"
# }

# 2. サービスアカウント用のパーソナルアクセストークンを作成
curl --request POST \
  --header "PRIVATE-TOKEN: <管理者トークン>" \
  --data "name=deploy_key_management&scopes[]=api" \
  "https://gitlab.com/api/v4/service_accounts/789/personal_access_tokens"

# 3. サービスアカウントをプロジェクトに招待(UI操作)

# 4. サービスアカウントのトークンを使用してデプロイキーを作成
curl --request POST \
  --header "PRIVATE-TOKEN: <サービスアカウントのトークン>" \
  --header "Content-Type: application/json" \
  --data '{
    "title": "本番環境デプロイキー",
    "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILx...",
    "can_push": true
  }' \
  "https://gitlab.com/api/v4/projects/12345/deploy_keys"

5.3.2 保護ブランチへのプッシュ権限

デプロイキーで保護ブランチにプッシュするには、作成者が適切な権限を持っている必要があります。

確認項目:

  • 作成者がプロジェクトメンバーである
  • 作成者がMaintainer以上のロールを持つ
  • デプロイキーに書き込み権限がある
  • 保護ブランチ設定で「Allowed to push」が適切に設定されている

保護ブランチ設定例:

Settings > Repository > Protected branches

Branch: main
Allowed to merge: Maintainers
Allowed to push: Maintainers + Deploy keys with write access

5.4 デプロイトークン固有の注意点

5.4.1 有効期限なしトークンの管理

デプロイトークンはデフォルトで有効期限がありません。

推奨事項:

  • 本番環境でも可能な限り有効期限を設定
  • 有効期限なしの場合、定期的な棚卸しを実施(四半期ごとなど)
  • 使用されていないトークンは即座にリボーク

棚卸しチェックリスト:

## デプロイトークン棚卸し(2024年Q1)

### プロジェクトA
- [ ] k8s-image-pull: 使用中(Kubernetes本番環境)
- [ ] ci-package-push: 使用中(CI/CDパイプライン)
- [ ] old-deploy-token: 未使用 → リボーク済み

### プロジェクトB
- [ ] docker-registry: 使用中(外部サーバー)
- [ ] test-token: 未使用 → リボーク済み

5.4.2 CI/CDランナーのセキュリティ

gitlab-deploy-tokenを使用する場合、ランナーのセキュリティ設定が重要です。

避けるべき設定:

# 悪い例: privilegedモードの使用
services:
  - docker:dind

variables:
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""

build:
  image: docker:latest
  script:
    - docker build --privileged -t $CI_REGISTRY_IMAGE .  # 危険

推奨設定:

# 良い例: 必要最小限の権限
services:
  - docker:dind

variables:
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: "/certs"

build:
  image: docker:latest
  script:
    - docker build -t $CI_REGISTRY_IMAGE .

ランナー設定(config.toml):

[[runners]]
  name = "secure-runner"
  executor = "docker"
  
  [runners.docker]
    privileged = false  # privilegedモードを無効化
    volumes = ["/cache", "/certs/client"]
    
  [runners.cache]
    Type = "s3"
    Shared = true

5.5 トークン漏洩時の対応手順

監査ログの確認方法:

Project Settings > Audit Events

確認項目:

  • トークンを使用したAPI呼び出し
  • Gitプッシュ/プル操作
  • レジストリへのアクセス
  • 設定変更

6. ライフサイクル管理

6.1 作成フェーズ

6.1.1 作成時のチェックリスト

プロジェクトアクセストークン:

- [ ] トークン名: {環境}_{用途}_{作成日}
- [ ] 説明: 用途、使用場所、担当者を記載
- [ ] 有効期限: 30〜365日(用途に応じて)
- [ ] ロール: 必要最小限(Guest/Reporter/Developer/Maintainer/Owner)
- [ ] スコープ: 必要最小限のみ選択
- [ ] 作成後: トークン値を安全に保管(1Password、Vault等)
- [ ] ドキュメント: 社内Wikiやドキュメントに記録

デプロイキー:

- [ ] キー名: {環境}_{用途}_{作成日}
- [ ] SSHキー: ed25519形式で生成
- [ ] 権限: 読み取り専用 or 読み書き
- [ ] 有効期限: 設定する場合は記載
- [ ] 作成者: サービスアカウント推奨
- [ ] 秘密鍵: 安全に保管(使用サーバーのみ)
- [ ] 公開鍵: GitLabに登録

デプロイトークン:

- [ ] トークン名: {環境}_{用途}_{作成日}
- [ ] ユーザー名: カスタマイズする場合は記載
- [ ] 有効期限: 可能な限り設定
- [ ] スコープ: 必要最小限のみ選択
- [ ] レベル: プロジェクト or グループ
- [ ] 作成後: ユーザー名とトークンを安全に保管
- [ ] CI/CD変数: 必要に応じて設定

6.2 運用フェーズ

6.2.1 定期的な棚卸し

月次チェック:

  • 有効期限が30日以内のトークンを確認
  • 更新が必要なトークンをリストアップ

四半期チェック:

  • 全トークンの使用状況を確認
  • 未使用トークンをリボーク
  • トークン一覧をドキュメント更新

棚卸しスクリプト例:

#!/usr/bin/env python3
import requests
from datetime import datetime, timedelta

GITLAB_URL = "https://gitlab.com"
PROJECT_ID = "12345"
TOKEN = "glpat-xxxxxxxxxxxxxxxxxxxx"

headers = {"PRIVATE-TOKEN": TOKEN}

def check_project_access_tokens():
    """プロジェクトアクセストークンの有効期限をチェック"""
    response = requests.get(
        f"{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/access_tokens",
        headers=headers
    )
    
    if response.status_code == 200:
        tokens = response.json()
        now = datetime.now()
        
        print("=== プロジェクトアクセストークン一覧 ===\n")
        
        for token in tokens:
            name = token['name']
            expires_at = datetime.fromisoformat(token['expires_at'].replace('Z', '+00:00'))
            days_until_expiry = (expires_at - now).days
            
            status = "正常"
            if days_until_expiry < 0:
                status = "期限切れ"
            elif days_until_expiry < 7:
                status = "要更新(7日以内)"
            elif days_until_expiry < 30:
                status = "要注意(30日以内)"
            
            print(f"名前: {name}")
            print(f"有効期限: {expires_at.strftime('%Y-%m-%d')}")
            print(f"残り日数: {days_until_expiry}")
            print(f"ステータス: {status}")
            print(f"スコープ: {', '.join(token['scopes'])}")
            print("-" * 50)

if __name__ == "__main__":
    check_project_access_tokens()

6.2.2 監視とアラート

監視項目:

  • トークンの使用頻度
  • 異常なアクセスパターン
  • 有効期限切れ間近のトークン
  • 失敗したアクセス試行

GitLab監査イベントの活用:

Project Settings > Audit Events

フィルタ:
- Event Type: Token
- Date Range: 過去30日

6.3 更新・ローテーションフェーズ

6.3.1 プロジェクトアクセストークンのローテーション

GitLab 17.9以降、self_rotateスコープを持つトークンは自動ローテーション可能です。

手動ローテーション手順:

API経由のローテーション(GitLab 17.9以降):

# self_rotateスコープを持つトークンの自動ローテーション
curl --request POST \
  --header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxxxxxxxxxx" \
  "https://gitlab.com/api/v4/personal_access_tokens/self/rotate"

# レスポンス例:
# {
#   "id": 123,
#   "name": "prod_api_automation_2024-01",
#   "revoked": false,
#   "created_at": "2024-01-15T10:00:00.000Z",
#   "scopes": ["api", "self_rotate"],
#   "user_id": 456,
#   "last_used_at": "2024-03-10T14:30:00.000Z",
#   "active": true,
#   "expires_at": "2024-07-15",
#   "token": "glpat-yyyyyyyyyyyyyyyyyyyy"  # 新しいトークン
# }

6.3.2 デプロイキーのローテーション

手順:

# 1. 新しいSSHキーペアを生成
ssh-keygen -t ed25519 -C "デプロイキー_2024-04" -f ~/.ssh/gitlab_deploy_key_new

# 2. 新しい公開鍵をGitLabに登録(UI操作)

# 3. 使用箇所で新しい秘密鍵をテスト
export GIT_SSH_COMMAND="ssh -i ~/.ssh/gitlab_deploy_key_new"
git clone git@gitlab.com:組織名/プロジェクト名.git

# 4. 正常動作を確認後、すべての使用箇所を更新

# 5. 旧デプロイキーを無効化(UI操作)

# 6. 旧秘密鍵を削除
rm ~/.ssh/gitlab_deploy_key

6.3.3 デプロイトークンのローテーション

手順:

# 1. 新しいデプロイトークンを作成(UI操作)

# 2. CI/CD変数を更新
# Settings > CI/CD > Variables
# DEPLOY_TOKEN_USER: 新しいユーザー名
# DEPLOY_TOKEN: 新しいトークン

# 3. パイプラインを実行して動作確認

# 4. Kubernetes Secretを更新(該当する場合)
kubectl delete secret gitlab-registry --namespace=production
kubectl create secret docker-registry gitlab-registry \
  --docker-server=registry.gitlab.com \
  --docker-username=新しいユーザー名 \
  --docker-password=新しいトークン \
  --namespace=production

# 5. 旧デプロイトークンをリボーク(UI操作)

6.4 廃止フェーズ

6.4.1 リボーク手順

プロジェクトアクセストークン:

Project Settings > Access tokens > Active tokens > Revoke

リボーク後、30日間は非アクティブトークンとして保持され、その後自動削除されます。

デプロイキー:

Project Settings > Repository > Deploy keys > Disable

デプロイトークン:

Project Settings > Repository > Deploy tokens > Revoke

6.4.2 リボーク後の確認事項

- [ ] 監査ログで最終使用日時を確認
- [ ] 関連するCI/CD変数を削除
- [ ] Kubernetes Secretを削除(該当する場合)
- [ ] ドキュメントから削除
- [ ] 秘密鍵/トークン値を安全に削除

7. トラブルシューティング

7.1 プロジェクトアクセストークン関連

7.1.1 トークンが作成できない

症状:

「You don't have permission to create project access tokens」というエラーが表示される。

原因と対策:

原因 対策
Freeティアを使用している Premium/Ultimateにアップグレード
トライアルで既に1つ作成済み 既存トークンを削除してから作成
グループ設定で制限されている グループオーナーに設定変更を依頼
Maintainer権限がない プロジェクトオーナーに権限付与を依頼

グループ設定の確認:

Group Settings > General > Permissions and group features
> Users can create project access tokens and group access tokens in this group

7.1.2 APIアクセスが403エラーになる

症状:

curl --header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxxxxxxxxxx" \
  "https://gitlab.com/api/v4/projects/12345/issues"

# レスポンス:
# {"message":"403 Forbidden"}

原因と対策:

原因 対策
apiスコープがない apiまたはread_apiスコープを持つトークンを作成
トークンが期限切れ 新しいトークンを作成
プロジェクトIDが間違っている 正しいプロジェクトIDを確認
ボットユーザーの権限不足 トークン作成時のロールを上げる

スコープの確認:

Project Settings > Access tokens > Active tokens

7.1.3 内部プロジェクトに意図せずアクセスできる

症状:

作成したトークンで、他の内部プロジェクトにもアクセスできてしまう。

原因:

内部ユーザーが作成したプロジェクトアクセストークンは、可視性レベルが「Internal」のすべてのプロジェクトにアクセス可能です。

対策:

  1. プロジェクトの可視性を「Private」に変更
  2. トークンのスコープを最小限に制限
  3. 必要に応じてサービスアカウントを使用

7.2 デプロイキー関連

7.2.1 保護ブランチにプッシュできない

症状:

git push origin main

# エラー:
# remote: GitLab: You are not allowed to push code to protected branches on this project.

原因と対策:

原因 対策
デプロイキーが読み取り専用 書き込み権限を付与
作成者がプロジェクトメンバーでない サービスアカウントで再作成
作成者の権限が不足 Maintainer以上の権限を付与
保護ブランチ設定で許可されていない 「Allowed to push」にデプロイキーを追加

保護ブランチ設定の確認:

Settings > Repository > Protected branches

Branch: main
Allowed to push: Maintainers + Deploy keys with write access

サービスアカウントを使用した解決策:

# 1. グループサービスアカウントを作成(API)
curl --request POST \
  --header "PRIVATE-TOKEN: <管理者トークン>" \
  --data "name=デプロイ用SA&username=deploy_sa" \
  "https://gitlab.com/api/v4/groups/456/service_accounts"

# 2. サービスアカウント用のPATを作成

# 3. サービスアカウントをプロジェクトにMaintainerとして招待

# 4. サービスアカウントのPATを使用してデプロイキーを作成
curl --request POST \
  --header "PRIVATE-TOKEN: <サービスアカウントのPAT>" \
  --header "Content-Type: application/json" \
  --data '{
    "title": "本番デプロイキー",
    "key": "ssh-ed25519 AAAA...",
    "can_push": true
  }' \
  "https://gitlab.com/api/v4/projects/12345/deploy_keys"

7.2.2 デプロイキーが突然使えなくなった

症状:

以前は動作していたデプロイキーで、突然アクセスできなくなった。

原因と対策:

原因 対策
作成者がブロックされた サービスアカウントで再作成
作成者がプロジェクトから削除された サービスアカウントで再作成
デプロイキーが無効化された 再度有効化、または新規作成
有効期限が切れた 新しいデプロイキーを作成

使用できないデプロイキーの特定(Self-Managed限定):

Rails Consoleで以下のスクリプトを実行します。

DeployKeysProject.with_write_access.find_each do |deploy_key_mapping|
  project = deploy_key_mapping.project
  deploy_key = deploy_key_mapping.deploy_key
  user = deploy_key.user

  access_checker = Gitlab::DeployKeyAccess.new(deploy_key, container: project)

  can_push = access_checker.can_do_action?(:push_code)
  can_push_to_default = access_checker.can_push_for_ref?(project.repository.root_ref)

  next if access_checker.allowed? && can_push && can_push_to_default

  if user.nil? || user.ghost?
    username = 'なし'
    state = '-'
  else
    username = user.username
    user_state = user.state
  end

  puts "デプロイキー: #{deploy_key.id}, プロジェクト: #{project.full_path}, " \
       "プッシュ可能?: #{can_push ? 'はい' : 'いいえ'}, " \
       "デフォルトブランチへのプッシュ可能?: #{can_push_to_default ? 'はい' : 'いいえ'}, " \
       "ユーザー: #{username}, ユーザー状態: #{user_state}"
end

7.2.3 公開デプロイキーが有効化できない

症状:

公開デプロイキーを有効化しようとすると、エラーが表示される。

原因と対策:

原因 対策
Maintainer権限がない プロジェクトオーナーに依頼
同じ公開鍵が既に登録されている 既存のデプロイキーを確認
公開デプロイキーが存在しない 管理者に公開デプロイキーの作成を依頼

7.3 デプロイトークン関連

7.3.1 コンテナレジストリにログインできない

症状:

echo "$DEPLOY_TOKEN" | docker login -u $DEPLOY_TOKEN_USER --password-stdin registry.gitlab.com

# エラー:
# Error response from daemon: Get https://registry.gitlab.com/v2/: unauthorized

原因と対策:

原因 対策
read_registryスコープがない 正しいスコープを持つトークンを作成
ユーザー名が間違っている 正しいユーザー名を確認(gitlab+deploy-token-{n}
トークンが間違っている トークン値を再確認(作成時のみ表示)
トークンがリボークされている 新しいトークンを作成
プロジェクトがプライベートでない プロジェクトの可視性を確認

正しいユーザー名の確認:

Project Settings > Repository > Deploy tokens > Active Deploy Tokens

7.3.2 CI/CDで環境変数が利用できない

症状:

gitlab-deploy-tokenを作成したが、CI_DEPLOY_USERCI_DEPLOY_PASSWORDが利用できない。

原因と対策:

原因 対策
トークン名が正確にgitlab-deploy-tokenでない 正確な名前で再作成
グループレベルで作成している プロジェクトレベルで作成
GitLabバージョンが古い GitLab 15.1以降にアップグレード

正しい作成方法:

Project Settings > Repository > Deploy tokens

Name: gitlab-deploy-token(正確にこの名前)
Username: (空欄またはカスタマイズ)
Scopes: read_registry, write_registry

7.3.3 パッケージレジストリにアクセスできない

症状:

nuget push mypkg.nupkg -Source GitLab

# エラー:
# Response status code does not indicate success: 401 (Unauthorized)

原因と対策:

原因 対策
write_package_registryスコープがない 正しいスコープを持つトークンを作成
NuGetソースの設定が間違っている URLとプロジェクトIDを確認
認証情報が間違っている ユーザー名とトークンを再確認

正しいNuGetソース設定:

# ソースの追加
nuget source Add \
  -Name GitLab \
  -Source "https://gitlab.com/api/v4/projects/12345/packages/nuget/index.json" \
  -UserName gitlab+deploy-token-789 \
  -Password xxxxxxxxxxxxxxxxxxxx \
  -StorePasswordInClearText

# パッケージのプッシュ
nuget push mypkg.1.0.0.nupkg -Source GitLab

7.4 共通のトラブルシューティング

7.4.1 トークン/キーの値を紛失した

症状:

作成したトークンやデプロイトークンの値を記録し忘れた。

対策:

GitLabでは、セキュリティ上の理由から、作成後にトークン値を再表示することはできません。

解決方法:

  1. 既存のトークン/キーをリボーク
  2. 新しいトークン/キーを作成
  3. 今度は安全に保管(1Password、HashiCorp Vault等)

7.4.2 監査ログでトークンの使用状況を確認したい

手順:

Project Settings > Audit Events

フィルタ:
- Entity Type: Project Access Token / Deploy Key / Deploy Token
- Date Range: 確認したい期間

確認できる情報:

  • トークンの作成日時
  • 最終使用日時
  • 使用したIPアドレス
  • 実行された操作

7.4.3 大量のトークンを一括管理したい

推奨ツール:

  • 1Password: チーム向けパスワード管理
  • HashiCorp Vault: エンタープライズ向けシークレット管理
  • AWS Secrets Manager: AWSインフラと統合
  • Azure Key Vault: Azureインフラと統合

管理のベストプラクティス:

## トークン管理台帳

### プロジェクトA

| 名前 | 種類 | 用途 | 有効期限 | 保管場所 | 担当者 |
|------|------|------|---------|---------|--------|
| prod_api_2024-01 | PAT | API自動化 | 2024-07-01 | 1Password | 山田太郎 |
| k8s-deploy-key | Deploy Key | K8s デプロイ | なし | Vault | 佐藤花子 |
| gitlab-deploy-token | Deploy Token | CI/CD | なし | CI/CD変数 | 鈴木一郎 |

8. まとめ

8.1 選択の決定木

8.2 重要なポイント

1. 最小権限の原則

必要最小限のスコープと権限のみを付与します。

2. 有効期限の設定

可能な限り有効期限を設定し、定期的にローテーションします。

3. サービスアカウントの活用

デプロイキーは個人アカウントではなく、サービスアカウントで作成します。

4. 定期的な棚卸し

四半期ごとに全トークンの使用状況を確認し、未使用のものはリボークします。

5. 安全な保管

トークン値は1PasswordやVaultなどのシークレット管理ツールで保管します。

6. ドキュメント化

作成したトークンの用途、使用場所、担当者を必ず記録します。

8.3 クイックリファレンス

やりたいこと 推奨方式 スコープ/権限
GitLab APIでIssue作成 プロジェクトアクセストークン api
CI/CDでイメージプッシュ デプロイトークン(gitlab-deploy-token) read_registry, write_registry
外部サーバーからクローン(SSH) デプロイキー 読み取り専用
外部サーバーからクローン(HTTP) デプロイトークン read_repository
Kubernetesからイメージプル グループデプロイトークン read_registry
パッケージの公開 デプロイトークン write_package_registry
複数プロジェクトへのSSHアクセス 公開デプロイキー 読み取り専用/読み書き
ランナーの管理 プロジェクトアクセストークン manage_runner

適切な認証方式を選択し、セキュリティベストプラクティスに従うことで、安全で効率的な自動化を実現できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?