Skip to content

Commit

Permalink
refactor: extract generation of signer key and resolver of public key
Browse files Browse the repository at this point in the history
  • Loading branch information
osmman committed Sep 4, 2024
1 parent 64e0bc7 commit 3c9ce56
Show file tree
Hide file tree
Showing 27 changed files with 2,104 additions and 774 deletions.
27 changes: 27 additions & 0 deletions internal/controller/constants/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,33 @@ func LabelsRHTAS() map[string]string {
}
}

func AddLabel(ctx context.Context, object *metav1.PartialObjectMetadata, c client.Client, label string, value string) error {
object.SetGroupVersionKind(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "Secret",
})
patch, err := json.Marshal([]map[string]any{
{
"op": "add",
"path": "/metadata/labels",
"value": map[string]string{
label: value,
},
},
})
if err != nil {
return fmt.Errorf("failed to marshal patch: %v", err)
}

err = c.Patch(ctx, object, client.RawPatch(types.JSONPatchType, patch))
if err != nil {
return fmt.Errorf("unable to add '%s' label to object: %w", label, err)
}

return nil
}

func RemoveLabel(ctx context.Context, object *metav1.PartialObjectMetadata, c client.Client, label string) error {
object.SetGroupVersionKind(schema.GroupVersionKind{
Group: "",
Expand Down
8 changes: 6 additions & 2 deletions internal/controller/ctlog/actions/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ const (
RBACName = "ctlog"
MonitoringRoleName = "prometheus-k8s-ctlog"

CertCondition = "FulcioCertAvailable"
SignerCondition = "SignerAvailable"
CertCondition = "FulcioCertAvailable"
ServerConfigCondition = "ServerConfigAvailable"
PublicKeyCondition = "PublicKeyAvailable"
TreeCondition = "TreeAvailable"

ServerPortName = "http"
ServerPort = 80
ServerTargetPort = 6962
MetricsPortName = "metrics"
MetricsPort = 6963
ServerCondition = "ServerAvailable"

CTLPubLabel = constants.LabelNamespace + "/ctfe.pub"
)
151 changes: 151 additions & 0 deletions internal/controller/ctlog/actions/generate_signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package actions

import (
"context"
"errors"
"fmt"

"github.com/securesign/operator/internal/controller/ctlog/utils"

"github.com/securesign/operator/api/v1alpha1"
"github.com/securesign/operator/internal/controller/common/action"
k8sutils "github.com/securesign/operator/internal/controller/common/utils/kubernetes"
"github.com/securesign/operator/internal/controller/constants"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const KeySecretNameFormat = "ctlog-%s-keys-"

var (
ErrGenerateSignerKey = errors.New("failed to generate signer key")
ErrParseSignerKey = errors.New("failed to parse signer key")
)

func NewGenerateSignerAction() action.Action[*v1alpha1.CTlog] {
return &generateSigner{}
}

type generateSigner struct {
action.BaseAction
}

func (g generateSigner) Name() string {
return "generate-signer"
}

func (g generateSigner) CanHandle(_ context.Context, instance *v1alpha1.CTlog) bool {

if instance.Status.PrivateKeyRef == nil {
return true
}

if !equality.Semantic.DeepDerivative(instance.Spec.PrivateKeyRef, instance.Status.PrivateKeyRef) {
return true
}

if !equality.Semantic.DeepDerivative(instance.Spec.PrivateKeyPasswordRef, instance.Status.PrivateKeyPasswordRef) {
return true
}

return !meta.IsStatusConditionTrue(instance.Status.Conditions, SignerCondition)
}

func (g generateSigner) Handle(ctx context.Context, instance *v1alpha1.CTlog) *action.Result {
// Force to change SignerCondition when spec has changed
if meta.IsStatusConditionTrue(instance.Status.Conditions, SignerCondition) {
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
Type: SignerCondition,
Status: metav1.ConditionFalse,
Reason: constants.Pending,
Message: "resolving signer key",
})
return g.StatusUpdate(ctx, instance)
}

if instance.Spec.PrivateKeyRef != nil {
instance.Status.PrivateKeyRef = instance.Spec.PrivateKeyRef
if instance.Spec.PrivateKeyPasswordRef != nil {
instance.Status.PrivateKeyPasswordRef = instance.Spec.PrivateKeyPasswordRef
}

g.Recorder.Eventf(instance, v1.EventTypeNormal, "SignerKeyCreated", "Using signer key from `%s` secret", instance.Spec.PrivateKeyRef.Name)
} else {

var (
err error
)

config, err := utils.NewSignerConfig(utils.WithGeneratedKey())
if err != nil {
return g.Failed(fmt.Errorf("%w: %w", ErrGenerateSignerKey, err))
}

labels := constants.LabelsFor(ComponentName, DeploymentName, instance.Name)

privateKey, err := config.PrivateKeyPEM()
if err != nil {
return g.Failed(fmt.Errorf("%w, %w", ErrParseSignerKey, err))
}
password := config.PrivateKeyPassword()

data := map[string][]byte{
"private": privateKey,
"password": password,
}

secret := k8sutils.CreateImmutableSecret(fmt.Sprintf(KeySecretNameFormat, instance.Name), instance.Namespace,
data, labels)
if _, err = g.Ensure(ctx, secret); err != nil {
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
Type: SignerCondition,
Status: metav1.ConditionFalse,
Reason: constants.Failure,
Message: err.Error(),
})
return g.FailedWithStatusUpdate(ctx, fmt.Errorf("could not create secret: %w", err), instance)
}
g.Recorder.Eventf(instance, v1.EventTypeNormal, "SignerKeyCreated", "Signer private key created: %s", secret.Name)

instance.Status.PrivateKeyRef = &v1alpha1.SecretKeySelector{
Key: "private",
LocalObjectReference: v1alpha1.LocalObjectReference{
Name: secret.Name,
},
}

if len(secret.Data["password"]) > 0 && instance.Spec.PrivateKeyPasswordRef == nil {
instance.Status.PrivateKeyPasswordRef = &v1alpha1.SecretKeySelector{
Key: "password",
LocalObjectReference: v1alpha1.LocalObjectReference{
Name: secret.Name,
},
}
} else {
instance.Status.PrivateKeyPasswordRef = instance.Spec.PrivateKeyPasswordRef
}
}

// invalidate server config
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
Type: ServerConfigCondition,
Status: metav1.ConditionFalse,
Reason: constants.Pending,
Message: "signer key changed",
})
// invalidate public key
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
Type: PublicKeyCondition,
Status: metav1.ConditionFalse,
Reason: constants.Pending,
Message: "signer key changed",
})
meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{
Type: SignerCondition,
Status: metav1.ConditionTrue,
Reason: constants.Ready,
})
return g.StatusUpdate(ctx, instance)
}
Loading

0 comments on commit 3c9ce56

Please sign in to comment.