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
- Start Simple - Begin with SAST and Secret Detection
- Use Schedules for Slow Scans - Run DAST weekly, not on every commit
- Exclude Test Paths - Reduce noise by excluding test directories
- Progressive Enhancement - Add more scanners gradually
- Monitor Performance - Track pipeline duration impact
- 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
- Zero Tolerance for Critical - Block critical vulnerabilities completely
- Graduated Response - Different thresholds for different severities
- New vs Existing - Focus on newly introduced vulnerabilities
- Multiple Approvers - Require security and technical approval
- Comprehensive Scanners - Apply to all relevant scanners
- Protected Branches - Focus on main and production branches
- 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:
- Create new GitLab project (e.g.,
security-policies) - Navigate to group or project
- Go to: Security & Compliance > Policies
- Click "Edit policy project"
- 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:
- Navigate to: Group > Security & Compliance > Policies
- Select security policy project
- All subgroups and projects automatically inherit policies
Project-Level Policy:
- Navigate to: Project > Security & Compliance > Policies
- Click "Edit policy project"
- Select security policy project
- 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.ymlfiles
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
- Start Simple - Begin with basic SAST and Secret Detection
- Progressive Enhancement - Add scanners and rules gradually
- Test First - Test policies on pilot projects before wide rollout
- Document Everything - Explain why each policy exists
- 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:
-
Create Test Project
- Set up dedicated test project
- Link security policy project
- Verify policies apply
-
Test Scan Execution
- Create merge request
- Verify security scans run
- Check scan results appear
-
Test Scan Results
- Introduce vulnerable code
- Verify MR is blocked
- Test approval workflow
-
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
- Security Policies Documentation
- Scan Execution Policies Documentation
- Scan Result Policies Documentation
- Policy Project Documentation
Next Steps
- Security Scanning - Configure security scanners
- Vulnerability Management - Triage and remediate findings
- Access Control - Configure branch protection and approvals