Skip to content

feat(pki): check the PKI folder before an apply - #741

Open
ralgozino wants to merge 3 commits into
mainfrom
feat/validate-pki-folder
Open

feat(pki): check the PKI folder before an apply#741
ralgozino wants to merge 3 commits into
mainfrom
feat/validate-pki-folder

Conversation

@ralgozino

@ralgozino ralgozino commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary 💡

furyctl did not check the folder in .spec.kubernetes.pkiPath (Immutable) or .spec.kubernetes.pkiFolder (OnPremises) before an apply.

When the folder or one of its files was absent, the apply failed in the middle with an Ansible error hard to understand.

Closes sighupio/distribution#584

Relates:

Description 📝

furyctl did not check the folder in .spec.kubernetes.pkiPath (Immutable) or .spec.kubernetes.pkiFolder (OnPremises) before an apply. When the folder or one of its files was absent, the apply failed in the middle, inside an Ansible task. The message did not say how to correct the fault.

furyctl apply and furyctl validate config now check that the folder holds the files that the installer roles copy to the nodes:

  • under master/: ca.crt, ca.key, front-proxy-ca.crt, front-proxy-ca.key, sa.key and sa.pub
  • under etcd/: ca.crt and ca.key

furyctl apply skips the check when the selected phases don't need the PKI. As a result, an apply of the distribution or the plugins phase alone does not ask for the CA keys. A dry run also skips the check, with a warning, because it stops before Ansible.

Failure modes

An absent folder names the furyctl create pki command to run.

An incomplete folder, names the files that are absent or empty.

A file that furyctl cannot read gives a read error, and not a name in that list. The message for an incomplete folder tells the user to delete the folder, and that step destroys the CA of a cluster that exists.

The table below gives the commands and the phases that do the check:

Command The check
apply, apply --phase infrastructure|kubernetes runs
apply --phase distribution|plugins does not run
apply --start-from a distribution or plugins sub-phase does not run
apply --start-from post-kubernetes does not run, because coreKubernetes skips apply.yaml
apply --post-apply-phases kubernetes runs, because extraPhases repeats that phase
apply --dry-run does not run, and gives a warning
validate config runs
the other 6 commands that call config.Validate do not run it

Worth noting that during the resume of an upgrade the PKI check will be done because the start phase comes from the saved state in the configmap and is not known at validate config time. If the user specifies --upgrade and --start-from the starting phase will be known and the check will be skipped if not needed.

Breaking Changes 💔

None. Each new check is preventive. The blocked cases make the apply fail later, inside an Ansible task.

A test in CI can fail if it does not create the PKI folder before it uses it. The correction is simple: create the pki first. From what I checked, distribution and furyctl tests are not affected.

Tests performed 🧪

  • furyctl create config --kind Immutable and --kind OnPremises, against a local distribution: the file is written, and it is not deleted.
  • validate config with the folder absent, with a complete folder, and with 2 files removed.
  • validate config with pkiPath: pki (a relative value without a prefix), with {path://realpki} and with {env://PKI_DIR}.
  • validate config with a relative --config value from 2 different working folders: the message gives the same absolute path.
  • validate config with an Immutable configuration without pkiPath, against the schema of distribution#585: the schema reports the absent field first.
  • apply --phase distribution with an incomplete folder: the check does not run.
  • apply --phase kubernetes with an incomplete folder: exit code 1, with the message for an incomplete folder.
  • apply --dry-run with the folder absent: a warning, and the apply continues.
  • A folder that furyctl cannot read (mode 0o000): a read error, and not a message for absent files.
  • furyctl dump template in distribution/tests/templates/immutable/01-full-calico-nginx, which holds pkiPath: ./pki and no pki folder: exit code 0, and the result is the same as the baseline. This is the command that test:templates:regressions runs.
  • An apply against a real Immutable cluster.

Future work 🔧

  • We could ask the user if wants to create the missing PKI folder instead of erroring out, but this feature needs some planning. Evaluate whether furyctl writes the path into furyctl.yaml.

Self-assessment checklist 🏁

Important

Make sure that you completed this checklist before asking for review.

PRs that do not have this checklist ready won't be reviewed.

  • My PR has a clear scope and does not mix together several unrelated changes
  • I've updated the docs/releases/unreleased.md file (or equivalent)
  • I've tested the proposed changes and wrote the tests performed in the section above
  • My branch is up-to-date with the target branch and there are no conflicts
  • I've considered all the different cluster kinds (KFDDistribution, OnPremises, EKSCluster, Immutable) that may be affected by this change — NewPKIValidatorFactory returns nil for EKSCluster and KFDDistribution, so their behavior does not change
  • CI is green

furyctl did not check the folder in .spec.kubernetes.pkiPath (Immutable)
or .spec.kubernetes.pkiFolder (OnPremises) before an apply. When the
folder or one of its files was absent, the apply failed in the middle,
inside an Ansible task. The message did not say how to correct the
fault.

`furyctl apply` and `furyctl validate config` now check that the folder
holds the files that the installer roles copy to the nodes:

- under master/: ca.crt, ca.key, front-proxy-ca.crt, front-proxy-ca.key,
sa.key
  and sa.pub
- under etcd/: ca.crt and ca.key

An absent folder names the `furyctl create pki` command to run. An
incomplete folder names the files that are absent or empty. A file that
furyctl cannot read gives a read error, and not a name in that list. The
message for an incomplete folder tells the user to delete the folder,
and that step destroys the CA of a cluster that exists.

The check is a separate function, and not a rule of config.Validate,
because 6 more commands call config.Validate and read no local PKI.
`furyctl create config` writes a configuration whose PKI folder cannot
exist yet, and it deletes the file when validation fails.

`furyctl apply` skips the check when the selected phases read no local
PKI. As a result, an apply of the distribution or the plugins phase
alone does not ask for the CA keys. A dry run also skips the check, with
a warning, because it stops before Ansible.

The path resolution repeats what the template mapper does with the same
value before it renders the playbooks. First it expands the dynamic
values, for example "{env://PKI_DIR}" and "{path://pki}". Then it
resolves a relative path against the folder of the configuration file. A
relative path without a "./" prefix is an error, because the mapper does
not make such a value absolute.

The result is always absolute, because `furyctl validate config` does
not make the path of the configuration file absolute. A relative path in
a message is correct in one working folder only.
@ralgozino ralgozino self-assigned this Aug 5, 2026
@ralgozino
ralgozino marked this pull request as ready for review August 5, 2026 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

immutable: pki folder not validated

1 participant