Cloud Native 9 min read

How to Build a Secure Centralized Push‑Based GitOps Pipeline with GitLab CI

This article explains how to replace a naïve push‑based GitOps workflow with a centralized, permission‑controlled deployment pipeline using GitLab CI, detailing the architecture, advantages such as improved security and maintainability, and providing complete YAML examples for both service and central pipelines.

Ops Development & AI Practice
Ops Development & AI Practice
Ops Development & AI Practice
How to Build a Secure Centralized Push‑Based GitOps Pipeline with GitLab CI

Introduction

When a team cannot or does not want to adopt Argo CD Image Updater, a push‑based GitOps workflow is still possible if the push operation is performed by a dedicated, centrally managed pipeline rather than by each service’s CI job.

Why a naive push model fails

Directly letting every service CI modify the GitOps repository scatters deployment logic and high‑privilege write tokens, leading to unclear responsibilities, over‑privileged access, and difficult maintenance.

Centralized Deployment Pipeline Architecture

Architecture diagram
Architecture diagram

Key principles

Responsibility separation Service CI builds and pushes the container image, then stops.

Trigger and delegation After the image is ready, Service CI triggers the central pipeline via an API call, webhook, or GitLab downstream pipeline trigger instead of editing the GitOps repo itself.

Centralized authority The central pipeline is the sole entity with write access to the GitOps repository. It receives parameters such as application name, image tag, and target environment and performs all Git operations in a standardized way.

Improved flow diagram
Improved flow diagram

Advantages of the refined push model

Security improvement The high‑privilege token for the GitOps repo is stored only in the central pipeline’s CI/CD variables, dramatically reducing the attack surface.

True decoupling Service CI no longer needs to understand Kustomize, Helm, or any Git logic; it only signals that the image is ready for deployment.

High maintainability (DRY) All scripts that modify manifests—whether Kustomize, Helm, or plain YAML—are centralized. Switching tools (e.g., from sed to yq ) requires a single change.

Powerful flow control and extensibility The central pipeline can host complex deployment strategies such as manual approvals, integration testing, or canary releases with tools like Flagger.

Manual approval – add a job with when: manual.

Integration testing – run a test job before merging deployment changes.

Canary release – integrate with Flagger for progressive rollouts.

Hands‑On Example: Implementing with GitLab CI

1. Service CI configuration ( service-repo/.gitlab-ci.yml )

The service pipeline builds the image and then triggers the central pipeline using GitLab’s trigger keyword.

stages:
  - build
  - deploy

build-image:
  stage: build
  script:
    - echo "Building and pushing image docker.io/my-org/my-app:$CI_COMMIT_TAG..."
    # (docker build & push commands omitted)
  only:
    - tags

trigger-deployment:
  stage: deploy
  trigger:
    project: 'your-group/gitops-repo'   # GitOps repository path
    branch: 'main'
    strategy: depend
  variables:
    APP_NAME: "my-app"
    APP_IMAGE_TAG: $CI_COMMIT_TAG
    TARGET_ENV: "staging"
  only:
    - tags

2. Central deployment pipeline ( gitops-repo/.gitlab-ci.yml )

This pipeline receives the variables and updates the manifest in the target environment.

workflow:
  rules:
    - if: $APP_NAME && $APP_IMAGE_TAG && $TARGET_ENV   # Run only when triggered

stages:
  - update-manifest

update-kustomization-manifest:
  stage: update-manifest
  image:
    name: alpine/k8s:1.23.5   # Contains kubectl and kustomize
  script:
    - echo "Updating $APP_NAME in $TARGET_ENV to tag $APP_IMAGE_TAG"
    - git config --global user.email "[email protected]"
    - git config --global user.name "GitLab CI"
    - cd apps/$TARGET_ENV/$APP_NAME
    - kustomize edit set image my-app=docker.io/my-org/my-app:$APP_IMAGE_TAG
    - git add kustomization.yaml
    - git commit -m "ci: Bump $APP_NAME in $TARGET_ENV to $APP_IMAGE_TAG"
    - git push https://gitlab-ci-token:[email protected]/your-group/gitops-repo.git HEAD:main

Note: $GITOPS_REPO_TOKEN is a Project Access Token with write permission, stored securely in the CI/CD variables of the gitops-repo project.

Conclusion

A centralized push model provides a pragmatic, secure, and maintainable alternative to the pure pull‑based Argo CD Image Updater. By consolidating deployment responsibilities in a single authoritative pipeline, teams retain the proactive nature of push while preserving the GitOps principle of separation of concerns.

CI/CDKubernetesGitLabGitOpsArgo CDDeployment Pipeline
Ops Development & AI Practice
Written by

Ops Development & AI Practice

DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.