Skip to content

Commit cf1203c

Browse files
author
Martin Jackson
committed
Revert "Merge branch 'bootstrap_secrets_single_file' into feature/sscsi-vp-proxy-cluster-ca-chart"
This reverts commit 8bbdc7b, reversing changes made to 74657c3.
1 parent 8bbdc7b commit cf1203c

38 files changed

Lines changed: 190 additions & 988 deletions

.github/workflows/jsonschema.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ jobs:
3232
- name: Verify secrets json schema
3333
run: |
3434
set -e
35-
for i in values-secret-v2-base values-secret-v2-generic-onlygenerate values-secret-v2-block-yamlstring values-secret-v2-bootstrap-mixed; do echo "$i"; check-jsonschema --fill-defaults --schemafile ./roles/vault_utils/values-secrets.v2.schema.json "tests/unit/v2/$i.yaml"; done
35+
for i in values-secret-v2-base values-secret-v2-generic-onlygenerate values-secret-v2-block-yamlstring; do echo "$i"; check-jsonschema --fill-defaults --schemafile ./roles/vault_utils/values-secrets.v2.schema.json "tests/unit/v2/$i.yaml"; done

.github/workflows/superlinter.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ jobs:
2727
VALIDATE_ALL_CODEBASE: true
2828
DEFAULT_BRANCH: main
2929
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30-
# Skip installed collection copies under .ansible/ (duplicate paths break PYTHON_MYPY and other tools).
31-
FILTER_REGEX_EXCLUDE: '(^|/)\.ansible/'
3230
# These are the validation we disable atm
3331
VALIDATE_ANSIBLE: false
3432
VALIDATE_BIOME_FORMAT: false

.github/workflows/trigger-utility-imperative-container-builds.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
steps:
1414
- name: Generate GitHub App token
1515
id: generate-token
16-
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
16+
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
1717
with:
1818
app-id: ${{ secrets.GH_WORKFLOW_AUTOMATION_CLIENT_ID }}
1919
private-key: ${{ secrets.GH_WORKFLOW_AUTOMATION_PRIVATE_KEY }}

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ help: ## This help message
77

88
.PHONY: super-linter
99
super-linter: ## Runs super linter locally
10-
rm -rf .mypy_cache .ansible
10+
rm -rf .mypy_cache
11+
rm -rf .ansible
1112
podman run -e RUN_LOCAL=true -e USE_FIND_ALGORITHM=true \
12-
-e FILTER_REGEX_EXCLUDE='(^|/)\\.ansible/' \
1313
-e VALIDATE_ANSIBLE=false \
1414
-e VALIDATE_BASH=false \
1515
-e VALIDATE_BIOME_FORMAT=false \
@@ -49,4 +49,4 @@ test: ansible-sanitytest ansible-unittest
4949
.PHONY: check-jsonschema
5050
check-jsonschema: ## Runs check-jsonschema against all unit test files except known broken ones
5151
set -e; \
52-
for i in values-secret-v2-base values-secret-v2-generic-onlygenerate values-secret-v2-block-yamlstring values-secret-v2-bootstrap-mixed; do echo "$$i"; check-jsonschema --schemafile ./roles/vault_utils/values-secrets.v2.schema.json "tests/unit/v2/$$i.yaml"; done
52+
for i in values-secret-v2-base values-secret-v2-generic-onlygenerate values-secret-v2-block-yamlstring; do echo "$$i"; check-jsonschema --schemafile ./roles/vault_utils/values-secrets.v2.schema.json "tests/unit/v2/$$i.yaml"; done

README.md

Lines changed: 81 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -9,94 +9,84 @@ loading local secrets files into VP secrets stores.
99

1010
2. Help manage imperative and other utility functions of the cluster
1111

12-
## Secrets loading
13-
14-
Secrets are loaded from a **single primary** values-secret file (plus optional `values-secret.yaml.template` under the
15-
pattern tree as a last-resort discovery path). There are **no** separate `*-bootstrap.yaml` files or `VALUES_SECRET_BOOTSTRAP`
16-
paths; early cluster bootstrap uses **per-entry** `bootstrap` fields on v2 secrets in that same primary file.
17-
18-
### Primary values-secret
19-
20-
- **Backing store** comes from `values-global.yaml`: `.global.secretStore.backend` (default `vault`). That drives parsing
21-
and whether secrets go to Vault or Kubernetes.
22-
- **Discovery order** when `VALUES_SECRET` is unset (first existing file wins):
23-
`~/.config/hybrid-cloud-patterns/values-secret-<pattern>.yaml`,
24-
`~/.config/validated-patterns/values-secret-<pattern>.yaml`,
25-
`~/values-secret-<pattern>.yaml`,
26-
`~/values-secret.yaml`,
27-
then `<pattern_dir>/values-secret.yaml.template`.
28-
- When `VALUES_SECRET` is set to an existing path, that file is used for the primary load.
29-
30-
Files may be plain YAML or `ansible-vault` encrypted.
31-
32-
### Per-secret `bootstrap` in v2 primary files
33-
34-
On schema **2.0** primary values-secret files, each secret may set `bootstrap`:
35-
36-
- **`bootstrap: true`** (or string equivalents such as `yes`, `both`) — the secret is included in the **early**
37-
Kubernetes inject pass (`none` backend) and is **also** parsed in the **primary** pass into the configured backend
38-
(Vault or Kubernetes as in `values-global.yaml`). It must not use `onMissingValue: generate` on any field (the early
39-
pass cannot generate in Vault).
40-
- **`bootstrap: only`** (or `early`) — the secret is **only** in the early inject pass; the primary pass **omits** it.
41-
- **Unset / false** — normal primary-only secret.
42-
43-
Invalid `bootstrap` scalars fail parsing with a clear error.
44-
45-
Early inject runs **before** the primary backend load: during `playbooks/install.yml`, immediately after the
46-
pattern-install manifests are applied (`operator_deploy.yml`), then again inside `load_secrets` unless that early pass
47-
already completed (duplicate inject is skipped).
48-
49-
### Playbooks and flows
50-
51-
- **`playbooks/load_secrets.yml`**
52-
Respects `.global.secretLoader.disabled` in `values-global.yaml`. When enabled: `cluster_pre_check`, primary file
53-
discovery, early Kubernetes inject for bootstrap-tagged v2 entries (when present), then parse and load the rest into
54-
the configured backend.
55-
56-
- **`playbooks/load_bootstrap_secrets.yml`**
57-
Convenience wrapper: `determine_pattern_dir`, `determine_pattern_name`, then imports `load_secrets.yml` (same behavior
58-
as install).
59-
60-
- **`playbooks/load_bootstrap_secrets_only.yml`**
61-
**Early bootstrap inject only**: same pattern discovery plays and `pattern_settings`, then only the Kubernetes inject
62-
for bootstrap-tagged secrets in the primary file (with retries). **Fails** if no primary file exists or there are no
63-
bootstrap-tagged v2 entries. Does **not** read `secretLoader.disabled` or load into Vault / primary backend.
64-
65-
- **`playbooks/display_secrets_info.yml`**
66-
Loads and displays parsed secrets (using the backend from `values-global`). For v2 files with any bootstrap-tagged
67-
entries, output is split into **`early_bootstrap_inject`** (none backend, early K8s view; includes `bootstrap: true`
68-
and `bootstrap: only`) and **`primary_backend`** (configured backend; includes normal secrets and **`bootstrap: true`**
69-
again so dual-mode entries appear in both groups). Otherwise a single parse is shown as before.
70-
71-
Typical usage passes the pattern checkout as `pattern_dir` (for example `-e pattern_dir=/path/to/pattern`). If you omit
72-
it, the same resolution as `pattern_settings` applies: `PATTERN_DIR`, then `PWD`, then the `pwd` command.
73-
74-
`playbooks/install.yml` imports `load_secrets.yml` after the pattern install playbook. When secret loading is enabled,
75-
early bootstrap inject from the primary file runs at the end of `operator_deploy.yml` (right after apply), then
76-
`load_secrets.yml` continues without repeating that inject when it already succeeded.
77-
78-
### Early bootstrap inject retries
79-
80-
Outer retries (parse plus Kubernetes apply) are controlled on the role defaults / extra-vars:
81-
82-
- `vp_secrets_bootstrap_retry_max` (default `20`)
83-
- `vp_secrets_bootstrap_retry_delay` (seconds between attempts, default `30`)
84-
85-
These apply to the early inject path inside `load_secrets` and to `load_bootstrap_secrets_only.yml`.
86-
87-
Per-secret namespace readiness (before each `kubernetes.core.k8s` apply) uses role defaults on `k8s_secret_utils`:
88-
89-
- `k8s_secret_namespace_check_retries` (default `5`) and `k8s_secret_namespace_check_delay` (seconds between attempts, default `45`).
90-
91-
If the namespace still does not exist after those attempts, the inject fails and the **outer** retry re-runs parse plus
92-
all secret injections from the start.
93-
94-
### Roles (implementation notes)
95-
96-
- `roles/load_secrets/tasks/main.yml` implements the **combined** flow (early inject from primary file, then primary
97-
backend load).
98-
- `roles/load_secrets/tasks/bootstrap_only.yml` is used only when you invoke the `load_secrets` role with
99-
`tasks_from: bootstrap_only.yml` (as `load_bootstrap_secrets_only.yml` does).
100-
- `roles/find_vp_secrets` resolves the primary file (`tasks/main.yml`).
101-
- v2 parsing and phase filters (`bootstrap_only`, `exclude_bootstrap`, `all`) are implemented in
102-
`plugins/module_utils/parse_secrets_v2.py` (single `bootstrap` normalizer: off / dual / early-only).
12+
## SS CSI workload auth notes
13+
14+
SS CSI task files live in **`roles/vault_utils/tasks/ss_csi/`**; paths below match **`include_tasks`** from the role (**`ss_csi/<file>`** relative to **`tasks/`**).
15+
16+
`vault_utils` can read `ssCsiWorkloadAuth` entries from clustergroup values and
17+
create Vault Kubernetes auth roles for hub and spoke workloads.
18+
19+
### Parsing (load YAML)
20+
21+
With **`vault_ss_csi_aggregate_clustergroup_sources`** true (default), SS CSI
22+
uses the **`clustergroup_discovery`** role to determine stems: **main** from
23+
`values-global.yaml`, then **managed** names from `clusterGroup.managedClusterGroups`
24+
in the main `values-<main>.yaml|yml`. For **each** stem it loads a document from
25+
the in-cluster **`ConfigMap` `values-<stem>`** (namespace
26+
`openshift-gitops` by default), then falls back to **`pattern_dir/values-<stem>.yaml|yml`**
27+
when enabled. ConfigMap data keys follow **`vault_ss_csi_clustergroup_configmap_key`**
28+
and **`vault_ss_csi_clustergroup_configmap_key_candidates`**. Each document must
29+
include **`clusterGroup`**. Stems are merged in **`clustergroup_load_order`**
30+
(main first, then managed stems sorted) so later sources override duplicate
31+
`clusterGroup.applications` keys. Set **`vault_ss_csi_aggregate_clustergroup_sources`**
32+
to false to load only the **main** document (legacy: single ConfigMap or
33+
`values-<main>.yaml`).
34+
35+
### Extraction (find `ssCsiWorkloadAuth`)
36+
37+
The role builds **`_vault_ss_csi_apps_by_stem`** (per-stem `clusterGroup.applications`)
38+
and a merged **`clusterGroup.managedClusterGroups`**. It collects:
39+
40+
- **`clusterGroup.applications.*.ssCsiWorkloadAuth`** — per stem; omit **`cluster`**
41+
in values: the **main** stem resolves to **hub**; **managed** stems resolve to
42+
that **stem name** so entries under `values-<managed>.yaml` stay spoke-scoped.
43+
- **`clusterGroup.managedClusterGroups.*.applications.*.ssCsiWorkloadAuth`**
44+
from the merged map; omit **`cluster`** and the row targets that managed group
45+
(**`name`**, else the group map key).
46+
47+
### Projection (Vault roles)
48+
49+
Rows are appended to **`_ss_csi_all_entries`**, split into hub vs spoke using
50+
the computed **`cluster`** field (from stem or managed group when omitted in YAML), then **hub** identities get Vault Kubernetes
51+
auth roles via **`ss_csi/vault_ss_csi_apply_one_hub_sscsi_role.yaml`**. Spoke rows are
52+
normalized to **`vault_path`** later in the play (**`ss_csi/vault_ss_csi_normalize_spoke_entries_to_vault_path.yaml`**
53+
during **`vault_spokes_init`**) and roles are written on each spoke mount
54+
(**`ss_csi/vault_ss_csi_apply_one_spoke_sscsi_role.yaml`**). Role names use
55+
**`<mount>-sscsi-<slug>`**; slugs come from **`ss_csi/vault_ss_csi_compute_role_slug.yaml`**.
56+
57+
To **inspect** stems and files locally, run **`playbooks/list_clustergroups.yml`**
58+
or **`playbooks/parse_clustergroup_values.yml`** (see **`roles/clustergroup_discovery/README.md`**).
59+
60+
At the application level (`clusterGroup.applications.<app>`), the relevant
61+
inputs are:
62+
63+
- `ssCsiWorkloadAuth` (list)
64+
- `ssCsiWorkloadAuth[].serviceAccount` (required)
65+
- `ssCsiWorkloadAuth[].namespace` (optional)
66+
- Omit **`cluster`** in pattern YAML; hub vs spoke comes from **which file or
67+
`managedClusterGroups` branch** defines the list (see extraction above). Spoke
68+
handling still normalizes to **`vault_path`** (full DNS), same as External Secrets.
69+
- `ssCsiWorkloadAuth[].roleSlug` / `role_slug` (optional): suffix only; Vault
70+
role is **`<mount>-sscsi-<slug>`** where **`<mount>`** is hub **`hub`** (or
71+
configured hub path) or the spoke **`vault_path`**. When using the
72+
**vp-sscsi-spc** chart, `spec.parameters.roleName` uses the same **mount**
73+
as `vaultKubernetesMountPath` (typically **`global.clusterDomain`** on
74+
spokes), not a short clustergroup label.
75+
- application `namespace` (optional default for entry namespace)
76+
77+
CA material management for SS CSI is not handled in this collection anymore.
78+
Provide CA distribution using a separate chart or platform mechanism.
79+
80+
For the complete flow and task ordering, see
81+
`secrets-initialization-and-vault-unseal.md`.
82+
83+
## Pattern repository directory (`pattern_dir`)
84+
85+
Playbooks need the path to your pattern Git checkout (where `values-global.yaml`
86+
and related files live). Resolution order: extra var `pattern_dir`, environment
87+
variable `PATTERN_DIR`, then `PWD` and `pwd`.
88+
89+
When running from the imperative container or another fixed working directory,
90+
pass the repository root explicitly, for example `-e pattern_dir=/git/repo` (or add
91+
equivalent extra vars via `clusterGroup.imperative.extraPlaybookArgs` in the
92+
clustergroup chart).
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
---
2-
# Resolves pattern_dir the same way as the pattern_settings role (extra-vars, PATTERN_DIR, PWD, pwd),
3-
# then fails if still unset. Used by display_secrets_info, load_values_global, load_bootstrap_secrets*, etc.
42
- name: Determine pattern dir
53
hosts: localhost
64
connection: local
75
gather_facts: false
86
become: false
7+
vars:
8+
pattern_dir: ''
99
tasks:
10-
- name: Resolve pattern_dir from extra-vars, PATTERN_DIR, PWD, or pwd
11-
ansible.builtin.include_role:
12-
name: pattern_settings
13-
tasks_from: resolve_overrides.yml
14-
15-
- name: Fail if pattern directory is not set after resolution
10+
- name: Fail if directory is not set
1611
ansible.builtin.fail:
17-
msg: >-
18-
pattern_dir is not set. Pass -e pattern_dir=/path/to/pattern, export PATTERN_DIR to that path,
19-
or run the playbook from the pattern directory so PWD is correct.
20-
when: pattern_dir | default('') | string | trim | length == 0
12+
msg: "pattern_dir variable must be set"
13+
when: pattern_dir | length == 0
2114

2215
- name: Set pattern_dir fact for future plays
2316
ansible.builtin.set_fact:
24-
pattern_dir: "{{ pattern_dir | string | trim }}"
17+
pattern_dir: '{{ pattern_dir }}'

playbooks/display_secrets_info.yml

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -29,70 +29,12 @@
2929
ansible.builtin.set_fact:
3030
secrets_yaml: "{{ values_secrets_data if values_secrets_data is not string else values_secrets_data | from_yaml }}"
3131

32-
- name: Detect inline bootstrap secrets in primary v2 file
33-
ansible.builtin.set_fact:
34-
_vp_has_inline_bootstrap_secrets: >-
35-
{{
36-
(secrets_yaml.version | default('2.0')) is version('2.0', '>=')
37-
and (
38-
(secrets_yaml.secrets | default([])
39-
| selectattr('bootstrap', 'defined')
40-
| selectattr('bootstrap')
41-
| list
42-
| length) > 0
43-
)
44-
}}
45-
46-
- name: Parse secrets data (v2 with bootstrap — two display groups)
47-
when: _vp_has_inline_bootstrap_secrets | bool
48-
block:
49-
- name: Parse early-bootstrap inject portion for display (none backend)
50-
no_log: '{{ hide_sensitive_output }}'
51-
parse_secrets_info:
52-
values_secrets_plaintext: "{{ values_secrets_data }}"
53-
secrets_backing_store: none
54-
secrets_parse_filter: bootstrap_only
55-
register: _display_bootstrap_parse
56-
57-
- name: Parse primary-backend portion for display (configured backend)
58-
no_log: '{{ hide_sensitive_output }}'
59-
parse_secrets_info:
60-
values_secrets_plaintext: "{{ values_secrets_data }}"
61-
secrets_backing_store: "{{ secrets_backing_store }}"
62-
secrets_parse_filter: exclude_bootstrap
63-
register: _display_primary_parse
64-
65-
- name: Build two-group secrets display (dual bootstrap entries appear in both)
66-
ansible.builtin.set_fact:
67-
secrets_results:
68-
early_bootstrap_inject:
69-
parsed_secrets: "{{ _display_bootstrap_parse.parsed_secrets }}"
70-
kubernetes_secret_objects: "{{ _display_bootstrap_parse.kubernetes_secret_objects }}"
71-
vault_policies: "{{ _display_bootstrap_parse.vault_policies | default({}) }}"
72-
unique_vault_prefixes: "{{ _display_bootstrap_parse.unique_vault_prefixes | default([]) }}"
73-
backing_store: none
74-
primary_backend:
75-
parsed_secrets: "{{ _display_primary_parse.parsed_secrets }}"
76-
kubernetes_secret_objects: "{{ _display_primary_parse.kubernetes_secret_objects }}"
77-
vault_policies: "{{ _display_primary_parse.vault_policies | default({}) }}"
78-
secret_store_namespace: "{{ _display_primary_parse.secret_store_namespace }}"
79-
unique_vault_prefixes: "{{ _display_primary_parse.unique_vault_prefixes | default([]) }}"
80-
secrets_backing_store: "{{ secrets_backing_store }}"
81-
82-
# Do not register: secrets_results here — a skipped task still overwrites the register
83-
# and would wipe the two-group set_fact when bootstrap secrets are present.
84-
- name: Parse secrets data (single phase)
85-
when: not (_vp_has_inline_bootstrap_secrets | bool)
32+
- name: Parse secrets data
8633
no_log: '{{ hide_sensitive_output }}'
8734
parse_secrets_info:
8835
values_secrets_plaintext: "{{ values_secrets_data }}"
8936
secrets_backing_store: "{{ secrets_backing_store }}"
90-
register: _display_single_phase_parse
91-
92-
- name: Set secrets_results from single-phase parse
93-
when: not (_vp_has_inline_bootstrap_secrets | bool)
94-
ansible.builtin.set_fact:
95-
secrets_results: "{{ _display_single_phase_parse }}"
37+
register: secrets_results
9638

9739
- name: Display secrets data
9840
ansible.builtin.debug:

playbooks/load_bootstrap_secrets.yml

Lines changed: 0 additions & 12 deletions
This file was deleted.

playbooks/load_bootstrap_secrets_only.yml

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)