Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9a7f129
chore: Add documentation for Google ambient credentials
irby Nov 6, 2025
35e4870
feat: add timeout to getting azure default credentials
irby Nov 6, 2025
30047c6
Update generated docs
Nov 6, 2025
978d0e8
chore: update docs and attach parent context to timeout
irby Dec 15, 2025
3ad8cfe
chore(ci): update GH Actions to leverage latest starter workflow
irby Jan 15, 2026
5435700
feat(e2e): update e2e tests to use the caSecretName spec field
irby Jan 15, 2026
867284f
chore(docs): add docs around trust-manager
irby Jan 15, 2026
60c078b
chore(docs): improve ca-bundle documentation for trust-manager
irby Jan 16, 2026
24adc37
Update generated docs
Jan 16, 2026
994c8fd
chore: re-run Make generate to regenerate templates
irby Jan 20, 2026
92f9d23
chore(tests): update e2e test documentation
irby Jan 20, 2026
9651164
chore(tests): add unit tests around method to generate command config
irby Jan 20, 2026
d9e2ff3
feat(issuer): add configmap spec for ca bundle
irby Jan 20, 2026
35d1481
feat(issuer): add caConfigMap and caBundleKey to deployment chart
irby Jan 20, 2026
088cc34
feat(e2e): add test cases for ClusterIsusers handling CA certs. Fix i…
irby Jan 21, 2026
837328c
chore(docs): add updated documentation for configmaps in trust-manage…
irby Jan 21, 2026
fa59b4e
chore(ci): revert bootstrap workflow upgrade
irby Jan 21, 2026
328de03
Update generated docs
Jan 21, 2026
5439906
chore: update e2e tests to have better handling of testing cert -> is…
irby Jan 21, 2026
bdf80f5
feat: add health check interval to issuer spec
irby Oct 24, 2025
d43f635
chore: update docs
irby Oct 24, 2025
cba82d0
feat: implement health check logic
irby Oct 24, 2025
075be33
feat(actions): Ensure that CRDs are not out of date
irby Oct 24, 2025
482917a
Update generated docs
Oct 24, 2025
2b0cbaf
chore(docs): update changelog version number
irby Oct 24, 2025
7fef163
chore: Convert to healthcheck block instead of healthCheckIntervalSec…
irby Oct 27, 2025
519c8a4
Update generated docs
Oct 27, 2025
b7de2e3
chore: Change the specificaiton update to 2.4
irby Oct 27, 2025
aec2b8a
Add the ability to specify the default issuer timeout across all issu…
JSpon Nov 3, 2025
7452292
chore: address copilot feedback
irby Nov 11, 2025
2a89658
chore: fix autogenerated CRDs
irby Nov 11, 2025
6ffbe63
Update generated docs
Nov 11, 2025
d8215c1
chore: address github copilot feedback
irby Nov 11, 2025
a5f0e29
fix: resolve issue with default health check interval override
irby Nov 11, 2025
5491e16
Update cmd/main.go
irby Nov 11, 2025
15264a4
chore: fix some typos and serialization per recommendations
irby Nov 12, 2025
840879c
Update generated docs
Jan 21, 2026
459847f
Merge branch 'main' into feat/AB#75464/ca-bundle-ambient-credential-u…
irby Jan 21, 2026
fa32ffa
chore(CHANGELOG): add 2.5.0 changelog
irby Jan 21, 2026
1baab03
chore(tests): update key for objects to add to unit tests
irby Jan 21, 2026
b1bb554
Update generated docs
Jan 21, 2026
25ac002
chore: address copilot recommendations
irby Jan 21, 2026
98a01f7
Add environmental variables to deployment for use with proxy configur…
JSpon Sep 30, 2025
ae2b3e8
chore(CHANGELOG): add env variable support to changelog
irby Jan 21, 2026
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# v2.5.0
## Features
- Add support to specify a ConfigMap for CA trust bundles in Issuer / ClusterIssuer resources via the `caBundleConfigMapName` specification.
- Add support for specifying a key on a Secret / ConfigMap resource for the CA trust bundle via the `caBundleKey` specification on an Issuer / ClusterIssuer resource.
- Add a timeout when fetching ambient Azure credentials to move onto other ambient credential methods.
- Ability to specify environment variables on issuer deployment to set additional configuration options (i.e. HTTP proxy settings, etc.)

## Chores
- Add documentation for how to configure command-cert-manager-issuer with ambient credentials on Google Kubernetes Engine (GKE).
- Add documentation for configuring CA trust bundles via Secret and ConfigMap resources using trust-manager.

# v2.4.0
## Features
- Add a `healthcheck` specification to Issuer / ClusterIssuer resources, allowing flexibility in the health check interval.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ test: manifests generate fmt vet envtest ## Run tests.
# 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:
go test ./test/e2e/ -v -ginkgo.v
cd e2e && source .env && ./run_tests.sh

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
Expand Down
36 changes: 27 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,25 @@ Command Issuer is installed using a Helm chart. The chart is available in the [C
--create-namespace
```

> For all possible configuration values for the command-cert-manager-issuer Helm chart, please refer to [this list](./deploy/charts/command-cert-manager-issuer/README.md#configuration)
You can also install a specific version of the command-cert-manager-issuer Helm chart:

```shell
helm search repo command-issuer/command-cert-manager-issuer --versions
```

```shell
helm install command-cert-manager-issuer command-issuer/command-cert-manager-issuer \
--namespace command-issuer-system \
--version 2.4.0
--create-namespace
```

> For all possible configuration values for the command-cert-manager-issuer Helm chart, please refer to [this list](./deploy/charts/command-cert-manager-issuer/README.md#configuration)

> The Helm chart installs the Command Issuer CRDs by default. The CRDs can be installed manually with the `make install` target.

> A list of configurable Helm chart parameters can be found [in the Helm chart docs](./deploy/charts/command-cert-manager-issuer/README.md#configuration)

# Authentication

## Explicit Credentials
Expand All @@ -166,6 +181,7 @@ These credentials must be configured using a Kubernetes Secret. By default, the
Command Issuer also supports ambient authentication, where a token is fetched from an Authorization Server using a cloud provider's auth infrastructure and passed to Command directly. The following methods are supported:

- [Managed Identity Using Azure Entra ID Workload Identity](./docs/ambient-providers/azure.md) (if running in [AKS](https://azure.microsoft.com/en-us/products/kubernetes-service))
- [Workload Identity Using Google Kubernetes Engine](./docs/ambient-providers/google.md) (if running in [GKE](https://cloud.google.com/kubernetes-engine))

If you are running your Kubernetes workload in a cloud provider not listed above, you can use workload identity federation with [Azure AD](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation).

Expand Down Expand Up @@ -212,11 +228,7 @@ This section has moved. Please refer to [this link](./docs/ambient-providers/azu

# CA Bundle

If the 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 as a Kubernetes secret.

```shell
kubectl -n command-issuer-system create secret generic command-ca-secret --from-file=ca.crt
```
This section has been moved. Please refer to the new [CA Bundle docs](./docs/ca-bundle/README.md) documentation regarding CA trust with command-cert-manager-issuer.

# Creating Issuer and ClusterIssuer resources

Expand All @@ -243,7 +255,9 @@ For example, ClusterIssuer resources can be used to issue certificates for resou
| hostname | The hostname of the Command API Server. |
| apiPath | (optional) The base path of the Command REST API. Defaults to `KeyfactorAPI`. |
| commandSecretName | (optional) The name of the Kubernetes secret containing basic auth credentials or OAuth 2.0 credentials. Omit if using ambient credentials. |
| caSecretName | (optional) The name of the Kubernetes secret containing the CA certificate. Required if the Command API uses a self-signed certificate or it was signed by a CA that is not widely trusted. |
| caSecretName | (optional) The name of the Kubernetes secret containing the CA certificate trust chain. See the [CA Bundle docs](./docs/ca-bundle/README.md) for more information. |
| caBundleConfigMapName | (optional) The name of the Kubernetes ConfigMap containing the CA certificate trust chain. See the [CA Bundle docs](./docs/ca-bundle/README.md) for more information. |
| caBundleKey | (optional) The name of the key in the ConfigMap or Secret specified by `caSecretName` or `caBundleConfigMapName` that contains the CA bundle. If omitted, the last key of the ConfigMap / Secret resource will be used. |
| certificateAuthorityLogicalName | The logical name of the Certificate Authority to use in Command. For example, `Sub-CA` |
| certificateAuthorityHostname | (optional) The hostname of the Certificate Authority specified by `certificateAuthorityLogicalName`. This field is usually only required if the CA in Command is a DCOM (MSCA-like) CA. |
| enrollmentPatternId | The ID of the [Enrollment Pattern](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Enrollment-Patterns.htm) to use when this Issuer/ClusterIssuer enrolls CSRs. **Supported by Keyfactor Command 25.1 and above**. If `certificateTemplate` and `enrollmentPatternId` are both specified, the enrollment pattern parameter will take precedence. If `enrollmentPatternId` and `enrollmentPatternName` are both specified, `enrollmentPatternId` will take precedence. Enrollment will fail if the specified certificate template is not compatible with the enrollment pattern. |
Expand Down Expand Up @@ -276,7 +290,9 @@ For example, ClusterIssuer resources can be used to issue certificates for resou
hostname: "$HOSTNAME"
apiPath: "/KeyfactorAPI" # Preceding & trailing slashes are handled automatically
commandSecretName: "command-secret" # references the secret created above. Omit if using ambient credentials.
caSecretName: "command-ca-secret" # references the secret created above
# caSecretName: "command-ca-secret" # references a secret containing the CA trust chain (see CA Bundle docs for more info)
# caBundleConfigMapName: "command-ca-configmap" # references a configmap containing the CA trust chain (see CA Bundle docs for more info)
# caBundleKey: "ca.crt" # references the key in the secret/configmap containing the CA trust chain (see CA Bundle docs for more info)

# certificateAuthorityHostname: "$COMMAND_CA_HOSTNAME" # Uncomment if required
certificateAuthorityLogicalName: "$COMMAND_CA_LOGICAL_NAME"
Expand Down Expand Up @@ -309,7 +325,9 @@ For example, ClusterIssuer resources can be used to issue certificates for resou
hostname: "$HOSTNAME"
apiPath: "/KeyfactorAPI" # Preceding & trailing slashes are handled automatically
commandSecretName: "command-secret" # references the secret created above. Omit if using ambient credentials.
caSecretName: "command-ca-secret" # references the secret created above
# caSecretName: "command-ca-secret" # references a secret containing the CA trust chain (see CA Bundle docs for more info)
# caBundleConfigMapName: "command-ca-configmap" # references a configmap containing the CA trust chain (see CA Bundle docs for more info)
# caBundleKey: "ca.crt" # references the key in the secret/configmap containing the CA trust chain (see CA Bundle docs for more info)

# certificateAuthorityHostname: "$COMMAND_CA_HOSTNAME" # Uncomment if required
certificateAuthorityLogicalName: "$COMMAND_CA_LOGICAL_NAME"
Expand Down
16 changes: 15 additions & 1 deletion api/v1alpha1/issuer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,24 @@ type IssuerSpec struct {

// The name of the secret containing the CA bundle to use when verifying
// Command's server certificate. If specified, the CA bundle will be added to
// the client trust roots for the Command issuer.
// the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
// are specified, caBundleConfigMapName will take precedence.
// +optional
CaSecretName string `json:"caSecretName,omitempty"`

// The name of the ConfigMap containing the CA bundle to use when verifying
// Command's server certificate. If specified, the CA bundle will be added to
// the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
// are specified, caBundleConfigMapName will take precedence.
// +optional
CaBundleConfigMapName string `json:"caBundleConfigMapName,omitempty"`

// The key in the Secret or ConfigMap containing the CA certificate bundle.
// Applies to both caSecretName and caBundleConfigMapName.
// If unspecified, the last key alphabetically in the Secret or ConfigMap data will be used.
// +optional
CaBundleKey string `json:"caBundleKey,omitempty"`

// A list of comma separated scopes used when requesting a Bearer token from an ambient token provider implied
// by the environment, rather than by commandSecretName. For example, could be set to
// api://{tenant ID}/.default when requesting an access token for Entra ID (DefaultAzureCredential). Has no
Expand Down
36 changes: 27 additions & 9 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func main() {
var clusterResourceNamespace string
var disableApprovedCheck bool
var secretAccessGrantedAtClusterLevel bool
var configMapAccessGrantedAtClusterLevel bool

flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
Expand All @@ -88,6 +89,8 @@ func main() {
"Disables waiting for CertificateRequests to have an approved condition before signing.")
flag.BoolVar(&secretAccessGrantedAtClusterLevel, "secret-access-granted-at-cluster-level", false,
"Set this flag to true if the secret access is granted at cluster level. This will allow the controller to access secrets in any namespace. ")
flag.BoolVar(&configMapAccessGrantedAtClusterLevel, "configmap-access-granted-at-cluster-level", false,
"Set this flag to true if the config map access is granted at cluster level. This will allow the controller to access config maps in any namespace. ")
opts := zap.Options{
Development: true,
}
Expand Down Expand Up @@ -130,16 +133,31 @@ func main() {
}

var cacheOpts cache.Options
if secretAccessGrantedAtClusterLevel {
setupLog.Info("expecting SA to have Get+List+Watch permissions for corev1 Secret resources at cluster level")
} else {
setupLog.Info(fmt.Sprintf("expecting SA to have Get+List+Watch permissions for corev1 Secret resources in the %q namespace", clusterResourceNamespace))

// Build the ByObject map if either resource is namespace-scoped
if !secretAccessGrantedAtClusterLevel || !configMapAccessGrantedAtClusterLevel {
byObject := make(map[client.Object]cache.ByObject)

if !secretAccessGrantedAtClusterLevel {
setupLog.Info(fmt.Sprintf("expecting SA to have Get+List+Watch permissions for corev1 Secret resources in the %q namespace", clusterResourceNamespace))
byObject[&corev1.Secret{}] = cache.ByObject{
Namespaces: map[string]cache.Config{clusterResourceNamespace: {}},
}
} else {
setupLog.Info("expecting SA to have Get+List+Watch permissions for corev1 Secret resources at cluster level")
}

if !configMapAccessGrantedAtClusterLevel {
setupLog.Info(fmt.Sprintf("expecting SA to have Get+List+Watch permissions for corev1 ConfigMap resources in the %q namespace", clusterResourceNamespace))
byObject[&corev1.ConfigMap{}] = cache.ByObject{
Namespaces: map[string]cache.Config{clusterResourceNamespace: {}},
}
} else {
setupLog.Info("expecting SA to have Get+List+Watch permissions for corev1 ConfigMap resources at cluster level")
}

cacheOpts = cache.Options{
ByObject: map[client.Object]cache.ByObject{
&corev1.Secret{}: {
Namespaces: map[string]cache.Config{clusterResourceNamespace: cache.Config{}},
},
},
ByObject: byObject,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,25 @@ spec:
the URL of your Command environment.Has no effect on OAuth 2.0 Client Credential configuration - please specify
the audience for this method in an Opaque secret.
type: string
caBundleConfigMapName:
description: |-
The name of the ConfigMap containing the CA bundle to use when verifying
Command's server certificate. If specified, the CA bundle will be added to
the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
are specified, caBundleConfigMapName will take precedence.
type: string
caBundleKey:
description: |-
The key in the Secret or ConfigMap containing the CA certificate bundle.
Applies to both caSecretName and caBundleConfigMapName.
If unspecified, the last key alphabetically in the Secret or ConfigMap data will be used.
type: string
caSecretName:
description: |-
The name of the secret containing the CA bundle to use when verifying
Command's server certificate. If specified, the CA bundle will be added to
the client trust roots for the Command issuer.
the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
are specified, caBundleConfigMapName will take precedence.
type: string
certificateAuthorityHostname:
description: |-
Expand Down
16 changes: 15 additions & 1 deletion config/crd/bases/command-issuer.keyfactor.com_issuers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,25 @@ spec:
the URL of your Command environment.Has no effect on OAuth 2.0 Client Credential configuration - please specify
the audience for this method in an Opaque secret.
type: string
caBundleConfigMapName:
description: |-
The name of the ConfigMap containing the CA bundle to use when verifying
Command's server certificate. If specified, the CA bundle will be added to
the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
are specified, caBundleConfigMapName will take precedence.
type: string
caBundleKey:
description: |-
The key in the Secret or ConfigMap containing the CA certificate bundle.
Applies to both caSecretName and caBundleConfigMapName.
If unspecified, the last key alphabetically in the Secret or ConfigMap data will be used.
type: string
caSecretName:
description: |-
The name of the secret containing the CA bundle to use when verifying
Command's server certificate. If specified, the CA bundle will be added to
the client trust roots for the Command issuer.
the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
are specified, caBundleConfigMapName will take precedence.
type: string
certificateAuthorityHostname:
description: |-
Expand Down
1 change: 1 addition & 0 deletions deploy/charts/command-cert-manager-issuer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,6 @@ The following table lists the configurable parameters of the `command-cert-manag
| `resources` | CPU/Memory resource requests/limits | `{}` (with commented out options) |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `tolerations` | Tolerations for pod assignment | `[]` |
| `env` | Environmental variables set for pod | `{}` |
| `secretConfig.useClusterRoleForSecretAccess` | Specifies if the ServiceAccount should be granted access to the Secret resource using a ClusterRole | `false` |
| `defaultHealthCheckInterval` | Specifies the default health check interval for issuers | `""` (uses the default in the code which is 60s) |
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,25 @@ spec:
description: APIPath is the base path of the Command API. KeyfactorAPI
by default
type: string
caBundleConfigMapName:
description: |-
The name of the ConfigMap containing the CA bundle to use when verifying
Command's server certificate. If specified, the CA bundle will be added to
the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
are specified, caBundleConfigMapName will take precedence.
type: string
caBundleKey:
description: |-
The key in the Secret or ConfigMap containing the CA certificate bundle.
Applies to both caSecretName and caBundleConfigMapName.
If unspecified, the last key alphabetically in the Secret or ConfigMap data will be used.
type: string
caSecretName:
description: |-
The name of the secret containing the CA bundle to use when verifying
Command's server certificate. If specified, the CA bundle will be added to
the client trust roots for the Command issuer.
the client trust roots for the Command issuer. If both caSecretName and caBundleConfigMapName
are specified, caBundleConfigMapName will take precedence.
type: string
certificateAuthorityHostname:
description: |-
Expand Down
Loading
Loading