Skip to content

JWK Provisioner Template not being honored #2390

@PrymalInstynct

Description

@PrymalInstynct

I am attempting to use step-ca as an external, offline root CA to sign a subordinate CA certificate for a new FreeIPA installation. The entire workflow is automated in a GitLab CI/CD pipeline.

The workflow is as follows:

  1. An Ansible playbook running on a GitLab runner configures a new FreeIPA server using the freeipa.ansible_freeipa.ipaserver role. As part of this process, the ipa-server-install command generates a Certificate Signing Request (CSR) for its own CA (/tmp/ipa.csr).
  2. A script in the GitLab CI job then needs to get this CSR signed by the step-ca instance.

The Problem
The FreeIPA installation process is strict and requires that the final signed certificate has a subject that exactly matches the subject from the CSR.

  • CSR Subject: CN=Certificate Authority,O=LOCAL.DOMAIN
  • Required Certificate Subject: CN=Certificate Authority,O=LOCAL.DOMAIN

However, the certificate being issued by the step-ca server consistently has the subject of CN=Certificate Authority, stripping the O=LOCAL.DOMAIN part. This causes the second stage of the FreeIPA installation to fail.

step-ca Server Configuration
I have configured a dedicated JWK provisioner on the step-ca server specifically for this purpose. I am using a custom template that is intended to preserve the full subject from the CSR.

Here is the output of the step ca provisioner list command for the relevant provisioner:

{
   "type": "JWK",
   "name": "idm@local.domain",
   "key": {...},
   "encryptedKey": "...",
   "claims": {
      "minTLSCertDuration": "5m0s",
      "maxTLSCertDuration": "87600h0m0s",
      "defaultTLSCertDuration": "24h0m0s",
      "enableSSHCA": true
   },
   "options": {
      "x509": {
         "template": "{\n  \"subject\": {{ toJson .Insecure.CR.RawSubject }},\n  \"sans\": {{ toJson .SANs }},\n  \"keyUsage\": [\"certSign\", \"crlSign\"],\n  \"basicConstraints\": {\n    \"isCA\": true,\n    \"maxPathLen\": 1\n  }\n}\n"
      },
      "ssh": {}
   }
}

Client-side Steps (GitLab CI)

The CI script performs the following steps:

  1. Extracts the Common Name from the CSR to satisfy the server's authorization policy (token.subject == csr.common_name).
CN=$(openssl req -in /tmp/ipa.csr -noout -subject | sed -n 's/.*CN= *//p')
  1. Generates a token using the extracted CN as the subject.
TOKEN=$(step ca token "${CN}" --provisioner "idm@domain.local" --key "key.jwk" --password-file "password.txt")
  1. Attempts to sign the CSR.
step ca sign "/tmp/ipa.csr" "/tmp/ipa.crt" --token "$TOKEN"

Expected vs. Actual Behavior

  • Expected: I expect the step-ca server to apply the x509.template defined in the provisioner. The template's {{ toJson .Insecure.CR.RawSubject }} directive should force the new certificate's subject to be an exact copy of the subject in the CSR.
  • Actual: The step ca sign command succeeds, but a subsequent inspection of the generated /tmp/ipa.crt reveals its subject is only CN=Certificate Authority. The template appears to be ignored or is not functioning as expected.

Question
Is this a bug, or is there a misconfiguration in the provisioner or template that would cause the .Insecure.CR.RawSubject variable to be ignored in favor of the token's subject? What is the correct way to configure a JWK provisioner to sign a subordinate CA CSR while preserving the full, original subject from the CSR?

System Config

  • OS: Ubuntu 24.04.3
  • Architecture: aarch64
  • Step-CA Version: Smallstep CA/0.28.4 (linux/arm64)
  • Build Date: 2025-09-14 18:54 UTC

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions