アクセス制御設計
1. 概要
業務委託メンバーが社内GitLabリポジトリにアクセスする際の、適切な権限管理と情報隔離を実現するための設計書。Issue単位での動的アクセス制御、機密情報の保護、委託者間の作業隔離を定義する。
2. GitLabリポジトリアクセス制御
2.1 ロール設計
| ロール | 対象者 | 権限概要 |
|---|---|---|
| Owner | プロジェクトオーナー(社内管理者) | 全権限 |
| Maintainer | 社内開発リード | マージ権限、ブランチ保護設定 |
| Developer | 業務委託メンバー | MR作成可、マージ不可、Issue閲覧は割当分のみ |
| Reporter | レビュー専任(該当する場合) | 閲覧のみ |
業務委託メンバーには Developer ロールを付与する。これにより以下が可能となる:
- コードのクローン・プル
- ブランチの作成・プッシュ
- Merge Request(MR)の作成
- 割り当てられたIssueへのコメント
以下は 不可:
- mainブランチへの直接プッシュ
- MRのマージ(Maintainer以上のみ)
- プロジェクト設定の変更
- メンバーの招待・削除
2.2 Issue単位でのアクセス付与・剥奪の自動化
フロー概要
Issue割当 → Webhook発火 → アクセス付与API呼出 → Developer権限付与
Issue完了 → Webhook発火 → アクセス剥奪API呼出 → メンバー削除GitLab Webhook設定
| 項目 | 設定値 |
|---|---|
| URL | https://api.internal.example.com/hooks/gitlab/access-control |
| Trigger | Issues events |
| Secret Token | CI/CD Variablesで管理 |
| SSL verification | 有効 |
Webhook受信側の処理ロジック
python
# 擬似コード: Webhook受信時の処理
def handle_issue_event(payload):
action = payload["object_attributes"]["action"]
assignee = payload["object_attributes"]["assignee_id"]
project_id = payload["project"]["id"]
if action == "open" or action == "update":
# 新規アサイン時: Developer権限付与
if assignee and is_outsource_member(assignee):
grant_access(project_id, assignee, access_level="developer")
log_audit("ACCESS_GRANTED", assignee, project_id)
elif action == "close":
# Issue完了時: アクセス剥奪
if assignee and is_outsource_member(assignee):
revoke_access(project_id, assignee)
log_audit("ACCESS_REVOKED", assignee, project_id)GitLab API呼出例
bash
# アクセス付与(Developer = access_level 30)
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "user_id=${USER_ID}&access_level=30&expires_at=${EXPIRY_DATE}" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}/members"
# アクセス剥奪
curl --request DELETE \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}/members/${USER_ID}"アクセス有効期限
- Issue割当時に
expires_atを設定(契約終了日 or Issue期限日の早い方) - 期限超過時はGitLabが自動的にアクセスを無効化
- 日次バッチで期限切れアクセスの棚卸しを実施
2.3 フォーク禁止設定
GitLabプロジェクト設定で以下を適用する:
| 設定項目 | 値 | 説明 |
|---|---|---|
| Forking | 無効 | Settings > General > Visibility > Forking |
| Visibility Level | Private | 外部からの検索・アクセスを防止 |
bash
# API経由でのフォーク禁止設定
curl --request PUT \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "forking_access_level=disabled" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}"2.4 Protected Branch設定
mainブランチへの直接push・マージを制限する。
| 設定項目 | 値 |
|---|---|
| Branch | main |
| Allowed to merge | Maintainers |
| Allowed to push and merge | No one |
| Allowed to force push | No |
| Code owner approval | Required |
bash
# Protected Branch設定
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "name=main&push_access_level=0&merge_access_level=40&allow_force_push=false" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}/protected_branches"ブランチ命名規則
業務委託メンバーは以下のブランチ命名規則に従う:
feature/issue-{ISSUE_ID}/{short-description}例: feature/issue-12/add-login-validation
GitLab Push Rulesで命名規則を強制する:
bash
curl --request PUT \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "branch_name_regex=^(feature|fix|hotfix)/issue-[0-9]+/[a-z0-9-]+$" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}/push_rule"3. 情報隔離
3.1 委託者間の作業内容隔離
Issue可視性制御
- 業務委託メンバーは 自身にアサインされたIssueのみ 閲覧可能
- GitLab Confidential Issueを活用し、未アサインIssueは非表示
bash
# Issueを作成時にconfidentialフラグを設定
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "title=タスク名&confidential=true&assignee_ids[]=${USER_ID}" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}/issues"MR可視性制御
- MRはデフォルトでアサイン者とレビュアーのみ通知
- GitLab CI/CDのパイプライン結果は自身のMRのみ閲覧可能(Developerロールの標準動作)
3.2 機密コード・設定ファイルへのアクセス制限
.gitattributes による制御
リポジトリルートに .gitattributes を配置し、機密ファイルにフィルターを適用する。
gitattributes
# 機密設定ファイルの制御
config/secrets.yml filter=smudge-secrets
config/credentials/ filter=smudge-secrets
.env.* filter=smudge-secrets
# インフラ設定の制御
terraform/ filter=smudge-infra
k8s/production/ filter=smudge-infraGitLab CI による機密ファイルチェック
MR作成時に、機密ファイルへの変更を検知してブロックする:
yaml
# .gitlab-ci.yml
check_sensitive_files:
stage: validate
rules:
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^feature\/issue-/'
script: |
SENSITIVE_PATHS="config/secrets.yml config/credentials/ .env terraform/ k8s/production/"
CHANGED_FILES=$(git diff --name-only $CI_MERGE_REQUEST_DIFF_BASE_SHA...$CI_COMMIT_SHA)
for path in $SENSITIVE_PATHS; do
if echo "$CHANGED_FILES" | grep -q "^$path"; then
echo "ERROR: 機密ファイル ${path} への変更は禁止されています"
exit 1
fi
done
echo "OK: 機密ファイルへの変更なし"CODEOWNERS による保護
機密ファイルに対してコードオーナー承認を必須にする:
# CODEOWNERS
config/secrets.yml @security-team
config/credentials/ @security-team
.env* @security-team
terraform/ @infra-team
k8s/production/ @infra-team
docker-compose.prod* @infra-team3.3 環境変数・シークレットの管理
CI/CD Variables設定
| 変数名 | Type | Protected | Masked | 環境 | 説明 |
|---|---|---|---|---|---|
DB_PASSWORD | Variable | Yes | Yes | production | DB接続パスワード |
API_SECRET_KEY | Variable | Yes | Yes | all | APIシークレット |
DEPLOY_TOKEN | Variable | Yes | Yes | production | デプロイトークン |
WEBHOOK_SECRET | Variable | Yes | Yes | all | Webhookシークレット |
SENTRY_DSN | Variable | No | No | all | エラー監視DSN |
設定方針
- Protected:
mainブランチのパイプラインでのみ利用可能(委託メンバーのブランチでは参照不可) - Masked: CI/CDログに値が出力されない
- Group-level Variables: 複数プロジェクト共通のシークレットはGroup Variablesで管理
bash
# CI/CD Variable設定例
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "key=DB_PASSWORD&value=${DB_PASSWORD_VALUE}&protected=true&masked=true&variable_type=env_var" \
"https://gitlab.example.com/api/v4/projects/${PROJECT_ID}/variables"ローカル開発環境向けシークレット
- 委託メンバーには 開発用ダミー値 を記載した
.env.exampleを提供 - 本番・ステージング用シークレットは一切共有しない
- 開発環境用のシークレットはプロジェクトWikiの限定ページで管理
4. アクセス制御マトリクス
| リソース | 社内Owner | 社内Maintainer | 委託Developer | 備考 |
|---|---|---|---|---|
| mainブランチ push | No | No | No | CI/CDのみ |
| mainブランチ merge | Yes | Yes | No | - |
| featureブランチ作成 | Yes | Yes | Yes | 命名規則準拠 |
| MR作成 | Yes | Yes | Yes | - |
| MRマージ | Yes | Yes | No | - |
| CI/CD設定変更 | Yes | No | No | - |
| Protected Variables閲覧 | Yes | No | No | - |
| プロジェクト設定変更 | Yes | No | No | - |
| メンバー管理 | Yes | No | No | - |
| フォーク | No | No | No | 全員禁止 |
| 機密ファイル変更 | Yes | Yes(要承認) | No(CIブロック) | - |
5. 定期棚卸し
| 項目 | 頻度 | 実施者 | 内容 |
|---|---|---|---|
| メンバー権限確認 | 月次 | プロジェクトOwner | 不要なアクセス権の削除 |
| Protected Branch設定 | 月次 | プロジェクトOwner | 設定の変更有無確認 |
| CI/CD Variables | 四半期 | セキュリティチーム | 不要な変数の削除、ローテーション |
| CODEOWNERS | 四半期 | プロジェクトOwner | オーナー情報の最新化 |
| Webhook | 四半期 | インフラチーム | 不要なWebhookの削除 |