diff --git a/api/v1beta1/stepclusterissuer_types.go b/api/v1beta1/stepclusterissuer_types.go
index 9ae71741eb7e0d4474306e6ed6ec9b768300eea1..d59f78e77a77ace0314027bad3923adb19587d6a 100644
--- a/api/v1beta1/stepclusterissuer_types.go
+++ b/api/v1beta1/stepclusterissuer_types.go
@@ -48,13 +48,15 @@ type StepClusterIssuerSpec struct {
 type StepClusterIssuerStatus struct {
 	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
 	// Important: Run "make" to regenerate code after modifying this file
+
+	// +optional
 	Conditions []StepClusterIssuerCondition `json:"conditions,omitempty"`
 }
 
 // +kubebuilder:object:root=true
-// +kubebuilder:resource:scope=Cluster
 
 // StepClusterIssuer is the Schema for the stepclusterissuers API
+// +kubebuilder:subresource:status
 type StepClusterIssuer struct {
 	metav1.TypeMeta   `json:",inline"`
 	metav1.ObjectMeta `json:"metadata,omitempty"`
@@ -72,59 +74,6 @@ type StepClusterIssuerList struct {
 	Items           []StepClusterIssuer `json:"items"`
 }
 
-// SecretKeySelector contains the reference to a secret.
-type SecretKeySelector struct {
-	// The name of the secret in the pod's namespace to select from.
-	Name string `json:"name"`
-
-	// The key of the secret to select from. Must be a valid secret key.
-	// +optional
-	Key string `json:"key,omitempty"`
-}
-
-// StepProvisioner contains the configuration used to create step certificate
-// tokens used to grant certificates.
-type StepProvisioner struct {
-	// Names is the name of the JWK provisioner.
-	Name string `json:"name"`
-
-	// KeyID is the kid property of the JWK provisioner.
-	KeyID string `json:"kid"`
-
-	// PasswordRef is a reference to a Secret containing the provisioner
-	// password used to decrypt the provisioner private key.
-	PasswordRef SecretKeySelector `json:"passwordRef"`
-}
-
-// ConditionType represents a StepClusterIssuer condition type.
-// +kubebuilder:validation:Enum=Ready
-type ConditionType string
-
-const (
-	// ConditionReady indicates that a StepClusterIssuer is ready for use.
-	ConditionReady ConditionType = "Ready"
-)
-
-// ConditionStatus represents a condition's status.
-// +kubebuilder:validation:Enum=True;False;Unknown
-type ConditionStatus string
-
-// These are valid condition statuses. "ConditionTrue" means a resource is in
-// the condition; "ConditionFalse" means a resource is not in the condition;
-// "ConditionUnknown" means kubernetes can't decide if a resource is in the
-// condition or not. In the future, we could add other intermediate
-// conditions, e.g. ConditionDegraded.
-const (
-	// ConditionTrue represents the fact that a given condition is true
-	ConditionTrue ConditionStatus = "True"
-
-	// ConditionFalse represents the fact that a given condition is false
-	ConditionFalse ConditionStatus = "False"
-
-	// ConditionUnknown represents the fact that a given condition is unknown
-	ConditionUnknown ConditionStatus = "Unknown"
-)
-
 // StepClusterIssuerCondition contains condition information for the step issuer.
 type StepClusterIssuerCondition struct {
 	// Type of the condition, currently ('Ready').
@@ -148,4 +97,4 @@ type StepClusterIssuerCondition struct {
 	// transition, complementing reason.
 	// +optional
 	Message string `json:"message,omitempty"`
-}
\ No newline at end of file
+}
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index 64ea5cd46bf7704e7375ba6e2ad5314b40f1ec7a..5808ce0316ef80d1303f3c95f5a8c77ba649386b 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -43,8 +43,8 @@ func (in *StepClusterIssuer) DeepCopyInto(out *StepClusterIssuer) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	out.Spec = in.Spec
-	out.Status = in.Status
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepClusterIssuer.
@@ -65,6 +65,25 @@ func (in *StepClusterIssuer) DeepCopyObject() runtime.Object {
 	return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepClusterIssuerCondition) DeepCopyInto(out *StepClusterIssuerCondition) {
+	*out = *in
+	if in.LastTransitionTime != nil {
+		in, out := &in.LastTransitionTime, &out.LastTransitionTime
+		*out = (*in).DeepCopy()
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepClusterIssuerCondition.
+func (in *StepClusterIssuerCondition) DeepCopy() *StepClusterIssuerCondition {
+	if in == nil {
+		return nil
+	}
+	out := new(StepClusterIssuerCondition)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *StepClusterIssuerList) DeepCopyInto(out *StepClusterIssuerList) {
 	*out = *in
@@ -100,6 +119,12 @@ func (in *StepClusterIssuerList) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *StepClusterIssuerSpec) DeepCopyInto(out *StepClusterIssuerSpec) {
 	*out = *in
+	out.Provisioner = in.Provisioner
+	if in.CABundle != nil {
+		in, out := &in.CABundle, &out.CABundle
+		*out = make([]byte, len(*in))
+		copy(*out, *in)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepClusterIssuerSpec.
@@ -115,6 +140,13 @@ func (in *StepClusterIssuerSpec) DeepCopy() *StepClusterIssuerSpec {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *StepClusterIssuerStatus) DeepCopyInto(out *StepClusterIssuerStatus) {
 	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]StepClusterIssuerCondition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepClusterIssuerStatus.
diff --git a/config/crd/bases/certmanager.step.sm_stepclusterissuers.yaml b/config/crd/bases/certmanager.step.sm_stepclusterissuers.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1c592d6f061f0ef234b5ca21d7564110ab46f5eb
--- /dev/null
+++ b/config/crd/bases/certmanager.step.sm_stepclusterissuers.yaml
@@ -0,0 +1,122 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.5.0
+  creationTimestamp: null
+  name: stepclusterissuers.certmanager.step.sm
+spec:
+  group: certmanager.step.sm
+  names:
+    kind: StepClusterIssuer
+    listKind: StepClusterIssuerList
+    plural: stepclusterissuers
+    singular: stepclusterissuer
+  scope: Namespaced
+  versions:
+  - name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: StepClusterIssuer is the Schema for the stepclusterissuers API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: StepClusterIssuerSpec defines the desired state of StepClusterIssuer
+            properties:
+              caBundle:
+                description: CABundle is a base64 encoded TLS certificate used to verify connections to the step certificates server. If not set the system root certificates are used to validate the TLS connection.
+                format: byte
+                type: string
+              provisioner:
+                description: Provisioner contains the step certificates provisioner configuration.
+                properties:
+                  kid:
+                    description: KeyID is the kid property of the JWK provisioner.
+                    type: string
+                  name:
+                    description: Names is the name of the JWK provisioner.
+                    type: string
+                  passwordRef:
+                    description: PasswordRef is a reference to a Secret containing the provisioner password used to decrypt the provisioner private key.
+                    properties:
+                      key:
+                        description: The key of the secret to select from. Must be a valid secret key.
+                        type: string
+                      name:
+                        description: The name of the secret in the pod's namespace to select from.
+                        type: string
+                    required:
+                    - name
+                    type: object
+                required:
+                - kid
+                - name
+                - passwordRef
+                type: object
+              url:
+                description: URL is the base URL for the step certificates instance.
+                type: string
+            required:
+            - provisioner
+            - url
+            type: object
+          status:
+            description: StepClusterIssuerStatus defines the observed state of StepClusterIssuer
+            properties:
+              conditions:
+                items:
+                  description: StepClusterIssuerCondition contains condition information for the step issuer.
+                  properties:
+                    lastTransitionTime:
+                      description: LastTransitionTime is the timestamp corresponding to the last status change of this condition.
+                      format: date-time
+                      type: string
+                    message:
+                      description: Message is a human readable description of the details of the last transition, complementing reason.
+                      type: string
+                    reason:
+                      description: Reason is a brief machine readable explanation for the condition's last transition.
+                      type: string
+                    status:
+                      allOf:
+                      - enum:
+                        - "True"
+                        - "False"
+                        - Unknown
+                      - enum:
+                        - "True"
+                        - "False"
+                        - Unknown
+                      description: Status of the condition, one of ('True', 'False', 'Unknown').
+                      type: string
+                    type:
+                      description: Type of the condition, currently ('Ready').
+                      enum:
+                      - Ready
+                      type: string
+                  required:
+                  - status
+                  - type
+                  type: object
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/config/crd/bases/certmanager.step.sm_stepissuers.yaml b/config/crd/bases/certmanager.step.sm_stepissuers.yaml
index 3d883661b62115f265fc35cc415ee8b7896c8487..3c7f1ff3b94b7cf2bcccbc3233ebd286c099b79b 100644
--- a/config/crd/bases/certmanager.step.sm_stepissuers.yaml
+++ b/config/crd/bases/certmanager.step.sm_stepissuers.yaml
@@ -22,14 +22,10 @@ spec:
         description: StepIssuer is the Schema for the stepissuers API
         properties:
           apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
             type: string
           kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
             type: string
           metadata:
             type: object
@@ -37,14 +33,11 @@ spec:
             description: StepIssuerSpec defines the desired state of StepIssuer
             properties:
               caBundle:
-                description: CABundle is a base64 encoded TLS certificate used to
-                  verify connections to the step certificates server. If not set the
-                  system root certificates are used to validate the TLS connection.
+                description: CABundle is a base64 encoded TLS certificate used to verify connections to the step certificates server. If not set the system root certificates are used to validate the TLS connection.
                 format: byte
                 type: string
               provisioner:
-                description: Provisioner contains the step certificates provisioner
-                  configuration.
+                description: Provisioner contains the step certificates provisioner configuration.
                 properties:
                   kid:
                     description: KeyID is the kid property of the JWK provisioner.
@@ -53,17 +46,13 @@ spec:
                     description: Names is the name of the JWK provisioner.
                     type: string
                   passwordRef:
-                    description: PasswordRef is a reference to a Secret containing
-                      the provisioner password used to decrypt the provisioner private
-                      key.
+                    description: PasswordRef is a reference to a Secret containing the provisioner password used to decrypt the provisioner private key.
                     properties:
                       key:
-                        description: The key of the secret to select from. Must be
-                          a valid secret key.
+                        description: The key of the secret to select from. Must be a valid secret key.
                         type: string
                       name:
-                        description: The name of the secret in the pod's namespace
-                          to select from.
+                        description: The name of the secret in the pod's namespace to select from.
                         type: string
                     required:
                     - name
@@ -85,21 +74,17 @@ spec:
             properties:
               conditions:
                 items:
-                  description: StepIssuerCondition contains condition information
-                    for the step issuer.
+                  description: StepIssuerCondition contains condition information for the step issuer.
                   properties:
                     lastTransitionTime:
-                      description: LastTransitionTime is the timestamp corresponding
-                        to the last status change of this condition.
+                      description: LastTransitionTime is the timestamp corresponding to the last status change of this condition.
                       format: date-time
                       type: string
                     message:
-                      description: Message is a human readable description of the
-                        details of the last transition, complementing reason.
+                      description: Message is a human readable description of the details of the last transition, complementing reason.
                       type: string
                     reason:
-                      description: Reason is a brief machine readable explanation
-                        for the condition's last transition.
+                      description: Reason is a brief machine readable explanation for the condition's last transition.
                       type: string
                     status:
                       allOf:
@@ -111,8 +96,7 @@ spec:
                         - "True"
                         - "False"
                         - Unknown
-                      description: Status of the condition, one of ('True', 'False',
-                        'Unknown').
+                      description: Status of the condition, one of ('True', 'False', 'Unknown').
                       type: string
                     type:
                       description: Type of the condition, currently ('Ready').
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index edff2da4120587951b158fc820dca855c6265ea0..305ff4d83687a06e9e2c3a3300e03d4761e7afb1 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -41,7 +41,6 @@ rules:
 - apiGroups:
   - certmanager.step.sm
   resources:
-  - stepissuers
   - stepclusterissuers
   verbs:
   - create
@@ -54,7 +53,6 @@ rules:
 - apiGroups:
   - certmanager.step.sm
   resources:
-  - stepissuers/status
   - stepclusterissuers/status
   verbs:
   - get
diff --git a/controllers/step_status_cluster_reconciler.go b/controllers/step_status_cluster_reconciler.go
new file mode 100644
index 0000000000000000000000000000000000000000..86b93e0e2ddaf3cf88623c4d371dafaa8e42e136
--- /dev/null
+++ b/controllers/step_status_cluster_reconciler.go
@@ -0,0 +1,90 @@
+package controllers
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/go-logr/logr"
+	api "github.com/smallstep/step-issuer/api/v1beta1"
+	core "k8s.io/api/core/v1"
+	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type stepStatusClusterReconciler struct {
+	*StepClusterIssuerReconciler
+	issuer *api.StepClusterIssuer
+	logger logr.Logger
+}
+
+func newStepStatusClusterReconciler(r *StepClusterIssuerReconciler, iss *api.StepClusterIssuer, log logr.Logger) *stepStatusClusterReconciler {
+	return &stepStatusClusterReconciler{
+		StepClusterIssuerReconciler: r,
+		issuer:                      iss,
+		logger:                      log,
+	}
+}
+
+func (r *stepStatusClusterReconciler) Update(ctx context.Context, status api.ConditionStatus, reason, message string, args ...interface{}) error {
+	completeMessage := fmt.Sprintf(message, args...)
+	r.setCondition(status, reason, completeMessage)
+
+	// Fire an Event to additionally inform users of the change
+	eventType := core.EventTypeNormal
+	if status == api.ConditionFalse {
+		eventType = core.EventTypeWarning
+	}
+	r.Recorder.Event(r.issuer, eventType, reason, completeMessage)
+
+	return r.Client.Status().Update(ctx, r.issuer)
+}
+
+func (r *stepStatusClusterReconciler) UpdateNoError(ctx context.Context, status api.ConditionStatus, reason, message string, args ...interface{}) {
+	if err := r.Update(ctx, status, reason, message, args...); err != nil {
+		r.logger.Error(err, "failed to update", "status", status, "reason", reason)
+	}
+}
+
+// setCondition will set a 'condition' on the given api.StepClusterIssuer resource.
+//
+// - If no condition of the same type already exists, the condition will be
+//   inserted with the LastTransitionTime set to the current time.
+// - If a condition of the same type and state already exists, the condition
+//   will be updated but the LastTransitionTime will not be modified.
+// - If a condition of the same type and different state already exists, the
+//   condition will be updated and the LastTransitionTime set to the current
+//   time.
+func (r *stepStatusClusterReconciler) setCondition(status api.ConditionStatus, reason, message string) {
+	now := meta.NewTime(r.Clock.Now())
+	c := api.StepClusterIssuerCondition{
+		Type:               api.ConditionReady,
+		Status:             status,
+		Reason:             reason,
+		Message:            message,
+		LastTransitionTime: &now,
+	}
+
+	// Search through existing conditions
+	for idx, cond := range r.issuer.Status.Conditions {
+		// Skip unrelated conditions
+		if cond.Type != api.ConditionReady {
+			continue
+		}
+
+		// If this update doesn't contain a state transition, we don't update
+		// the conditions LastTransitionTime to Now()
+		if cond.Status == status {
+			c.LastTransitionTime = cond.LastTransitionTime
+		} else {
+			r.logger.Info("found status change for StepIssuer condition; setting lastTransitionTime", "condition", cond.Type, "old_status", cond.Status, "new_status", status, "time", now.Time)
+		}
+
+		// Overwrite the existing condition
+		r.issuer.Status.Conditions[idx] = c
+		return
+	}
+
+	// If we've not found an existing condition of this type, we simply insert
+	// the new condition into the slice.
+	r.issuer.Status.Conditions = append(r.issuer.Status.Conditions, c)
+	r.logger.Info("setting lastTransitionTime for StepIssuer condition", "condition", api.ConditionReady, "time", now.Time)
+}
diff --git a/controllers/stepclusterissuer_controller.go b/controllers/stepclusterissuer_controller.go
index 50bc59d40b45476cbde905ca9101980c2ee6c2ee..8fca0d8e20980b4f6e9f9955d532bb7a3525ee5e 100644
--- a/controllers/stepclusterissuer_controller.go
+++ b/controllers/stepclusterissuer_controller.go
@@ -46,7 +46,7 @@ type StepClusterIssuerReconciler struct {
 
 // Reconcile will read and validate the StepClusterIssuer resources, it will set the
 // status condition ready to true if everything is right.
-func (r *StepClusterIssuerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
+func (r *StepClusterIssuerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := r.Log.WithValues("stepclusterissuer", req.NamespacedName)
 
 	iss := new(api.StepClusterIssuer)
@@ -55,7 +55,7 @@ func (r *StepClusterIssuerReconciler) Reconcile(req ctrl.Request) (ctrl.Result,
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}
 
-	statusReconciler := newStepStatusReconciler(r, iss, log)
+	statusReconciler := newStepStatusClusterReconciler(r, iss, log)
 	if err := validateStepClusterIssuerSpec(iss.Spec); err != nil {
 		log.Error(err, "failed to validate StepClusterIssuer resource")
 		statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "Validation", "Failed to validate resource: %v", err)
@@ -86,7 +86,7 @@ func (r *StepClusterIssuerReconciler) Reconcile(req ctrl.Request) (ctrl.Result,
 	}
 
 	// Initialize and store the provisioner
-	p, err := provisioners.New(iss, password)
+	p, err := provisioners.NewFromStepClusterIssuer(iss, password)
 	if err != nil {
 		log.Error(err, "failed to initialize provisioner")
 		statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "Error", "failed initialize provisioner")
@@ -97,6 +97,8 @@ func (r *StepClusterIssuerReconciler) Reconcile(req ctrl.Request) (ctrl.Result,
 	return ctrl.Result{}, statusReconciler.Update(ctx, api.ConditionTrue, "Verified", "StepClusterIssuer verified and ready to sign certificates")
 }
 
+// SetupWithManager initializes the StepClusterIssuer controller into the controller
+// runtime.
 func (r *StepClusterIssuerReconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&api.StepClusterIssuer{}).
@@ -118,4 +120,4 @@ func validateStepClusterIssuerSpec(s api.StepClusterIssuerSpec) error {
 	default:
 		return nil
 	}
-}
\ No newline at end of file
+}
diff --git a/controllers/stepissuer_controller.go b/controllers/stepissuer_controller.go
index cdbe4dc6ded7aafef44cf0f9525676b8020320ca..e935b3e48c353eb13302eafc24c71cb72444ab50 100644
--- a/controllers/stepissuer_controller.go
+++ b/controllers/stepissuer_controller.go
@@ -87,7 +87,7 @@ func (r *StepIssuerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	}
 
 	// Initialize and store the provisioner
-	p, err := provisioners.New(iss, password)
+	p, err := provisioners.NewFromStepIssuer(iss, password)
 	if err != nil {
 		log.Error(err, "failed to initialize provisioner")
 		statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "Error", "failed initialize provisioner")
diff --git a/controllers/suite_test.go b/controllers/suite_test.go
index d8d6b31e862a838e71c8aae8d6136c9dddd9faff..6fb9465713bbb4387256a5f8b591acce5b9b2dbb 100644
--- a/controllers/suite_test.go
+++ b/controllers/suite_test.go
@@ -30,7 +30,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/envtest"
 	"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
-	"sigs.k8s.io/controller-runtime/pkg/log/zap"	
+	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 	// +kubebuilder:scaffold:imports
 )
 
diff --git a/main.go b/main.go
index 0a9ad46c250f79a31e40142334f315ddeeb08b02..593a4c13a9da6e327f23ed335db5aed3b8a5ac35 100644
--- a/main.go
+++ b/main.go
@@ -89,9 +89,9 @@ func main() {
 	}
 
 	if err = (&controllers.StepClusterIssuerReconciler{
-		Client: mgr.GetClient(),
-		Log:    ctrl.Log.WithName("controllers").WithName("StepClusterIssuer"),
-		Clock:  clock.RealClock{},
+		Client:   mgr.GetClient(),
+		Log:      ctrl.Log.WithName("controllers").WithName("StepClusterIssuer"),
+		Clock:    clock.RealClock{},
 		Recorder: mgr.GetEventRecorderFor("stepclusterissuer-controller"),
 	}).SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "StepClusterIssuer")
diff --git a/provisioners/step.go b/provisioners/step.go
index 440ed34ca484a3f8f803efca726474f10efcaaa9..32d20b3377a17122c1e8894eaf1c2f18bbe572ee 100644
--- a/provisioners/step.go
+++ b/provisioners/step.go
@@ -26,7 +26,34 @@ type Step struct {
 
 // New returns a new Step provisioner, configured with the information in the
 // given issuer.
-func New(iss *api.StepIssuer, password []byte) (*Step, error) {
+func NewFromStepIssuer(iss *api.StepIssuer, password []byte) (*Step, error) {
+	var options []ca.ClientOption
+	if len(iss.Spec.CABundle) > 0 {
+		options = append(options, ca.WithCABundle(iss.Spec.CABundle))
+	}
+	provisioner, err := ca.NewProvisioner(iss.Spec.Provisioner.Name, iss.Spec.Provisioner.KeyID, iss.Spec.URL, password, options...)
+	if err != nil {
+		return nil, err
+	}
+
+	p := &Step{
+		name:        iss.Name + "." + iss.Namespace,
+		provisioner: provisioner,
+	}
+
+	// Request identity certificate if required.
+	if version, err := provisioner.Version(); err == nil {
+		if version.RequireClientAuthentication {
+			if err := p.createIdentityCertificate(); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return p, nil
+}
+
+func NewFromStepClusterIssuer(iss *api.StepClusterIssuer, password []byte) (*Step, error) {
 	var options []ca.ClientOption
 	if len(iss.Spec.CABundle) > 0 {
 		options = append(options, ca.WithCABundle(iss.Spec.CABundle))