Skip to content

Commit 3dcb8de

Browse files
indrorairbyspbsolubleclaudeCopilot
authored
Merge 2.5.1 to main (#65)
* feat: release 2.5.0 2.5.0: CA Bundle with ConfigMap + GKE Ambient Credentials Documentation * release: 2.5.1 * 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> --------- Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Matthew H. Irby <irby@users.noreply.github.com> Co-authored-by: spb <1661003+spbsoluble@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>
1 parent 3340f53 commit 3dcb8de

13 files changed

Lines changed: 594 additions & 87 deletions

File tree

.github/workflows/keyfactor-bootstrap-workflow.yml

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,8 @@ on:
1010
- 'release-*.*'
1111

1212
jobs:
13-
14-
build:
15-
name: Build and Check CRDs
16-
runs-on: ubuntu-latest
17-
timeout-minutes: 8
18-
steps:
19-
- uses: actions/checkout@v4
20-
- uses: actions/setup-go@v4.2.1
21-
with:
22-
go-version-file: 'go.mod'
23-
cache: true
24-
- run: go mod download
25-
- run: go build -v ./cmd/main.go
26-
- name: Regenerate CRDs
27-
run: make generate manifests
28-
- name: Check for CRD drift
29-
run: |
30-
git diff --compact-summary --exit-code || \
31-
(echo; echo "Unexpected difference in directories after code generation. Run 'make generate manifests' and commit."; exit 1)
32-
# - name: Run linters
33-
# uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # v3.4.0
34-
# with:
35-
# version: latest
36-
37-
test:
38-
name: Go Test
39-
needs: build
40-
runs-on: ubuntu-latest
41-
timeout-minutes: 5
42-
steps:
43-
- name: Checkout
44-
uses: actions/checkout@v4
45-
- name: Set up Go 1.x
46-
uses: actions/setup-go@v4.2.1
47-
with:
48-
go-version-file: 'go.mod'
49-
cache: true
50-
- run: go mod download
51-
- name: Run go test
52-
run: go test -v ./...
53-
5413
call-starter-workflow:
5514
uses: keyfactor/actions/.github/workflows/starter.yml@3.2.0
56-
needs: test
5715
secrets:
5816
token: ${{ secrets.V2BUILDTOKEN}}
5917
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}

.github/workflows/test.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Build and Test
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- 'main'
7+
- 'release-*.*'
8+
jobs:
9+
build:
10+
name: Build and Lint
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 8
13+
steps:
14+
# Checkout code
15+
# https://github.com/actions/checkout
16+
- name: Checkout code
17+
uses: actions/checkout@v5
18+
19+
# Setup GoLang build environment
20+
# https://github.com/actions/setup-go
21+
- name: Set up Go 1.x
22+
uses: actions/setup-go@v6
23+
with:
24+
go-version-file: 'go.mod'
25+
cache: true
26+
27+
# Download dependencies
28+
- run: go mod download
29+
30+
# Build Go binary
31+
- run: go build -v cmd/main.go
32+
33+
- name: Regenerate CRDs
34+
run: make generate manifests
35+
36+
- name: Check for CRD drift
37+
run: |
38+
git diff --compact-summary --exit-code || \
39+
(echo; echo "Unexpected difference in directories after code generation. Run 'make generate manifests' and commit."; exit 1)
40+
41+
test:
42+
name: Go Test
43+
needs: build
44+
runs-on: ubuntu-latest
45+
timeout-minutes: 15
46+
steps:
47+
# Checkout code
48+
# https://github.com/actions/checkout
49+
- name: Checkout code
50+
uses: actions/checkout@v5
51+
52+
# Setup GoLang build environment
53+
# https://github.com/actions/setup-go
54+
- name: Set up Go 1.x
55+
uses: actions/setup-go@v6
56+
with:
57+
go-version-file: 'go.mod'
58+
cache: true
59+
60+
# Run Go tests
61+
- name: Run go test
62+
run: go test -v ./...

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v2.5.1
2+
## Fixes
3+
- Fixes an issue where OAuth 2.0 client credentials were being regenerated on every API call.
4+
15
# v2.5.0
26
## Features
37
- Add support to specify a ConfigMap for CA trust bundles in Issuer / ClusterIssuer resources via the `caBundleConfigMapName` specification.

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ WORKDIR /workspace
77
# Copy the Go Modules manifests
88
COPY go.mod go.mod
99
COPY go.sum go.sum
10+
11+
1012
# cache deps before building and copying source so that we don't need to re-download as much
1113
# and so that source changes don't invalidate our downloaded layer
1214
RUN go mod download

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ vet: ## Run go vet against code.
6464
test: manifests generate fmt vet envtest ## Run tests.
6565
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
6666

67-
# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
68-
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
69-
test-e2e:
67+
# Run e2e tests against the current kubeconfig context (set USE_MINIKUBE=true to use minikube instead)
68+
# Configure e2e/.env with Command instance credentials before running
69+
.PHONY: test-e2e
70+
test-e2e: ## Run e2e tests against a Kubernetes cluster
7071
cd e2e && source .env && ./run_tests.sh
7172

7273
.PHONY: lint

cmd/main.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,18 +196,23 @@ func main() {
196196
os.Exit(1)
197197
}
198198

199-
if defaultHealthCheckInterval < time.Duration(30) * time.Second {
199+
if defaultHealthCheckInterval < time.Duration(30)*time.Second {
200200
setupLog.Error(errors.New(fmt.Sprintf("interval %s is invalid, must be greater than or equal to '30s'", healthCheckInterval)), "invalid health check interval")
201201
os.Exit(1)
202202
}
203203

204+
// Create a shared client cache to avoid re-authenticating (fetching new OAuth tokens)
205+
// for every certificate request. Clients are cached by configuration hash.
206+
clientCache := command.NewClientCache()
207+
setupLog.Info("initialized Command client cache for OAuth token reuse")
208+
204209
if err = (&controller.IssuerReconciler{
205210
Client: mgr.GetClient(),
206211
Kind: "Issuer",
207212
ClusterResourceNamespace: clusterResourceNamespace,
208213
SecretAccessGrantedAtClusterLevel: secretAccessGrantedAtClusterLevel,
209214
Scheme: mgr.GetScheme(),
210-
HealthCheckerBuilder: command.NewHealthChecker,
215+
HealthCheckerBuilder: clientCache.GetOrCreateHealthChecker,
211216
DefaultHealthCheckInterval: defaultHealthCheckInterval,
212217
}).SetupWithManager(mgr); err != nil {
213218
setupLog.Error(err, "unable to create controller", "controller", "Issuer")
@@ -219,7 +224,7 @@ func main() {
219224
Kind: "ClusterIssuer",
220225
ClusterResourceNamespace: clusterResourceNamespace,
221226
SecretAccessGrantedAtClusterLevel: secretAccessGrantedAtClusterLevel,
222-
HealthCheckerBuilder: command.NewHealthChecker,
227+
HealthCheckerBuilder: clientCache.GetOrCreateHealthChecker,
223228
DefaultHealthCheckInterval: defaultHealthCheckInterval,
224229
}).SetupWithManager(mgr); err != nil {
225230
setupLog.Error(err, "unable to create controller", "controller", "ClusterIssuer")
@@ -229,7 +234,7 @@ func main() {
229234
Client: mgr.GetClient(),
230235
Scheme: mgr.GetScheme(),
231236
ClusterResourceNamespace: clusterResourceNamespace,
232-
SignerBuilder: command.NewSignerBuilder,
237+
SignerBuilder: clientCache.GetOrCreateSigner,
233238
CheckApprovedCondition: !disableApprovedCheck,
234239
SecretAccessGrantedAtClusterLevel: secretAccessGrantedAtClusterLevel,
235240
Clock: clock.RealClock{},

e2e/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
.env
12
certs/*
23
!**/.gitkeep

e2e/README.md

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,34 @@ The test suite does the following:
1313
This is currently configured as a Bash script, so it is necessary to run this on a UNIX-compatible machine.
1414

1515
## Requirements
16-
- An available Command instance is running and configured as described in the [root README](../README.md#configuring-command)
17-
- OAuth is used to communicate with Command
16+
17+
**Local tools:**
1818
- Docker (>= 28.2.2)
19-
- Minikube (>= v1.35.0)
2019
- kubectl (>= v1.32.2)
2120
- helm (>= v3.17.1)
2221
- cmctl (>= v2.1.1)
22+
- Minikube (>= v1.35.0) - only required if using `USE_MINIKUBE=true`
23+
24+
**Kubernetes cluster:**
25+
- By default, tests run against your current kubeconfig context
26+
- Set `USE_MINIKUBE=true` to use minikube instead
27+
28+
**Command instance:**
29+
- An available Command instance configured as described in the [root README](../README.md#configuring-command)
30+
- OAuth credentials for API access
31+
- An enrollment pattern (default: "Default Pattern") with CSR Enrollment enabled
32+
- A security role (default: "InstanceOwner") with Enrollment permissions
33+
34+
On the Command side:
35+
- An enrollment pattern is created called "Test Enrollment Pattern" that is has CSR Enrollment, CSR Generation, and PFX Enrollment enabled
36+
- A security role by the name of "InstanceOwner" exists and has the ability to perform Enrollment
2337

2438
On the Command side:
2539
- An enrollment pattern is created called "Test Enrollment Pattern" that is has CSR Enrollment, CSR Generation, and PFX Enrollment enabled
2640
- A security role by the name of "InstanceOwner" exists and has the ability to perform Enrollment
2741

2842
## Configuring the environment variables
43+
2944
command-cert-manager-issuer interacts with an external Command instance. An environment variable file `.env` can be used to store the environment variables to be used to talk to the Command instance.
3045

3146
A `.env.example` file is available as a template for your environment variables.
@@ -35,24 +50,86 @@ A `.env.example` file is available as a template for your environment variables.
3550
cp .env.example .env
3651
```
3752

38-
Modify the fields as needed.
53+
### Required variables
54+
55+
| Variable | Description |
56+
|----------|-------------|
57+
| `HOSTNAME` | Command instance hostname |
58+
| `API_PATH` | API path (default: `KeyfactorAPI`) |
59+
| `OAUTH_TOKEN_URL` | OAuth token endpoint URL |
60+
| `OAUTH_CLIENT_ID` | OAuth client ID |
61+
| `OAUTH_CLIENT_SECRET` | OAuth client secret |
62+
| `CERTIFICATE_TEMPLATE` | Certificate template short name |
63+
| `CERTIFICATE_AUTHORITY_LOGICAL_NAME` | CA logical name in Command |
64+
65+
### Optional variables
66+
67+
| Variable | Description | Default |
68+
|----------|-------------|---------|
69+
| `IMAGE_TAG` | Docker image version to test | `2.5.0` |
70+
| `HELM_CHART_VERSION` | Helm chart version | `2.5.0` |
71+
| `E2E_ENROLLMENT_PATTERN_NAME` | Enrollment pattern name | `Default Pattern` |
72+
| `E2E_OWNER_ROLE_NAME` | Owner role name | `InstanceOwner` |
73+
| `DISABLE_CA_CHECK` | Skip TLS CA verification | `false` |
74+
| `USE_MINIKUBE` | Use minikube instead of current kubeconfig | `false` |
75+
| `IMAGE_REGISTRY` | Registry to push local builds (when `IMAGE_TAG=local`) | - |
3976

4077
## Configuring the trusted certificate store
78+
4179
The issuer created in the end-to-end tests can leverage the `caSecretName` specification to determine a collection of CAs to trust in order to establish a trusted connection with the remote Keyfactor Command instance. The certificates defined in this secret will be pulled from the `certs` folder in this directory.
4280

43-
Please place the CA certificates for the Keyfactor Command instance you'd like to connect to (the intermediate and/or root CAs) under `certs` directory.
81+
Place the CA certificates for the Keyfactor Command instance you'd like to connect to (the intermediate and/or root CAs) under `certs` directory.
4482

4583
> NOTE: This check can be disabled by setting the env variable `DISABLE_CA_CHECK=true`.
4684
47-
## Running the script
85+
## Running the tests
86+
87+
### Using current kubeconfig context (default)
88+
89+
```bash
90+
# Configure your .env file first
91+
source .env
92+
93+
# Run the tests
94+
./run_tests.sh
95+
```
96+
97+
Or from the project root:
98+
```bash
99+
make test-e2e
100+
```
101+
102+
### Using minikube
48103

49104
```bash
50-
# enable the script to be executed
51-
chmod +x ./run_tests.sh
105+
export USE_MINIKUBE=true
106+
source .env
107+
./run_tests.sh
108+
```
109+
110+
### Testing a specific version
52111

53-
# load the environment variables
112+
```bash
113+
export IMAGE_TAG="2.4.0"
114+
export HELM_CHART_VERSION="2.4.0"
54115
source .env
116+
./run_tests.sh
117+
```
118+
119+
### Testing local changes
120+
121+
```bash
122+
# With minikube (image built directly into minikube's docker)
123+
export IMAGE_TAG="local"
124+
export HELM_CHART_VERSION="local"
125+
export USE_MINIKUBE=true
126+
source .env
127+
./run_tests.sh
55128

56-
# run the end-to-end tests
129+
# With a remote cluster (requires pushing to a registry)
130+
export IMAGE_TAG="local"
131+
export HELM_CHART_VERSION="local"
132+
export IMAGE_REGISTRY="your-registry.com/your-repo"
133+
source .env
57134
./run_tests.sh
58-
```
135+
```

0 commit comments

Comments
 (0)