Enterprise-Grade ArgoCD SSO with GitLab Integration

Production-ready guide to implementing secure ArgoCD SSO with GitLab including advanced RBAC and multi-cluster federation

Featured image



Overview

In the last post, I tried configuring ArgoCD SSO using Google Oauth,

This post explains how to configure Single Sign-On (SSO) for ArgoCD using GitLab. We’ll walk through the process of setting up GitLab OAuth and integrating it with ArgoCD.


Enterprise GitOps Authentication Architecture

Modern enterprise environments require sophisticated authentication strategies that can scale across multiple clusters while maintaining security and compliance. The integration between ArgoCD and GitLab provides a robust foundation for enterprise GitOps workflows.

graph TB subgraph "Identity Provider Layer" GitLab[GitLab OAuth Provider] SAML[Enterprise SAML/LDAP] end subgraph "Authentication Layer" Dex[Dex Identity Proxy] OAuth[OAuth2 Flow] end subgraph "ArgoCD Platform" Server[ArgoCD Server] RBAC[RBAC Engine] JWT[JWT Validation] end subgraph "Multi-Cluster Environment" Prod[Production Cluster] Staging[Staging Cluster] Dev[Development Cluster] end GitLab --> Dex SAML --> GitLab Dex --> OAuth OAuth --> Server Server --> RBAC RBAC --> JWT JWT --> Prod JWT --> Staging JWT --> Dev


Benefits of GitLab SSO Integration

  • Unified Authentication
    Allows developers to use their existing GitLab credentials for ArgoCD access.
  • Streamlined Access Management
    Leverages GitLab's groups and user management for ArgoCD authorization.
  • Improved Developer Experience
    Eliminates the need to manage separate credentials for GitLab and ArgoCD.
  • Consistent Permissions
    GitLab groups can be mapped directly to ArgoCD roles for consistent access control.


Prerequisites

Security Planning Considerations

Before implementing SSO, consider these enterprise security requirements:

Security Domain Requirements Implementation
Identity Provider Multi-factor authentication, SAML integration GitLab + Enterprise SSO
Network Security TLS 1.3, Network policies, WAF Ingress + cert-manager
Access Control Least privilege, role separation RBAC + Project isolation
Audit & Compliance Complete audit trails, compliance reporting Centralized logging + monitoring


Steps


1. Create GitLab Application

Console Method


Command Line Setup

If you’re using GitLab API to create the application:


GitLab Application Security Considerations

Application Security Best Practices:
Enterprise Security Enhancements:
# Enhanced security configuration
dex.config: |
  connectors:
    - type: gitlab
      id: gitlab
      name: GitLab
      config:
        baseURL: https://gitlab.your-domain.com
        clientID: $dex.gitlab.clientId
        clientSecret: $dex.gitlab.clientSecret
        redirectURI: https://argocd.your-domain.com/api/dex/callback
        groups:
          - engineering
          - platform
        # Enhanced security options
        useLoginAsID: false
        insecureSkipVerify: false
        # Custom CA certificate for private GitLab
        rootCAs: |
          -----BEGIN CERTIFICATE-----
          ... your CA certificate ...
          -----END CERTIFICATE-----


2. Configure ArgoCD Installation

Create values/mgmt.yaml with production-ready configuration:

global:
  domain: argocd.your-domain.com

configs:
  params:
    create: true
    server.insecure: false  # Always use TLS in production
    # Security hardening
    server.enable.grpc.web: true
    server.grpc.keepalive.time: 60s
    server.grpc.keepalive.timeout: 5s

  ssh:
    extraHosts: |
      gitlab.your-domain.com ssh-rsa AAAAB3N...
      gitlab.your-domain.com ecdsa-sha2-nistp256...
      gitlab.your-domain.com ssh-ed25519 AAAA..

  # Global security configurations
  cm:
    # Session timeout for security
    timeout.hard.reconciliation: 0
    timeout.reconciliation: 180s
    # Application source restrictions
    application.instanceLabelKey: argocd.argoproj.io/instance
    # Repository credentials template
    repositories: |
      - type: git
        url: https://gitlab.your-domain.com
        passwordSecret:
          name: gitlab-secret
          key: password
        usernameSecret:
          name: gitlab-secret
          key: username

controller:
  replicas: 3  # High availability
  resources:
    limits:
      cpu: 2000m
      memory: 4Gi
    requests:
      cpu: 500m
      memory: 1Gi
  # Application controller metrics
  metrics:
    enabled: true
    serviceMonitor:
      enabled: true

dex:
  enabled: true
  resources:
    limits:
      cpu: 500m
      memory: 256Mi
    requests:
      cpu: 250m
      memory: 128Mi

redis:
  enabled: true
  resources:
    limits:
      cpu: 200m
      memory: 128Mi
    requests:
      cpu: 100m
      memory: 64Mi

server:
  replicas: 3  # High availability
  resources:
    limits:
      cpu: 1000m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
  ingress:
    enabled: true
    annotations:
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/grpc-backend: "true"
    ingressClassName: "nginx"
    path: /
    pathType: Prefix
    tls:
      - secretName: argocd-server-tls
        hosts:
          - argocd.your-domain.com
  # Server metrics
  metrics:
    enabled: true
    serviceMonitor:
      enabled: true

repoServer:
  replicas: 3  # High availability
  resources:
    limits:
      cpu: 1000m
      memory: 2Gi
    requests:
      cpu: 250m
      memory: 512Mi
  # Repo server metrics
  metrics:
    enabled: true
    serviceMonitor:
      enabled: true

applicationSet:
  replicas: 2  # High availability
  resources:
    limits:
      cpu: 500m
      memory: 512Mi
    requests:
      cpu: 100m
      memory: 128Mi

notifications:
  enabled: true
  resources:
    limits:
      cpu: 500m
      memory: 128Mi
    requests:
      cpu: 100m
      memory: 64Mi
  # Notification integrations
  notifiers:
    service.slack: |
      token: $slack-token
    service.email.gmail: |
      username: $email-username
      password: $email-password
      host: smtp.gmail.com
      port: 587
      from: $email-username


3. Configure GitLab SSO

Update values/mgmt.yaml with SSO configuration:

configs:
  cm:
    timeout.reconciliation: 60s
    dex.config: |
      connectors:
        - type: gitlab
          id: gitlab
          name: GitLab
          config:
            baseURL: <gitlab url>
            clientID: <application id>
            clientSecret: <secret>
            redirectURI: https://<argocd url>/api/dex/callback
            groups:
              - server
              
  rbac:
    create: true
    policy.csv: |
      p, role:org-admin, applications, *, */*, allow
      p, role:org-admin, clusters, get, *, allow
      p, role:org-admin, repositories, *, *, allow
      p, role:org-admin, projects, get, *, allow
      p, role:org-admin, logs, get, *, allow
      p, role:org-admin, exec, create, */*, allow
      
      g, <group>, role:org-admin

  secrets:
    dex.gitlab.clientId: "<application id>"
    dex.gitlab.clientSecret: "<secret>"


Apply the changes:

helm upgrade argocd . -n argocd -f ./values/mgmt.yaml
kubectl rollout restart -n argocd deployment argocd-dex-server


4. Test Login

Access your ArgoCD instance and verify GitLab SSO login works correctly.

ArgoCD SSO GitLab Login


Advanced GitLab SSO Configuration


Multi-Environment RBAC Strategy

Implement a comprehensive RBAC strategy that scales across multiple environments:

configs:
  rbac:
    policy.csv: |
      # Global Admin Role - Full cluster access
      p, role:global-admin, applications, *, */*, allow
      p, role:global-admin, clusters, *, *, allow
      p, role:global-admin, repositories, *, *, allow
      p, role:global-admin, projects, *, *, allow
      p, role:global-admin, accounts, *, *, allow
      p, role:global-admin, certificates, *, *, allow
      p, role:global-admin, gpgkeys, *, *, allow
      p, role:global-admin, logs, *, *, allow
      p, role:global-admin, exec, *, *, allow
      
      # Platform Team - Infrastructure management
      p, role:platform-admin, applications, *, platform/*, allow
      p, role:platform-admin, applications, *, infrastructure/*, allow
      p, role:platform-admin, clusters, get, *, allow
      p, role:platform-admin, repositories, *, *, allow
      p, role:platform-admin, projects, get, *, allow
      p, role:platform-admin, logs, *, platform/*, allow
      p, role:platform-admin, logs, *, infrastructure/*, allow
      
      # DevOps Team - Application deployment
      p, role:devops-engineer, applications, *, */prod, allow
      p, role:devops-engineer, applications, *, */staging, allow
      p, role:devops-engineer, applications, sync, */*, allow
      p, role:devops-engineer, repositories, get, *, allow
      p, role:devops-engineer, logs, *, */*, allow
      p, role:devops-engineer, exec, create, */staging, allow
      
      # Senior Developers - Production read, staging full
      p, role:senior-developer, applications, get, */prod, allow
      p, role:senior-developer, applications, *, */staging, allow
      p, role:senior-developer, applications, *, */dev, allow
      p, role:senior-developer, logs, *, */*, allow
      p, role:senior-developer, exec, create, */dev, allow
      p, role:senior-developer, exec, create, */staging, allow
      
      # Regular Developers - Development environment only
      p, role:developer, applications, get, */prod, allow
      p, role:developer, applications, get, */staging, allow
      p, role:developer, applications, *, */dev, allow
      p, role:developer, logs, *, */dev, allow
      p, role:developer, exec, create, */dev, allow
      
      # Security Team - Read-only audit access
      p, role:security-auditor, applications, get, */*, allow
      p, role:security-auditor, logs, get, */*, allow
      p, role:security-auditor, repositories, get, *, allow
      p, role:security-auditor, clusters, get, *, allow
      
      # Map GitLab groups to roles
      g, gitlab:platform-admins, role:global-admin
      g, gitlab:infrastructure-team, role:platform-admin
      g, gitlab:devops-engineers, role:devops-engineer
      g, gitlab:senior-developers, role:senior-developer
      g, gitlab:developers, role:developer
      g, gitlab:security-team, role:security-auditor
      
    # Default policy for authenticated users
    policy.default: role:readonly
    # Required scopes for group mapping
    scopes: "[groups, email, profile]"

Role-Based Access Control with GitLab Groups

You can map different GitLab groups to different ArgoCD roles for granular access control:

configs:
  rbac:
    policy.csv: |
      # Administrators with full access
      p, role:admin, applications, *, */*, allow
      p, role:admin, clusters, *, *, allow
      p, role:admin, repositories, *, *, allow
      p, role:admin, projects, *, *, allow
      p, role:admin, accounts, *, *, allow
      p, role:admin, gpgkeys, *, *, allow
      p, role:admin, logs, *, *, allow
      p, role:admin, exec, *, *, allow
      p, role:admin, certificates, *, *, allow
      
      # DevOps team with broad access but not admin
      p, role:devops, applications, *, */*, allow
      p, role:devops, clusters, get, *, allow
      p, role:devops, repositories, *, *, allow
      p, role:devops, logs, *, *, allow
      p, role:devops, exec, create, */*, allow
      
      # Developers with limited access
      p, role:developer, applications, get, */*, allow
      p, role:developer, applications, sync, */*, allow
      p, role:developer, repositories, get, *, allow
      p, role:developer, logs, get, */*, allow
      
      # Map GitLab groups to roles
      g, gitlab:platform-admin, role:admin
      g, gitlab:devops-team, role:devops
      g, gitlab:developers, role:developer

Project-Specific Access Control

You can also configure access to specific ArgoCD projects:

configs:
  rbac:
    policy.csv: |
      # Team A access to Team A projects only
      p, role:team-a, applications, *, team-a/*, allow
      p, role:team-a, logs, *, team-a/*, allow
      g, gitlab:team-a, role:team-a
      
      # Team B access to Team B projects only
      p, role:team-b, applications, *, team-b/*, allow
      p, role:team-b, logs, *, team-b/*, allow
      g, gitlab:team-b, role:team-b

Using GitLab Subgroups

If you have GitLab subgroups, you can map them in ArgoCD:

configs:
  cm:
    dex.config: |
      connectors:
        - type: gitlab
          id: gitlab
          name: GitLab
          config:
            baseURL: https://gitlab.your-domain.com
            clientID: <application_id>
            clientSecret: <secret>
            redirectURI: https://argocd.your-domain.com/api/dex/callback
            groups:
              - engineering/backend
              - engineering/frontend
              - operations/platform


Manual Installation and Configuration

If you’re not using Helm, here’s how to configure ArgoCD manually:


1. Create argocd-cm ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.your-domain.com
  dex.config: |
    connectors:
      - type: gitlab
        id: gitlab
        name: GitLab
        config:
          baseURL: https://gitlab.your-domain.com
          clientID: <application_id>
          clientSecret: $dex.gitlab.clientSecret
          redirectURI: https://argocd.your-domain.com/api/dex/callback
          groups:
            - devops
            - engineering


2. Create argocd-secret for GitLab Credentials

# Convert client secret to base64
GITLAB_CLIENT_SECRET_BASE64=$(echo -n "your-gitlab-client-secret" | base64)

# Apply the secret
kubectl patch secret argocd-secret -n argocd --type=json -p='[{"op": "add", "path": "/data/dex.gitlab.clientSecret", "value":"'$GITLAB_CLIENT_SECRET_BASE64'"}]'


3. Configure RBAC

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    p, role:org-admin, applications, *, */*, allow
    p, role:org-admin, clusters, get, *, allow
    p, role:org-admin, repositories, *, *, allow
    p, role:org-admin, projects, get, *, allow
    p, role:org-admin, logs, get, *, allow
    p, role:org-admin, exec, create, */*, allow
    
    g, gitlab:devops, role:org-admin
  policy.default: role:readonly
  scopes: "[groups, email]"


Troubleshooting GitLab SSO


Common Issues and Solutions:

1. Authentication Failed: - Verify client ID and secret match GitLab application
- Check baseURL points to correct GitLab instance
- Ensure redirectURI matches exactly (including trailing slash)
- Verify required scopes are enabled in GitLab application

2. User Successfully Authenticates but Has No Access: - Check if user belongs to the correct GitLab group
- Verify groups are correctly mapped in RBAC policy
- Confirm 'groups' is included in scopes setting
- Check ArgoCD logs for group claim issues

3. Redirect URI Error: - Double check the redirect URI in both GitLab and ArgoCD config
- Ensure the ArgoCD server is accessible at the configured URL
- Check for TLS/SSL certificate issues

4. Timeout During Authentication: - Check network connectivity between ArgoCD and GitLab
- Verify GitLab instance is running and accessible
- Check for firewall or proxy issues


Debugging Steps

# Check Dex logs for authentication issues
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-dex-server

# Check ArgoCD server logs
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-server

# Verify configuration
kubectl get configmap argocd-cm -n argocd -o yaml
kubectl get configmap argocd-rbac-cm -n argocd -o yaml

# Check if secret is properly configured (will be masked)
kubectl get secret argocd-secret -n argocd -o yaml


Self-Hosted GitLab SSL Issues

If you’re using a self-signed certificate with GitLab, you may need to add it to ArgoCD:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  # ... existing config ...
  dex.config: |
    connectors:
      - type: gitlab
        id: gitlab
        name: GitLab
        config:
          baseURL: https://gitlab.your-domain.com
          clientID: <application_id>
          clientSecret: $dex.gitlab.clientSecret
          redirectURI: https://argocd.your-domain.com/api/dex/callback
          groups:
            - devops
          # For self-signed certificates:
          insecureSkipVerify: true

Note: Using insecureSkipVerify: true is not recommended for production environments. Instead, properly configure certificates.


Security Best Practices

  1. Access Control:
    • Implement least privilege principle in RBAC policies
    • Regularly audit group memberships in GitLab
    • Periodically review ArgoCD access
  2. Credentials Management:
    • Rotate GitLab client secret periodically
    • Store secrets in Kubernetes secrets, not in plain text
    • Consider using a secrets management solution
  3. Network Security:
    • Use HTTPS for all communication
    • Implement network policies in Kubernetes
    • Consider IP restrictions if applicable
  4. Audit and Monitoring:
    • Enable and review audit logs
    • Set up alerts for unauthorized access attempts
    • Monitor SSO configuration changes


Advanced Security Configuration

Network Policies for ArgoCD

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: argocd-security-policy
  namespace: argocd
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    ports:
    - protocol: TCP
      port: 443
  - to: []
    ports:
    - protocol: TCP
      port: 443  # HTTPS to GitLab

External Secrets Integration

Pod Security Standards

apiVersion: v1
kind: Namespace
metadata:
  name: argocd
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted


Enterprise Automation Framework

Here’s an enhanced automation script for enterprise GitLab SSO configuration:



Monitoring and Observability

Prometheus Metrics Configuration

Grafana Dashboard Integration

{
  "dashboard": {
    "title": "ArgoCD SSO Monitoring",
    "panels": [
      {
        "title": "Login Success Rate",
        "type": "stat",
        "targets": [
          {
            "expr": "rate(argocd_server_login_successes_total[5m]) / (rate(argocd_server_login_successes_total[5m]) + rate(argocd_server_login_failures_total[5m])) * 100"
          }
        ]
      },
      {
        "title": "Active Sessions",
        "type": "graph",
        "targets": [
          {
            "expr": "argocd_server_sessions_total"
          }
        ]
      }
    ]
  }
}


Multi-Cluster Federation

Hub Cluster Configuration

# Hub cluster ArgoCD configuration
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: spoke-cluster-apps
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitlab.your-domain.com/platform/cluster-configs
    targetRevision: HEAD
    path: spoke-clusters
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Spoke Cluster Integration

# Register spoke cluster with hub
apiVersion: v1
kind: Secret
metadata:
  name: spoke-cluster-secret
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
  name: spoke-cluster-prod
  server: https://spoke-cluster-api.your-domain.com
  config: |
    {
      "bearerToken": "spoke-cluster-token",
      "tlsClientConfig": {
        "insecure": false,
        "caData": "base64-encoded-ca-cert"
      }
    }


Advanced Authentication Patterns

SAML Integration with GitLab

For enterprise environments requiring SAML integration:

configs:
  cm:
    dex.config: |
      connectors:
        - type: gitlab
          id: gitlab
          name: GitLab
          config:
            baseURL: https://gitlab.your-domain.com
            clientID: $dex.gitlab.clientId
            clientSecret: $dex.gitlab.clientSecret
            redirectURI: https://argocd.your-domain.com/api/dex/callback
            groups:
              - engineering
              - platform
        - type: saml
          id: saml
          name: Enterprise SSO
          config:
            ssoURL: https://sso.your-domain.com/saml/login
            redirectURI: https://argocd.your-domain.com/api/dex/callback
            entityIssuer: https://argocd.your-domain.com/api/dex/callback
            caData: |
              -----BEGIN CERTIFICATE-----
              ... enterprise CA certificate ...
              -----END CERTIFICATE-----
            usernameAttr: email
            emailAttr: email
            groupsAttr: groups

JWT Token Configuration

configs:
  cm:
    # JWT token configuration
    oidc.config: |
      name: GitLab
      issuer: https://gitlab.your-domain.com
      clientId: your-application-id
      clientSecret: $oidc.gitlab.clientSecret
      requestedScopes: ["openid", "profile", "email", "groups"]
      requestedIDTokenClaims: {"groups": {"essential": true}}
      # Token lifetime configuration
      skipClientIDCheck: false
      skipIssuerCheck: false
      # Custom claims mapping
      claimsMapping:
        groups: gitlab_groups
        email: email
        preferred_username: preferred_username


Production Deployment Checklist
  • Security Configuration:
    • TLS/SSL certificates properly configured
    • Network policies implemented
    • RBAC policies tested and validated
    • Secret rotation strategy in place
    • Audit logging enabled
  • High Availability:
    • Multiple replicas for all components
    • Resource limits and requests defined
    • Pod disruption budgets configured
    • Health checks and readiness probes
  • Monitoring & Observability:
    • Prometheus metrics collection
    • Grafana dashboards configured
    • Alert rules defined
    • Log aggregation setup
  • Operational Excellence:
    • Backup and disaster recovery plan
    • Documentation and runbooks
    • Incident response procedures
    • Performance testing completed
  • Compliance & Governance:
    • Security policies enforced
    • Compliance requirements met
    • Change management process
    • Access control regularly audited


Enterprise Deployment Patterns

Blue-Green Deployment for ArgoCD

# Blue environment
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argocd-blue
  namespace: argocd-system
spec:
  destination:
    namespace: argocd-blue
    server: https://kubernetes.default.svc
  source:
    path: argocd
    repoURL: https://gitlab.your-domain.com/platform/argocd-config
    targetRevision: v2.8.4
---
# Green environment  
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argocd-green
  namespace: argocd-system
spec:
  destination:
    namespace: argocd-green
    server: https://kubernetes.default.svc
  source:
    path: argocd
    repoURL: https://gitlab.your-domain.com/platform/argocd-config
    targetRevision: v2.9.0

GitOps Repository Structure

├── clusters/
│   ├── production/
│   │   ├── cluster-config.yaml
│   │   └── applications/
│   ├── staging/
│   │   ├── cluster-config.yaml
│   │   └── applications/
│   └── development/
│       ├── cluster-config.yaml
│       └── applications/
├── applications/
│   ├── base/
│   ├── overlays/
│   │   ├── production/
│   │   ├── staging/
│   │   └── development/
├── projects/
│   ├── platform.yaml
│   ├── application-team-a.yaml
│   └── application-team-b.yaml
└── bootstrap/
    └── argocd-apps.yaml



Conclusion

This comprehensive guide provides a production-ready approach to implementing enterprise-grade ArgoCD SSO with GitLab integration. By following these patterns and best practices, organizations can achieve:

The integration between ArgoCD and GitLab creates a powerful platform for modern software delivery, enabling teams to maintain velocity while ensuring security and compliance requirements are met at scale.

References