Skip to content

Commit 62dc5ea

Browse files
committed
fix: ztvp-certificates merges existing proxy CA on private repo installs
When deploying from an internal Git host (e.g. gitlab.cee.redhat.com), users must add corporate CAs to proxy/cluster before install. Previously the ztvp-certificates job refused to overwrite a user-set trustedCA, leaving ACS Central unable to trust Keycloak via the ingress CA. Changes: - PHASE 8.5: include all extracted CAs (custom, additional, cluster) in the proxy CA bundle, not just ingress + service - PHASE 8.6: merge existing proxy CA ConfigMap content into ztvp-proxy-ca before taking over trustedCA management - docs/private-repos.md: document pre-install CA requirement and explain automatic merge behavior - values-secret.yaml.template: add ACM workaround bootstrap_secrets entry Signed-off-by: Min Zhang <minzhang@redhat.com>
1 parent 491ca2a commit 62dc5ea

3 files changed

Lines changed: 158 additions & 20 deletions

File tree

charts/ztvp-certificates/files/extract-certificates.sh.tpl

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -342,11 +342,18 @@ fi
342342
{{- if .Values.proxyCA.enabled }}
343343
log "Creating proxy CA ConfigMap for cluster trustedCA injection"
344344

345-
# Build a bundle with ONLY the custom CAs (ingress + service).
346-
# The Cluster Network Operator automatically merges these with system CAs.
345+
# Build the proxy CA bundle with ALL extracted custom CAs so that workloads
346+
# trusting the injected bundle can reach both cluster-internal services
347+
# (via ingress/service CA) and external hosts behind corporate CAs
348+
# (via additionalCertificates / customCA).
349+
# The Cluster Network Operator merges these with the system (Mozilla) CAs.
347350
> "${TEMP_DIR}/proxy-ca-bundle.pem"
348-
for cert_file in "${TEMP_DIR}"/ingress-ca-*.crt "${TEMP_DIR}/service-ca.crt"; do
351+
for cert_file in "${TEMP_DIR}"/ingress-ca-*.crt "${TEMP_DIR}/service-ca.crt" "${TEMP_DIR}/custom-ca.crt" "${TEMP_DIR}"/*.crt; do
349352
[[ -f "$cert_file" ]] || continue
353+
# Deduplicate: skip if already appended (the *.crt glob may re-match earlier files)
354+
if grep -qF "$(head -2 "$cert_file")" "${TEMP_DIR}/proxy-ca-bundle.pem" 2>/dev/null; then
355+
continue
356+
fi
350357
cat "$cert_file" >> "${TEMP_DIR}/proxy-ca-bundle.pem"
351358
echo "" >> "${TEMP_DIR}/proxy-ca-bundle.pem"
352359
done
@@ -384,8 +391,38 @@ CURRENT_TRUSTED_CA=$(oc get proxy/cluster -o jsonpath='{.spec.trustedCA.name}' 2
384391
if [[ "$CURRENT_TRUSTED_CA" == "{{ .Values.proxyCA.configMapName }}" ]]; then
385392
log "Proxy trustedCA already set to {{ .Values.proxyCA.configMapName }}, skipping"
386393
elif [[ -n "$CURRENT_TRUSTED_CA" && "$CURRENT_TRUSTED_CA" != "{{ .Values.proxyCA.configMapName }}" ]]; then
387-
log "WARNING: Proxy trustedCA is already set to '$CURRENT_TRUSTED_CA' (not overwriting)"
388-
log "WARNING: To use ZTVP proxy CA, manually run: oc patch proxy/cluster --type=merge -p '{\"spec\":{\"trustedCA\":{\"name\":\"{{ .Values.proxyCA.configMapName }}\"}}}}'"
394+
# Merge any CAs from the existing proxy ConfigMap into our bundle so
395+
# nothing is lost when we take over trustedCA management.
396+
log "Existing proxy trustedCA ConfigMap: $CURRENT_TRUSTED_CA"
397+
EXISTING_CA_DATA=$(oc get configmap "$CURRENT_TRUSTED_CA" -n {{ .Values.global.namespace }} \
398+
-o jsonpath='{.data.ca-bundle\.crt}' 2>/dev/null || echo "")
399+
if [[ -n "$EXISTING_CA_DATA" ]]; then
400+
echo "$EXISTING_CA_DATA" > "${TEMP_DIR}/existing-proxy-ca.crt"
401+
# Append any certs not already in our bundle
402+
while IFS= read -r line; do
403+
echo "$line"
404+
done < "${TEMP_DIR}/existing-proxy-ca.crt" >> "${TEMP_DIR}/proxy-ca-bundle.pem"
405+
PROXY_BUNDLE_SIZE=$(wc -c < "${TEMP_DIR}/proxy-ca-bundle.pem" 2>/dev/null || echo 0)
406+
log "Merged existing proxy CAs into {{ .Values.proxyCA.configMapName }}"
407+
# Re-create the ConfigMap with merged content
408+
cat <<MERGEEOF | oc apply -f -
409+
apiVersion: v1
410+
kind: ConfigMap
411+
metadata:
412+
name: {{ .Values.proxyCA.configMapName }}
413+
namespace: {{ .Values.global.namespace }}
414+
labels:
415+
{{- range $key, $value := .Values.configMapLabels }}
416+
{{ $key }}: {{ $value | quote }}
417+
{{- end }}
418+
data:
419+
ca-bundle.crt: |
420+
$(cat "${TEMP_DIR}/proxy-ca-bundle.pem" | sed 's/^/ /')
421+
MERGEEOF
422+
fi
423+
log "Updating proxy/cluster trustedCA from '$CURRENT_TRUSTED_CA' to {{ .Values.proxyCA.configMapName }}"
424+
oc patch proxy/cluster --type=merge -p '{"spec":{"trustedCA":{"name":"{{ .Values.proxyCA.configMapName }}"}}}'
425+
log "OK: Proxy trustedCA configured (previous: $CURRENT_TRUSTED_CA)"
389426
else
390427
if [[ $PROXY_BUNDLE_SIZE -gt 100 ]]; then
391428
log "Setting proxy/cluster trustedCA to {{ .Values.proxyCA.configMapName }}"

docs/private-repos.md

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ Cluster ArgoCD and Hub ArgoCD instances can pull the pattern manifests.
1919
* A fork or private copy of this repository
2020
* A deploy key (SSH) or Personal Access Token (HTTPS) with **read** access
2121

22+
> [!IMPORTANT]
23+
> The git remote URL in your local clone **must match** the auth type in
24+
> your `bootstrap_secrets`. The Makefile passes the remote URL to the
25+
> Pattern CR verbatim when `TOKEN_SECRET` is set:
26+
>
27+
> * SSH auth: remote must be `git@host:org/repo.git`
28+
> * HTTPS/PAT auth: remote must be `https://host/org/repo.git`
29+
>
30+
> Set with: `git remote set-url origin <matching-url>`
31+
2232
## Option A: SSH Key Authentication
2333

2434
### 1. Generate a deploy key
@@ -38,10 +48,10 @@ Deploy keys, etc.).
3848
Copy the template and uncomment the SSH `bootstrap_secrets` block:
3949

4050
```shell
41-
cp values-secret.yaml.template ~/values-secret-layered-zero-trust.yaml
51+
cp values-secret.yaml.template ~/values-secret.yaml
4252
```
4353

44-
Edit `~/values-secret-layered-zero-trust.yaml` and uncomment **Option A**
54+
Edit `~/values-secret.yaml` and uncomment **Option A**
4555
under the "BOOTSTRAP SECRETS" section. Update the `url` field with your
4656
repository's SSH URL:
4757

@@ -61,6 +71,21 @@ bootstrap_secrets:
6171
value: "true"
6272
- name: sshPrivateKey
6373
path: ~/.ssh/ztvp-deploy-key
74+
# ACM workaround (see Troubleshooting)
75+
- name: vp-private-repo-credentials
76+
targetNamespaces:
77+
- openshift-gitops
78+
labels:
79+
argocd.argoproj.io/secret-type: repository
80+
fields:
81+
- name: type
82+
value: git
83+
- name: url
84+
value: git@github.com:YOUR-ORG/layered-zero-trust.git
85+
- name: insecureIgnoreHostKey
86+
value: "true"
87+
- name: sshPrivateKey
88+
path: ~/.ssh/ztvp-deploy-key
6489
```
6590
6691
### 4. Deploy
@@ -75,7 +100,8 @@ bootstrap_secrets:
75100

76101
* **GitHub:** Settings -> Developer settings -> Personal access tokens ->
77102
Fine-grained tokens. Grant **Contents: Read** on the target repository.
78-
* **GitLab:** Settings -> Access Tokens. Grant `read_repository` scope.
103+
* **GitLab:** Settings -> Access Tokens. Grant **Reporter** role with
104+
`read_repository` scope (Guest role is insufficient to clone code).
79105

80106
Store the token in a local file:
81107

@@ -90,10 +116,10 @@ chmod 600 ~/.config/validated-patterns/git-pat
90116
Copy the template and uncomment the HTTPS `bootstrap_secrets` block:
91117

92118
```shell
93-
cp values-secret.yaml.template ~/values-secret-layered-zero-trust.yaml
119+
cp values-secret.yaml.template ~/values-secret.yaml
94120
```
95121

96-
Edit `~/values-secret-layered-zero-trust.yaml` and uncomment **Option B**
122+
Edit `~/values-secret.yaml` and uncomment **Option B**
97123
under the "BOOTSTRAP SECRETS" section. Update the `url`, `username`, and
98124
`password` path:
99125

@@ -113,6 +139,21 @@ bootstrap_secrets:
113139
value: YOUR-USERNAME
114140
- name: password
115141
path: ~/.config/validated-patterns/git-pat
142+
# ACM workaround (see Troubleshooting)
143+
- name: vp-private-repo-credentials
144+
targetNamespaces:
145+
- openshift-gitops
146+
labels:
147+
argocd.argoproj.io/secret-type: repository
148+
fields:
149+
- name: type
150+
value: git
151+
- name: url
152+
value: https://github.com/YOUR-ORG/layered-zero-trust.git
153+
- name: username
154+
value: YOUR-USERNAME
155+
- name: password
156+
path: ~/.config/validated-patterns/git-pat
116157
```
117158
118159
> [!NOTE]
@@ -176,13 +217,12 @@ Expected output: `Synced` (or `OutOfSync` if you have uncommitted changes).
176217

177218
## Troubleshooting
178219

179-
* **ACM shows Degraded during initial install** -- This is expected. The
180-
ACM policy `vp-private-hub-policy` copies the repository credentials to
181-
the `open-cluster-management` namespace, but depends on the VP operator
182-
first propagating the secret to `openshift-gitops`. On a fresh install
183-
this takes an extra reconciliation cycle (1-2 minutes) while namespaces
184-
are being created. The ACM application will self-heal once the VP
185-
operator completes the copy.
220+
* **ACM shows Degraded (vp-private-hub-policy NonCompliant)** -- The ACM
221+
chart policy copies repo credentials from `openshift-gitops`, but the VP
222+
operator only places them in `vp-gitops`. Fix this by adding a second
223+
`bootstrap_secrets` entry named `vp-private-repo-credentials` targeting
224+
`openshift-gitops` (see the "ACM workaround" section in
225+
`values-secret.yaml.template`). Then re-run `load-secrets`.
186226

187227
* **ArgoCD shows "repository not accessible"** -- Verify the SSH key or PAT
188228
has read access. For SSH, confirm the key has no passphrase (`ssh-keygen
@@ -192,9 +232,36 @@ Expected output: `Synced` (or `OutOfSync` if you have uncommitted changes).
192232
field is missing from the bootstrap secret. The ArgoCD repo-server runs
193233
in a container without your Git host's fingerprint in known_hosts.
194234

195-
* **Secret not found during install** -- Ensure you ran `load-secrets` (part
196-
of `post-install`) *after* the bootstrap secret was created. The
197-
`TOKEN_SECRET` and `TOKEN_NAMESPACE` values must match exactly.
235+
* **HTTPS: "x509: certificate signed by unknown authority"** -- This
236+
affects internal/self-hosted GitLab instances whose TLS certificates are
237+
signed by a corporate CA. GitHub and public GitLab (`gitlab.com`) use
238+
publicly trusted CAs and do not require this step.
239+
240+
The corporate CA must be in the cluster trust store **before** install
241+
because the VP operator needs it to clone the repo. Add the internal CA
242+
as a pre-install step:
243+
244+
```shell
245+
oc create configmap custom-ca -n openshift-config \
246+
--from-file=ca-bundle.crt=/path/to/corporate-ca-bundle.pem
247+
oc patch proxy/cluster --type=merge \
248+
-p '{"spec":{"trustedCA":{"name":"custom-ca"}}}'
249+
```
250+
251+
Wait a few minutes for operator pods to restart with the updated bundle.
252+
253+
> [!NOTE]
254+
> After the pattern deploys, the `ztvp-certificates` chart automatically
255+
> merges your `custom-ca` content into its managed `ztvp-proxy-ca`
256+
> ConfigMap and switches `proxy/cluster.spec.trustedCA` to
257+
> `ztvp-proxy-ca`. This adds the cluster ingress and service CAs so
258+
> that workloads like ACS Central can reach Keycloak without additional
259+
> manual steps. You do **not** need to manually add the ingress CA to
260+
> your `custom-ca`.
261+
262+
* **Secret not found during install** -- Ensure you ran
263+
`./pattern.sh make load-secrets` *after* the bootstrap secret was created.
264+
The `TOKEN_SECRET` and `TOKEN_NAMESPACE` values must match exactly.
198265

199266
* **GitLab HTTPS fails** -- Remember that GitLab PAT auth requires
200267
`username: oauth2`, not your GitLab user handle.

values-secret.yaml.template

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,24 @@ secrets:
438438
# value: "true"
439439
# - name: sshPrivateKey
440440
# path: ~/.ssh/ztvp-deploy-key
441+
#
442+
# ACM workaround: The ACM chart policy copies repo credentials from
443+
# openshift-gitops, but the VP operator only places them in vp-gitops.
444+
# This second entry ensures the ACM policy can resolve.
445+
#- name: vp-private-repo-credentials
446+
# targetNamespaces:
447+
# - openshift-gitops
448+
# labels:
449+
# argocd.argoproj.io/secret-type: repository
450+
# fields:
451+
# - name: type
452+
# value: git
453+
# - name: url
454+
# value: git@github.com:YOUR-ORG/layered-zero-trust.git
455+
# - name: insecureIgnoreHostKey
456+
# value: "true"
457+
# - name: sshPrivateKey
458+
# path: ~/.ssh/ztvp-deploy-key
441459

442460
# --- OPTION B: HTTPS with Personal Access Token (PAT) ---
443461
# Create a PAT with read access to your repository.
@@ -459,3 +477,19 @@ secrets:
459477
# value: YOUR-USERNAME
460478
# - name: password
461479
# path: ~/.config/validated-patterns/git-pat
480+
#
481+
# ACM workaround (HTTPS version):
482+
#- name: vp-private-repo-credentials
483+
# targetNamespaces:
484+
# - openshift-gitops
485+
# labels:
486+
# argocd.argoproj.io/secret-type: repository
487+
# fields:
488+
# - name: type
489+
# value: git
490+
# - name: url
491+
# value: https://github.com/YOUR-ORG/layered-zero-trust.git
492+
# - name: username
493+
# value: YOUR-USERNAME
494+
# - name: password
495+
# path: ~/.config/validated-patterns/git-pat

0 commit comments

Comments
 (0)