diff --git a/api/v1alpha1/common.go b/api/v1alpha1/common.go index 3bb8edbd..a8d3940d 100644 --- a/api/v1alpha1/common.go +++ b/api/v1alpha1/common.go @@ -21,6 +21,19 @@ type MonitoringConfig struct { Enabled bool `json:"enabled"` } +// TrillianService configuration to connect Trillian server +type TrillianService struct { + // Address to Trillian Log Server End point + //+optional + Address string `json:"address,omitempty"` + // Port of Trillian Log Server End point + //+kubebuilder:validation:Minimum:=1 + //+kubebuilder:validation:Maximum:=65535 + //+kubebuilder:default:=8091 + //+optional + Port *int32 `json:"port,omitempty"` +} + // LocalObjectReference contains enough information to let you locate the // referenced object inside the same namespace. // +structType=atomic diff --git a/api/v1alpha1/rekor_types.go b/api/v1alpha1/rekor_types.go index 7c36c325..c5663684 100644 --- a/api/v1alpha1/rekor_types.go +++ b/api/v1alpha1/rekor_types.go @@ -13,6 +13,8 @@ type RekorSpec struct { // If it is unset, the operator will create new Merkle tree in the Trillian backend //+optional TreeID *int64 `json:"treeID,omitempty"` + // Trillian service configuration + Trillian TrillianService `json:"trillian,omitempty"` // Define whether you want to export service or not ExternalAccess ExternalAccess `json:"externalAccess,omitempty"` //Enable Service monitors for rekor diff --git a/api/v1alpha1/rekor_types_test.go b/api/v1alpha1/rekor_types_test.go index e9660ad8..0f52cbc9 100644 --- a/api/v1alpha1/rekor_types_test.go +++ b/api/v1alpha1/rekor_types_test.go @@ -198,6 +198,7 @@ var _ = Describe("Rekor", func() { It("outputs the CR", func() { storage := k8sresource.MustParse("987Gi") tree := int64(1269875) + port := int32(8091) rekorInstance = Rekor{ ObjectMeta: metav1.ObjectMeta{ @@ -241,6 +242,10 @@ var _ = Describe("Rekor", func() { Key: "key", }, }, + Trillian: TrillianService{ + Address: "trillian-system.default.svc", + Port: &port, + }, }, } @@ -254,7 +259,6 @@ var _ = Describe("Rekor", func() { When("CR is partially set", func() { It("sets spec.pvc.storage if spec.pvc is partially set", func() { - rekorInstance = Rekor{ ObjectMeta: metav1.ObjectMeta{ Name: "rekor-storage", @@ -300,6 +304,9 @@ func generateRekorObject(name string) *Rekor { Retain: utils.Pointer(true), Size: &storage, }, + Trillian: TrillianService{ + Port: utils.Pointer(int32(8091)), + }, }, } } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 90e5fbe2..a241f701 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -564,6 +564,7 @@ func (in *RekorSpec) DeepCopyInto(out *RekorSpec) { *out = new(int64) **out = **in } + in.Trillian.DeepCopyInto(&out.Trillian) out.ExternalAccess = in.ExternalAccess out.Monitoring = in.Monitoring in.RekorSearchUI.DeepCopyInto(&out.RekorSearchUI) @@ -865,6 +866,26 @@ func (in *TrillianList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrillianService) DeepCopyInto(out *TrillianService) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrillianService. +func (in *TrillianService) DeepCopy() *TrillianService { + if in == nil { + return nil + } + out := new(TrillianService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TrillianSpec) DeepCopyInto(out *TrillianSpec) { *out = *in diff --git a/bundle/manifests/rhtas-operator.clusterserviceversion.yaml b/bundle/manifests/rhtas-operator.clusterserviceversion.yaml index 1da8d6cf..998f7dc9 100644 --- a/bundle/manifests/rhtas-operator.clusterserviceversion.yaml +++ b/bundle/manifests/rhtas-operator.clusterserviceversion.yaml @@ -192,7 +192,7 @@ metadata: ] capabilities: Seamless Upgrades containerImage: registry.redhat.io/rhtas/rhtas-rhel9-operator@sha256:a21f7128694a64989bf0d84a7a7da4c1ffc89edf62d594dc8bea7bcfe9ac08d3 - createdAt: "2024-05-28T11:15:21Z" + createdAt: "2024-06-03T14:37:13Z" features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" features.operators.openshift.io/csi: "false" @@ -204,7 +204,7 @@ metadata: features.operators.openshift.io/token-auth-azure: "false" features.operators.openshift.io/token-auth-gcp: "false" operators.openshift.io/valid-subscription: '["Red Hat Trusted Artifact Signer"]' - operators.operatorframework.io/builder: operator-sdk-v1.34.1 + operators.operatorframework.io/builder: operator-sdk-v1.34.2 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/securesign/secure-sign-operator support: Red Hat diff --git a/bundle/manifests/rhtas.redhat.com_rekors.yaml b/bundle/manifests/rhtas.redhat.com_rekors.yaml index 7dfc7fad..69840e28 100644 --- a/bundle/manifests/rhtas.redhat.com_rekors.yaml +++ b/bundle/manifests/rhtas.redhat.com_rekors.yaml @@ -204,6 +204,20 @@ spec: If it is unset, the operator will create new Merkle tree in the Trillian backend format: int64 type: integer + trillian: + description: Trillian service configuration + properties: + address: + description: Address to Trillian Log Server End point + type: string + port: + default: 8091 + description: Port of Trillian Log Server End point + format: int32 + maximum: 65535 + minimum: 1 + type: integer + type: object type: object status: description: RekorStatus defines the observed state of Rekor diff --git a/bundle/manifests/rhtas.redhat.com_securesigns.yaml b/bundle/manifests/rhtas.redhat.com_securesigns.yaml index 51225a2b..0081cdad 100644 --- a/bundle/manifests/rhtas.redhat.com_securesigns.yaml +++ b/bundle/manifests/rhtas.redhat.com_securesigns.yaml @@ -551,6 +551,20 @@ spec: If it is unset, the operator will create new Merkle tree in the Trillian backend format: int64 type: integer + trillian: + description: Trillian service configuration + properties: + address: + description: Address to Trillian Log Server End point + type: string + port: + default: 8091 + description: Port of Trillian Log Server End point + format: int32 + maximum: 65535 + minimum: 1 + type: integer + type: object type: object trillian: description: TrillianSpec defines the desired state of Trillian diff --git a/config/crd/bases/rhtas.redhat.com_rekors.yaml b/config/crd/bases/rhtas.redhat.com_rekors.yaml index 5d89022f..c6023a48 100644 --- a/config/crd/bases/rhtas.redhat.com_rekors.yaml +++ b/config/crd/bases/rhtas.redhat.com_rekors.yaml @@ -204,6 +204,20 @@ spec: If it is unset, the operator will create new Merkle tree in the Trillian backend format: int64 type: integer + trillian: + description: Trillian service configuration + properties: + address: + description: Address to Trillian Log Server End point + type: string + port: + default: 8091 + description: Port of Trillian Log Server End point + format: int32 + maximum: 65535 + minimum: 1 + type: integer + type: object type: object status: description: RekorStatus defines the observed state of Rekor diff --git a/config/crd/bases/rhtas.redhat.com_securesigns.yaml b/config/crd/bases/rhtas.redhat.com_securesigns.yaml index d8b1df23..44acb39c 100644 --- a/config/crd/bases/rhtas.redhat.com_securesigns.yaml +++ b/config/crd/bases/rhtas.redhat.com_securesigns.yaml @@ -551,6 +551,20 @@ spec: If it is unset, the operator will create new Merkle tree in the Trillian backend format: int64 type: integer + trillian: + description: Trillian service configuration + properties: + address: + description: Address to Trillian Log Server End point + type: string + port: + default: 8091 + description: Port of Trillian Log Server End point + format: int32 + maximum: 65535 + minimum: 1 + type: integer + type: object type: object trillian: description: TrillianSpec defines the desired state of Trillian diff --git a/controllers/rekor/actions/pending.go b/controllers/rekor/actions/pending.go deleted file mode 100644 index ebe79ce1..00000000 --- a/controllers/rekor/actions/pending.go +++ /dev/null @@ -1,48 +0,0 @@ -package actions - -import ( - "context" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - "github.com/securesign/operator/controllers/common/action" - utils "github.com/securesign/operator/controllers/common/utils/kubernetes" - "github.com/securesign/operator/controllers/constants" - trillian "github.com/securesign/operator/controllers/trillian/actions" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func NewPendingAction() action.Action[rhtasv1alpha1.Rekor] { - return &pendingAction{} -} - -type pendingAction struct { - action.BaseAction -} - -func (i pendingAction) Name() string { - return "pending" -} - -func (i pendingAction) CanHandle(_ context.Context, instance *rhtasv1alpha1.Rekor) bool { - c := meta.FindStatusCondition(instance.Status.Conditions, constants.Ready) - return c.Reason == constants.Pending -} - -func (i pendingAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Rekor) *action.Result { - var err error - _, err = utils.GetInternalUrl(ctx, i.Client, instance.Namespace, trillian.LogserverDeploymentName) - if err != nil { - meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{ - Type: constants.Ready, - Status: metav1.ConditionFalse, - Reason: constants.Pending, - Message: "Waiting for Trillian Logserver service", - }) - i.StatusUpdate(ctx, instance) - return i.Requeue() - } - - return i.Continue() - -} diff --git a/controllers/rekor/actions/server/createTree.go b/controllers/rekor/actions/server/createTree.go index e352f205..26dd722b 100644 --- a/controllers/rekor/actions/server/createTree.go +++ b/controllers/rekor/actions/server/createTree.go @@ -3,14 +3,14 @@ package server import ( "context" "fmt" - + "github.com/google/trillian" rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" "github.com/securesign/operator/controllers/common" "github.com/securesign/operator/controllers/common/action" - k8sutils "github.com/securesign/operator/controllers/common/utils/kubernetes" "github.com/securesign/operator/controllers/constants" "github.com/securesign/operator/controllers/rekor/actions" - trillian "github.com/securesign/operator/controllers/trillian/actions" + "github.com/securesign/operator/controllers/rekor/utils" + actions2 "github.com/securesign/operator/controllers/trillian/actions" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -39,12 +39,20 @@ func (i createTrillianTreeAction) Handle(ctx context.Context, instance *rhtasv1a return i.StatusUpdate(ctx, instance) } var err error + var tree *trillian.Tree + var trillUrl string - trillUrl, err := k8sutils.GetInternalUrl(ctx, i.Client, instance.Namespace, trillian.LogserverDeploymentName) - if err != nil { - return i.Failed(err) + switch { + case instance.Spec.Trillian.Port == nil: + err = fmt.Errorf("%s: %w", i.Name(), utils.TrillianPortNotSpecified) + case instance.Spec.Trillian.Address == "": + trillUrl = fmt.Sprintf("%s.%s.svc:%d", actions2.LogserverDeploymentName, instance.Namespace, instance.Spec.Trillian.Port) + i.Logger.V(1).Info("trillian logserver", "address", trillUrl) + default: + trillUrl = fmt.Sprintf("%s:%d", instance.Spec.Trillian.Address, instance.Spec.Trillian.Port) } - tree, err := common.CreateTrillianTree(ctx, "rekor-tree", trillUrl+":8091") + + tree, err = common.CreateTrillianTree(ctx, "rekor-tree", trillUrl) if err != nil { meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{ Type: actions.ServerCondition, diff --git a/controllers/rekor/actions/server/deployment.go b/controllers/rekor/actions/server/deployment.go index b73f1370..3faffa24 100644 --- a/controllers/rekor/actions/server/deployment.go +++ b/controllers/rekor/actions/server/deployment.go @@ -3,6 +3,7 @@ package server import ( "context" "fmt" + actions2 "github.com/securesign/operator/controllers/trillian/actions" "github.com/securesign/operator/controllers/common/action" "github.com/securesign/operator/controllers/constants" @@ -38,7 +39,14 @@ func (i deployAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Rekor) updated bool ) labels := constants.LabelsFor(actions.ServerComponentName, actions.ServerDeploymentName, instance.Name) - dp, err := utils.CreateRekorDeployment(instance, actions.ServerDeploymentName, actions.RBACName, labels) + + insCopy := instance.DeepCopy() + if insCopy.Spec.Trillian.Address == "" { + insCopy.Spec.Trillian.Address = fmt.Sprintf("%s.%s.svc", actions2.LogserverDeploymentName, instance.Namespace) + } + i.Logger.V(1).Info("trillian logserver", "address", insCopy.Spec.Trillian.Address) + dp, err := utils.CreateRekorDeployment(insCopy, actions.ServerDeploymentName, actions.RBACName, labels) + if err != nil { meta.SetStatusCondition(&instance.Status.Conditions, metav1.Condition{ Type: actions.ServerCondition, diff --git a/controllers/rekor/rekor_controller.go b/controllers/rekor/rekor_controller.go index 48998b84..53f99dfb 100644 --- a/controllers/rekor/rekor_controller.go +++ b/controllers/rekor/rekor_controller.go @@ -90,8 +90,6 @@ func (r *RekorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl // NONE -> PENDING actions2.NewInitializeConditions(), - // PENDING - actions2.NewPendingAction(), // PENDING -> CREATE server.NewGenerateSignerAction(), diff --git a/controllers/rekor/rekor_controller_test.go b/controllers/rekor/rekor_controller_test.go index 2c1d0bf6..a48b2803 100644 --- a/controllers/rekor/rekor_controller_test.go +++ b/controllers/rekor/rekor_controller_test.go @@ -23,11 +23,9 @@ import ( "github.com/securesign/operator/controllers/common/utils" "github.com/securesign/operator/api/v1alpha1" - "github.com/securesign/operator/controllers/common/utils/kubernetes" "github.com/securesign/operator/controllers/constants" "github.com/securesign/operator/controllers/rekor/actions" "github.com/securesign/operator/controllers/rekor/actions/server" - trillian "github.com/securesign/operator/controllers/trillian/actions" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -128,15 +126,6 @@ var _ = Describe("Rekor controller", func() { return meta.IsStatusConditionPresentAndEqual(found.Status.Conditions, constants.Ready, metav1.ConditionFalse) }, time.Minute, time.Second).Should(BeTrue()) - Eventually(func() string { - found := &v1alpha1.Rekor{} - Expect(k8sClient.Get(ctx, typeNamespaceName, found)).Should(Succeed()) - return meta.FindStatusCondition(found.Status.Conditions, constants.Ready).Reason - }, time.Minute, time.Second).Should(Equal(constants.Pending)) - - By("Move to CreatingPhase by creating trillian service") - Expect(k8sClient.Create(ctx, kubernetes.CreateService(Namespace, trillian.LogserverDeploymentName, 8091, constants.LabelsForComponent(trillian.LogServerComponentName, instance.Name)))).To(Succeed()) - By("Rekor signer created") found := &v1alpha1.Rekor{} Eventually(func() *v1alpha1.SecretKeySelector { diff --git a/controllers/rekor/utils/errors.go b/controllers/rekor/utils/errors.go new file mode 100644 index 00000000..e7d475b0 --- /dev/null +++ b/controllers/rekor/utils/errors.go @@ -0,0 +1,11 @@ +package utils + +import "errors" + +var ( + ServerConfigNotSpecified = errors.New("server config name not specified") + TreeNotSpecified = errors.New("tree not specified") + TrillianAddressNotSpecified = errors.New("trillian address not specified") + TrillianPortNotSpecified = errors.New("trillian port not specified") + SignerKeyNotSpecified = errors.New("signer key reference not specified") +) diff --git a/controllers/rekor/utils/rekor_deployment.go b/controllers/rekor/utils/rekor_deployment.go index 63ca3fa0..d1b8e566 100644 --- a/controllers/rekor/utils/rekor_deployment.go +++ b/controllers/rekor/utils/rekor_deployment.go @@ -1,7 +1,6 @@ package utils import ( - "errors" "fmt" "github.com/securesign/operator/api/v1alpha1" @@ -12,17 +11,23 @@ import ( ) func CreateRekorDeployment(instance *v1alpha1.Rekor, dpName string, sa string, labels map[string]string) (*apps.Deployment, error) { - if instance.Status.ServerConfigRef == nil { - return nil, errors.New("server config name not specified") - } - if instance.Status.TreeID == nil { - return nil, errors.New("reference to trillian TreeID not set") + switch { + case instance.Status.ServerConfigRef == nil: + return nil, fmt.Errorf("CreateRekorDeployment: %w", ServerConfigNotSpecified) + case instance.Status.TreeID == nil: + return nil, fmt.Errorf("CreateRekorDeployment: %w", TreeNotSpecified) + case instance.Spec.Trillian.Address == "": + return nil, fmt.Errorf("CreateRekorDeployment: %w", TrillianAddressNotSpecified) + case instance.Spec.Trillian.Port == nil: + return nil, fmt.Errorf("CreateRekorDeployment: %w", TrillianPortNotSpecified) } + env := make([]core.EnvVar, 0) + appArgs := []string{ "serve", - "--trillian_log_server.address=trillian-logserver." + instance.Namespace + ".svc", - "--trillian_log_server.port=8091", + "--trillian_log_server.address=" + instance.Spec.Trillian.Address, + fmt.Sprintf("--trillian_log_server.port=%d", *instance.Spec.Trillian.Port), "--trillian_log_server.sharding_config=/sharding/sharding-config.yaml", "--redis_server.address=rekor-redis", "--redis_server.port=6379", @@ -71,7 +76,7 @@ func CreateRekorDeployment(instance *v1alpha1.Rekor, dpName string, sa string, l // KMS secret if instance.Spec.Signer.KMS == "secret" || instance.Spec.Signer.KMS == "" { if instance.Status.Signer.KeyRef == nil { - return nil, errors.New("signer key ref not specified") + return nil, SignerKeyNotSpecified } svsPrivate := &core.SecretVolumeSource{ SecretName: instance.Status.Signer.KeyRef.Name,