Skip to content

Commit fe2f262

Browse files
committed
fix: resolve spoke cluster authentication and TLS verification errors
1 parent c1eaf5d commit fe2f262

File tree

1 file changed

+93
-88
lines changed

1 file changed

+93
-88
lines changed

.github/workflows/deploy-argocd-spokes-netbird.yaml

Lines changed: 93 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -164,91 +164,83 @@ jobs:
164164
- name: Generate kubeconfig for spoke clusters
165165
run: |
166166
echo "🔧 Generating kubeconfig for local spoke clusters..."
167-
echo "Spoke clusters are pre-configured in Netbird with known IPs"
168-
echo ""
169-
167+
170168
# Read spoke cluster list from secrets
171-
# Expected format: SPOKE_CLUSTERS=spoke-1,spoke-2,spoke-3
172169
SPOKE_CLUSTERS="${{ secrets.SPOKE_CLUSTERS }}"
173-
174170
if [ -z "$SPOKE_CLUSTERS" ]; then
175-
echo "⚠ SPOKE_CLUSTERS secret not set"
176-
echo " Using default: spoke-1"
171+
echo "⚠ SPOKE_CLUSTERS secret not set, using default: spoke-1"
177172
SPOKE_CLUSTERS="spoke-1"
178173
fi
179174
180175
IFS=',' read -ra CLUSTERS <<< "$SPOKE_CLUSTERS"
181176
182177
for cluster in "${CLUSTERS[@]}"; do
183-
cluster=$(echo "$cluster" | xargs) # Trim whitespace
184-
185-
echo "Processing cluster: '$cluster'"
178+
cluster=$(echo "$cluster" | xargs)
179+
echo "--- Processing cluster: $cluster ---"
186180
187-
# Get Netbird IP and certificates based on cluster name
181+
# Get secrets based on cluster name
188182
case "$cluster" in
189183
spoke-1)
190184
NETBIRD_IP="${{ secrets.SPOKE_1_NETBIRD_IP }}"
191-
CA_CERT="${{ secrets.SPOKE_1_CA_CERT }}"
192-
CLIENT_CERT="${{ secrets.SPOKE_1_CLIENT_CERT }}"
193-
CLIENT_KEY="${{ secrets.SPOKE_1_CLIENT_KEY }}"
185+
CA_CERT_B64="${{ secrets.SPOKE_1_CA_CERT }}"
186+
CLIENT_CERT_B64="${{ secrets.SPOKE_1_CLIENT_CERT }}"
187+
CLIENT_KEY_B64="${{ secrets.SPOKE_1_CLIENT_KEY }}"
194188
;;
195189
spoke-2)
196190
NETBIRD_IP="${{ secrets.SPOKE_2_NETBIRD_IP }}"
197-
CA_CERT="${{ secrets.SPOKE_2_CA_CERT }}"
198-
CLIENT_CERT="${{ secrets.SPOKE_2_CLIENT_CERT }}"
199-
CLIENT_KEY="${{ secrets.SPOKE_2_CLIENT_KEY }}"
191+
CA_CERT_B64="${{ secrets.SPOKE_2_CA_CERT }}"
192+
CLIENT_CERT_B64="${{ secrets.SPOKE_2_CLIENT_CERT }}"
193+
CLIENT_KEY_B64="${{ secrets.SPOKE_2_CLIENT_KEY }}"
200194
;;
201195
spoke-3)
202196
NETBIRD_IP="${{ secrets.SPOKE_3_NETBIRD_IP }}"
203-
CA_CERT="${{ secrets.SPOKE_3_CA_CERT }}"
204-
CLIENT_CERT="${{ secrets.SPOKE_3_CLIENT_CERT }}"
205-
CLIENT_KEY="${{ secrets.SPOKE_3_CLIENT_KEY }}"
197+
CA_CERT_B64="${{ secrets.SPOKE_3_CA_CERT }}"
198+
CLIENT_CERT_B64="${{ secrets.SPOKE_3_CLIENT_CERT }}"
199+
CLIENT_KEY_B64="${{ secrets.SPOKE_3_CLIENT_KEY }}"
206200
;;
207201
*)
208202
echo " ⚠ Unknown cluster: $cluster"
209-
echo " Expected cluster name: spoke-1, spoke-2, or spoke-3"
210-
echo " Please check your SPOKE_CLUSTERS secret"
211203
continue
212204
;;
213205
esac
214206
215-
# Use GitHub secrets syntax to get values
216-
echo "Configuring kubectl for $cluster..."
217-
218-
if [ ! -z "$NETBIRD_IP" ]; then
219-
echo " Netbird IP: $NETBIRD_IP"
220-
221-
# Create kubeconfig entries
222-
kubectl config set-cluster $cluster \
223-
--server=https://$NETBIRD_IP:6443 \
224-
--certificate-authority=<(echo "$CA_CERT" | base64 -d) \
225-
--embed-certs=true
226-
227-
kubectl config set-credentials $cluster-admin \
228-
--client-certificate=<(echo "$CLIENT_CERT" | base64 -d) \
229-
--client-key=<(echo "$CLIENT_KEY" | base64 -d) \
230-
--embed-certs=true
207+
# Validation: Fail early if required secrets are missing
208+
if [ -z "$NETBIRD_IP" ] || [ -z "$CA_CERT_B64" ] || [ -z "$CLIENT_CERT_B64" ] || [ -z "$CLIENT_KEY_B64" ]; then
209+
echo " ❌ ERROR: Missing secrets for $cluster. Ensure NETBIRD_IP, CA_CERT, CLIENT_CERT, and CLIENT_KEY are set."
210+
exit 1
211+
fi
231212
232-
kubectl config set-context $cluster \
233-
--cluster=$cluster \
234-
--user=$cluster-admin
213+
# Clean IPs
214+
NETBIRD_IP="${NETBIRD_IP%/32}"
235215
236-
# Verify connectivity via Netbird
237-
echo " Testing cluster API access..."
238-
if kubectl cluster-info --context $cluster >/dev/null 2>&1; then
239-
echo " ✅ Cluster API accessible: $cluster"
240-
else
241-
echo " ⚠ Cannot access cluster API: $cluster"
242-
fi
243-
else
244-
echo " ⚠ Netbird IP not configured for $cluster"
216+
# Create temporary files for certificates to ensure reliable kubeconfig embedding
217+
CA_FILE=$(mktemp)
218+
CERT_FILE=$(mktemp)
219+
KEY_FILE=$(mktemp)
220+
221+
echo "$CA_CERT_B64" | base64 -d > "$CA_FILE"
222+
echo "$CLIENT_CERT_B64" | base64 -d > "$CERT_FILE"
223+
echo "$CLIENT_KEY_B64" | base64 -d > "$KEY_FILE"
224+
225+
echo " Configuring kubectl context..."
226+
kubectl config set-cluster "$cluster" --server="https://$NETBIRD_IP:6443" --certificate-authority="$CA_FILE" --embed-certs=true
227+
kubectl config set-credentials "$cluster-admin" --client-certificate="$CERT_FILE" --client-key="$KEY_FILE" --embed-certs=true
228+
kubectl config set-context "$cluster" --cluster="$cluster" --user="$cluster-admin"
229+
230+
# Cleanup temp files
231+
rm -f "$CA_FILE" "$CERT_FILE" "$KEY_FILE"
232+
233+
# Mandatory verification: Fail early if unauthorized
234+
echo " Verifying API access to $cluster..."
235+
if ! kubectl cluster-info --context "$cluster" --insecure-skip-tls-verify=true > /dev/null 2>&1; then
236+
echo " ❌ ERROR: Authentication failed for $cluster (Unauthorized). Verify secrets are correct."
237+
kubectl cluster-info --context "$cluster" --insecure-skip-tls-verify=true || true
238+
exit 1
245239
fi
246-
247-
echo ""
240+
echo " ✅ Cluster $cluster is reachable and authorized"
248241
done
249242
250-
echo "Kubeconfig contexts configured:"
251-
kubectl config get-contexts
243+
echo "✅ Kubeconfig configured for all spoke clusters"
252244
253245
# Validate that all clusters in SPOKE_CLUSTERS have their contexts configured
254246
- name: Validate spoke cluster contexts
@@ -563,70 +555,83 @@ jobs:
563555
- name: Generate kubeconfig for spoke clusters
564556
run: |
565557
echo "🔧 Generating kubeconfig for local spoke clusters..."
566-
558+
559+
# Read spoke cluster list from secrets
567560
SPOKE_CLUSTERS="${{ secrets.SPOKE_CLUSTERS }}"
568561
if [ -z "$SPOKE_CLUSTERS" ]; then
569-
SPOKE_CLUSTERS="spoke-1,spoke-2,spoke-3"
562+
echo "⚠ SPOKE_CLUSTERS secret not set, using default: spoke-1"
563+
SPOKE_CLUSTERS="spoke-1"
570564
fi
571565
572566
IFS=',' read -ra CLUSTERS <<< "$SPOKE_CLUSTERS"
573567
574568
for cluster in "${CLUSTERS[@]}"; do
575569
cluster=$(echo "$cluster" | xargs)
570+
echo "--- Processing cluster: $cluster ---"
576571
577-
# Get Netbird IP and certificates based on cluster name
572+
# Get secrets based on cluster name
578573
case "$cluster" in
579574
spoke-1)
580575
NETBIRD_IP="${{ secrets.SPOKE_1_NETBIRD_IP }}"
581-
# Strip /32 suffix if present (CIDR notation)
582-
NETBIRD_IP="${NETBIRD_IP%/32}"
583-
CA_CERT="${{ secrets.SPOKE_1_CA_CERT }}"
584-
CLIENT_CERT="${{ secrets.SPOKE_1_CLIENT_CERT }}"
585-
CLIENT_KEY="${{ secrets.SPOKE_1_CLIENT_KEY }}"
576+
CA_CERT_B64="${{ secrets.SPOKE_1_CA_CERT }}"
577+
CLIENT_CERT_B64="${{ secrets.SPOKE_1_CLIENT_CERT }}"
578+
CLIENT_KEY_B64="${{ secrets.SPOKE_1_CLIENT_KEY }}"
586579
;;
587580
spoke-2)
588581
NETBIRD_IP="${{ secrets.SPOKE_2_NETBIRD_IP }}"
589-
NETBIRD_IP="${NETBIRD_IP%/32}"
590-
CA_CERT="${{ secrets.SPOKE_2_CA_CERT }}"
591-
CLIENT_CERT="${{ secrets.SPOKE_2_CLIENT_CERT }}"
592-
CLIENT_KEY="${{ secrets.SPOKE_2_CLIENT_KEY }}"
582+
CA_CERT_B64="${{ secrets.SPOKE_2_CA_CERT }}"
583+
CLIENT_CERT_B64="${{ secrets.SPOKE_2_CLIENT_CERT }}"
584+
CLIENT_KEY_B64="${{ secrets.SPOKE_2_CLIENT_KEY }}"
593585
;;
594586
spoke-3)
595587
NETBIRD_IP="${{ secrets.SPOKE_3_NETBIRD_IP }}"
596-
NETBIRD_IP="${NETBIRD_IP%/32}"
597-
CA_CERT="${{ secrets.SPOKE_3_CA_CERT }}"
598-
CLIENT_CERT="${{ secrets.SPOKE_3_CLIENT_CERT }}"
599-
CLIENT_KEY="${{ secrets.SPOKE_3_CLIENT_KEY }}"
588+
CA_CERT_B64="${{ secrets.SPOKE_3_CA_CERT }}"
589+
CLIENT_CERT_B64="${{ secrets.SPOKE_3_CLIENT_CERT }}"
590+
CLIENT_KEY_B64="${{ secrets.SPOKE_3_CLIENT_KEY }}"
600591
;;
601592
*)
602593
echo " ⚠ Unknown cluster: $cluster"
603-
echo " Expected cluster name: spoke-1, spoke-2, or spoke-3"
604-
echo " Please check your SPOKE_CLUSTERS secret"
605594
continue
606595
;;
607596
esac
608597
609-
echo "Configuring $cluster..."
610-
611-
if [ ! -z "$NETBIRD_IP" ]; then
612-
echo " Netbird IP: $NETBIRD_IP"
613-
614-
kubectl config set-cluster $cluster \
615-
--server=https://$NETBIRD_IP:6443 \
616-
--certificate-authority=<(echo "$CA_CERT" | base64 -d) \
617-
--embed-certs=true
598+
# Validation: Fail early if required secrets are missing
599+
if [ -z "$NETBIRD_IP" ] || [ -z "$CA_CERT_B64" ] || [ -z "$CLIENT_CERT_B64" ] || [ -z "$CLIENT_KEY_B64" ]; then
600+
echo " ❌ ERROR: Missing secrets for $cluster. Ensure NETBIRD_IP, CA_CERT, CLIENT_CERT, and CLIENT_KEY are set."
601+
exit 1
602+
fi
618603
619-
kubectl config set-credentials $cluster-admin \
620-
--client-certificate=<(echo "$CLIENT_CERT" | base64 -d) \
621-
--client-key=<(echo "$CLIENT_KEY" | base64 -d) \
622-
--embed-certs=true
604+
# Clean IPs
605+
NETBIRD_IP="${NETBIRD_IP%/32}"
623606
624-
kubectl config set-context $cluster \
625-
--cluster=$cluster \
626-
--user=$cluster-admin
607+
# Create temporary files for certificates to ensure reliable kubeconfig embedding
608+
CA_FILE=$(mktemp)
609+
CERT_FILE=$(mktemp)
610+
KEY_FILE=$(mktemp)
611+
612+
echo "$CA_CERT_B64" | base64 -d > "$CA_FILE"
613+
echo "$CLIENT_CERT_B64" | base64 -d > "$CERT_FILE"
614+
echo "$CLIENT_KEY_B64" | base64 -d > "$KEY_FILE"
615+
616+
echo " Configuring kubectl context..."
617+
kubectl config set-cluster "$cluster" --server="https://$NETBIRD_IP:6443" --certificate-authority="$CA_FILE" --embed-certs=true
618+
kubectl config set-credentials "$cluster-admin" --client-certificate="$CERT_FILE" --client-key="$KEY_FILE" --embed-certs=true
619+
kubectl config set-context "$cluster" --cluster="$cluster" --user="$cluster-admin"
620+
621+
# Cleanup temp files
622+
rm -f "$CA_FILE" "$CERT_FILE" "$KEY_FILE"
623+
624+
# Mandatory verification: Fail early if unauthorized
625+
echo " Verifying API access to $cluster..."
626+
if ! kubectl cluster-info --context "$cluster" --insecure-skip-tls-verify=true > /dev/null 2>&1; then
627+
echo " ❌ ERROR: Authentication failed for $cluster (Unauthorized). Verify secrets are correct."
628+
kubectl cluster-info --context "$cluster" --insecure-skip-tls-verify=true || true
629+
exit 1
627630
fi
631+
echo " ✅ Cluster $cluster is reachable and authorized"
628632
done
629633
634+
echo "✅ Kubeconfig configured for all spoke clusters"
630635
kubectl config get-contexts
631636
632637
# Get hub context and dynamically resolve principal address

0 commit comments

Comments
 (0)