CoursesSecure CI/CD with GitLabSecuring the pipeline itself

Protected branches, tags & environments

Who can change and deploy what.

Intermediate12 min · lesson 5 of 17

Protection in GitLab starts with branches. A protected branch — typically main — restricts who can push and merge to it, so code only reaches the default branch through a reviewed merge request. That review gate is the foundation everything else builds on: if anyone can push to main, then anyone can change the pipeline, the deploy config, and what ships. Protect main, require merge requests, and require approvals.

Settings → Repository → Protected branches
# main:
# Allowed to push: No one (force all changes through MRs)
# Allowed to merge: Maintainers
# Require approval from Code Owners: on
# protected tags (e.g. v*): only maintainers can create release tags

Protected variables and tags

GitLab ties secrets to protection. A CI/CD variable can be marked "protected," which means it is only exposed to jobs running on protected branches and tags — so a feature branch or a fork pipeline literally cannot see your production credentials. Protected tags similarly restrict who can create release tags, so a tag that triggers a production deploy cannot be pushed by just anyone. Protection is the mechanism that keeps privileged secrets away from unprivileged pipelines.

Protected environments

An environment in GitLab (staging, production) can be protected so that only specific users or roles can run deployment jobs to it, with optional required approvals before the job proceeds. This gives you change control and an audit trail for every production deploy — who approved it, when — without bolting on a separate ticketing system. Combined with a manual rule, a production deploy becomes a deliberate, reviewed, recorded action.

.gitlab-ci.yml
deploy-prod:
stage: deploy
environment:
name: production # protected in Settings → CI/CD → Environments
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual # a maintainer clicks deploy; approval recorded
Unprotected variables leak to fork pipelines
A CI/CD variable that is not marked protected is available to any pipeline, including those triggered from feature branches and — depending on settings — forks. That is how production tokens end up readable by a merge request from an outside contributor. Mark every sensitive variable protected (and masked), so only reviewed code on protected refs can ever see it.