Chapter 27Lesson 01~300 minutes

Security Policies, Scan Execution, Pipeline Execution, Approval Policies, and Compliance Controls: Concepts, Architecture, and Mental Model

Build a precise mental model of GitLab security policy projects, policy scope and inheritance, scan and pipeline enforcement, merge-request approval policies, compliance frameworks, evidence, and separation of duties.

Mental modelPolicy scopeSeparation of dutiesUltimate boundaryGitLab 19.3

Learning objectives

  • Separate a security policy project from an ordinary application project and from project-owned .gitlab-ci.yml.
  • Explain policy linking, inheritance, policy_scope, update propagation, and separation of duties.
  • Distinguish scan execution, pipeline execution, scheduled pipeline execution, and merge request approval policies by enforcement point.
  • Place compliance frameworks and controls correctly relative to security policies.
  • Inspect policy state and expected evidence before making any governance change.
Availability baseline — verified 2026-08-22 against GitLab 19.3. Security policies (scan execution, pipeline execution, merge request approval, scheduled pipeline execution, vulnerability management) and security policy projects are currently Ultimate across GitLab.com, Self-Managed, and Dedicated. Compliance frameworks are Premium/Ultimate; using frameworks as policy-enforcement scope and broader security/compliance controls is an Ultimate operating model. Instance-wide compliance and security policy groups are Ultimate on Self-Managed/Dedicated and administrator-controlled. Therefore the mandatory chapter path is a Free-compatible local/CI fixture simulation; live enforcement is optional only when a disposable Ultimate/trial environment and required roles already exist.

1. The practical problem: one project can be configured correctly while the organization is still unsafe

Earlier chapters taught scanners, vulnerability evidence, pipelines, protected resources, and approvals inside individual projects. Large organizations need something stronger than copying the same YAML into hundreds of repositories. A central requirement such as “every default-branch pipeline must run a trusted security check” must survive project refactors, onboarding of new repositories, and ordinary maintainer changes.

GitLab security policies solve that organizational problem by separating policy intent and ownership from the application project’s ordinary CI configuration. This separation is powerful, but it creates new failure modes: a policy can exist without being linked, inherit farther than expected, conflict with project CI, depend on a file users cannot read, or silently become an unaudited exception process.

2. Mental model: requirement → policy project → assignment → evaluation → evidence

A security policy project is a special GitLab project that stores policy-as-code in .gitlab/security-policies/policy.yml. Linking that policy project to a group, subgroup, or project makes the linked objects enforceable. The link establishes the organizational relationship; each policy’s policy_scope can then narrow which descendants are actually affected.

Security-policy enforcement chain
flowchart TD
  A[Security / compliance requirement] --> B[Policy intent]
  B --> C[Security policy project
policy.yml]
  C --> D[Link to group / subgroup / project]
  D --> E[Inheritance + policy_scope]
  E --> F[Scan execution policy]
  E --> G[Pipeline execution policy]
  E --> H[MR approval policy]
  F --> I[Security scan jobs]
  G --> J[Enforced CI/CD jobs]
  H --> K[Approval / merge constraints]
  I --> L[Evidence]
  J --> L
  K --> L
  L --> M[Audit / exception review]

The policy project does not become the application repository. It contributes centrally governed behavior at evaluation time. The application project still owns its source, merge requests, ordinary CI jobs, runners, packages, and environments. The trust boundary is therefore explicit: policy maintainers govern constraints; project maintainers build software inside those constraints.

3. Linking, inheritance, and scope are three different concepts

Linking associates a security policy project with an organizational unit. Inheritance means a linked group policy applies to descendant subgroups and projects by default. Policy scope narrows a specific policy to selected projects, groups, or compliance frameworks.

Scope trap: an empty scope collection such as projects: { including: [] } is treated like the scope field was omitted; it does not mean “apply to zero projects.” To disable a policy, set enabled: false.
Question Correct GitLab surface
Which organizational units know about this policy project? Policy-project link.
Which descendants receive enforcement by default? Inheritance from the linked group/subgroup.
Which subset should this policy actually target? policy_scope.
Who is allowed to change the link? Owner or custom role with manage_security_policy_link.

4. Choose the enforcement mechanism by the thing you must control

All of the following are Ultimate security-policy types, but they solve different problems:

Policy type What it enforces When it is the right tool
Scan execution GitLab security scans in pipelines or on a schedule. You need a supported GitLab scanner applied consistently with relatively little customization.
Pipeline execution Custom CI/CD configuration/jobs injected or used to replace project CI according to strategy. You need custom compliance jobs, third-party tools, pre/post gates, or stronger CI behavior control.
Scheduled pipeline execution Independent policy-created pipelines on daily/weekly/monthly cadence. You need centrally scheduled CI even when a project has no new commits; GA since GitLab 19.2.
MR approval Approval rules and project settings based on scanner/branch conditions. You need merge prevention or approvals after completed evidence is evaluated.

Do not use a merge-request approval policy to “run” a scanner. It consumes completed pipeline evidence. Conversely, a scan execution policy runs a scanner but does not by itself express every merge-approval decision.

5. Evaluation timing explains many surprises

Policy evaluation is not one single moment. Scan and pipeline execution policies affect future pipeline creation. Merge request approval policies evaluate completed pipeline evidence and can require approvals when required scanner reports are missing. Protected-branch policy rules synchronize with a short delay. Policy changes merged through a security-policy-project merge request take effect after merge; direct commits to the policy YAML can take up to about ten minutes to propagate.

That timing matters during incidents: a pipeline already in progress is not rewritten because you changed policy. Record the policy commit SHA, target project/ref, pipeline ID, and observed enforcement state before concluding that GitLab ignored the change.

6. Separation of duties is part of the control, not an organizational preference

A control is weak if the same project maintainer being constrained can silently change or unlink it. GitLab recommends central policy ownership, protected default branches in security policy projects, approval rules for policy changes, and restricted policy-management permissions. Linking requires Owner or a custom role with manage_security_policy_link. Policy creation/management roles also depend on whether enforcement is at group or project scope.

Visibility warning. Linking a private security policy project can expose its policy contents through the Policies page to members of linked projects. Never place passwords, tokens, or other secrets in policy YAML or policy variables; policy configuration is Git content.

7. Compliance frameworks label scope; security policies enforce behavior

A compliance framework is a top-level-group construct that labels projects with compliance requirements. Frameworks are Premium/Ultimate. In Ultimate, frameworks can be used as policy scope and can carry GitLab compliance controls. This makes a useful operating model: framework answers “which projects are regulated?” while a security policy answers “what must GitLab enforce for those projects?”

On Self-Managed/Dedicated Ultimate, administrators can also designate a centralized compliance and security policy group for instance-wide policy/framework governance. That is an administrative platform feature, not a mandatory developer exercise.

8. Read-only inspection comes before policy editing

On an Ultimate environment, inspect Secure → Policies for current policy status and linked policy project; inspect the security policy project default branch and policy.yml; inspect the target project’s framework labels; and inspect recent pipelines/MRs for policy-originated jobs or approvals. On Free, use the same checklist against the fixtures in Lesson 2.

# Read-only Git evidence in a policy fixture repository
git rev-parse HEAD
git log -1 --oneline -- .gitlab/security-policies/policy.yml
git diff -- .gitlab/security-policies/policy.yml
# Never print tokens or dump complete environments while collecting policy evidence.

9. DevOps connection: central policy expands capability and blast radius

A central policy can protect hundreds of projects, but one bad scope, inaccessible policy file, duplicated job, or incorrect approval condition can also stop hundreds of delivery pipelines. Treat policy changes like production code: version them, review them, test them on a small disposable scope, predict affected projects, collect audit evidence, and roll them out incrementally.

Knowledge check

What is the difference between linking a security policy project and setting policy_scope?

Does projects: { including: [] } mean the policy applies to no projects?

Which policy type should enforce a custom license-validation script before project jobs run?

Why can an MR approval policy block when scanner reports are missing?

Why is protecting the security policy project default branch important?

Summary and bridge

Policy intent, assignment, scope, enforcement type, evidence, and ownership are separate dimensions. Lesson 2 turns this model into a disposable Free-compatible policy-as-code exercise, with an optional Ultimate live path only if a safe trial or licensed sandbox already exists.

Primary sources and version notes

These lessons were finalized against current official GitLab documentation on 2026-08-22. Re-check tier, feature status, policy schema, permission, audit-event, and Self-Managed-version behavior before applying the same design later.

Next lesson

Guided Hands-On Workflow and Core Operations

Author realistic policy fixtures, predict scope, simulate a violation, and map evidence to optional Ultimate enforcement.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.