Conversation
2.5.0: CA Bundle with ConfigMap + GKE Ambient Credentials Documentation
* feat: release 2.5.0 (#62) 2.5.0: CA Bundle with ConfigMap + GKE Ambient Credentials Documentation Co-authored-by: Matthew H. Irby <irby@users.noreply.github.com> * feat: add client caching to reduce OAuth token requests Previously, every certificate request reconciliation created a new Command API client, which meant a new OAuth token was fetched for each request. For customers with OAuth provider quotas, this caused rate limiting issues. This change introduces a ClientCache that: - Caches Command API clients by configuration hash - Reuses cached clients across reconciliations for the same issuer - Allows the underlying oauth2 library's token caching to work as intended - Is thread-safe for concurrent reconciliations The cache key is a SHA-256 hash of all configuration fields that affect the client connection (hostname, API path, credentials, scopes, etc.), ensuring different issuers get different clients while the same issuer reuses its client. Fixes: OAuth token re-authentication on every request Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(scripts): update scripting usability * feat: update keyfactor-auth-client-go to v1.3.1 Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: remove test short circuit Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Revert "Potential fix for pull request finding" This reverts commit 19bc19b. * chore: cleanup Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: break build & test into its own workflow Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * fix: remove lint from CI Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore(docs): update CHANGELOG Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> --------- Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com> Co-authored-by: Matthew H. Irby <irby@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Automated merge of the release-2.5 line into main, bringing in v2.5.0/v2.5.1 updates including CA bundle enhancements, OAuth client reuse, expanded docs, and updated CI/e2e workflows.
Changes:
- Add CA bundle support via ConfigMap and an optional key selector; update CRDs/docs accordingly.
- Introduce a shared Command client cache to reuse OAuth tokens and reduce re-authentication churn; add Azure token timeout.
- Refresh e2e tooling/docs and replace legacy CI workflow with a new build/test workflow.
Reviewed changes
Copilot reviewed 30 out of 32 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds Helm version install instructions; updates CA bundle and ambient auth docs references. |
| docsource/content.md | Mirrors README documentation updates for publishing. |
| CHANGELOG.md | Documents v2.5.0/v2.5.1 features/fixes. |
| Makefile | Updates test-e2e target to run the e2e script. |
| cmd/main.go | Adds configmap access flag, cache scoping for ConfigMaps, and shared client cache wiring. |
| api/v1alpha1/issuer_types.go | Adds caBundleConfigMapName and caBundleKey to IssuerSpec. |
| internal/controller/issuer_controller.go | Implements ConfigMap CA bundle loading and key selection logic. |
| internal/controller/issuer_controller_test.go | Adds unit tests for commandConfigFromIssuer CA bundle variants. |
| internal/command/client.go | Adds a short timeout for Azure ambient token retrieval. |
| internal/command/client_cache.go | Adds cached signer/healthchecker creation keyed by config hash. |
| internal/command/client_cache_test.go | Adds tests for hash determinism and basic cache operations. |
| deploy/charts/command-cert-manager-issuer/values.yaml | Adds configmap RBAC option and env values passthrough. |
| deploy/charts/command-cert-manager-issuer/templates/deployment.yaml | Plumbs configmap access flag + optional env vars into the manager container. |
| deploy/charts/command-cert-manager-issuer/templates/role.yaml | Adds Role/ClusterRole rules for ConfigMap reads. |
| deploy/charts/command-cert-manager-issuer/templates/rolebinding.yaml | Adds RoleBinding/ClusterRoleBinding for the ConfigMap reader role. |
| deploy/charts/command-cert-manager-issuer/templates/crds/issuers.yaml | Updates chart CRD template schema/descriptions for new CA fields. |
| deploy/charts/command-cert-manager-issuer/templates/crds/clusterissuers.yaml | Updates chart CRD template schema/descriptions for new CA fields. |
| deploy/charts/command-cert-manager-issuer/README.md | Documents the new env Helm value. |
| config/crd/bases/command-issuer.keyfactor.com_issuers.yaml | Updates generated CRD base with new CA fields. |
| config/crd/bases/command-issuer.keyfactor.com_clusterissuers.yaml | Updates generated CRD base with new CA fields. |
| docs/ca-bundle/README.md | Adds detailed CA bundle guidance (including trust-manager examples). |
| docs/ambient-providers/google.md | Adds GKE ambient credential documentation. |
| e2e/run_tests.sh | Improves configurability (current context vs minikube), CA bundle resources, and new CA tests. |
| e2e/README.md | Expands e2e prerequisites/config and adds usage examples. |
| e2e/.env.example | Adds DISABLE_CA_CHECK example. |
| e2e/.gitignore | Ignores .env and local cert material. |
| e2e/certs/.gitkeep | Keeps empty cert directory in git. |
| Dockerfile | Minor whitespace change. |
| go.mod | Bumps keyfactor-auth-client-go to v1.3.1 and adjusts Go directive/toolchain lines. |
| go.sum | Updates module checksums for the bumped dependency. |
| .github/workflows/test.yml | Adds a new Build/Test workflow (build + CRD drift + tests). |
| .github/workflows/keyfactor-bootstrap-workflow.yml | Removes inline build/test jobs and relies on starter workflow call. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if issuer.GetSpec().CaBundleConfigMapName != "" { | ||
| var configMap corev1.ConfigMap | ||
| err := c.Get(ctx, types.NamespacedName{ | ||
| Name: issuer.GetSpec().CaBundleConfigMapName, | ||
| Namespace: secretNamespace, | ||
| }, &configMap) |
There was a problem hiding this comment.
caBundleConfigMapName is fetched from secretNamespace, but the namespace used for CA ConfigMaps can differ from the namespace used for Secrets now that there is a separate --configmap-access-granted-at-cluster-level flag (see cmd/main.go). As written, certain flag combinations can force the controller to look for the ConfigMap in the wrong namespace (and/or outside the manager cache scope), causing false NotFound errors. Consider resolving the ConfigMap namespace independently of the Secret namespace (or pass both namespaces into commandConfigFromIssuer).
| } else { | ||
| // If no caBundleKey is specified, take the last entry in the caData map | ||
| for _, bytes := range caData { | ||
| caCertBytes = bytes | ||
| } | ||
| } |
There was a problem hiding this comment.
The fallback behavior when caBundleKey is omitted selects the “last” entry by iterating over a Go map, which is intentionally randomized. This makes CA bundle selection nondeterministic and also contradicts the CRD/docs text that says the last key alphabetically is used. Sort the keys (or otherwise make selection deterministic) and update/add a unit test that covers multiple-key resources without caBundleKey.
| ```shell | ||
| helm install command-cert-manager-issuer command-issuer/command-cert-manager-issuer \ | ||
| --namespace command-issuer-system \ | ||
| --version 2.4.0 |
There was a problem hiding this comment.
This Helm install example is missing a line-continuation (\) after --version 2.4.0, which will cause --create-namespace to be interpreted as a separate shell command. Add the continuation so the command can be copied/pasted successfully.
| --version 2.4.0 | |
| --version 2.4.0 \ |
| ```shell | ||
| helm install command-cert-manager-issuer command-issuer/command-cert-manager-issuer \ | ||
| --namespace command-issuer-system \ | ||
| --version 2.4.0 |
There was a problem hiding this comment.
This Helm install example is missing a line-continuation (\) after --version 2.4.0, which will cause --create-namespace to be interpreted as a separate shell command. Add the continuation so the command can be copied/pasted successfully.
| --version 2.4.0 | |
| --version 2.4.0 \ |
|
|
||
| ## Using Self-Signed Certificates | ||
|
|
||
| If the targeted Keyfactor Command API is configured to use a self-signed certificate or with a certificate whose issuer isn't widely trusted, the CA certificate **must be provided** via a Kubernetes Secret of ConfigMap. The secret must belong to the same namespace that command-cert-manager-issuer is deployed to (i.e. `command-issuer-system`). |
There was a problem hiding this comment.
Typo/grammar: “via a Kubernetes Secret of ConfigMap” should be “via a Kubernetes Secret or ConfigMap”.
| If the targeted Keyfactor Command API is configured to use a self-signed certificate or with a certificate whose issuer isn't widely trusted, the CA certificate **must be provided** via a Kubernetes Secret of ConfigMap. The secret must belong to the same namespace that command-cert-manager-issuer is deployed to (i.e. `command-issuer-system`). | |
| If the targeted Keyfactor Command API is configured to use a self-signed certificate or with a certificate whose issuer isn't widely trusted, the CA certificate **must be provided** via a Kubernetes Secret or ConfigMap. The secret must belong to the same namespace that command-cert-manager-issuer is deployed to (i.e. `command-issuer-system`). |
| rules: | ||
| - apiGroups: [""] | ||
| resources: ["secrets"] | ||
| verbs: ["create", "update", "patch", "delete", "read"] |
There was a problem hiding this comment.
The RBAC example uses verbs: ["create", "update", "patch", "delete", "read"], but read is not a valid Kubernetes RBAC verb. Replace it with the appropriate verbs (typically get, list, watch and/or create/update/patch/delete as needed) so the manifest can be applied as-is.
| verbs: ["create", "update", "patch", "delete", "read"] | |
| verbs: ["create", "update", "patch", "delete", "get", "list", "watch"] |
| | `IMAGE_TAG` | Docker image version to test | `2.5.0` | | ||
| | `HELM_CHART_VERSION` | Helm chart version | `2.5.0` | |
There was a problem hiding this comment.
The “Default” column for IMAGE_TAG / HELM_CHART_VERSION says 2.5.0, but run_tests.sh defaults both to local (IMAGE_TAG and HELM_CHART_VERSION are set via ${...:-local}). Either update this table to match the script defaults or change the script defaults to match the documentation.
| | `IMAGE_TAG` | Docker image version to test | `2.5.0` | | |
| | `HELM_CHART_VERSION` | Helm chart version | `2.5.0` | | |
| | `IMAGE_TAG` | Docker image version to test | `local` | | |
| | `HELM_CHART_VERSION` | Helm chart version | `local` | |
| type ClientCache struct { | ||
| mu sync.RWMutex | ||
| clients map[string]*cachedClient | ||
| } |
There was a problem hiding this comment.
ClientCache can grow without bound: the cache key includes credentials/CA bytes (so routine secret rotations will create new entries), but the cache is never invalidated in normal controller operation. Consider adding a bounded eviction strategy (LRU/TTL), or wiring Invalidate calls to Secret/ConfigMap change events, to prevent unbounded memory growth over time.
Merge release-2.5 to main - Automated PR