Skip to content
Snippets Groups Projects
Unverified Commit b11b091c authored by Christian Wolf's avatar Christian Wolf Committed by Tobias Gurtzick
Browse files

adapt files for stepclusterissuer

parent 32f66b86
No related branches found
No related tags found
No related merge requests found
......@@ -22,19 +22,33 @@ import (
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
func init() {
SchemeBuilder.Register(&StepClusterIssuer{}, &StepClusterIssuerList{})
}
// StepClusterIssuerSpec defines the desired state of StepClusterIssuer
type StepClusterIssuerSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Foo is an example field of StepClusterIssuer. Edit StepClusterIssuer_types.go to remove/update
Foo string `json:"foo,omitempty"`
// URL is the base URL for the step certificates instance.
URL string `json:"url"`
// Provisioner contains the step certificates provisioner configuration.
Provisioner StepProvisioner `json:"provisioner"`
// 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.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
}
// StepClusterIssuerStatus defines the observed state of StepClusterIssuer
type StepClusterIssuerStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
Conditions []StepClusterIssuerCondition `json:"conditions,omitempty"`
}
// +kubebuilder:object:root=true
......@@ -58,6 +72,80 @@ type StepClusterIssuerList struct {
Items []StepClusterIssuer `json:"items"`
}
func init() {
SchemeBuilder.Register(&StepClusterIssuer{}, &StepClusterIssuerList{})
// 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').
Type ConditionType `json:"type"`
// Status of the condition, one of ('True', 'False', 'Unknown').
// +kubebuilder:validation:Enum=True;False;Unknown
Status ConditionStatus `json:"status"`
// LastTransitionTime is the timestamp corresponding to the last status
// change of this condition.
// +optional
LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"`
// Reason is a brief machine readable explanation for the condition's last
// transition.
// +optional
Reason string `json:"reason,omitempty"`
// Message is a human readable description of the details of the last
// transition, complementing reason.
// +optional
Message string `json:"message,omitempty"`
}
\ No newline at end of file
......@@ -12,3 +12,4 @@ rules:
- approve
resourceNames:
- stepissuers.certmanager.step.sm/*
- stepclusterissuers.certmanager.step.sm/*
......@@ -42,6 +42,7 @@ rules:
- certmanager.step.sm
resources:
- stepissuers
- stepclusterissuers
verbs:
- create
- delete
......@@ -54,6 +55,7 @@ rules:
- certmanager.step.sm
resources:
- stepissuers/status
- stepclusterissuers/status
verbs:
- get
- patch
......
# permissions for end users to edit stepclusterissuers.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: stepclusterissuer-editor-role
rules:
- apiGroups:
- certmanager.step.sm
resources:
- stepclusterissuers
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- certmanager.step.sm
resources:
- stepclusterissuers/status
verbs:
- get
# permissions for end users to view stepclusterissuers.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: stepclusterissuer-viewer-role
rules:
- apiGroups:
- certmanager.step.sm
resources:
- stepclusterissuers
verbs:
- get
- list
- watch
- apiGroups:
- certmanager.step.sm
resources:
- stepclusterissuers/status
verbs:
- get
apiVersion: certmanager.step.sm/v1beta1
kind: StepClusterIssuer
metadata:
name: stepclusterissuer-sample
spec:
# Add fields here
foo: bar
apiVersion: certmanager.step.sm/v1beta1
kind: StepClusterIssuer
metadata:
name: step-cluster-issuer
spec:
# The CA URL.
url: https://step-certificates.default.svc.cluster.local
# The base64 encoded version of the CA root certificate in PEM format.
caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpekNDQVRHZ0F3SUJBZ0lRTytFQWg4eS8wVjlQMFhwSHJWajVOVEFLQmdncWhrak9QUVFEQWpBa01TSXcKSUFZRFZRUURFeGxUZEdWd0lFTmxjblJwWm1sallYUmxjeUJTYjI5MElFTkJNQjRYRFRFNU1EZ3hNekU1TVRVdwpNbG9YRFRJNU1EZ3hNREU1TVRVd01sb3dKREVpTUNBR0ExVUVBeE1aVTNSbGNDQkRaWEowYVdacFkyRjBaWE1nClVtOXZkQ0JEUVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkFNVkw3VzBQbTNvSlVmSTR3WGQKa2xERW5uNVhTbWo4NlgwYW1DQTBnY08xdElUUG1DVzNCcGU0cE9vV1V2WlZlUWRvU2NxN3pua1V0Mi9HMnQxTgo3MWlqUlRCRE1BNEdBMVVkRHdFQi93UUVBd0lCQmpBU0JnTlZIUk1CQWY4RUNEQUdBUUgvQWdFQk1CMEdBMVVkCkRnUVdCQlJ1Y1ByVm5QdlpOMHI0QVU5TGcyL2VCcng3a2pBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlCUlJBdGsKNXpMY0doQ2FobVBuVzIwZExpdEMzRVdNaVE0bERwN2FFeitFUEFJaEFJOWZWczVxb0l0bVQ4anA2WktVNVEydQphRFBrOGsyQ25OMjdyRnNZV3VwTAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
# The provisioner name, kid, and a reference to the provisioner password secret.
provisioner:
name: admin
kid: N6I99Yuk7iGDMk_eW3QaN2admCsrC9UuDN27dlFXUOs
passwordRef:
name: step-certificates-provisioner-password
key: password
\ No newline at end of file
......@@ -17,36 +17,105 @@ package controllers
import (
"context"
"fmt"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
api "github.com/smallstep/step-issuer/api/v1beta1"
"github.com/smallstep/step-issuer/provisioners"
core "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
"k8s.io/utils/clock"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
certmanagerv1beta1 "github.com/smallstep/step-issuer/api/v1beta1"
)
// StepClusterIssuerReconciler reconciles a StepClusterIssuer object
type StepClusterIssuerReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Log logr.Logger
Clock clock.Clock
Recorder record.EventRecorder
}
// +kubebuilder:rbac:groups=certmanager.step.sm,resources=stepclusterissuers,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=certmanager.step.sm,resources=stepclusterissuers/status,verbs=get;update;patch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
// 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) {
_ = context.Background()
_ = r.Log.WithValues("stepclusterissuer", req.NamespacedName)
log := r.Log.WithValues("stepclusterissuer", req.NamespacedName)
iss := new(api.StepClusterIssuer)
if err := r.Client.Get(ctx, req.NamespacedName, iss); err != nil {
log.Error(err, "failed to retrieve StepClusterIssuer resource")
return ctrl.Result{}, client.IgnoreNotFound(err)
}
statusReconciler := newStepStatusReconciler(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)
return ctrl.Result{}, err
}
// your logic here
// Fetch the provisioner password
var secret core.Secret
secretNamespaceName := types.NamespacedName{
Namespace: req.Namespace,
Name: iss.Spec.Provisioner.PasswordRef.Name,
}
if err := r.Client.Get(ctx, secretNamespaceName, &secret); err != nil {
log.Error(err, "failed to retrieve StepClusterIssuer provisioner secret", "namespace", secretNamespaceName.Namespace, "name", secretNamespaceName.Name)
if apierrors.IsNotFound(err) {
statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "NotFound", "Failed to retrieve provisioner secret: %v", err)
} else {
statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "Error", "Failed to retrieve provisioner secret: %v", err)
}
return ctrl.Result{}, err
}
password, ok := secret.Data[iss.Spec.Provisioner.PasswordRef.Key]
if !ok {
err := fmt.Errorf("secret %s does not contain key %s", secret.Name, iss.Spec.Provisioner.PasswordRef.Key)
log.Error(err, "failed to retrieve StepClusterIssuer provisioner secret", "namespace", secretNamespaceName.Namespace, "name", secretNamespaceName.Name)
statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "NotFound", "Failed to retrieve provisioner secret: %v", err)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
// Initialize and store the provisioner
p, err := provisioners.New(iss, password)
if err != nil {
log.Error(err, "failed to initialize provisioner")
statusReconciler.UpdateNoError(ctx, api.ConditionFalse, "Error", "failed initialize provisioner")
return ctrl.Result{}, err
}
provisioners.Store(req.NamespacedName, p)
return ctrl.Result{}, statusReconciler.Update(ctx, api.ConditionTrue, "Verified", "StepClusterIssuer verified and ready to sign certificates")
}
func (r *StepClusterIssuerReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&certmanagerv1beta1.StepClusterIssuer{}).
For(&api.StepClusterIssuer{}).
Complete(r)
}
func validateStepClusterIssuerSpec(s api.StepClusterIssuerSpec) error {
switch {
case s.URL == "":
return fmt.Errorf("spec.url cannot be empty")
case s.Provisioner.Name == "":
return fmt.Errorf("spec.provisioner.name cannot be empty")
case s.Provisioner.KeyID == "":
return fmt.Errorf("spec.provisioner.kid cannot be empty")
case s.Provisioner.PasswordRef.Name == "":
return fmt.Errorf("spec.provisioner.passwordRef.name cannot be empty")
case s.Provisioner.PasswordRef.Key == "":
return fmt.Errorf("spec.provisioner.passwordRef.key cannot be empty")
default:
return nil
}
}
\ No newline at end of file
......@@ -88,6 +88,16 @@ func main() {
os.Exit(1)
}
if err = (&controllers.StepClusterIssuerReconciler{
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")
os.Exit(1)
}
if err = (&controllers.CertificateRequestReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("CertificateRequest"),
......@@ -99,14 +109,6 @@ func main() {
os.Exit(1)
}
if err = (&controllers.StepClusterIssuerReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("StepClusterIssuer"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "StepClusterIssuer")
os.Exit(1)
}
// +kubebuilder:scaffold:builder
setupLog.Info("starting manager")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment