Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 0 additions & 42 deletions .github/workflows/keyfactor-bootstrap-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,8 @@ on:
- 'release-*.*'

jobs:

build:
name: Build and Check CRDs
runs-on: ubuntu-latest
timeout-minutes: 8
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4.2.1
with:
go-version-file: 'go.mod'
cache: true
- run: go mod download
- run: go build -v ./cmd/main.go
- name: Regenerate CRDs
run: make generate manifests
- name: Check for CRD drift
run: |
git diff --compact-summary --exit-code || \
(echo; echo "Unexpected difference in directories after code generation. Run 'make generate manifests' and commit."; exit 1)
# - name: Run linters
# uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # v3.4.0
# with:
# version: latest

test:
name: Go Test
needs: build
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go 1.x
uses: actions/setup-go@v4.2.1
with:
go-version-file: 'go.mod'
cache: true
- run: go mod download
- name: Run go test
run: go test -v ./...

call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@3.2.0
needs: test
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
Expand Down
62 changes: 62 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Build and Test
on:
pull_request:
push:
branches:
- 'main'
- 'release-*.*'
jobs:
build:
name: Build and Lint
runs-on: ubuntu-latest
timeout-minutes: 8
steps:
# Checkout code
# https://github.com/actions/checkout
- name: Checkout code
uses: actions/checkout@v5

# Setup GoLang build environment
# https://github.com/actions/setup-go
- name: Set up Go 1.x
uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
cache: true

# Download dependencies
- run: go mod download

# Build Go binary
- run: go build -v cmd/main.go

- name: Regenerate CRDs
run: make generate manifests

- name: Check for CRD drift
run: |
git diff --compact-summary --exit-code || \
(echo; echo "Unexpected difference in directories after code generation. Run 'make generate manifests' and commit."; exit 1)

test:
name: Go Test
needs: build
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
# Checkout code
# https://github.com/actions/checkout
- name: Checkout code
uses: actions/checkout@v5

# Setup GoLang build environment
# https://github.com/actions/setup-go
- name: Set up Go 1.x
uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
cache: true

# Run Go tests
- name: Run go test
run: go test -v ./...
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v2.5.1
## Fixes
- Fixes an issue where OAuth 2.0 client credentials were being regenerated on every API call.

# v2.5.0
## Features
- Add support to specify a ConfigMap for CA trust bundles in Issuer / ClusterIssuer resources via the `caBundleConfigMapName` specification.
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum


# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ vet: ## Run go vet against code.
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

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

.PHONY: lint
Expand Down
13 changes: 9 additions & 4 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,18 +196,23 @@ func main() {
os.Exit(1)
}

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

// Create a shared client cache to avoid re-authenticating (fetching new OAuth tokens)
// for every certificate request. Clients are cached by configuration hash.
clientCache := command.NewClientCache()
setupLog.Info("initialized Command client cache for OAuth token reuse")

if err = (&controller.IssuerReconciler{
Client: mgr.GetClient(),
Kind: "Issuer",
ClusterResourceNamespace: clusterResourceNamespace,
SecretAccessGrantedAtClusterLevel: secretAccessGrantedAtClusterLevel,
Scheme: mgr.GetScheme(),
HealthCheckerBuilder: command.NewHealthChecker,
HealthCheckerBuilder: clientCache.GetOrCreateHealthChecker,
DefaultHealthCheckInterval: defaultHealthCheckInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Issuer")
Expand All @@ -219,7 +224,7 @@ func main() {
Kind: "ClusterIssuer",
ClusterResourceNamespace: clusterResourceNamespace,
SecretAccessGrantedAtClusterLevel: secretAccessGrantedAtClusterLevel,
HealthCheckerBuilder: command.NewHealthChecker,
HealthCheckerBuilder: clientCache.GetOrCreateHealthChecker,
DefaultHealthCheckInterval: defaultHealthCheckInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ClusterIssuer")
Expand All @@ -229,7 +234,7 @@ func main() {
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
ClusterResourceNamespace: clusterResourceNamespace,
SignerBuilder: command.NewSignerBuilder,
SignerBuilder: clientCache.GetOrCreateSigner,
CheckApprovedCondition: !disableApprovedCheck,
SecretAccessGrantedAtClusterLevel: secretAccessGrantedAtClusterLevel,
Clock: clock.RealClock{},
Expand Down
1 change: 1 addition & 0 deletions e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.env
certs/*
!**/.gitkeep
95 changes: 84 additions & 11 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,30 @@ The test suite does the following:
This is currently configured as a Bash script, so it is necessary to run this on a UNIX-compatible machine.

## Requirements
- An available Command instance is running and configured as described in the [root README](../README.md#configuring-command)
- OAuth is used to communicate with Command

**Local tools:**
- Docker (>= 28.2.2)
- Minikube (>= v1.35.0)
- kubectl (>= v1.32.2)
- helm (>= v3.17.1)
- cmctl (>= v2.1.1)
- Minikube (>= v1.35.0) - only required if using `USE_MINIKUBE=true`

**Kubernetes cluster:**
- By default, tests run against your current kubeconfig context
- Set `USE_MINIKUBE=true` to use minikube instead

**Command instance:**
- An available Command instance configured as described in the [root README](../README.md#configuring-command)
- OAuth credentials for API access
- An enrollment pattern (default: "Default Pattern") with CSR Enrollment enabled
- A security role (default: "InstanceOwner") with Enrollment permissions

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

## Configuring the environment variables

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.

A `.env.example` file is available as a template for your environment variables.
Expand All @@ -35,24 +46,86 @@ A `.env.example` file is available as a template for your environment variables.
cp .env.example .env
```

Modify the fields as needed.
### Required variables

| Variable | Description |
|----------|-------------|
| `HOSTNAME` | Command instance hostname |
| `API_PATH` | API path (default: `KeyfactorAPI`) |
| `OAUTH_TOKEN_URL` | OAuth token endpoint URL |
| `OAUTH_CLIENT_ID` | OAuth client ID |
| `OAUTH_CLIENT_SECRET` | OAuth client secret |
| `CERTIFICATE_TEMPLATE` | Certificate template short name |
| `CERTIFICATE_AUTHORITY_LOGICAL_NAME` | CA logical name in Command |

### Optional variables

| Variable | Description | Default |
|----------|-------------|---------|
| `IMAGE_TAG` | Docker image version to test | `2.5.0` |
| `HELM_CHART_VERSION` | Helm chart version | `2.5.0` |
| `E2E_ENROLLMENT_PATTERN_NAME` | Enrollment pattern name | `Default Pattern` |
| `E2E_OWNER_ROLE_NAME` | Owner role name | `InstanceOwner` |
| `DISABLE_CA_CHECK` | Skip TLS CA verification | `false` |
| `USE_MINIKUBE` | Use minikube instead of current kubeconfig | `false` |
| `IMAGE_REGISTRY` | Registry to push local builds (when `IMAGE_TAG=local`) | - |

## Configuring the trusted certificate store

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.

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.
Place the CA certificates for the Keyfactor Command instance you'd like to connect to (the intermediate and/or root CAs) under `certs` directory.

> NOTE: This check can be disabled by setting the env variable `DISABLE_CA_CHECK=true`.

## Running the script
## Running the tests

### Using current kubeconfig context (default)

```bash
# Configure your .env file first
source .env

# Run the tests
./run_tests.sh
```

Or from the project root:
```bash
make test-e2e
```

### Using minikube

```bash
# enable the script to be executed
chmod +x ./run_tests.sh
export USE_MINIKUBE=true
source .env
./run_tests.sh
```

# load the environment variables
### Testing a specific version

```bash
export IMAGE_TAG="2.4.0"
export HELM_CHART_VERSION="2.4.0"
source .env
./run_tests.sh
```

# run the end-to-end tests
### Testing local changes

```bash
# With minikube (image built directly into minikube's docker)
export IMAGE_TAG="local"
export HELM_CHART_VERSION="local"
export USE_MINIKUBE=true
source .env
./run_tests.sh
```

# With a remote cluster (requires pushing to a registry)
export IMAGE_TAG="local"
export HELM_CHART_VERSION="local"
export IMAGE_REGISTRY="your-registry.com/your-repo"
source .env
./run_tests.sh
```
Loading
Loading