GitLab Permissions ve Group Yönetimi: Kapsamlı Rehber
Yıllar önce bir müşterinin GitLab kurulumuna baktığımda gördüğüm manzara hâlâ aklımda: Herkes “Maintainer”, hiç kimse ne yaptığını bilmiyor, production branch’e doğrudan push yapılıyor ve bir geliştirici yanlışlıkla başka bir ekibin projesini silmiş. O günden beri GitLab izin yönetimini ciddiye almanın ne kadar kritik olduğunu her fırsatta vurgularım. Bu yazıda gerçek dünya senaryolarıyla GitLab permissions sistemini ve group yönetimini derinlemesine ele alacağız.
GitLab İzin Modeli: Temel Kavramlar
GitLab’ın izin sistemi hiyerarşik bir yapı üzerine kurulu. En tepede instance (kurulum) seviyesi var, altında group’lar, onun altında subgroup’lar, en altta ise project’ler bulunuyor. Her seviyede atanan roller, alt seviyelere miras olarak aktarılıyor.
Beş temel rol var:
- Guest: Sadece issue görebilir, yorum yapabilir. Private projelerde bile son derece kısıtlı.
- Reporter: Kod okuyabilir, issue ve merge request takibi yapabilir ama kod değiştiremez.
- Developer: Kod yazabilir, branch oluşturabilir, merge request açabilir. Günlük geliştirme işleri için standart rol.
- Maintainer: Protected branch yönetimi, CI/CD ayarları, proje bazlı konfigürasyonlar.
- Owner: Grup veya projeyi silebilir, tüm ayarlara erişebilir. Sadece güvendiğiniz kişilere verin.
Burada kritik bir nokta var: Birisi hem grup seviyesinde hem de proje seviyesinde farklı rollere sahip olabilir. GitLab her zaman en yüksek izni uygular. Yani grup seviyesinde Reporter olan biri, proje seviyesinde Maintainer yapılmışsa o projede Maintainer gibi davranır. Bu davranışı anlamak, beklenmedik izin sorunlarının önüne geçmek için şart.
Group Yapısını Doğru Kurmak
Yanlış yapılandırılmış bir group hiyerarşisini sonradan düzeltmek hem zahmetli hem de riskli. İlk kurulumda doğru yapmak için biraz düşünmek gerekiyor.
Tipik bir kurumsal yapı şöyle görünebilir:
company/
├── backend/
│ ├── api-service
│ ├── worker-service
│ └── shared-libs
├── frontend/
│ ├── web-app
│ └── mobile-app
├── devops/
│ ├── infrastructure
│ ├── ci-templates
│ └── monitoring
└── data/
├── pipelines
└── analytics
Bu yapıyı GitLab CLI ya da API ile oluşturabilirsiniz. GitLab API kullanarak group oluşturma:
# Yeni bir subgroup oluşturma
curl --request POST
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
--header "Content-Type: application/json"
--data '{
"name": "backend",
"path": "backend",
"parent_id": 42,
"visibility": "private",
"description": "Backend ekibi projeleri"
}'
"https://gitlab.example.com/api/v4/groups"
Subgroup oluştururken parent_id değerini bilmek gerekiyor. Üst grubun ID’sini bulmak için:
curl --header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
"https://gitlab.example.com/api/v4/groups?search=company" |
python3 -m json.tool | grep '"id"'
Üye Yönetimi ve Role Atama
Group’a üye eklemek arayüzden yapılabileceği gibi API üzerinden toplu işlemler de yapılabilir. Özellikle büyük organizasyonlarda yeni bir ekip üyesi geldiğinde ya da biri ayrıldığında toplu operasyonlar hayat kurtarır.
# Bir kullanıcıyı group'a ekle (access_level: 10=Guest, 20=Reporter, 30=Developer, 40=Maintainer, 50=Owner)
curl --request POST
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
--header "Content-Type: application/json"
--data '{
"user_id": 156,
"access_level": 30,
"expires_at": "2024-12-31"
}'
"https://gitlab.example.com/api/v4/groups/42/members"
expires_at parametresini genellikle gözden kaçırıyorlar ama bu altın değerinde bir özellik. Stajyer, danışman ya da geçici proje için dışarıdan birini ekleyecekseniz mutlaka bir süre sonu belirleyin. Yoksa o kişi ayrıldıktan aylarca sonra hâlâ erişimi olduğunu görürsünüz.
Bir grup üyelerini listelemek ve mevcut rolleri denetlemek için:
# Gruptaki tüm üyeleri listele
curl --header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
"https://gitlab.example.com/api/v4/groups/42/members/all" |
python3 -c "
import json, sys
members = json.load(sys.stdin)
for m in members:
print(f"{m['username']:30} {m['access_level']:5} {m.get('expires_at', 'N/A')}")"
Protected Branch Yönetimi
Bu konu izin sisteminin en kritik parçası. Protected branch olmadan, Developer rolündeki biri doğrudan main‘e ya da production‘a push yapabilir. Bu, büyük organizasyonlarda felakete davet çıkarmaktır.
# main branch'i koru: sadece Maintainer push edebilir, Developer sadece merge request ile katkı sağlayabilir
curl --request POST
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
--header "Content-Type: application/json"
--data '{
"name": "main",
"push_access_level": 40,
"merge_access_level": 30,
"allow_force_push": false,
"code_owner_approval_required": true
}'
"https://gitlab.example.com/api/v4/projects/78/protected_branches"
Buradaki parametrelere dikkat:
- push_access_level: 40: Sadece Maintainer ve üstü doğrudan push yapabilir
- merge_access_level: 30: Developer ve üstü merge request yoluyla katkı sağlayabilir
- allow_force_push: false: Force push tamamen kapalı, geçmiş korunuyor
- code_owner_approval_required: true: CODEOWNERS dosyasında belirtilen kişilerin onayı zorunlu
CODEOWNERS dosyası çoğu ekibin ihmal ettiği ama son derece güçlü bir araç. Repository kökünde ya da .gitlab/ dizininde oluşturulur:
# .gitlab/CODEOWNERS dosyası örneği
# Format: dosya/dizin pattern @kullanici veya @grup
# Tüm değişiklikler için varsayılan sahipler
* @company/tech-leads
# Backend değişiklikleri
/backend/ @company/backend @ahmet.yilmaz
# Kritik konfigürasyonlar
*.env.production @company/devops @fatma.kaya
/kubernetes/ @company/devops
# Veritabanı migrasyonları özellikle dikkat
/db/migrations/ @company/backend @company/dba-team
# Frontend
/frontend/ @company/frontend
Deploy Token ve Access Token Yönetimi
CI/CD pipeline’larında ve otomasyonda şifre kullanmak yerine token kullanmak hem güvenli hem de yönetilebilir. Grup seviyesinde oluşturulan deploy token’lar, grubun altındaki tüm projelere erişim sağlar.
# Grup için deploy token oluştur
curl --request POST
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
--header "Content-Type: application/json"
--data '{
"name": "ci-registry-token",
"scopes": ["read_registry", "read_repository"],
"expires_at": "2025-06-30"
}'
"https://gitlab.example.com/api/v4/groups/42/deploy_tokens"
Dönen token değerini bir yere not edin çünkü bir daha göremezsiniz. Bu token’ı CI/CD değişkenlerine kaydedin:
# Group CI/CD variable olarak kaydet
curl --request POST
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
--header "Content-Type: application/json"
--data '{
"key": "DEPLOY_TOKEN",
"value": "token-değeri-buraya",
"protected": true,
"masked": true,
"environment_scope": "production"
}'
"https://gitlab.example.com/api/v4/groups/42/variables"
masked: true yapmanın önemi şu: Pipeline loglarında bu değer [MASKED] olarak görünür. Hassas değerler için ihmal edilmemeli.
Gerçek Dünya Senaryosu: Çok Ekipli Organizasyon
Diyelim ki 50 kişilik bir yazılım şirketindesiniz. Backend, frontend, mobil ve DevOps olmak üzere dört ekip var. Birbirinin işine karışmadan ama ortak kütüphaneleri görebilecek şekilde bir yapı kurmak istiyorsunuz.
İzlenecek yol:
Önce ekip bazlı gruplar oluşturulur ve her ekip sadece kendi subgroup’una Developer ya da Maintainer olarak atanır. Ortak kütüphane projeleri ayrı bir shared subgroup’unda tutulur ve tüm ekiplere Reporter erişimi verilir. CI template’leri ise sadece DevOps ekibinin yazabildiği, diğerlerinin okuduğu ayrı bir project olarak yapılandırılır.
Bir kullanıcının hangi gruplara üye olduğunu ve rollerini kontrol etmek için:
#!/bin/bash
# Kullanıcının tüm grup üyeliklerini kontrol et
USER_ID=156
TOKEN="glpat-xxxxxxxxxxxx"
GITLAB_URL="https://gitlab.example.com"
echo "=== Kullanıcı $USER_ID'nin Grup Üyelikleri ==="
curl -s --header "PRIVATE-TOKEN: $TOKEN"
"$GITLAB_URL/api/v4/users/$USER_ID/memberships?type=Group" |
python3 -c "
import json, sys
data = json.load(sys.stdin)
access_map = {10: 'Guest', 20: 'Reporter', 30: 'Developer', 40: 'Maintainer', 50: 'Owner'}
for item in data:
role = access_map.get(item['access_level'], 'Unknown')
print(f" {item['source_name']:40} -> {role}")
"
İzin Denetimi ve Güvenlik Taraması
Periyodik olarak izinleri denetlemek iyi bir pratik. Özellikle Owner yetkisi kimlerde var, süresi dolmuş hesaplar var mı, devre dışı kullanıcılar hâlâ erişime sahip mi sorularına yanıt aramalısınız.
#!/bin/bash
# Owner yetkisi olan tüm kullanıcıları bul
TOKEN="glpat-xxxxxxxxxxxx"
GITLAB_URL="https://gitlab.example.com"
GROUP_ID=42
echo "=== Owner Yetkisi Olan Kullanıcılar ==="
curl -s --header "PRIVATE-TOKEN: $TOKEN"
"$GITLAB_URL/api/v4/groups/$GROUP_ID/members/all?access_level=50" |
python3 -c "
import json, sys
from datetime import datetime
members = json.load(sys.stdin)
today = datetime.now().date()
for m in members:
exp = m.get('expires_at')
status = 'KALICI' if not exp else ('SURESI DOLMUS' if exp < str(today) else f'Bitis: {exp}')
blocked = '[BLOCKED]' if m.get('state') == 'blocked' else ''
print(f" {m['username']:30} {status} {blocked}")
"
Bloklanmış ya da ayrılmış kullanıcılar hâlâ group üyeliği listesinde görünebilir. Bunları temizlemek önemli:
# Belirli bir kullanıcıyı gruptan çıkar
curl --request DELETE
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
"https://gitlab.example.com/api/v4/groups/42/members/156"
Merge Request Onay Kuralları
Sadece erişim kontrolü yetmez; kod kalitesi için merge request onay kurallarını da izin sistemiyle birleştirmek gerekir. Bu kurallar proje bazlı ya da grup bazlı tanımlanabilir.
# Proje için approval rule oluştur
curl --request POST
--header "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx"
--header "Content-Type: application/json"
--data '{
"name": "Backend Reviewers",
"approvals_required": 2,
"user_ids": [101, 102, 103],
"group_ids": [55]
}'
"https://gitlab.example.com/api/v4/projects/78/approval_rules"
Burada approvals_required: 2 demek, merge edilebilmesi için listede yer alan kullanıcılardan en az ikisinin onayı gerekiyor demek. Tek kişi onaylıyor ve production’a gidiyor dönemine son vermek isteyenler için bu kural zorunlu hale getirilmeli.
Approval kurallarında dikkat edilmesi gereken detaylar:
- Aynı kişi hem merge request açan hem de onaylayan olamaz (self-approval kapalıysa)
- prevent_author_approval ayarını aktif etmek iyi pratik
- reset_approvals_on_push açıksa yeni commit sonrası önceki onaylar sıfırlanır, bu güvenli bir davranış
Inherited Permissions ve Override Sorunları
Miras alınan izinler bazen beklenmedik durumlar yaratır. Bir geliştiriciye proje bazında Reporter vermek istiyorsunuz ama üst gruptan Developer olarak geliyor. GitLab en yüksek izni uygulayacağı için bunu aşağıya çekmenin doğrudan yolu yok.
Bu sorunu çözmek için birkaç yaklaşım var:
Birinci yaklaşım: O geliştiriciyi üst gruptan çıkarıp sadece erişmesi gereken projelere doğrudan eklemek. Daha granüler kontrol sağlar ama yönetimi zorlaşır.
İkinci yaklaşım: Hassas projeleri ayrı bir subgroup’a taşımak ve o subgroup’a sadece ihtiyacı olanları eklemek. Üst gruptan miras gelen izinler bu subgroup’a yansımaz çünkü kullanıcı o subgroup’un altında değil.
Üçüncü yaklaşım: GitLab Enterprise sürümünde mevcut olan “minimal access” özelliğini kullanmak. Bu özellik, üst gruba sadece grup varlığını görebilecek düzeyde minimum erişim verilmesini sağlar.
Sonuç
GitLab izin yönetimi, kurmak yerine düzeltmek zorunda kaldığınızda on kat daha fazla zaman alan bir konu. Doğru group hiyerarşisini baştan kurmak, roller arasındaki farkı ekibe anlatmak ve periyodik denetim yapmak sizi pek çok baş ağrısından korur.
Pratikte en çok karşılaşılan sorun şu: Herkesin Maintainer yapıldığı, protected branch olmayan, deploy token yerine gerçek kullanıcı şifresinin CI’a yazıldığı kurulumlar. Bunların her biri ayrı bir güvenlik açığı.
Bugün yapılabilecek en küçük ama en etkili adım: Tüm projelerde main ve production branch’lerini korumaya alın, force push’u kapatın ve en az iki kişi onayı zorunlu kılın. Geri kalan her şey bu temelin üzerine inşa edilebilir. API ile yapılan toplu işlemler ise büyüdükçe vazgeçilmez hale gelir, o yüzden bu becerileri erken edinmek her zaman işe yarar.
