Skip to content

test(e2e): prove cert-manager gets a CryptOS certificate over ACME in kind - #294

Merged
Bugs5382 merged 1 commit into
mainfrom
test/293-kind-acme-cert-manager
Sep 30, 2026
Merged

Bugs5382 merged 1 commit into
mainfrom
test/293-kind-acme-cert-manager

Conversation

@Bugs5382

Copy link
Copy Markdown
Contributor

What and why

Nothing in CI showed that a real Kubernetes client can get a certificate from CryptOS over ACME. This adds a kind job that does exactly that.

  • Node side: the in-process e2e harness builds a Root and an Intermediate it signs (software key backend, embedded etcd, no TPM, no OS image). The Intermediate's machine config carries a pki.acme block with an External Account Binding key and goes through config.Parse. The handler is built by cinit.NewACMEHandler, the same function the boot now calls, with the real HTTP01Validator and the production issued-set recorder. A small TLS front on the kind bridge address proxies to the plain-HTTP ACME origin, the deployment docs/acme.md describes. Its certificate is issued by the Intermediate, so the cluster trusts it through the root it gets as caBundle.
  • Cluster side: kind with cert-manager, Contour (Envoy on hostPort 80/443) and traefik/whoami. A ClusterIssuer points at the node with EAB and an http-01 solver through Contour. A Certificate asks for an ECDSA P-384 key.
  • Assertions: the Certificate goes Ready; tls.crt verifies to the CryptOS root for the name; the SANs are exactly that name; tls.key matches the leaf; the serial is in the node's issued set under the ACME profile with the same DER; the ingress serves that serial over HTTPS. A forced renewal (Issuing=True on the status, which is what cmctl renew does) gives a new serial, and the same checks run again.
  • Name resolution, no bypass: the node's http-01 fetch resolves the test name through /etc/hosts (one line, added and removed by the script) to 127.0.0.1:80, which kind maps to Envoy. cert-manager's in-cluster self-check resolves it through a CoreDNS hosts entry pointing at Envoy's service. The validator and port 80 are untouched.
  • Production code: the only change is a refactor with no behaviour change. The ACME handler construction moves out of boot into NewACMEHandler, which returns the same errors and uses the same validator, and issuedRecorder is exported as IssuedRecorder. The two renamed call sites in internal/init tests are mechanical.
  • Running it: task e2e:kind (Linux with docker) runs test/kind/run.sh. It skips with a message on non-Linux, without docker, or when the pinned kind can't be downloaded. The Go test skips unless the script sets CRYPTOS_E2E_KIND=1, so task test is unaffected.
  • CI: ci-kind-acme.yml runs on pull requests only, touching internal/acme, internal/config, internal/node, internal/e2e, internal/init/acme.go, test/kind or the workflow itself. It skips drafts, has a 25-minute timeout, runs on ubuntu-latest and is not a required check.
  • Pins (test/kind/versions.env): kind v0.33.0 and kubectl v1.37.0 by SHA-256 (amd64 and arm64), kindest/node:v1.37.0 by digest, cert-manager v1.21.2 and Contour v1.33.7 manifests by SHA-256, and traefik/whoami:v1.12.0 by digest.

Design calls:

Closes #293

No docs change on the docs site in this PR. Once this merges, a short "Tested in CI with kind and cert-manager" note goes on the Kubernetes use-case page (CryptOS-PKI/docs#31). The repo README lists the new task and workflow.

Verification

  • Lint clean (golangci-lint v2.12.2, go vet, gofmt, actionlint, shellcheck)
  • Tests pass (full go test ./...)
  • Build succeeds
  • Documentation updated (README: layout, task e2e:kind, the CI list)

How this was verified

  • go test ./... passes locally, including internal/init after the refactor.
  • The node side was run locally against a stock golang.org/x/crypto/acme client with EAB and a real http-01 responder on port 80. The directory, account, order, challenge, finalize and download all went through the TLS front, the chain verified to the root, and the serial was in the issued set.
  • The full kind run is this PR's ci-kind-acme job.

… kind

Stand up a Root and an ACME-serving Intermediate in-process with the e2e
harness (software keys, embedded etcd, no TPM) and let cert-manager in a
kind cluster enrol against it with an External Account Binding and an
http-01 solver behind Contour. The test checks that the Certificate goes
Ready, the chain verifies to the CryptOS root, the SANs are the requested
name, the node recorded the serial, the ingress serves it, and a forced
renewal yields a new, recorded serial.

The handler the test drives is the one the boot serves: the ACME wiring in
the boot moves into cinit.NewACMEHandler, and the issued-set recorder is
exported as cinit.IssuedRecorder, with no change in behaviour.

task e2e:kind runs it on a Linux host with docker and skips without one.
The ci-kind-acme workflow runs it on pull requests that touch the ACME
path. kind, kubectl, the node image, cert-manager, Contour and the test
app are pinned by checksum or digest in test/kind/versions.env.

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
@Bugs5382 Bugs5382 added this to the v1.0.0 milestone Sep 30, 2026
@Bugs5382 Bugs5382 added the skip-changelog Excluded from release notes (chore/ci/test/style). label Sep 30, 2026
@Bugs5382 Bugs5382 self-assigned this Sep 30, 2026
@Bugs5382
Bugs5382 marked this pull request as ready for review September 30, 2026 09:57
Bugs5382 added a commit to CryptOS-PKI/docs that referenced this pull request Sep 30, 2026
Add a note to the Kubernetes page that every cryptos pull request touching
the ACME code runs cert-manager in a kind cluster against an intermediate,
what that test checks, and that the node there runs from the code with
software keys rather than from the OS image.

Depends on CryptOS-PKI/cryptos-node#294 and should merge after it.

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
@Bugs5382

Copy link
Copy Markdown
Contributor Author

Closing summary: a CI job proves a real Kubernetes client gets a real CryptOS certificate over ACME: the e2e harness runs a Root and an Intermediate with the production ACME handler, and cert-manager in a pinned kind cluster issues and renews a P-384 certificate that chains to the root and shows in the node's issued set. Runs on PRs touching ACME, and locally as task e2e:kind. Closes #293.

@Bugs5382
Bugs5382 merged commit b85e647 into main Sep 30, 2026
@Bugs5382
Bugs5382 deleted the test/293-kind-acme-cert-manager branch September 30, 2026 10:05
Bugs5382 added a commit to CryptOS-PKI/docs that referenced this pull request Sep 30, 2026
Add a note to the Kubernetes page that every cryptos pull request touching
the ACME code runs cert-manager in a kind cluster against an intermediate,
what that test checks, and that the node there runs from the code with
software keys rather than from the OS image.

Depends on CryptOS-PKI/cryptos-node#294 and should merge after it.

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Excluded from release notes (chore/ci/test/style).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(e2e): prove cert-manager gets a CryptOS certificate over ACME in a kind cluster

1 participant