Skip to main content

access control

GitLab Ultimate Access Control

This guide covers access control mechanisms in GitLab Ultimate including protected branches, merge request approvals, code owners, push rules, and environment protection. Access control ensures code quality, security, and compliance through enforced workflows.

Overview

GitLab Ultimate provides comprehensive access control capabilities:

  • Protected Branches - Control who can merge and push to critical branches
  • Protected Tags - Prevent unauthorized tag creation and deletion
  • Merge Request Approvals - Require code review before merging
  • Code Owners (CODEOWNERS) - Assign ownership and require approval
  • Push Rules - Enforce commit standards and prevent problematic changes
  • Environment Protection - Control deployments to sensitive environments
  • Branch Rules - Unified interface for all protection rules

Protected Branches

Overview

Protected branches control which users can merge and push code changes, prevent accidental deletion, enforce code review, and manage approval requirements.

Configuration

Basic Protection:

  1. Navigate to: Settings > Repository > Branch Rules
  2. Select branch to protect (e.g., main, production)
  3. Configure protection rules:
    • Allowed to merge
    • Allowed to push and merge
    • Allowed to force push
    • Require approval before merging

Protection Levels:

  • No one - Completely blocks action
  • Maintainers - Only project maintainers
  • Developers + Maintainers - Developer role and above
  • Specific users/groups - Granular control (Premium/Ultimate)

Production Branch:

Branch: main
 Allowed to merge: Maintainers only
 Allowed to push: No one (force merge requests)
 Allowed to force push: No one (disabled)
 Require approval: Yes (2 approvals)
 Code owner approval: Required
 Pipelines must succeed: Yes

Development Branch:

Branch: development
 Allowed to merge: Developers + Maintainers
 Allowed to push: No one (force merge requests)
 Allowed to force push: No one (disabled)
 Require approval: Yes (1 approval)
 Code owner approval: Optional
 Pipelines must succeed: Yes

Release Branches:

Branches: release/*
 Allowed to merge: Maintainers only
 Allowed to push: No one (force merge requests)
 Allowed to force push: No one (disabled)
 Require approval: Yes (2 approvals)
 Code owner approval: Required
 Pipelines must succeed: Yes

Advanced Protection Rules

Wildcard Patterns:

Protect multiple branches with patterns:

Pattern: release/*
  Protects: release/v1.0, release/v2.0, release/v2.1, etc.

Pattern: hotfix/*
  Protects: hotfix/security-patch, hotfix/critical-bug, etc.

Pattern: feature/*
  Protects: All feature branches

Premium/Ultimate Features:

  • Specific users/groups - Granular permission assignment
  • Deploy keys - Allow automated deployments
  • No one exception - Completely block operations
  • Code owner approval - Require approval from code owners
  • Multiple approval rules - Different rules for different changes

Branch Protection Best Practices

  1. Always Protect main - Never allow direct pushes to production branch
  2. Force Merge Requests - Set "Allowed to push" to "No one"
  3. Disable Force Push - Maintain commit history integrity
  4. Require Pipeline Success - Ensure tests pass before merge
  5. Enable Code Owners - Assign ownership and responsibility
  6. Multiple Approvals - Require 2+ approvals for critical branches
  7. Separation of Duties - Prevent author approval

Example: Enterprise Configuration

Protected Branches Configuration - Enterprise Standards main (production): merge: allowed: ["@maintainers", "@tech-leads"] approvals_required: 2 code_owners_required: true prevent_author_approval: true push: allowed: [] # No one can push directly force_push: false pipeline: must_succeed: true required_jobs: - security_scanning - automated_tests - code_quality development (staging): merge: allowed: ["@developers", "@maintainers"] approvals_required: 1 code_owners_required: false prevent_author_approval: true push: allowed: [] # Force merge requests force_push: false pipeline: must_succeed: true release/* (release branches): merge: allowed: ["@release-managers"] approvals_required: 3 # Tech lead, QA, Product code_owners_required: true prevent_author_approval: true push: allowed: [] force_push: false pipeline: must_succeed: true deployment_approvals: - environment: production approvers: ["@devops-team", "@cto"] approvals_required: 2

Protected Tags

Overview

Protected tags prevent unauthorized creation and deletion of Git tags, ensuring release integrity and version control.

Configuration

Protecting Tags:

  1. Navigate to: Settings > Repository > Protected Tags
  2. Click "Add tag"
  3. Configure:
    • Tag name or pattern
    • Allowed to create
    • Allowed to delete (Ultimate only)

Tag Protection Levels:

  • No one - Block all tag creation
  • Maintainers - Only maintainers can create tags
  • Developers + Maintainers - Developer role and above
  • Specific users/groups - Granular control (Ultimate)

Release Tags:

Pattern: v*
 Allowed to create: Maintainers only
 Allowed to delete: No one
 Purpose: Protect version tags (v1.0.0, v2.1.3, etc.)

Deployment Tags:

Pattern: deploy-*
 Allowed to create: @devops-team
 Allowed to delete: Maintainers only
 Purpose: Control deployment markers

Best Practices

  1. Protect Version Tags - Use pattern v* for semantic versions
  2. Block Deletion - Set "Allowed to delete" to "No one"
  3. Restrict Creation - Only allow maintainers or release managers
  4. Use Patterns - Protect entire tag namespaces
  5. Audit Tag Changes - Monitor audit events for tag operations

Merge Request Approvals

Overview

Merge request approvals enforce code review by requiring explicit approval before merging. They ensure code quality, knowledge sharing, and compliance with change management policies.

Configuration

Basic Approval Rules:

  1. Navigate to: Settings > Merge Requests > Approval Rules
  2. Click "Add approval rule"
  3. Configure:
    • Rule name
    • Approvals required
    • Eligible approvers
    • Target branches
    • Additional settings

Approval Rule Structure:

Approval Rule: Code Review
 Approvals required: 2
 Eligible approvers: @senior-developers, @tech-leads
 Target branches: main, development
 Prevent author approval: Yes
 Prevent committers approval: Yes
 Remove approvals on push: Yes

Approval Rule Types

Basic Rules:

Simple approval requirements:

Rule: General Code Review
Approvals Required: 1
Eligible Approvers: All project members with Developer role or higher

Specific Approvers (Premium/Ultimate):

Require approval from designated individuals or groups:

Rule: Senior Developer Review
Approvals Required: 1
Eligible Approvers:
  - @alice
  - @bob
  - @senior-dev-team
Target Branches: main

Code Owner Rules (Premium/Ultimate):

Require approval from code owners:

Rule: Code Owner Approval
Approvals Required: 1 per code owner section
Eligible Approvers: Defined in CODEOWNERS file
Applies to: Files matching CODEOWNERS patterns

External Approval (Ultimate):

Require approval from external systems:

Rule: External Security Scan
Type: External approval
External URL: https://security-tool.example.com/approve
External Token: $SECURITY_TOOL_TOKEN

Advanced Approval Settings

Prevent Author Approval:

Author cannot approve their own merge request:

Setting: Prevent approval by author
Status: Enabled
Effect: MR author must get approval from others
Compliance: Separation of duties

Prevent Committers Approval:

Users who committed to MR cannot approve:

Setting: Prevent approval by merge request committers
Status: Enabled
Effect: Only non-contributors can approve
Use Case: Strict separation of duties

Remove Approvals on Push:

New commits remove existing approvals:

Setting: Remove all approvals when commits are added
Status: Enabled
Effect: Forces re-review after changes
Ensures: Latest code is reviewed

Require Approval from Code Owners:

Code owner approval required for files they own:

Setting: Require approval from code owners
Status: Enabled
Effect: CODEOWNERS file controls approvals
Target: Protected branches only

Override Approval Rules:

Allow approvers to approve despite approval rules:

Setting: Allow approval by committers
Status: Disabled (recommended)
Effect: Strict approval enforcement
Use Case: Compliance requirements

Multiple Approval Rules

Combining Rules:

Multiple approval rules can be configured simultaneously:

Rule 1: General Code Review
  Approvals: 1
  Approvers: @developers

Rule 2: Senior Developer Review
  Approvals: 1
  Approvers: @senior-developers
  Applies when: Changes to /app/models/*

Rule 3: Security Review
  Approvals: 1
  Approvers: @security-team
  Applies when: Changes to /app/controllers/auth*

Rule 4: Database Review
  Approvals: 1
  Approvers: @dba-team
  Applies when: Changes to /db/migrate/*

Total Required Approvals: Depends on files changed
Example: MR touching /app/models/user.rb requires 2 approvals
  (General + Senior Developer)

Approval Workflows

Standard Workflow:

1. Developer creates MR
2. CI/CD pipeline runs
3. Reviewer(s) review code
4. Reviewer(s) approve MR
5. All approval rules satisfied
6. Developer (or maintainer) merges

Separation of Duties Workflow:

1. Developer creates MR
2. CI/CD pipeline runs
3. Code owner reviews (cannot be author)
4. Code owner approves
5. Senior developer reviews (cannot be author or committer)
6. Senior developer approves
7. Security scans pass
8. Maintainer merges (cannot be author)

Best Practices

  1. Require Multiple Approvals - At least 2 approvals for production code
  2. Prevent Self-Approval - Enable "Prevent author approval"
  3. Remove on Push - Force re-review after changes
  4. Use Code Owners - Assign ownership and responsibility
  5. Target Critical Branches - Apply strict rules to main, production
  6. External Approvals - Integrate security tools and scanners
  7. Document Rules - Explain why each rule exists

Code Owners (CODEOWNERS)

Overview

CODEOWNERS files define individuals or teams responsible for specific code sections. Code owners are automatically requested as reviewers and can be required to approve changes.

CODEOWNERS File

File Location:

GitLab checks three locations (in order):

  1. ./CODEOWNERS (repository root)
  2. ./docs/CODEOWNERS (docs directory)
  3. ./.gitlab/CODEOWNERS (GitLab directory)

Basic Syntax:

# CODEOWNERS

# Default owners for everything
* @tech-lead

# Frontend code
/app/javascript/ @frontend-team

# Backend code
/app/models/ @backend-team
/app/controllers/ @backend-team

# Database migrations
/db/migrate/ @dba-team

# Infrastructure
/terraform/ @devops-team
/kubernetes/ @devops-team

# Security-critical code
/app/models/user.rb @security-team
/app/controllers/sessions_controller.rb @security-team

# Documentation
/docs/ @technical-writers

# CI/CD configuration
/.gitlab-ci.yml @devops-team

Advanced CODEOWNERS Syntax

Multiple Owners:

# All listed owners must approve
/app/api/ @api-team @architecture-team

Groups as Owners:

# Use GitLab groups
/secure/ @security/appsec-team
/payments/ @finance/payment-team

Specific Files:

# Exact file matches
package.json @frontend-lead
Dockerfile @devops-lead

Wildcard Patterns:

# Any file with specific extension
*.rb @ruby-team
*.js @javascript-team
*.sql @dba-team

# Any file matching pattern
test_*.py @qa-team
*_spec.rb @test-automation-team

Sectional Code Owners (Ultimate):

Require multiple approvals from different sections:

# CODEOWNERS

# Section: Frontend [2]
# Requires 2 approvals from frontend team
/app/javascript/ @frontend-team

# Section: Backend [1]
# Requires 1 approval from backend team
/app/models/ @backend-team
/app/controllers/ @backend-team

# Section: Security [2]
# Requires 2 approvals from security team
/app/controllers/sessions_controller.rb @security-team
/app/models/user.rb @security-team

Syntax Format:

# Section: <name> [<number>]
<path> <owners>

Enabling Code Owner Approval

Configuration:

  1. Navigate to: Settings > Repository > Branch Rules
  2. Select protected branch
  3. Enable: "Require approval from code owners"

Effect:

  • Code owners automatically added as reviewers
  • Code owner approval required before merge
  • MR cannot merge without code owner approval
  • Applies only to protected branches

Code Owner Workflow

Developer Perspective:

1. Create feature branch
2. Make changes to /app/models/user.rb
3. Create MR
4. GitLab detects CODEOWNERS file
5. @security-team automatically added as reviewers
6. Developer waits for security team approval
7. After approval, developer can merge (if has permission)

Code Owner Perspective:

1. Notification: MR ready for review
2. Review changes in owned files
3. Check security implications
4. Test changes if needed
5. Approve or request changes
6. MR can now merge (if all rules satisfied)

Best Practices

  1. Start Broad, Get Specific - Default owner for everything, specific owners for critical code
  2. Use Teams, Not Individuals - Avoid single points of failure
  3. Document Sections - Use comments to explain ownership
  4. Regular Reviews - Update CODEOWNERS as team structure changes
  5. Test Changes - Verify CODEOWNERS patterns match intended files
  6. Multiple Approvals - Use sectional owners for critical code
  7. Balance Coverage - Don't make every file require approval

Troubleshooting

Code owner approval showing as optional:

  • Verify "Require approval from code owners" enabled on protected branch
  • Check CODEOWNERS file is in correct location
  • Ensure code owners have at least Developer role
  • Verify patterns match changed files

Wrong code owners requested:

  • Check CODEOWNERS file syntax
  • Verify GitLab group/user references
  • Test patterns with different files
  • Review CODEOWNERS precedence (last match wins)

Code owners not receiving notifications:

  • Verify notification settings
  • Check group membership
  • Ensure email notifications enabled
  • Review user's merge request notification preferences

Push Rules

Overview

Push rules enforce standards on commits before they're accepted into the repository. They prevent problematic changes and ensure quality and compliance.

Availability

  • Premium/Ultimate: Full push rule capabilities
  • Free: Limited push rules via server hooks

Configuration

Enabling Push Rules:

  1. Navigate to: Settings > Repository > Push Rules
  2. Configure desired rules
  3. Save changes

Available Push Rules

Commit Message Rules:

Rule: Require commit message pattern
Pattern: ^(feat|fix|docs|style|refactor|test|chore):\s.+
Example: feat: add user authentication
Effect: Rejects commits not following conventional commits

Rule: Deny commit messages matching pattern
Pattern: (WIP|fixup|squash)
Effect: Prevents work-in-progress commits on protected branches

Rule: Require branch name pattern
Pattern: ^(feature|bugfix|hotfix|release)/
Example: feature/user-authentication
Effect: Enforces branch naming convention

File and Path Rules:

Rule: Reject files over size limit
Size: 100 MB
Effect: Prevents large files (binaries, datasets)

Rule: Prevent files matching pattern
Pattern: .(exe|dll|so)$
Effect: Blocks executable files

Rule: Require files matching pattern
Pattern: ^CHANGELOG.md$
Effect: Ensures changelog is updated

Author and Committer Rules:

Rule: Check whether author is GitLab user
Effect: Commits must have valid GitLab user email

Rule: Reject unsigned commits
Effect: Requires GPG-signed commits

Rule: Do not allow users to remove Git tags with git push
Effect: Prevents accidental tag deletion

Advanced Rules (Ultimate):

Rule: Maximum file name length
Length: 255 characters
Effect: Prevents filesystem issues

Rule: Commit author's email
Pattern: @company.com$
Effect: Requires corporate email addresses

Example Push Rule Configuration

Enterprise Standards:

Push Rules Configuration Commit Messages: Commit message must match: ^(feat|fix|docs|refactor|test|chore):\s.+ Branch name must match: ^(feature|bugfix|hotfix|release)/[a-z0-9-]+$ Commit message cannot contain: WIP|TODO|FIXME Files: Maximum file size: 50 MB Prevent pushing files matching: \.(exe|dll|so|dylib)$ Prevent pushing secret files: (\.env|credentials|secrets) Authors: Check whether author is GitLab user: Yes Require GPG-signed commits: Yes Author email must match: @company\.com$ Tags: Do not allow users to remove Git tags: Yes Member Check: Restrict commits by author (email) to existing GitLab users: Yes

Best Practices

  1. Conventional Commits - Enforce commit message format
  2. Block Large Files - Prevent repository bloat
  3. Require Signatures - Enable GPG signing for verification
  4. Corporate Emails - Require company email addresses
  5. Protect Tags - Prevent accidental tag deletion
  6. Branch Naming - Enforce consistent branch names
  7. Test Rules - Verify rules work as expected before enforcing

Troubleshooting

Push rejected by push rule:

Error: Commit message does not match required pattern

Resolution:
1. Review push rule configuration
2. Check commit message format
3. Amend commit message: git commit --amend
4. Force push: git push --force-with-lease

False rejections:

Issue: Valid commits rejected

Resolution:
1. Review push rule patterns
2. Test regex patterns with actual commit messages
3. Adjust pattern or exclude specific commits
4. Temporarily disable rule if needed

Environment Protection

Overview

Environment protection controls deployments to sensitive environments like production and staging. It ensures only authorized personnel can deploy and provides approval workflows.

Configuration

Protecting Environments:

  1. Navigate to: Deployments > Environments
  2. Select environment (e.g., production)
  3. Click "Protect"
  4. Configure protection rules:
    • Allowed to deploy
    • Required approvals
    • Approval users/groups

Protection Levels

Basic Protection:

Environment: production
Allowed to deploy: Maintainers only
Required approvals: 0
Effect: Only maintainers can trigger deployments

Approval-Required Protection (Premium/Ultimate):

Environment: production
Allowed to deploy: Developers + Maintainers
Required approvals: 2
Approval groups:
  - @devops-team
  - @product-owners
Effect: Deployment must be approved by both groups

Deployment Approval Workflow

Approval Process:

1. Pipeline reaches deployment job
2. Job pauses, waiting for approval
3. Notification sent to approval groups
4. Approvers review deployment
5. Approvers approve or reject
6. If approved: Deployment proceeds
7. If rejected: Deployment cancelled

Example:

# .gitlab-ci.yml deploy_production: stage: deploy environment: name: production url: https://app.example.com script: - ./deploy.sh production rules: - if: '$CI_COMMIT_BRANCH == "main"' when: manual # Deployment approval required (configured in environment settings)

Approval UI:

Pipeline: #12345
Job: deploy_production
Status: Waiting for approval

Required Approvals: 2
   @alice (DevOps Lead) - Approved
  ³ @bob (Product Owner) - Pending

Approve  |  Reject

Multiple Approvals

Configuration:

Environment: production
Approvals Required: 3
Approval Groups:
  - @devops-team (1 approval)
  - @security-team (1 approval)
  - @product-team (1 approval)

Effect: At least 1 person from each group must approve

Best Practices

  1. Protect Production - Always protect production environment
  2. Multiple Approvals - Require 2+ approvals for critical environments
  3. Diverse Approvers - Include different teams (DevOps, Security, Product)
  4. Manual Deployments - Use when: manual for production jobs
  5. Rollback Capability - Ensure easy rollback if issues occur
  6. Audit Deployments - Review deployment audit events
  7. Schedule Windows - Consider maintenance windows for deployments

Branch Rules (Unified Interface)

Overview

Branch Rules provide a unified interface for managing all protection rules in one place. They simplify configuration by consolidating protected branches, approval rules, and other protections.

Accessing Branch Rules

Navigation: Settings > Repository > Branch Rules

Features:

  • View all protection rules for a branch
  • Configure multiple protections in one interface
  • See effective permissions clearly
  • Manage push rules and approval rules together

Branch Rule Components

Complete Branch Rule:

Branch: main

Protection Rules:
   Allowed to merge: Maintainers
   Allowed to push: No one
   Allowed to force push: No one
   Require code owner approval: Yes

Approval Rules:
   General Review: 2 approvals required
  ‚   Approvers: @senior-developers
   Security Review: 1 approval required
  ‚   Approvers: @security-team
  ‚   Applies to: Security-related files
   Prevent author approval: Yes

Pipeline Requirements:
   Pipelines must succeed: Yes
   Required jobs:
  ‚   - security_scanning
  ‚   - automated_tests
   Optional jobs:
      - performance_tests

Push Rules:
   Commit message pattern: ^(feat|fix|docs):\s.+
   Reject unsigned commits: Yes
   Maximum file size: 50 MB

Status Checks:
   External approval: Security Scanner
   External approval: License Compliance

Configuring Branch Rules

Creating Complete Rule:

  1. Navigate to Branch Rules
  2. Add target branches (use patterns for multiple)
  3. Configure all protections:
    • Push and merge permissions
    • Approval requirements
    • Pipeline requirements
    • Push rules
    • External checks

Example:

Target: release/*

Protection:
  - Merge: Release Managers only
  - Push: No one
  - Force push: Disabled

Approvals:
  - 3 approvals required
  - Code owners must approve
  - No self-approval

Pipeline:
  - Must succeed
  - Security scans required
  - E2E tests required

Push Rules:
  - Signed commits required
  - Corporate email required

Best Practices

  1. Use Patterns - Protect multiple branches with wildcards
  2. Consistent Rules - Apply same rules to similar branches
  3. Document Rules - Add descriptions explaining requirements
  4. Regular Review - Audit rules quarterly
  5. Test Changes - Verify rules work as expected
  6. Gradual Rollout - Start strict on main, expand to other branches

Security Best Practices

Defense in Depth

Multiple Layers:

Layer 1: Branch Protection
  - No direct push to main
  - Force push disabled

Layer 2: Merge Request Approval
  - 2 approvals required
  - No self-approval
  - Code owner approval

Layer 3: Pipeline Requirements
  - Security scans must pass
  - Tests must pass
  - Code quality checks

Layer 4: Deployment Approval
  - Production requires approval
  - Multiple approvers
  - Audit trail

Layer 5: Monitoring
  - Audit events enabled
  - Real-time alerts
  - Regular reviews

Compliance Configuration

SOC 2 / SOX Compliance:

Protected Branches:
   main protected
   No direct push
   Force push disabled
   Code owner approval required

Merge Requests:
   2+ approvals required
   Prevent author approval
   Prevent committer approval
   Remove approvals on push

Separation of Duties:
   Different person approves
   Different person merges
   Different person deploys

Audit Trail:
   All changes logged
   Audit events enabled
   Event streaming configured

Regular Audits

Quarterly Review Checklist:

 Verify protected branch configuration
 Review approval rule effectiveness
 Check code owner assignments
 Audit push rule violations
 Review environment protection
 Verify separation of duties
 Check audit event retention
 Update documentation

Troubleshooting

Common Issues

Cannot push to protected branch:

Error: You are not allowed to push code to protected branch main.

Resolution:
1. Check protected branch settings
2. Verify user role and permissions
3. Use merge request instead of direct push
4. Contact project maintainer if needed

Merge request blocked by approval rules:

Issue: MR cannot merge despite having approvals

Checklist:
 All approval rules satisfied?
 Code owner approval obtained?
 Pipeline passed successfully?
 No conflicts with target branch?
 Protected branch rules met?

Code owner approval not working:

Issue: Code owner approval shown as optional

Resolution:
1. Verify CODEOWNERS file exists
2. Check file location (root, docs/, or .gitlab/)
3. Ensure "Require code owner approval" enabled
4. Verify patterns match changed files
5. Check code owners have correct role

References

Next Steps