UiPath Documentation
automation-suite
2.2510
true
Automation Suite on Linux installation guide

Manual ArgoCD NetworkPolicy mitigation (GHSA-47m3-95c7-g2g8)

Solutions for unauthenticated network access to the ArgoCD repo-server and Redis in Automation Suite, with a manual NetworkPolicy mitigation procedure.

Description

A vulnerability affecting the ArgoCD repo-server component was recently published and is not fixed by ArgoCD at this moment.

The ArgoCD repo-server (port 8081) and ArgoCD Redis are reachable from any pod in the cluster network, because no NetworkPolicy restricts ingress to these components by default. As a result, any pod within the cluster network can connect to them directly, since ArgoCD does not require authentication for these internal components. For details, refer to GHSA-47m3-95c7-g2g8.

To mitigate the issue, you must manually apply the NetworkPolicy described in the Solution section on this page.

Prerequisites

  • Run this procedure from a host with kubectl access to the cluster.
  • The procedure assumes the default Automation Suite argocd namespace. If ArgoCD uses a different namespace, set ARGOCD_NS before running the script.
  • This mitigation relies on Kubernetes NetworkPolicy enforcement. Automation Suite supported clusters use a compatible CNI (Container Network Interface) configuration.

Solution

  1. Run the following script. It detects your ArgoCD release and Redis mode (standalone or high availability, HA), and applies the matching NetworkPolicy automatically:

    export ARGOCD_NS="${ARGOCD_NS:-argocd}"
    export ARGOCD_RELEASE="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-server -o jsonpath='{.items[0].metadata.labels.app\.kubernetes\.io/instance}')"
    
    test -n "$ARGOCD_RELEASE" || { echo "Cannot detect Argo CD Helm release"; exit 1; }
    
    if kubectl -n "$ARGOCD_NS" get pod -l "release=${ARGOCD_RELEASE},app=redis-ha-haproxy,component=haproxy" --no-headers 2>/dev/null | grep -q .; then
      REDIS_MODE=ha
    else
      REDIS_MODE=standalone
    fi
    
    echo "Argo CD namespace: $ARGOCD_NS"
    echo "Argo CD release: $ARGOCD_RELEASE"
    echo "Redis mode: $REDIS_MODE"
    
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-repo-server-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          app.kubernetes.io/name: argocd-repo-server
          app.kubernetes.io/instance: ${ARGOCD_RELEASE}
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-application-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-applicationset-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-notifications-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
          ports:
            - protocol: TCP
              port: 8081
        - from:
            - namespaceSelector: {}
          ports:
            - protocol: TCP
              port: 8084
    EOF
    
    if [ "$REDIS_MODE" = "ha" ]; then
      cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-ha-server-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          release: ${ARGOCD_RELEASE}
          app: redis-ha
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  release: ${ARGOCD_RELEASE}
                  app: redis-ha
            - podSelector:
                matchLabels:
                  release: ${ARGOCD_RELEASE}
                  app: redis-ha-haproxy
                  component: haproxy
          ports:
            - protocol: TCP
              port: 6379
            - protocol: TCP
              port: 26379
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-ha-haproxy-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          release: ${ARGOCD_RELEASE}
          app: redis-ha-haproxy
          component: haproxy
          app.kubernetes.io/name: argocd-redis-ha-haproxy
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-repo-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-application-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
          ports:
            - protocol: TCP
              port: 6379
    EOF
    else
      cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          app.kubernetes.io/name: argocd-redis
          app.kubernetes.io/instance: ${ARGOCD_RELEASE}
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-repo-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-application-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
          ports:
            - protocol: TCP
              port: 6379
        - from:
            - namespaceSelector: {}
          ports:
            - protocol: TCP
              port: 9121
    EOF
    fi
    export ARGOCD_NS="${ARGOCD_NS:-argocd}"
    export ARGOCD_RELEASE="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-server -o jsonpath='{.items[0].metadata.labels.app\.kubernetes\.io/instance}')"
    
    test -n "$ARGOCD_RELEASE" || { echo "Cannot detect Argo CD Helm release"; exit 1; }
    
    if kubectl -n "$ARGOCD_NS" get pod -l "release=${ARGOCD_RELEASE},app=redis-ha-haproxy,component=haproxy" --no-headers 2>/dev/null | grep -q .; then
      REDIS_MODE=ha
    else
      REDIS_MODE=standalone
    fi
    
    echo "Argo CD namespace: $ARGOCD_NS"
    echo "Argo CD release: $ARGOCD_RELEASE"
    echo "Redis mode: $REDIS_MODE"
    
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-repo-server-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          app.kubernetes.io/name: argocd-repo-server
          app.kubernetes.io/instance: ${ARGOCD_RELEASE}
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-application-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-applicationset-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-notifications-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
          ports:
            - protocol: TCP
              port: 8081
        - from:
            - namespaceSelector: {}
          ports:
            - protocol: TCP
              port: 8084
    EOF
    
    if [ "$REDIS_MODE" = "ha" ]; then
      cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-ha-server-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          release: ${ARGOCD_RELEASE}
          app: redis-ha
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  release: ${ARGOCD_RELEASE}
                  app: redis-ha
            - podSelector:
                matchLabels:
                  release: ${ARGOCD_RELEASE}
                  app: redis-ha-haproxy
                  component: haproxy
          ports:
            - protocol: TCP
              port: 6379
            - protocol: TCP
              port: 26379
    ---
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-ha-haproxy-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          release: ${ARGOCD_RELEASE}
          app: redis-ha-haproxy
          component: haproxy
          app.kubernetes.io/name: argocd-redis-ha-haproxy
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-repo-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-application-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
          ports:
            - protocol: TCP
              port: 6379
    EOF
    else
      cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-manual-mitigation
      namespace: ${ARGOCD_NS}
    spec:
      podSelector:
        matchLabels:
          app.kubernetes.io/name: argocd-redis
          app.kubernetes.io/instance: ${ARGOCD_RELEASE}
      policyTypes:
        - Ingress
      ingress:
        - from:
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-repo-server
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
            - podSelector:
                matchLabels:
                  app.kubernetes.io/name: argocd-application-controller
                  app.kubernetes.io/instance: ${ARGOCD_RELEASE}
          ports:
            - protocol: TCP
              port: 6379
        - from:
            - namespaceSelector: {}
          ports:
            - protocol: TCP
              port: 9121
    EOF
    fi
    

Verify

Run the following commands to confirm the mitigation was applied successfully:

kubectl -n "$ARGOCD_NS" get networkpolicy
kubectl -n "$ARGOCD_NS" get pods
kubectl get applications.argoproj.io -A
kubectl -n "$ARGOCD_NS" get networkpolicy
kubectl -n "$ARGOCD_NS" get pods
kubectl get applications.argoproj.io -A

Confirm the following:

  • argocd-repo-server-manual-mitigation exists.
  • For Redis HA, argocd-redis-ha-server-manual-mitigation and argocd-redis-ha-haproxy-manual-mitigation exist.
  • For standalone Redis, argocd-redis-manual-mitigation exists.
  • ArgoCD pods are Running or Completed.
  • ArgoCD Applications remain Synced and Healthy.

Confirm Mitigation

Run these checks after applying the policies. They verify that required ArgoCD traffic still works and disallowed traffic is blocked.

  1. Run the following script:

    export ARGOCD_NS="${ARGOCD_NS:-argocd}"
    export ARGOCD_RELEASE="${ARGOCD_RELEASE:-$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-server -o jsonpath='{.items[0].metadata.labels.app\.kubernetes\.io/instance}')}"
    
    if kubectl -n "$ARGOCD_NS" get pod -l "release=${ARGOCD_RELEASE},app=redis-ha-haproxy,component=haproxy" --no-headers 2>/dev/null | grep -q .; then
      REDIS_MODE=ha
    else
      REDIS_MODE=standalone
    fi
    
    SERVER_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-server -o jsonpath='{.items[0].metadata.name}')"
    APPSET_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-applicationset-controller -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)"
    FAILED_CHECKS=""
    
    tcp_check() {
      pod="$1"
      host="$2"
      port="$3"
      expected="$4"
      name="$5"
    
      code="$(kubectl -n "$ARGOCD_NS" exec "$pod" -- sh -c '
        host="$1"
        port="$2"
        if command -v nc >/dev/null 2>&1; then
          timeout 5 nc -z -w 3 "$host" "$port" >/dev/null 2>&1
          printf "%s\n" "$?"
        elif command -v bash >/dev/null 2>&1; then
          timeout 5 bash -c "</dev/tcp/${host}/${port}" >/dev/null 2>&1
          printf "%s\n" "$?"
        else
          printf "%s\n" "NO_TCP_TOOL"
        fi
      ' sh "$host" "$port" 2>/dev/null | tail -n 1)"
    
      if [ "$expected" = "allow" ] && [ "$code" = "0" ]; then
        return
      elif [ "$expected" = "deny" ] && [ "$code" != "0" ] && [ "$code" != "NO_TCP_TOOL" ] && [ -n "$code" ]; then
        return
      else
        FAILED_CHECKS="${FAILED_CHECKS}
    - ${name}: expected ${expected}, got exit code ${code}"
      fi
    }
    
    tcp_check "$SERVER_POD" argocd-repo-server 8081 allow "argocd-server to repo-server:8081"
    
    if [ "$REDIS_MODE" = "ha" ]; then
      HAPROXY_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app=redis-ha-haproxy,component=haproxy -o jsonpath='{.items[0].metadata.name}')"
    
      tcp_check "$SERVER_POD" argocd-redis-ha-haproxy 6379 allow "argocd-server to redis-ha-haproxy:6379"
      tcp_check "$HAPROXY_POD" argocd-redis-ha 6379 allow "redis-ha-haproxy to redis-ha:6379"
      tcp_check "$HAPROXY_POD" argocd-repo-server 8081 deny "redis-ha-haproxy to repo-server:8081"
    
      if [ -n "$APPSET_POD" ]; then
        tcp_check "$APPSET_POD" argocd-redis-ha-haproxy 6379 deny "applicationset-controller to redis-ha-haproxy:6379"
      fi
    else
      REDIS_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-redis -o jsonpath='{.items[0].metadata.name}')"
    
      tcp_check "$SERVER_POD" argocd-redis 6379 allow "argocd-server to redis:6379"
      tcp_check "$REDIS_POD" argocd-repo-server 8081 deny "redis to repo-server:8081"
    
      if [ -n "$APPSET_POD" ]; then
        tcp_check "$APPSET_POD" argocd-redis 6379 deny "applicationset-controller to redis:6379"
      fi
    fi
    
    if [ -z "$FAILED_CHECKS" ]; then
      echo "MITIGATION CHECK: PASS"
    else
      echo "MITIGATION CHECK: FAIL"
      echo "$FAILED_CHECKS"
      exit 1
    fi
    export ARGOCD_NS="${ARGOCD_NS:-argocd}"
    export ARGOCD_RELEASE="${ARGOCD_RELEASE:-$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-server -o jsonpath='{.items[0].metadata.labels.app\.kubernetes\.io/instance}')}"
    
    if kubectl -n "$ARGOCD_NS" get pod -l "release=${ARGOCD_RELEASE},app=redis-ha-haproxy,component=haproxy" --no-headers 2>/dev/null | grep -q .; then
      REDIS_MODE=ha
    else
      REDIS_MODE=standalone
    fi
    
    SERVER_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-server -o jsonpath='{.items[0].metadata.name}')"
    APPSET_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-applicationset-controller -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)"
    FAILED_CHECKS=""
    
    tcp_check() {
      pod="$1"
      host="$2"
      port="$3"
      expected="$4"
      name="$5"
    
      code="$(kubectl -n "$ARGOCD_NS" exec "$pod" -- sh -c '
        host="$1"
        port="$2"
        if command -v nc >/dev/null 2>&1; then
          timeout 5 nc -z -w 3 "$host" "$port" >/dev/null 2>&1
          printf "%s\n" "$?"
        elif command -v bash >/dev/null 2>&1; then
          timeout 5 bash -c "</dev/tcp/${host}/${port}" >/dev/null 2>&1
          printf "%s\n" "$?"
        else
          printf "%s\n" "NO_TCP_TOOL"
        fi
      ' sh "$host" "$port" 2>/dev/null | tail -n 1)"
    
      if [ "$expected" = "allow" ] && [ "$code" = "0" ]; then
        return
      elif [ "$expected" = "deny" ] && [ "$code" != "0" ] && [ "$code" != "NO_TCP_TOOL" ] && [ -n "$code" ]; then
        return
      else
        FAILED_CHECKS="${FAILED_CHECKS}
    - ${name}: expected ${expected}, got exit code ${code}"
      fi
    }
    
    tcp_check "$SERVER_POD" argocd-repo-server 8081 allow "argocd-server to repo-server:8081"
    
    if [ "$REDIS_MODE" = "ha" ]; then
      HAPROXY_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app=redis-ha-haproxy,component=haproxy -o jsonpath='{.items[0].metadata.name}')"
    
      tcp_check "$SERVER_POD" argocd-redis-ha-haproxy 6379 allow "argocd-server to redis-ha-haproxy:6379"
      tcp_check "$HAPROXY_POD" argocd-redis-ha 6379 allow "redis-ha-haproxy to redis-ha:6379"
      tcp_check "$HAPROXY_POD" argocd-repo-server 8081 deny "redis-ha-haproxy to repo-server:8081"
    
      if [ -n "$APPSET_POD" ]; then
        tcp_check "$APPSET_POD" argocd-redis-ha-haproxy 6379 deny "applicationset-controller to redis-ha-haproxy:6379"
      fi
    else
      REDIS_POD="$(kubectl -n "$ARGOCD_NS" get pod -l app.kubernetes.io/name=argocd-redis -o jsonpath='{.items[0].metadata.name}')"
    
      tcp_check "$SERVER_POD" argocd-redis 6379 allow "argocd-server to redis:6379"
      tcp_check "$REDIS_POD" argocd-repo-server 8081 deny "redis to repo-server:8081"
    
      if [ -n "$APPSET_POD" ]; then
        tcp_check "$APPSET_POD" argocd-redis 6379 deny "applicationset-controller to redis:6379"
      fi
    fi
    
    if [ -z "$FAILED_CHECKS" ]; then
      echo "MITIGATION CHECK: PASS"
    else
      echo "MITIGATION CHECK: FAIL"
      echo "$FAILED_CHECKS"
      exit 1
    fi
    

    Expected result: MITIGATION CHECK: PASS

Rollback

If required, take the following steps to remove the mitigation:

  1. Delete the manual mitigation policies:

    kubectl -n "$ARGOCD_NS" delete networkpolicy \
      argocd-repo-server-manual-mitigation \
      argocd-redis-manual-mitigation \
      argocd-redis-ha-server-manual-mitigation \
      argocd-redis-ha-haproxy-manual-mitigation \
      --ignore-not-found
    kubectl -n "$ARGOCD_NS" delete networkpolicy \
      argocd-repo-server-manual-mitigation \
      argocd-redis-manual-mitigation \
      argocd-redis-ha-server-manual-mitigation \
      argocd-redis-ha-haproxy-manual-mitigation \
      --ignore-not-found
    
  2. Confirm the rollback completed successfully:

    kubectl -n "$ARGOCD_NS" get networkpolicy
    kubectl -n "$ARGOCD_NS" get pods
    kubectl get applications.argoproj.io -A
    kubectl -n "$ARGOCD_NS" get networkpolicy
    kubectl -n "$ARGOCD_NS" get pods
    kubectl get applications.argoproj.io -A
    

    Confirm the following:

    • The manual mitigation policies are removed.
    • ArgoCD pods remain Running or Completed.
    • ArgoCD Applications remain Synced and Healthy.
  • Description
  • Prerequisites
  • Solution
  • Verify
  • Confirm Mitigation
  • Rollback

Was this page helpful?

Connect

Need help? Support

Want to learn? UiPath Academy

Have questions? UiPath Forum

Stay updated