Skip to main content

policies

GitLab Ultimate Security Policies

This guide covers security policy management in GitLab Ultimate including scan execution policies, scan result policies, and policy enforcement. Security policies automate and enforce security requirements across projects.

Overview

GitLab Ultimate provides comprehensive security policy management:

  • Scan Execution Policies - Enforce security scanning requirements
  • Scan Result Policies - Block merges based on scan findings
  • Policy Projects - Centralized policy management
  • Group-Level Policies - Enforce across multiple projects
  • Policy Inheritance - Cascading policy application
  • Security Policy Bot - Automated policy execution

Security policies ensure consistent security practices across all projects and prevent vulnerabilities from reaching production.

Scan Execution Policies

Overview

Scan execution policies enforce security scanning requirements based on default or latest security CI/CD templates. They can run as part of pipelines or on scheduled intervals.

Key Capabilities:

  • Automatically inject security scanning jobs
  • Run scanners on schedule or pipeline triggers
  • Enforce scanning even without .gitlab-ci.yml
  • Cannot be disabled or modified by projects
  • Apply to all linked projects

Policy Structure

Basic Policy:

scan_execution_policy: - name: "Enforce SAST and Secret Detection" description: "Run SAST and Secret Detection on all commits" enabled: true rules: - type: pipeline branches: - main - development - release/* actions: - scan: sast - scan: secret_detection

Scheduled Policy:

scan_execution_policy: - name: "Weekly DAST Scan" description: "Run DAST scan every Monday at 2 AM" enabled: true rules: - type: schedule cadence: "0 2 * * 1" # Cron format: Monday 2 AM branches: - main actions: - scan: dast variables: DAST_WEBSITE: "https://staging.example.com"

Policy Rules

Rule Types:

  • pipeline - Run on pipeline execution
  • schedule - Run on cron schedule

Branch Targeting:

rules: - type: pipeline branches: - main # Exact match - release/* # Wildcard pattern - "feature/*" # Quoted patterns - "*" # All branches (use cautiously)

Schedule Format:

rules: - type: schedule cadence: "0 2 * * 1" # Cron: minute hour day month weekday # Examples: # "0 0 * * *" - Daily at midnight # "0 2 * * 1" - Mondays at 2 AM # "0 0 1 * *" - First day of month # "*/30 * * * *" - Every 30 minutes

Available Scanners

Supported Scan Types:

actions: - scan: sast # Static Application Security Testing - scan: secret_detection # Secret Detection - scan: dependency_scanning # Dependency Scanning - scan: container_scanning # Container Scanning - scan: dast # Dynamic Application Security Testing - scan: coverage_fuzzing # Coverage-Guided Fuzz Testing - scan: api_fuzzing # API Security Testing

Scanner Variables

Configuring Scanners:

actions: - scan: sast variables: SAST_EXCLUDED_PATHS: "spec,test,tests" SAST_CONFIDENCE_LEVEL: "medium" - scan: dast variables: DAST_WEBSITE: "$STAGING_URL" DAST_AUTH_URL: "$STAGING_URL/login" DAST_USERNAME: "$DAST_USERNAME" DAST_PASSWORD: "$DAST_PASSWORD" DAST_FULL_SCAN_ENABLED: "true" - scan: container_scanning variables: CS_IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" CS_SEVERITY_THRESHOLD: "high"

Example Policies

Comprehensive Security Policy:

scan_execution_policy: - name: "Complete Security Scanning" description: "Run all security scanners on protected branches" enabled: true rules: - type: pipeline branches: - main - release/* actions: # Static analysis - scan: sast variables: SAST_EXCLUDED_PATHS: "spec,test" # Secrets - scan: secret_detection variables: SECRET_DETECTION_EXCLUDED_PATHS: "test/,spec/" # Dependencies - scan: dependency_scanning variables: DS_EXCLUDED_PATHS: "spec,test" # Containers (if applicable) - scan: container_scanning variables: CS_IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" - name: "Weekly DAST Scan" description: "Run DAST against staging every Sunday night" enabled: true rules: - type: schedule cadence: "0 2 * * 0" # Sunday 2 AM branches: - main actions: - scan: dast variables: DAST_WEBSITE: "https://staging.example.com" DAST_FULL_SCAN_ENABLED: "true" DAST_AUTH_URL: "https://staging.example.com/login" DAST_USERNAME: "$DAST_USERNAME" DAST_PASSWORD: "$DAST_PASSWORD"

Fast Feedback Policy:

scan_execution_policy: - name: "Quick Security Checks" description: "Run fast security scans on all branches" enabled: true rules: - type: pipeline branches: - "*" # All branches actions: - scan: sast - scan: secret_detection - scan: dependency_scanning # Note: DAST excluded (too slow for every commit)

Policy Limits

Restrictions:

  • Maximum 5 rules per policy
  • Maximum 5 scan execution policies per security policy project
  • Local project YAML cannot override scan execution policies
  • Policies take precedence over project CI/CD configuration

Best Practices

  1. Start Simple - Begin with SAST and Secret Detection
  2. Use Schedules for Slow Scans - Run DAST weekly, not on every commit
  3. Exclude Test Paths - Reduce noise by excluding test directories
  4. Progressive Enhancement - Add more scanners gradually
  5. Monitor Performance - Track pipeline duration impact
  6. Document Policies - Explain why each policy exists

Scan Result Policies

Overview

Scan result policies evaluate security scan results and can block merge requests or require additional approvals based on findings. They enforce security standards by preventing vulnerable code from merging.

Key Capabilities:

  • Block merges with critical/high vulnerabilities
  • Require security team approval for findings
  • Define acceptable vulnerability thresholds
  • Apply to specific branches and scanners
  • Cannot be bypassed by project members

Policy Structure

Basic Blocking Policy:

scan_result_policy: - name: "Block Critical Vulnerabilities" description: "Prevent merging code with critical vulnerabilities" enabled: true rules: - type: scan_finding branches: - main - production scanners: - sast - dependency_scanning - container_scanning severity_levels: - critical vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 1 approvers: - "@security-team"

Threshold-Based Policy:

scan_result_policy: - name: "High Vulnerability Threshold" description: "Allow up to 2 high severity vulnerabilities" enabled: true rules: - type: scan_finding branches: - main scanners: - sast - dependency_scanning severity_levels: - high vulnerabilities_allowed: 2 actions: - type: require_approval approvals_required: 2 approvers: - "@security-team" - "@tech-lead"

Rule Configuration

Severity Levels:

severity_levels: - critical # Most severe, immediate attention - high # Serious, prompt attention - medium # Moderate risk - low # Minor risk - info # Informational only

Scanner Selection:

scanners: - sast - secret_detection - dependency_scanning - container_scanning - dast - coverage_fuzzing - api_fuzzing

Branch Targeting:

branches: - main - production - release/* - "*" # All branches (use cautiously)

Vulnerability States

Filtering by State:

rules: - type: scan_finding vulnerability_states: - newly_detected # New in this MR - detected # Exists in baseline # Options: newly_detected, detected

Example:

scan_result_policy: - name: "Block New Critical Vulnerabilities Only" description: "Prevent introducing new critical issues" enabled: true rules: - type: scan_finding branches: - main scanners: - sast - dependency_scanning severity_levels: - critical vulnerability_states: - newly_detected vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 1 approvers: - "@security-team"

Actions

Require Approval:

actions: - type: require_approval approvals_required: 1 # Number of approvals approvers: # Who can approve - "@security-team" - "@user-alice" - "Security Team" # GitLab group name

Multiple Approvers:

actions: - type: require_approval approvals_required: 2 approvers: - "@security-team" - "@tech-leads" - "@senior-developers" # Any 2 from the combined list can approve

Example Policies

Graduated Response:

scan_result_policy: # Critical: Block completely - name: "Zero Tolerance for Critical" enabled: true rules: - type: scan_finding branches: ["main", "production"] scanners: ["sast", "dependency_scanning", "container_scanning"] severity_levels: ["critical"] vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 2 approvers: ["@security-team", "@cto"] # High: Require security approval - name: "Security Review for High" enabled: true rules: - type: scan_finding branches: ["main"] scanners: ["sast", "dependency_scanning"] severity_levels: ["high"] vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 1 approvers: ["@security-team"] # Medium: Allow up to 5 - name: "Medium Severity Threshold" enabled: true rules: - type: scan_finding branches: ["main"] scanners: ["sast"] severity_levels: ["medium"] vulnerabilities_allowed: 5 actions: - type: require_approval approvals_required: 1 approvers: ["@senior-developers"]

Secret Detection Policy:

scan_result_policy: - name: "Block All Secrets" description: "Prevent any secrets from being committed" enabled: true rules: - type: scan_finding branches: ["*"] # All branches scanners: ["secret_detection"] severity_levels: ["critical", "high", "medium"] vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 1 approvers: ["@security-team"]

License Compliance Policy:

scan_result_policy: - name: "License Compliance Check" description: "Require approval for license violations" enabled: true rules: - type: license_finding branches: ["main"] license_types: - denied match_on_inclusion: true actions: - type: require_approval approvals_required: 1 approvers: ["@legal-team"]

Best Practices

  1. Zero Tolerance for Critical - Block critical vulnerabilities completely
  2. Graduated Response - Different thresholds for different severities
  3. New vs Existing - Focus on newly introduced vulnerabilities
  4. Multiple Approvers - Require security and technical approval
  5. Comprehensive Scanners - Apply to all relevant scanners
  6. Protected Branches - Focus on main and production branches
  7. Document Exceptions - Explain why vulnerabilities are accepted

Security Policy Projects

Overview

Security Policy Projects centralize policy management for multiple projects. Policies defined in a security policy project are automatically enforced across all linked projects.

Creating Security Policy Project

Setup:

  1. Create new GitLab project (e.g., security-policies)
  2. Navigate to group or project
  3. Go to: Security & Compliance > Policies
  4. Click "Edit policy project"
  5. Select or create security policy project

Project Structure:

security-policies/
 .gitlab-ci.yml (optional)
 README.md
 scan-execution-policies.yml
 scan-result-policies.yml
 .gitlab/
     security-policies/
         policy-1.yml
         policy-2.yml
         policy-3.yml

Policy Files

Scan Execution Policies (.gitlab/security-policies/scan-execution-policy.yml):

# .gitlab/security-policies/scan-execution-policy.yml scan_execution_policy: - name: "Enforce Security Scans" description: "Run SAST and Secret Detection on all commits" enabled: true rules: - type: pipeline branches: - main - development actions: - scan: sast - scan: secret_detection - scan: dependency_scanning - name: "Weekly DAST" description: "Weekly DAST scan" enabled: true rules: - type: schedule cadence: "0 2 * * 0" branches: - main actions: - scan: dast variables: DAST_WEBSITE: "$STAGING_URL"

Scan Result Policies (.gitlab/security-policies/scan-result-policy.yml):

# .gitlab/security-policies/scan-result-policy.yml scan_result_policy: - name: "Block Critical Vulnerabilities" description: "Prevent merging critical issues" enabled: true rules: - type: scan_finding branches: - main - production scanners: - sast - dependency_scanning - container_scanning severity_levels: - critical vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 1 approvers: - "@security-team" - name: "Security Review for High" description: "Require security approval for high severity" enabled: true rules: - type: scan_finding branches: - main scanners: - sast - dependency_scanning severity_levels: - high vulnerabilities_allowed: 0 actions: - type: require_approval approvals_required: 1 approvers: - "@security-team"

Linking Projects

Group-Level Policy:

  1. Navigate to: Group > Security & Compliance > Policies
  2. Select security policy project
  3. All subgroups and projects automatically inherit policies

Project-Level Policy:

  1. Navigate to: Project > Security & Compliance > Policies
  2. Click "Edit policy project"
  3. Select security policy project
  4. Policies apply to this project

Policy Inheritance

Inheritance Model:

Group: engineering-team
   Security Policy Project: security-policies
      Scan Execution Policies
      Scan Result Policies
  
   Subgroup: backend-team
      Project: api-service (inherits policies)
  
   Subgroup: frontend-team
      Project: web-app (inherits policies)
  
   Project: shared-library (inherits policies)

Override Behavior:

  • Cannot override - Projects cannot disable or modify inherited policies
  • Can supplement - Projects can add additional local policies
  • Group policies take precedence - Group-level policies always apply

GitLab Security Policy Bot

Overview

The GitLab Security Policy Bot is an internal user that executes security policies across the GitLab instance. It's essential for security policies and scheduled pipelines to function properly.

Bot Responsibilities:

  • Execute scan execution policies
  • Enforce scan result policies
  • Run scheduled security scans
  • Inject compliance pipeline jobs
  • Create implicit .gitlab-ci.yml files

Bot Configuration

Automatic Setup:

The Security Policy Bot is automatically configured when:

  • Security policy project is created
  • First policy is added
  • Policy is linked to projects

Bot Permissions:

  • Developer role on projects with policies
  • Access to run pipelines
  • Access to inject CI/CD jobs
  • Cannot be blocked or removed by project members

Troubleshooting

Policies not executing:

Check:
 Security Policy Bot user exists
 Bot has Developer role on projects
 Bot is not blocked
 Policies are enabled
 Policy project is linked correctly

Scheduled policies not running:

Check:
 Cron schedule is valid
 Bot has pipeline execution permission
 Project has GitLab Runner available
 No rate limits reached

Policy Management Best Practices

Policy Design

  1. Start Simple - Begin with basic SAST and Secret Detection
  2. Progressive Enhancement - Add scanners and rules gradually
  3. Test First - Test policies on pilot projects before wide rollout
  4. Document Everything - Explain why each policy exists
  5. Version Control - Track policy changes in Git

Policy Organization

Recommended Structure:

security-policies/
 README.md                          # Overview and documentation
 .gitlab/security-policies/
    01-scan-execution/
       fast-scans.yml            # Quick scans on every commit
       scheduled-scans.yml       # Weekly comprehensive scans
       compliance-scans.yml      # Compliance-required scans
   
    02-scan-results/
       critical-block.yml        # Block critical vulnerabilities
       high-review.yml           # Require review for high
       license-compliance.yml    # License policy enforcement
   
    03-compliance/
        soc2-policy.yml           # SOC 2 requirements
        hipaa-policy.yml          # HIPAA requirements
        gdpr-policy.yml           # GDPR requirements

 docs/
     policy-rationale.md           # Why policies exist
     approval-guidelines.md        # How to approve exceptions
     troubleshooting.md            # Common issues

Testing Policies

Testing Approach:

  1. Create Test Project

    • Set up dedicated test project
    • Link security policy project
    • Verify policies apply
  2. Test Scan Execution

    • Create merge request
    • Verify security scans run
    • Check scan results appear
  3. Test Scan Results

    • Introduce vulnerable code
    • Verify MR is blocked
    • Test approval workflow
  4. Test Scheduled Policies

    • Wait for scheduled trigger
    • Verify pipeline runs
    • Check scan results

Example Test MR:

Test MR: Verify Security Policy Enforcement

Changes:
1. Add SQL injection vulnerability (SAST should detect)
2. Add hardcoded API key (Secret Detection should detect)
3. Add vulnerable dependency (Dependency Scanning should detect)

Expected Behavior:
- Security scans run automatically
- Vulnerabilities detected
- MR blocked from merging
- Security team approval required

Actual Behavior:
[Document results]

Rollout Strategy

Phased Approach:

Phase 1: Pilot (2 weeks)
  - Select 2-3 non-critical projects
  - Enable basic policies (SAST, Secret Detection)
  - Collect feedback
  - Adjust policies

Phase 2: Expand (1 month)
  - Roll out to 25% of projects
  - Add more scanners (Dependency, Container)
  - Monitor impact on pipeline duration
  - Refine policies based on feedback

Phase 3: Full Rollout (2 months)
  - Enable for all projects
  - Add scan result policies
  - Enforce blocking for critical issues
  - Provide training and support

Phase 4: Optimization (Ongoing)
  - Monitor vulnerability trends
  - Adjust thresholds
  - Add new scanners
  - Improve documentation

Change Management

Policy Updates:

1. Propose Change
   - Document proposed change
   - Explain rationale
   - Estimate impact

2. Review
   - Security team reviews
   - Engineering team reviews
   - Stakeholders approve

3. Test
   - Test in pilot project
   - Verify expected behavior
   - Document issues

4. Communicate
   - Announce change to teams
   - Provide documentation
   - Offer training if needed

5. Deploy
   - Update policy files
   - Monitor for issues
   - Be ready to rollback

6. Retrospective
   - Collect feedback
   - Document lessons learned
   - Plan improvements

Monitoring and Reporting

Policy Effectiveness

Metrics to Track:

Security Metrics:
- Total vulnerabilities detected
- Vulnerabilities by severity
- Mean time to remediation
- Policy violations
- Approval rate and time

Pipeline Metrics:
- Scan execution rate
- Scan duration
- Pipeline duration impact
- Failure rate

Compliance Metrics:
- Projects with policies applied
- Policy compliance rate
- Audit findings
- Exception requests

Dashboards:

Security Policy Dashboard

Scan Coverage:
  - 98% of projects have SAST enabled
  - 95% have Secret Detection
  - 87% have Dependency Scanning
  - 75% have Container Scanning

Vulnerability Trends:
  - Critical: 2 (down from 8 last month)
  - High: 15 (down from 24)
  - Medium: 45 (stable)
  - Low: 89 (up from 78)

Policy Enforcement:
  - 23 MRs blocked this month
  - 18 required security approval
  - Average approval time: 4.2 hours
  - 2 policy exceptions granted

Reporting

Monthly Security Report:

Security Policy Report - December 2025

Executive Summary:
  - 234 security scans executed
  - 156 vulnerabilities detected
  - 142 vulnerabilities resolved
  - 12 MRs required security approval

Policy Coverage:
  - 100% of projects have scan execution policies
  - 98% have scan result policies
  - All critical branches protected

Key Achievements:
  - Reduced critical vulnerabilities by 75%
  - Mean time to remediation: 8 days (target: 14 days)
  - Zero security incidents related to detected vulnerabilities

Areas for Improvement:
  - Increase Container Scanning adoption (currently 75%)
  - Reduce false positive rate (currently 12%)
  - Improve approval workflow efficiency

Troubleshooting

Common Issues

Policy not enforcing:

Symptoms:
- Security scans not running
- MR not blocked despite vulnerabilities

Checklist:
 Policy enabled in security policy project
 Security policy project linked to target project
 Security Policy Bot has permissions
 Policy syntax is valid
 Target branches match policy rules

Scans not appearing in MR:

Symptoms:
- Scans run but results don't show in MR widget

Checklist:
 Pipeline completed successfully
 Scan job produced artifacts
 Artifacts contain valid reports
 MR targets protected branch
 GitLab tier supports security dashboard (Ultimate)

False MR blocking:

Symptoms:
- MR blocked despite no new vulnerabilities

Troubleshooting:
1. Check vulnerability state in policy
2. Verify baseline comparison
3. Review scanner output
4. Check for scan errors
5. Contact security team for review

Permission issues:

Error: User cannot approve security policy requirement

Resolution:
1. Verify user is in approver list
2. Check user role (Developer minimum)
3. Ensure user is not MR author (if separation of duties)
4. Contact security policy project maintainer

References

Next Steps