---
title: "Argo CD Field Notes: From Helm Install to Wiring Up GitLab SSO"
description: "A step-by-step record of installing Argo CD via Helm and integrating GitOps with GitLab SSO. Say goodbye to manual kubectl — make K8s deployments automated and traceable."
canonical_url: "https://blog.markkulab.net/en/post/argocd-gitops-helm-installation-and-gitlab-sso-setup"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2025-11-20 10:00:00 +0800"
category: "DevOps"
tags: ["kubernetes", "argocd", "gitops", "helm", "gitlab", "devops"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Argo CD Field Notes: From Helm Install to Wiring Up GitLab SSO

## Why Argo CD + GitOps?

If you only have one K8s cluster with low update frequency, manual deployment with `kubectl apply` is fine. But once the architecture grows and you hit the following scenarios, manual operations start to fall short:

- Need to manage **10–20 K8s clusters** (Dev/Staging/Prod and other environments)
- Frequently switching `kubectl context` is error-prone
- After manual Apply, hard to confirm whether the cluster's current state matches version control

This is where introducing **GitOps + Argo CD** effectively addresses these pain points.

The core idea is intuitive: **"automate the deployment operation, reduce human intervention."**

- **Git as the single source of truth**: All YAML and Helm values must go into Git version control.
- **Argo CD handles auto-sync**: Continuously monitors the Git repo; when code changes, it automatically syncs cluster state to the desired state.
- **Fast rollback**: If a deploy goes wrong, just Revert in Git and Argo CD will help switch back to the previous version, ensuring stability.

These notes record the key steps for setting up this flow: installing Argo CD via Helm, configuring GitLab SSO, and how to plan permission management properly.

---

## Core GitOps concept

I won't go too deep into theory, but one concept is essential.

Traditional deployment often lacks standardization — what each person manually applies may differ, and over time the environment "drifts" and becomes hard to trace.
GitOps treats Git as the "standard SOP," and Argo CD is the executor. It ensures the cluster's actual state (Live State) always matches the definition in the Git repo (Desired State). If someone manually modifies cluster resources, Argo CD detects the difference and marks it as OutOfSync — you can even configure self-healing to revert it.

Once you understand this, the configuration steps below have more context.

> (Prerequisites like adding the Helm Repo are skipped here — let's jump to the main course of SSO and permissions.)


## Implementation: settle authentication and installation

### Step 1: Prepare the Helm environment

Easy step — add the Helm repo and export the Argo CD default values.yaml for editing.

```bash
# Add Helm repository
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

# Export default values for editing
helm show values argo/argo-cd --version 8.3.2 > values.yaml
```

### Step 2: Create a GitLab OAuth Application

This step establishes trust between Argo CD and GitLab. By configuring an Application in GitLab, users can log in to Argo CD with their GitLab account — for unified account management.

1. Log in to GitLab → top-right avatar → `Settings → Applications`
2. Add an Application:
  - **Name**: `ArgoCD SSO`
  - **Redirect URI**: `http://<your-node-ip>:32009/api/dex/callback`
  - **Scopes**: check `openid`, `read_user`, `email`
3. After saving, get the **Application ID** and **Secret**

> ⚠️ Don't commit the Client ID and Secret to a Git repository.

![](https://blog.markkulab.net/content/markku/posts/argocd-gitops-helm-installation-and-gitlab-sso-setup/images/attachments/5a1836e9-f936-4e9c-9762-55b5eb67285e.png " =1548x674")

**Two configuration methods:**

A. Write directly into values.yaml (recommended — easy to automate)
B. Configure inside Argo CD UI after install (good for ad-hoc adjustments)

![](https://blog.markkulab.net/content/markku/posts/argocd-gitops-helm-installation-and-gitlab-sso-setup/images/attachments/b8ce9bbd-f83d-4715-96e8-ca016638d3ef.png " =1874x907")


### Step 3: Create a GitLab Group Access Token

Argo CD needs permission to access the Git repo to pull code.
Strongly recommend **not using a personal account's Token** — staff changes or password updates would interrupt production deployments. Best practice: get a dedicated **Group Access Token**.

1. Go to your GitLab Group page → `Settings` → `Access Tokens`.
2. Create a Token:
  - **Name**: something recognizable, e.g., `argocd-group-readonly`
  - **Scopes**: just check `read_repository` and `read_api` — least privilege is safest.
  - **Role**: pick `Reporter` (read-only suffices).
3. **Critical**: copy the Token immediately after creation — GitLab only displays it once.


### Step 4: Write values.yaml

This is the key step. We'll create a custom `values.yaml` filling in the SSO and Repo info gathered above, overriding Helm's default settings.

```yaml
configs:
  cm:
    # Argo CD's entrypoint URL — used by SSO callback
    url: http://<your-node-ip>:32009
    
    # The most likely place to get stuck: Dex (SSO) configuration
    dex.config: |
      connectors:
        - type: gitlab
          id: gitlab
          name: GitLab
          config:
            baseURL: https://gitlab.example.com
            clientID: <your-gitlab-oauth-client-id>
            clientSecret: <your-gitlab-oauth-client-secret>
            # Make sure the Callback URL in GitLab Application settings matches this
            redirectURI: http://<your-node-ip>:32009/api/dex/callback
  
  # Plug in the Token you just created so Argo CD recognizes your GitLab
  credentialTemplates:
    gitlab-group-token:
      url: https://gitlab.example.com
      username: oauth2  # always 'oauth2'
      password: <your-gitlab-group-access-token>
  
  # Pre-register repos to save adding them one-by-one in the UI later
  repositories:
    kong-api-gateway:
      url: https://gitlab.example.com/your-group/kong-api-gateway.git
      type: git
    argocd-deployment:
      url: https://gitlab.example.com/your-group/argocd-deployment.git
      type: git

# Server network setup (Lab uses NodePort for laziness; production should use Ingress)
server:
  service:
    type: NodePort
    nodePortHttp: 32009
    nodePortHttps: 32010
  
  # Allow HTTP in dev — otherwise certificate errors will keep popping up
  extraArgs:
    - --insecure
```

> 💡 Production recommendation: Ingress + TLS to replace NodePort, and remove `--insecure`.


### Step 5: Install Argo CD

Once configs are ready, fire away:

```bash
# Install Argo CD
helm upgrade --install homelab-argo argo/argo-cd \
  --version 8.3.2 \
  -f values.yaml \
  -n argocd --create-namespace

# Wait for Pods to come up
kubectl wait --for=condition=ready pod \
  -l app.kubernetes.io/name=argocd-server \
  -n argocd --timeout=300s

# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d
```

Change the admin password right after first login.

---


## Permission management

### Step 6: Configure RBAC and AppProject

After installing Argo CD, you still need to define "who can manage what resources" and "which clusters can be deployed to." The AppProject mechanism is essentially a permission whitelist — without proper config, Argo CD won't be able to deploy anything.

Create `argocd-projects.yaml`:

```yaml
apiVersion: v1
kind: List
items:
# Default Project — basic permissions
- apiVersion: argoproj.io/v1alpha1
  kind: AppProject
  metadata:
    name: default
    namespace: argocd
  spec:
    # Allow all source repos
    sourceRepos:
    - '*'
    
    # Allow deploy to all clusters and namespaces
    destinations:
    - namespace: '*'
      server: '*'
    
    # Allow operating cluster-level resources
    clusterResourceWhitelist:
    - group: '*'
      kind: '*'
    
    # Allow operating namespace-level resources
    namespaceResourceWhitelist:
    - group: '*'
      kind: '*'

# Custom Project — tune to your needs
- apiVersion: argoproj.io/v1alpha1
  kind: AppProject
  metadata:
    name: your-project
    namespace: argocd
  spec:
    description: Your project description
    
    sourceRepos:
    - 'https://gitlab.example.com/your-group/*'
    
    destinations:
    - namespace: '*'
      server: https://kubernetes.default.svc
    
    # Cluster-level resource whitelist
    clusterResourceWhitelist:
    - group: ''
      kind: Namespace
    - group: 'rbac.authorization.k8s.io'
      kind: ClusterRole
    - group: 'rbac.authorization.k8s.io'
      kind: ClusterRoleBinding
    - group: 'apiextensions.k8s.io'
      kind: CustomResourceDefinition
    
    # Namespace-level resource whitelist
    namespaceResourceWhitelist:
    - group: ''
      kind: ConfigMap
    - group: ''
      kind: Secret
    - group: ''
      kind: Service
    - group: ''
      kind: ServiceAccount
    - group: 'apps'
      kind: Deployment
    - group: 'apps'
      kind: StatefulSet
    - group: 'batch'
      kind: Job
    - group: 'batch'
      kind: CronJob
    - group: 'networking.k8s.io'
      kind: Ingress

# Extra RBAC permissions for Argo CD Controller (supports metrics-server, etc.)
- apiVersion: rbac.authorization.k8s.io/v1
  kind: ClusterRole
  metadata:
    name: argocd-application-controller-auth-delegator
    labels:
      app.kubernetes.io/component: application-controller
      app.kubernetes.io/name: argocd-application-controller
      app.kubernetes.io/part-of: argocd
  rules:
  # Auth delegation for metrics-server
  - apiGroups: ["authentication.k8s.io"]
    resources: ["tokenreviews"]
    verbs: ["create"]
  - apiGroups: ["authorization.k8s.io"]
    resources: ["subjectaccessreviews"]
    verbs: ["create"]
  # API Services management
  - apiGroups: ["apiregistration.k8s.io"]
    resources: ["apiservices"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

- apiVersion: rbac.authorization.k8s.io/v1
  kind: ClusterRoleBinding
  metadata:
    name: argocd-application-controller-auth-delegator
  roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: argocd-application-controller-auth-delegator
  subjects:
  - kind: ServiceAccount
    name: argocd-application-controller
    namespace: argocd
```


### Apply the config

```bash
# Apply AppProject and RBAC config
kubectl apply -f argocd-projects.yaml -n argocd

# Verify Projects are created
kubectl get appprojects -n argocd

# Check RBAC permissions too
kubectl get clusterrole | grep argocd
kubectl get clusterrolebinding | grep argocd
```


### Permission structure cheat sheet

When integrating Argo CD with GitLab, permissions split into three layers:

1. **SSO login (GitLab OAuth)**: manages user identity — decides who can log in to the Argo CD UI.
2. **Repo access (Group Access Token)**: manages code access — lets Argo CD read GitLab repos.
3. **Registry (optional)**: manages image-pull permissions — pulling private images requires an additional Deploy Token.

> 💡 SSO manages "people," Group Token manages "code," Registry Token manages "images."

![](https://blog.markkulab.net/content/markku/posts/argocd-gitops-helm-installation-and-gitlab-sso-setup/images/attachments/b8ce9bbd-f83d-4715-96e8-ca016638d3ef.png " =1874x907")

---


## Worked example

### Application status overview

![](https://blog.markkulab.net/content/markku/posts/argocd-gitops-helm-installation-and-gitlab-sso-setup/images/attachments/37293e96-21b9-4734-b8b8-8f657ecd65e6.png)

This is the [Argo CD](https://argo-cd.readthedocs.io/en/stable/) Application status page. Key indicators to watch:

- **Application name:** `testapp`
- **APP HEALTH:** ✅ **Healthy** — all resources running normally.
- **SYNC STATUS:** ✅ **Synced to HEAD** — Git config is fully synced to the cluster.
- **LAST SYNC:** ✅ **Sync OK** — most recent sync succeeded.
- **Auto sync:** ❌ Auto-sync not enabled.

---

### 🌳 Application resource tree

A K8s resource tree deployed via GitOps roughly looks like this:

1. **testapp (Application)**
   * **nginx-content (ConfigMap)**
   * **test-app (Namespace)**
   * **nginx-test-service (Service)**
   * **nginx-test (Deployment)**
     * **nginx-test-554867cd4b (ReplicaSet)**
       * **nginx-test-554867cd4b-65gtp (Pod)**
       * **nginx-test-554867cd4b-xgs9x (Pod)**

📌 As long as the top-right shows ✅ green status, the deployment succeeded.

---


## Quick command reference
A quick reference for common ops commands.

### Helm

```bash
# Install Helm (Windows)
choco install kubernetes-helm

# Install/upgrade Argo CD
helm upgrade --install argocd argo/argo-cd \
  --namespace argocd --create-namespace \
  -f values.yaml

# Export current settings
helm get values argocd -n argocd -o yaml > current-values.yaml
```

### K8s debug and config commands

```bash
# Inspect Argo CD Service
kubectl get svc argocd-server -n argocd

# Patch Service to NodePort
kubectl patch svc argocd-server -n argocd -p '{
  "spec": {
    "type": "NodePort",
    "ports": [
      {
        "port": 80,
        "targetPort": 8080,
        "nodePort": 32009
      }
    ]
  }
}'

# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

# Export AppProject config
kubectl get appprojects -n argocd -o yaml > argocd-projects.yaml
```

> ⚠️ Once you have the admin password, change it immediately.

---

## References

- [Argo CD official docs](https://argo-cd.readthedocs.io/)
- [Argo CD Helm Chart](https://github.com/argoproj/argo-helm)
- [GitLab OAuth setup](https://docs.gitlab.com/ee/integration/oauth_provider.html)
- [Argo CD implementation example](https://blog.csdn.net/cr7258/article/details/122028096)
- [GitOps best practices](https://ithelp.ithome.com.tw/articles/10266761)

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/argocd-gitops-helm-installation-and-gitlab-sso-setup)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
