Support · License · Related Integrations
The Command Issuer is open source and community supported, meaning that there is no SLA applicable.
To report a problem or suggest a new feature, use the Issues tab. If you want to contribute actual bug fixes or proposed enhancements, use the Pull requests tab.
The Command Issuer for cert-manager is a CertificateRequest controller that issues certificates using Keyfactor Command.
Before continuing, ensure that the following requirements are met:
- Keyfactor Command >= 10.5
- Command must be properly configured according to the product docs.
- You have access to the Command REST API. The following endpoints must be available:
/Status/Endpoints
/Enrollment/CSR
/MetadataFields
- Kubernetes >= v1.19
- Kubernetes, Minikube, Kind, etc.
You must have permission to create Custom Resource Definitions in your Kubernetes cluster.
- Supported cert-manager release installed in your cluster. Please see the cert-manager installation for details.
- Supported version of Helm for your Kubernetes version
Command Issuer enrolls certificates by submitting a POST request to the Command CSR Enrollment endpoint. Before using Command Issuer, you must create or identify a Certificate Authority and Certificate Template suitable for your usecase. Additionally, you should ensure that the identity used by the Issuer/ClusterIssuer has the appropriate permissions in Command.
-
Create or identify a Certificate Authority
A certificate authority (CA) is an entity that issues digital certificates. Within Keyfactor Command, a CA may be a Microsoft CA, EJBCA, or a Keyfactor gateway to a cloud-based or remote CA.
- If you haven't created a Certificate Authority before, refer to the Command documentation to learn how, or reach out to your Keyfactor support representative.
The CA that you choose must be configured to allow CSR Enrollment.
-
Identify a Certificate Template
Certificate Templates in Command define properties and constraints of the certificates being issued. This includes settings like key usage, extended key usage, validity period, allowed key algorithms, and signature algorithms. They also control the type of information that end entities must provide and how that information is validated before issuing certificates.
- If you don't have any suitable Certificate Templates, refer to the Command documentation or reach out to your Keyfactor support representative to learn more.
The Certificate Template that you shoose must be configured to allow CSR Enrollment.
You should make careful note of the allowed Key Types and Key Sizes on the Certificate Template. When creating cert-manager Certificates, you must make sure that the key
algorithm
andsize
are allowed by your Certificate Template in Command.The same goes for Enrollment RegExes and Policies defined on your Certificate Template. When creating cert-manager Certificates, you must make sure that the
subject
,commonName
,dnsNames
, etc. are allowed and/or configured correctly by your Certificate Template in Command. -
Configure Command Security Roles and Claims
In Command, Security Roles define groups of users or administrators with specific permissions. Users and subjects are identified by Claims. By adding a Claim to a Security Role, you can define what actions the user or subject can perform and what parts of the system it can interact with.
- If you haven't created Roles and Access rules before, this guide provides a primer on these concepts in Command.
If your security policy requires fine-grain access control, Command Issuer requires the following Access Rules.
Global Permissions CertificateMetadataTypes:Read
CertificateEnrollment:EnrollCSR
Command Issuer is installed using a Helm chart. The chart is available in the Command cert-manager Helm repository.
-
Verify that at least one Kubernetes node is running:
kubectl get nodes
-
Add the Helm repository:
helm repo add command-issuer https://keyfactor.github.io/command-cert-manager-issuer helm repo update
-
Then, install the chart:
helm install command-cert-manager-issuer command-issuer/command-cert-manager-issuer \ --namespace command-issuer-system \ --create-namespace
The Helm chart installs the Command Issuer CRDs by default. The CRDs can be installed manually with the
make install
target.
Command Issuer supports authentication to Command using one of the following methods:
- Basic Authentication (username and password)
- OAuth 2.0 "client credentials" token flow (sometimes called two-legged OAuth 2.0)
These credentials must be configured using a Kubernetes Secret. By default, the secret is expected to exist in the same namespace as the issuer controller (command-issuer-system
by default).
Command Issuer can read secrets in the Issuer namespace if
--set "secretConfig.useClusterRoleForSecretAccess=true"
flag is set when installing the Helm chart.
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 (if running in AKS)
Create a kubernetes.io/basic-auth
secret with the Keyfactor Command username and password:
cat <<EOF | kubectl -n command-issuer-system apply -f -
apiVersion: v1
kind: Secret
metadata:
name: command-secret
type: kubernetes.io/basic-auth
data:
username: <base64 encoded (domain\\)username>
password: <base64 encoded password>
EOF
Create an Opaque secret containing the client ID and client secret to authenticate with Command:
token_url="<token url>"
client_id="<client id>"
client_secret="<client secret>"
audience="<audience>"
scopes="<scopes>" # comma separated list of scopes
kubectl -n command-issuer-system create secret generic command-secret \
"--from-literal=tokenUrl=$token_url" \
"--from-literal=clientId=$client_id" \
"--from-literal=clientSecret=$client_secret" \
"--from-literal=audience=$audience" \
"--from-literal=scopes=$scopes"
Audience and Scopes are optional
Azure Entra ID workload identity in Azure Kubernetes Service (AKS) allows Command Issuer to exchange a Kubernetes ServiceAccount Token for an Azure Entra ID access token, which is then used to authenticate to Command.
-
Reconfigure the AKS cluster to enable workload identity federation.
az aks update \ --name ${CLUSTER} \ --enable-oidc-issuer \ --enable-workload-identity
The Azure Workload Identity extension can be installed on non-AKS or self-managed clusters if you're not using AKS.
Refer to the AKS documentation for more information on the
--enable-workload-identity
feature. -
Reconfigure or deploy Command Issuer with extra labels for the Azure Workload Identity webhook, which will result in the Command Issuer controller Pod having an extra volume containing a Kubernetes ServiceAccount token which it will exchange for a token from Azure.
helm install command-cert-manager-issuer command-issuer/command-cert-manager-issuer \ --namespace command-issuer-system \ --create-namespace \ --set "fullnameOverride=$chart_name" \ --set-string "podLabels.azure\.workload\.identity/use=true" \ --set-string "serviceAccount.labels.azure\.workload\.identity/use=true" # --set-string "serviceAccount.annotations.azure\.workload\.identity/client-id=<managed identity client ID>" # May be necessary, but is usually not.
If successful, the Command Issuer Pod will have new environment variables and the Azure WI ServiceAccount token as a projected volume:
kubectl -n command-issuer-system describe pod
Containers: command-cert-manager-issuer: ... Environment: AZURE_CLIENT_ID: <GUID> AZURE_TENANT_ID: <GUID> AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/azure/tokens/azure-identity-token AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/ Mounts: /var/run/secrets/azure/tokens from azure-identity-token (ro) /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-6rmzz (ro) ... Volumes: ... azure-identity-token: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3600
Refer to Azure Workload Identity docs more information on the role of the Mutating Admission Webhook.
-
Create a User Assigned Managed Identity in Azure.
export IDENTITY_NAME=command-issuer az identity create --name "${IDENTITY_NAME}"
Read more about the
az identity
command. -
Associate a Federated Identity Credential (FIC) with the User Assigned Managed Identity. The FIC allows Command Issuer to act on behalf of the Managed Identity by telling Azure to expect:
- The
iss
claim of the ServiceAccount token to match the cluster's OIDC Issuer. Azure will also use the Issuer URL to download the JWT signing certificate. - The
sub
claim of the ServiceAccount token to match the ServiceAccount's name and namespace.
export SERVICE_ACCOUNT_NAME=command-cert-manager-issuer # This is the default Kubernetes ServiceAccount used by the Command Issuer controller. export SERVICE_ACCOUNT_NAMESPACE=command-issuer-system # This is the default namespace for Command Issuer used in this doc. export SERVICE_ACCOUNT_ISSUER=$(az aks show --resource-group $AZURE_DEFAULTS_GROUP --name $CLUSTER --query "oidcIssuerProfile.issuerUrl" -o tsv) az identity federated-credential create \ --name "command-issuer" \ --identity-name "${IDENTITY_NAME}" \ --issuer "${SERVICE_ACCOUNT_ISSUER}" \ --subject "system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
Read more about Workload Identity federation in the Entra ID documentation.
Read more about the
az identity federated-credential
command. - The
-
Add Microsoft Entra ID as an Identity Provider in Command, and add the Managed Identity's Client ID as an
oid
claim to the Security Role created/identified earlier.
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.
kubectl -n command-issuer-system create secret generic command-ca-secret --from-file=ca.crt
The command-issuer.keyfactor.com/v1alpha1
API version supports Issuer and ClusterIssuer resources. The Issuer resource is namespaced, while the ClusterIssuer resource is cluster-scoped.
For example, ClusterIssuer resources can be used to issue certificates for resources in multiple namespaces, whereas Issuer resources can only be used to issue certificates for resources in the same namespace.
-
Prepare the
spec
export HOSTNAME="<hostname>" export COMMAND_CA_HOSTNAME="<certificateAuthorityName>" # Only required for non-HTTPS CA types export COMMAND_CA_LOGICAL_NAME="<certificateAuthorityName>" export CERTIFICATE_TEMPLATE_SHORT_NAME="<certificateTemplateShortName>"
The
spec
field of both the Issuer and ClusterIssuer resources use the following fields:Field Name Description hostname The hostname of the Command API Server. apiPath (optional) The base path of the Command REST API. Defaults to KeyfactorAPI
.commandSecretName The name of the Kubernetes secret containing basic auth credentials or OAuth 2.0 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. 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.certificateTemplate The Short Name of the Certificate Template to use when this Issuer/ClusterIssuer enrolls CSRs. If a different combination of hostname/certificate authority/certificate template is required, a new Issuer or ClusterIssuer resource must be created. Each resource instantiation represents a single configuration.
-
Create an Issuer or ClusterIssuer
-
Issuer
Create an Issuer resource using the environment variables prepared in step 1.
cat <<EOF > ./issuer.yaml apiVersion: command-issuer.keyfactor.com/v1alpha1 kind: Issuer metadata: name: issuer-sample namespace: default spec: hostname: "$HOSTNAME" apiPath: "/KeyfactorAPI" # Preceding & trailing slashes are handled automatically commandSecretName: "command-secret" # references the secret created above caSecretName: "command-ca-secret" # references the secret created above # certificateAuthorityHostname: "$COMMAND_CA_HOSTNAME" # Uncomment if required certificateAuthorityLogicalName: "$COMMAND_CA_LOGICAL_NAME" certificateTemplate: "$CERTIFICATE_TEMPLATE_SHORT_NAME" EOF kubectl -n default apply -f issuer.yaml
-
ClusterIssuer
Create a ClusterIssuer resource using the environment variables prepared in step 1.
cat <<EOF > ./clusterissuer.yaml apiVersion: command-issuer.keyfactor.com/v1alpha1 kind: ClusterIssuer metadata: name: clusterissuer-sample spec: hostname: "$HOSTNAME" apiPath: "/KeyfactorAPI" # Preceding & trailing slashes are handled automatically commandSecretName: "command-secret" # references the secret created above caSecretName: "command-ca-secret" # references the secret created above # certificateAuthorityHostname: "$COMMAND_CA_HOSTNAME" # Uncomment if required certificateAuthorityLogicalName: "$COMMAND_CA_LOGICAL_NAME" certificateTemplate: "$CERTIFICATE_TEMPLATE_SHORT_NAME" EOF kubectl apply -f clusterissuer.yaml
-
Once an Issuer or ClusterIssuer resource is created, they can be used to issue certificates using cert-manager. The two most important concepts are Certificate
and CertificateRequest
resources.
Certificate
resources represent a single X.509 certificate and its associated attributes. cert-manager maintains the corresponding certificate, including renewal when appropriate.- When
Certificate
resources are created, cert-manager creates a correspondingCertificateRequest
that targets a specific Issuer or ClusterIssuer to actually issue the certificate.
To learn more about cert-manager, see the cert-manager documentation.
The following is an example of a Certificate resource. This resource will create a corresponding CertificateRequest resource, and will use the issuer-sample
Issuer resource to issue the certificate. Once issued, the certificate will be stored in a Kubernetes secret named command-certificate
.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: command-certificate
spec:
issuerRef:
name: issuer-sample
group: command-issuer.keyfactor.com
kind: Issuer
commonName: example.com
secretName: command-certificate
Certificate resources support many more fields than the above example. See the Certificate resource documentation for more information.
Similarly, a CertificateRequest resource can be created directly. The following is an example of a CertificateRequest resource.
apiVersion: cert-manager.io/v1
kind: CertificateRequest
metadata:
name: command-certificate
spec:
issuerRef:
name: issuer-sample
group: command-issuer.keyfactor.com
kind: Issuer
request: <csr>
All fields in Command Issuer and ClusterIssuer
spec
can be overridden by applying Kubernetes Annotations to Certificates and CertificateRequests. See runtime customization for more
Unless the cert-manager internal approver automatically approves the request, newly created CertificateRequest resources
will be in a Pending
state until they are approved. CertificateRequest resources can be approved manually by using
cmctl. The following is an example
of approving a CertificateRequest resource named command-certificate
.
cmctl approve command-certificate
Once a certificate request has been approved, the certificate will be issued and stored in the secret specified in the CertificateRequest resource. The following is an example of retrieving the certificate from the secret.
kubectl get secret command-certificate -o jsonpath='{.data.tls\.crt}' | base64 -d
To learn more about certificate approval and RBAC configuration, see the cert-manager documentation.
Overriding the Issuer/ClusterIssuer spec
using Kubernetes Annotations on CertificateRequest Resources
Command Issuer allows you to override the certificateAuthorityHostname
, certificateAuthorityLogicalName
, and certificateTemplate
by setting Kubernetes Annotations on CertificateRequest resources. This may be useful if certain enrollment scenarios require a different Certificate Authority or Certificate Template, but you don't want to create a new Issuer/ClusterIssuer.
command-issuer.keyfactor.com/certificateAuthorityHostname
overridescertificateAuthorityHostname
command-issuer.keyfactor.com/certificateAuthorityLogicalName
overridescertificateAuthorityLogicalName
command-issuer.keyfactor.com/certificateTemplate
overridescertificateTemplate
cert-manager copies Annotations set on Certificate resources to the corresponding CertificateRequest.
How to Apply Annotations
Notes
To apply these annotations, include them in the metadata section of your Certificate/CertificateRequest resource:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: annotations: command-issuer.keyfactor.com/certificateTemplate: "Ephemeral2day" command-issuer.keyfactor.com/certificateAuthorityLogicalName: "InternalIssuingCA1" metadata.command-issuer.keyfactor.com/ResponsibleTeam: "theResponsibleTeam@example.com" # ... other annotations spec: # ... the rest of the spec
Keyfactor Command allows users to attach custom metadata to certificates that can be used to tag certificates with additional information. Command Issuer can attach Certificate Metadata upon enrollment.
-
Pre-defined Certificate Metadata
If all of the following metadata fields are defined in Command, Command Issuer will populate the fields upon certificate enrollment. All of the metadata fields are String types. Please refer to the Command docs to define these metadata fields in Command if you would like Command Issuer to populate these fields on certificates upon enrollment.
Field Name Description Issuer-Namespace The namespace that the Issuer resource was created in. Is always empty for ClusterIssuers. Controller-Reconcile-Id The GUID of the reconciliation run that corresponded to the issuance of this certificate. Certificate-Signing-Request-Namespace The namespace that the CertificateRequest resource was created in. Controller-Namespace The namespace that the controller container is running in. Controller-Kind The issuer type - Issuer or ClusterIssuer. Controller-Resource-Group-Name The group name of the Command Issuer CRD. Is always command-issuer.keyfactor.com
.Issuer-Name The name of the K8s Issuer/ClusterIssuer resource. You don't need to re-create the Issuer/ClusterIssuer when metadata fields are added/removed in Command. Command Issuer automatically detects the presence of these fields and tracks the state in the
SupportsMetadata
resource condition. -
Custom Certificate Metadata
You can also configure Command Issuer to attach Certificate Metadata by annotating Certificate/CertificateRequest resources. Command Issuer does not check for the presence of custom metadata fields configured in Annotations, and you should take special care that fields defined in annotations exist in Command prior to use. Certificate issuance will fail if any of the metadata fields specified aren't configured in Command. The syntax for specifying metadata is as follows:
metadata.command-issuer.keyfactor.com/<metadata-field-name>: <metadata-value>
Apache License 2.0, see LICENSE.
See all Keyfactor integrations.