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
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
97 changes: 83 additions & 14 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,26 @@ 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

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
**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

## 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 +42,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
# enable the script to be executed
chmod +x ./run_tests.sh
# Configure your .env file first
source .env

# load the environment variables
# Run the tests
./run_tests.sh
```

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

### Using minikube

```bash
export USE_MINIKUBE=true
source .env
./run_tests.sh
```

### 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
```
60 changes: 39 additions & 21 deletions e2e/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,17 @@
## ===========================================================================


IMAGE_REPO="keyfactor"
IMAGE_NAME="command-cert-manager-issuer"
# IMAGE_TAG="2.2.0-rc.9" # Uncomment if you want to use an existing image from the repository
IMAGE_TAG="local" # Uncomment if you want to build the image locally
# Image configuration - can be overridden via environment variables
# Set IMAGE_TAG=local to build locally, or use a published version (default: 2.5.0)
IMAGE_REPO="${IMAGE_REPO:-keyfactor}"
IMAGE_NAME="${IMAGE_NAME:-command-cert-manager-issuer}"
IMAGE_TAG="${IMAGE_TAG:-2.5.0}"
FULL_IMAGE_NAME="${IMAGE_REPO}/${IMAGE_NAME}:${IMAGE_TAG}"

# Helm chart configuration - can be overridden via environment variables
# Set HELM_CHART_VERSION=local to use the local chart, or use a published version (default: 2.5.0)
HELM_CHART_NAME="command-cert-manager-issuer"
# HELM_CHART_VERSION="2.1.0" # Uncomment if you want to use a specific version from the Helm repository
HELM_CHART_VERSION="local" # Uncomment if you want to use the local Helm chart
HELM_CHART_VERSION="${HELM_CHART_VERSION:-2.5.0}"

IS_LOCAL_DEPLOYMENT=$([ "$IMAGE_TAG" = "local" ] && echo "true" || echo "false")
IS_LOCAL_HELM=$([ "$HELM_CHART_VERSION" = "local" ] && echo "true" || echo "false")
Expand All @@ -58,11 +60,11 @@ ISSUER_CR_NAME="issuer"
ISSUER_CRD_FQTN="issuers.command-issuer.keyfactor.com"
CLUSTER_ISSUER_CRD_FQTN="clusterissuers.command-issuer.keyfactor.com"

ENROLLMENT_PATTERN_ID=1
ENROLLMENT_PATTERN_NAME="Test Enrollment Pattern"
ENROLLMENT_PATTERN_ID=${E2E_ENROLLMENT_PATTERN_ID:-1}
ENROLLMENT_PATTERN_NAME="${E2E_ENROLLMENT_PATTERN_NAME:-Default Pattern}"

OWNER_ROLE_ID=2
OWNER_ROLE_NAME="InstanceOwner"
OWNER_ROLE_ID=${E2E_OWNER_ROLE_ID:-2}
OWNER_ROLE_NAME="${E2E_OWNER_ROLE_NAME:-InstanceOwner}"

CHART_PATH="./deploy/charts/command-cert-manager-issuer"

Expand Down Expand Up @@ -854,18 +856,20 @@ cd ..
echo "⚙️ Local image deployment: ${IS_LOCAL_DEPLOYMENT}"
echo "⚙️ Local Helm chart: ${IS_LOCAL_HELM}"

if ! minikube status &> /dev/null; then
echo "Error: Minikube is not running. Please start it with 'minikube start'"
exit 1
# Use existing kubeconfig context (set USE_MINIKUBE=true to use minikube)
if [ "${USE_MINIKUBE:-false}" = "true" ]; then
if ! minikube status &> /dev/null; then
echo "Error: Minikube is not running. Please start it with 'minikube start'"
exit 1
fi
kubectl config use-context minikube
echo "📡 Connecting to Minikube Docker environment..."
eval $(minikube docker-env)
else
echo "📡 Using current kubeconfig context..."
fi

kubectl config use-context minikube
echo "Connected to Kubernetes context: $(kubectl config current-context)..."

# 1. Connect to minikube Docker env
echo "📡 Connecting to Minikube Docker environment..."
eval $(minikube docker-env)
echo "🚀 Starting deployment to Minikube..."
echo "🚀 Starting deployment..."

# 2. Deploy cert-manager Helm chart if not exists
echo "🔐 Checking for cert-manager installation..."
Expand All @@ -883,11 +887,25 @@ kubectl create namespace ${MANAGER_NAMESPACE} --dry-run=client -o yaml | kubectl

# 4. Build the command-cert-manager-issuer Docker image
# This step is only needed if the image tag is "local"
if "$IS_LOCAL_DEPLOYMENT" = "true"; then
if [ "$IS_LOCAL_DEPLOYMENT" = "true" ]; then
if [ "${USE_MINIKUBE:-false}" != "true" ]; then
echo "⚠️ WARNING: Local deployment without minikube requires pushing the image to a registry."
echo "⚠️ Set IMAGE_REGISTRY env var to push, or use a published IMAGE_TAG instead."
fi
echo "🐳 Building ${FULL_IMAGE_NAME} Docker image..."
docker build -t ${FULL_IMAGE_NAME} .
echo "✅ Docker image built successfully"

# If IMAGE_REGISTRY is set, push the image
if [ -n "${IMAGE_REGISTRY:-}" ]; then
REMOTE_IMAGE="${IMAGE_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
echo "📤 Tagging and pushing image to ${REMOTE_IMAGE}..."
docker tag ${FULL_IMAGE_NAME} ${REMOTE_IMAGE}
docker push ${REMOTE_IMAGE}
FULL_IMAGE_NAME="${REMOTE_IMAGE}"
echo "✅ Image pushed successfully"
fi

echo "📦 Listing Docker images..."
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.CreatedAt}}\t{{.Size}}" | head -5
fi
Expand Down
Loading
Loading