- Overview
- Requirements
- Pre-installation
- Preparing the installation
- Downloading the installation packages
- Configuring the OCI-compliant registry
- Granting installation permissions with cluster roles
- Granting installation permissions without cluster roles
- Installing and configuring the service mesh
- Installing and configuring the GitOps tool
- Installing the External Secrets Operator
- Deploying Redis through OperatorHub
- Applying miscellaneous configurations
- Running uipathctl
- Installation
- Post-installation
- Migration and upgrade
- Monitoring and alerting
- Cluster administration
- Product-specific configuration
- Orchestrator advanced configuration
- Configuring Orchestrator parameters
- Configuring appSettings
- Configuring the maximum request size
- Overriding cluster-level storage configuration
- Configuring NLog
- Saving robot logs to Elasticsearch
- Configuring credential stores
- Configuring encryption key per tenant
- Cleaning up the Orchestrator database
- Skipping host library installation
- AI Trust Layer
- Troubleshooting
- 500 errors and rate limiting on S3 requests in ODF
- External Secrets troubleshooting
- Configuring CSI driver tolerations for ODF 4.20
- Temporal as a Service troubleshooting
- AI Center and Document Understanding pods fail to start with TLS certificate verification enabled
- Studio Desktop cannot load Integration Service connectors and activities
- TLS certificate validation errors
- Manual ArgoCD NetworkPolicy mitigation (GHSA-47m3-95c7-g2g8)
- Configuring resource requests and limits for uipathctl-created workloads
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
kubectlaccess to the cluster. - The procedure detects the ArgoCD namespace automatically. If auto-detection is not suitable, set
ARGOCD_NSbefore running the script. - This mitigation relies on Kubernetes NetworkPolicy enforcement. Automation Suite supported clusters use a compatible CNI (Container Network Interface) configuration.
Solution
-
Run the following script. It detects your ArgoCD namespace and Redis mode (standalone or high availability, HA), and applies the matching NetworkPolicy automatically:
export ARGOCD_NS="${ARGOCD_NS:-$(kubectl get pod -A -l app.kubernetes.io/name=argocd-repo-server -o jsonpath='{.items[0].metadata.namespace}')}" test -n "$ARGOCD_NS" || { echo "Cannot detect Argo CD namespace"; exit 1; } if kubectl -n "$ARGOCD_NS" get pod -l app=redis-ha-haproxy --no-headers 2>/dev/null | grep -q .; then REDIS_MODE=ha else REDIS_MODE=standalone fi echo "Argo CD namespace: $ARGOCD_NS" 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 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: argocd-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-application-controller - podSelector: matchLabels: app.kubernetes.io/name: argocd-applicationset-controller - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller 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: app: redis-ha policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: redis-ha - podSelector: matchLabels: app: redis-ha-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: app: redis-ha-haproxy policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: argocd-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-application-controller 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 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: argocd-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-application-controller ports: - protocol: TCP port: 6379 - from: - namespaceSelector: {} ports: - protocol: TCP port: 9121 EOF fiexport ARGOCD_NS="${ARGOCD_NS:-$(kubectl get pod -A -l app.kubernetes.io/name=argocd-repo-server -o jsonpath='{.items[0].metadata.namespace}')}" test -n "$ARGOCD_NS" || { echo "Cannot detect Argo CD namespace"; exit 1; } if kubectl -n "$ARGOCD_NS" get pod -l app=redis-ha-haproxy --no-headers 2>/dev/null | grep -q .; then REDIS_MODE=ha else REDIS_MODE=standalone fi echo "Argo CD namespace: $ARGOCD_NS" 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 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: argocd-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-application-controller - podSelector: matchLabels: app.kubernetes.io/name: argocd-applicationset-controller - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller 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: app: redis-ha policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: redis-ha - podSelector: matchLabels: app: redis-ha-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: app: redis-ha-haproxy policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: argocd-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-application-controller 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 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: argocd-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - podSelector: matchLabels: app.kubernetes.io/name: argocd-application-controller 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-mitigationexists.- For Redis HA,
argocd-redis-ha-server-manual-mitigationandargocd-redis-ha-haproxy-manual-mitigationexist. - For standalone Redis,
argocd-redis-manual-mitigationexists. - ArgoCD pods are
RunningorCompleted. - ArgoCD Applications remain
SyncedandHealthy.
Confirm Mitigation
Run these checks after applying the policies. They verify that required ArgoCD traffic still works and disallowed traffic is blocked.
-
Run the following script:
export ARGOCD_NS="${ARGOCD_NS:-$(kubectl get pod -A -l app.kubernetes.io/name=argocd-repo-server -o jsonpath='{.items[0].metadata.namespace}')}" test -n "$ARGOCD_NS" || { echo "Cannot detect Argo CD namespace"; exit 1; } if kubectl -n "$ARGOCD_NS" get pod -l app=redis-ha-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 -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 fiexport ARGOCD_NS="${ARGOCD_NS:-$(kubectl get pod -A -l app.kubernetes.io/name=argocd-repo-server -o jsonpath='{.items[0].metadata.namespace}')}" test -n "$ARGOCD_NS" || { echo "Cannot detect Argo CD namespace"; exit 1; } if kubectl -n "$ARGOCD_NS" get pod -l app=redis-ha-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 -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 fiExpected result:
MITIGATION CHECK: PASS
Rollback
If required, take the following steps to remove the mitigation:
-
Delete the manual mitigation policies:
export ARGOCD_NS="${ARGOCD_NS:-$(kubectl get pod -A -l app.kubernetes.io/name=argocd-repo-server -o jsonpath='{.items[0].metadata.namespace}')}" test -n "$ARGOCD_NS" || { echo "Cannot detect Argo CD namespace"; exit 1; } 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-foundexport ARGOCD_NS="${ARGOCD_NS:-$(kubectl get pod -A -l app.kubernetes.io/name=argocd-repo-server -o jsonpath='{.items[0].metadata.namespace}')}" test -n "$ARGOCD_NS" || { echo "Cannot detect Argo CD namespace"; exit 1; } 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 -
Confirm the rollback completed successfully:
kubectl -n "$ARGOCD_NS" get networkpolicy kubectl -n "$ARGOCD_NS" get pods kubectl get applications.argoproj.io -Akubectl -n "$ARGOCD_NS" get networkpolicy kubectl -n "$ARGOCD_NS" get pods kubectl get applications.argoproj.io -AConfirm the following:
- The manual mitigation policies are removed.
- ArgoCD pods remain
RunningorCompleted. - ArgoCD Applications remain
SyncedandHealthy.