Skip to content
149 changes: 0 additions & 149 deletions charts/acs-central/templates/jobs/create-cluster-init-bundle.yaml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# NOTE: This CRS (Cluster Registration Secret) is for the local cluster (hub) only.
# For multi-cluster deployments, create separate CRS jobs
# for each remote secured cluster with their specific cluster names.
#
# CRS replaces the deprecated init-bundle approach (RHACS 4.10+).
# Unlike init bundles which contain long-lived certificates, a CRS contains
# a token that the secured cluster uses to request its own certificates.
# The CRS can be revoked after registration without disconnecting the cluster.

{{- if .Values.central.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: create-cluster-registration-secret
namespace: {{ .Release.Namespace }}
labels:
{{- include "acs-central.labels" . | nindent 4 }}
annotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
argocd.argoproj.io/sync-wave: "43"
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
template:
metadata:
name: create-cluster-registration-secret
labels:
app: create-cluster-registration-secret
{{- include "acs-central.labels" . | nindent 8 }}
spec:
containers:
- image: {{ .Values.integration.keycloak.jobImage.registry }}/{{ .Values.integration.keycloak.jobImage.repository }}:{{ .Values.integration.keycloak.jobImage.tag }}
imagePullPolicy: {{ .Values.integration.keycloak.jobImage.pullPolicy }}
env:
- name: PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.central.adminPassword.secretName }}
key: {{ .Values.central.adminPassword.secretKey }}
command:
- /bin/bash
- -c
- |
#!/usr/bin/env bash

# Skip if cluster is already registered (init-bundle) or CRS already applied
if kubectl get secret/sensor-tls &> /dev/null; then
echo "Cluster already registered (sensor-tls exists), skipping"
exit 0
fi
if kubectl get secret/cluster-registration-secret &> /dev/null; then
echo "CRS already applied (cluster-registration-secret exists), skipping"
exit 0
fi

echo "Waiting for ACS Central to be ready..."
attempt_counter=0
max_attempts=30

until $(curl -k --output /dev/null --silent --head --fail https://central); do
if [ ${attempt_counter} -eq ${max_attempts} ]; then
echo "Max attempts reached waiting for Central"
exit 1
fi

printf '.'
attempt_counter=$(($attempt_counter+1))
sleep 10
done

echo ""
echo "Central is ready"

CLUSTER_NAME="{{ .Values.clusterName | default .Values.global.localClusterName }}"
echo "Generating cluster registration secret for: $CLUSTER_NAME"

# Helper script to find an entry by name in a JSON list response
printf '%s\n' \
'import json, sys' \
'data = json.load(open(sys.argv[1]))' \
'for item in data.get("items", []):' \
' if item.get("name") == sys.argv[2]:' \
' print(item["id"])' \
' break' \
> /tmp/find_entry.py

# Revoke any existing init-bundle with the same name (migration from init-bundle to CRS).
# The CRS API rejects names that collide with existing init-bundles or CRS entries.
curl -k -s -u "admin:$PASSWORD" \
https://central/v1/cluster-init/init-bundles > /tmp/bundles_list.json

EXISTING_BUNDLE_ID=$(python3 /tmp/find_entry.py /tmp/bundles_list.json "$CLUSTER_NAME" 2>/dev/null)

if [ -n "$EXISTING_BUNDLE_ID" ]; then
echo "Revoking legacy init-bundle '$CLUSTER_NAME' (ID: $EXISTING_BUNDLE_ID)..."
curl -k -s -X PATCH -u "admin:$PASSWORD" \
-H "Content-Type: application/json" \
--data "{\"ids\":[\"$EXISTING_BUNDLE_ID\"],\"confirmImpactedClustersIds\":[]}" \
https://central/v1/cluster-init/init-bundles/revoke > /tmp/revoke_result.json
echo "Legacy init-bundle revoked"
sleep 2
fi

# Revoke any existing CRS with the same name (handles re-run after partial failure)
curl -k -s -u "admin:$PASSWORD" \
https://central/v1/cluster-init/crs > /tmp/crs_list.json

EXISTING_CRS_ID=$(python3 /tmp/find_entry.py /tmp/crs_list.json "$CLUSTER_NAME" 2>/dev/null)

if [ -n "$EXISTING_CRS_ID" ]; then
echo "Revoking existing CRS '$CLUSTER_NAME' (ID: $EXISTING_CRS_ID)..."
curl -k -s -X PATCH -u "admin:$PASSWORD" \
-H "Content-Type: application/json" \
--data "{\"ids\":[\"$EXISTING_CRS_ID\"],\"confirmImpactedClustersIds\":[]}" \
https://central/v1/cluster-init/crs/revoke > /tmp/crs_revoke_result.json
echo "Existing CRS revoked"
sleep 2
fi

curl -k -o /tmp/crs.json -X POST \
-u "admin:$PASSWORD" \
-H "Content-Type: application/json" \
--data "{\"name\":\"$CLUSTER_NAME\"}" \
https://central/v1/cluster-init/crs

if [ $? -ne 0 ]; then
echo "Failed to generate CRS"
cat /tmp/crs.json
exit 1
fi

if ! python3 -c 'import sys, json; json.load(open("/tmp/crs.json"))["crs"]' &> /dev/null; then
echo "API response does not contain crs field:"
cat /tmp/crs.json | python3 -m json.tool 2>/dev/null || cat /tmp/crs.json
exit 1
fi

echo "CRS received"

echo "Applying cluster registration secret..."
cat /tmp/crs.json | python3 -c 'import sys, json; print(json.load(sys.stdin)["crs"])' | base64 -d | oc apply -f -

if [ $? -eq 0 ]; then
echo "Cluster registration secret applied successfully"

if oc get SecuredCluster stackrox-secured-cluster-services &> /dev/null; then
oc label SecuredCluster stackrox-secured-cluster-services cluster-init-job-status=created --overwrite
echo "SecuredCluster labeled for reconciliation"
fi
else
echo "Failed to apply cluster registration secret"
exit 1
fi

echo "ACS cluster registration secret configuration complete"
name: create-cluster-registration-secret
dnsPolicy: ClusterFirst
restartPolicy: Never
serviceAccount: {{ .Values.integration.keycloak.serviceAccountName }}
serviceAccountName: {{ .Values.integration.keycloak.serviceAccountName }}
terminationGracePeriodSeconds: 30
{{- end }}
2 changes: 1 addition & 1 deletion charts/acs-central/values.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Default values for ACS Central Services
# This chart deploys the Central and Scanner components
#
# Cluster name for init bundle
# Cluster name for CRS (Cluster Registration Secret) registration
clusterName: "" # Will be set from global.localClusterName by pattern framework

global:
Expand Down
5 changes: 3 additions & 2 deletions charts/acs-secured-cluster/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ clusterName: "" # Will be overridden by values-hub.yaml
# Central endpoint configuration
centralEndpoint: "" # e.g., central-stackrox.apps.cluster.example.com:443

# Init bundle secret (from Vault)
# Cluster registration is handled by the CRS job in acs-central chart.
# The CRS (Cluster Registration Secret) replaces the deprecated init-bundle approach.
# Legacy init-bundle values kept for reference:
initBundle:
useExternalSecret: true
secretName: collector-tls
# If not using external secret, provide bundle data
data: ""

# Sensor configuration
Expand Down
2 changes: 1 addition & 1 deletion values-hub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ clusterGroup:
value: "ztvp"
- name: integration.keycloak.clientId
value: "acs-central"
# Must match acs-secured-cluster clusterName (init bundle API name)
# Must match acs-secured-cluster clusterName (CRS registration name)
- name: clusterName
value: hub
# ACS to scan images stored in Quay (Uncomment to enable)
Expand Down
Loading