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

first compiling version

parent b11b091c
No related branches found
No related tags found
No related merge requests found
......@@ -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
}
......@@ -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.
......
---
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: []
......@@ -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').
......
......@@ -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
......
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)
}
......@@ -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
}
......@@ -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")
......
......@@ -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
)
......
......@@ -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")
......
......@@ -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))
......
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