Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ type TrillianService struct {
Port *int32 `json:"port,omitempty"`
}

// TufService configuration to connect TUF server
type TufService struct {
// Address to TUF Server End point
//+optional
Address string `json:"address,omitempty"`
// Port of TUF Server End point
//+kubebuilder:validation:Minimum:=1
//+kubebuilder:validation:Maximum:=65535
//+kubebuilder:default:=8080
//+optional
Port *int32 `json:"port,omitempty"`
}

// CtlogService configuration to connect Ctlog server
type CtlogService struct {
// Address to Ctlog Log Server End point
Expand Down
3 changes: 3 additions & 0 deletions api/v1alpha1/rekor_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ type RekorSpec struct {
// Trillian service configuration
//+kubebuilder:default:={port: 8091}
Trillian TrillianService `json:"trillian,omitempty"`
// TUF service configuration
//+kubebuilder:default:={port: 8080}
Tuf TufService `json:"tuf,omitempty"`
// Define whether you want to export service or not
ExternalAccess ExternalAccess `json:"externalAccess,omitempty"`
//Enable Service monitors for rekor
Expand Down
16 changes: 16 additions & 0 deletions config/crd/bases/rhtas.redhat.com_rekors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2705,6 +2705,22 @@ spec:
- name
type: object
x-kubernetes-map-type: atomic
tuf:
default:
port: 8080
description: TUF service configuration
properties:
address:
description: Address to TUF Server End point
type: string
port:
default: 8080
description: Port of TUF Server End point
format: int32
maximum: 65535
minimum: 1
type: integer
type: object
type: object
status:
description: RekorStatus defines the observed state of Rekor
Expand Down
16 changes: 16 additions & 0 deletions config/crd/bases/rhtas.redhat.com_securesigns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5325,6 +5325,22 @@ spec:
- name
type: object
x-kubernetes-map-type: atomic
tuf:
default:
port: 8080
description: TUF service configuration
properties:
address:
description: Address to TUF Server End point
type: string
port:
default: 8080
description: Port of TUF Server End point
format: int32
maximum: 65535
minimum: 1
type: integer
type: object
type: object
trillian:
description: TrillianSpec defines the desired state of Trillian
Expand Down
2 changes: 1 addition & 1 deletion config/default/images.env
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ RELATED_IMAGE_HTTP_SERVER=registry.redhat.io/ubi9/httpd-24@sha256:ab5885d4368f83
RELATED_IMAGE_SEGMENT_REPORTING=registry.redhat.io/rhtas/segment-reporting-rhel9@sha256:e1790a0cac5eadef484e10d8f3f7ef6af9bdfabec4ab9fcc35c5ebd42b0205b3
RELATED_IMAGE_TIMESTAMP_AUTHORITY=registry.redhat.io/rhtas/timestamp-authority-rhel9@sha256:be623422f3f636c39397a66416b02a79f1d59cf593ca258e1701d1728755dde9
RELATED_IMAGE_CLIENT_SERVER=registry.redhat.io/rhtas/client-server-rhel9@sha256:c81aaa8f300021d7cdbb964524fc5e89ea2c79fdab5507f0ec036bf96b219332
RELATED_IMAGE_REKOR_MONITOR=registry.redhat.io/rhtas/rekor-monitor-rhel9@sha256:1944eff9f103d84380b9efac6adec9cb22613643968e51f07db58df977b6b982
RELATED_IMAGE_REKOR_MONITOR=registry.redhat.io/rhtas/rekor-monitor-rhel9@sha256:b7f9f8b24fe7db4e124f9e5e9289bc2d180a810e253f48feb7e1177bbef6d4d0
57 changes: 45 additions & 12 deletions internal/controller/rekor/actions/monitor/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import (

"github.com/securesign/operator/internal/images"

rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1"
"github.com/securesign/operator/internal/action"
"github.com/securesign/operator/internal/constants"
"github.com/securesign/operator/internal/controller/rekor/actions"
tufConstants "github.com/securesign/operator/internal/controller/tuf/constants"
"github.com/securesign/operator/internal/labels"
cutils "github.com/securesign/operator/internal/utils"
"github.com/securesign/operator/internal/utils/kubernetes"
Expand All @@ -21,11 +23,13 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1"
)

const storageVolumeName = "monitor-storage"
const (
storageVolumeName = "monitor-storage"
tufRepoVolumeName = "tuf-repository"
mountPath = "/data"
)

func NewStatefulSetAction() action.Action[*rhtasv1alpha1.Rekor] {
return &statefulSetAction{}
Expand All @@ -50,6 +54,11 @@ func (i statefulSetAction) Handle(ctx context.Context, instance *rhtasv1alpha1.R
result controllerutil.OperationResult
)

switch instance.Spec.Tuf.Address {
case "":
instance.Spec.Tuf.Address = fmt.Sprintf("%s.%s.svc", tufConstants.DeploymentName, instance.Namespace)
}
tufServerHost := fmt.Sprintf("http://%s", instance.Spec.Tuf.Address)
rekorServerHost := fmt.Sprintf("http://%s.%s.svc", actions.ServerComponentName, instance.Namespace)

labels := labels.For(actions.MonitorComponentName, actions.MonitorStatefulSetName, instance.Name)
Expand All @@ -60,8 +69,8 @@ func (i statefulSetAction) Handle(ctx context.Context, instance *rhtasv1alpha1.R
Namespace: instance.Namespace,
},
},
i.ensureMonitorStatefulSet(instance, actions.RBACName, labels, rekorServerHost),
i.ensureInitContainer(rekorServerHost),
i.ensureMonitorStatefulSet(instance, actions.RBACName, labels, rekorServerHost, tufServerHost),
i.ensureInitContainer(rekorServerHost, tufServerHost),
ensure.ControllerReference[*v1.StatefulSet](instance, i.Client),
ensure.Labels[*v1.StatefulSet](slices.Collect(maps.Keys(labels)), labels),
func(object *v1.StatefulSet) error {
Expand Down Expand Up @@ -90,7 +99,7 @@ func (i statefulSetAction) Handle(ctx context.Context, instance *rhtasv1alpha1.R
return i.Continue()
}

func (i statefulSetAction) ensureMonitorStatefulSet(instance *rhtasv1alpha1.Rekor, sa string, labels map[string]string, rekorServerHost string) func(*v1.StatefulSet) error {
func (i statefulSetAction) ensureMonitorStatefulSet(instance *rhtasv1alpha1.Rekor, sa string, labels map[string]string, rekorServerHost string, tufServerHost string) func(*v1.StatefulSet) error {
return func(ss *v1.StatefulSet) error {

spec := &ss.Spec
Expand All @@ -110,7 +119,9 @@ func (i statefulSetAction) ensureMonitorStatefulSet(instance *rhtasv1alpha1.Reko
container.Command = []string{
"/bin/sh",
"-c",
fmt.Sprintf(`/rekor_monitor --file=/data/checkpoint_log.txt --once=false --interval=%s --url=%s`, interval.String(), rekorServerHost),
fmt.Sprintf(
`/rekor_monitor --file=/data/checkpoint_log.txt --once=false --interval=%s --url=%s --tuf-repository=%s --tuf-root-path="%s/root.json"`,
interval.String(), rekorServerHost, tufServerHost, mountPath),
}

container.Ports = []core.ContainerPort{
Expand All @@ -120,9 +131,15 @@ func (i statefulSetAction) ensureMonitorStatefulSet(instance *rhtasv1alpha1.Reko
Protocol: core.ProtocolTCP,
},
}
container.Env = []core.EnvVar{
{
Name: "HOME",
Value: mountPath,
},
}

volumeMount := kubernetes.FindVolumeMountByNameOrCreate(container, storageVolumeName)
volumeMount.MountPath = "/data"
volumeMount.MountPath = mountPath

spec.VolumeClaimTemplates = []core.PersistentVolumeClaim{
{
Expand All @@ -141,19 +158,35 @@ func (i statefulSetAction) ensureMonitorStatefulSet(instance *rhtasv1alpha1.Reko
},
},
}

return nil
}
}

func (i statefulSetAction) ensureInitContainer(rekorServerHost string) func(*v1.StatefulSet) error {
func (i statefulSetAction) ensureInitContainer(rekorServerHost string, tufHost string) func(*v1.StatefulSet) error {
return func(ss *v1.StatefulSet) error {
initContainer := kubernetes.FindInitContainerByNameOrCreate(&ss.Spec.Template.Spec, "wait-for-rekor-server")
initContainer := kubernetes.FindInitContainerByNameOrCreate(&ss.Spec.Template.Spec, "tuf-init")
initContainer.Image = images.Registry.Get(images.RekorMonitor)

volumeMount := kubernetes.FindVolumeMountByNameOrCreate(initContainer, storageVolumeName)
volumeMount.MountPath = mountPath
initContainer.Command = []string{
"/bin/sh",
"-c",
fmt.Sprintf(`until curl -sf %s > /dev/null 2>&1; do echo 'Waiting for rekor-server to be ready...'; sleep 5; done`, rekorServerHost),
fmt.Sprintf(`
echo "Waiting for rekor-server...";
until curl -sf %s > /dev/null 2>&1; do
echo "rekor-server not ready...";
sleep 5;
done;
echo "Waiting for TUF server...";
until curl %s > /dev/null 2>&1; do
echo "TUF server not ready...";
sleep 5;
done;
echo "Downloading root.json";
curl %s/root.json > %s/root.json
echo "tuf-init completed."
`, rekorServerHost, tufHost, tufHost, mountPath),
}

return nil
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/rekor_monitor_log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ var _ = Describe("Rekor Monitor Log", Ordered, func() {
g.Expect(err).ToNot(HaveOccurred())
g.Expect(strings.Contains(logContent, "Root hash consistency verified")).To(BeFalse(),
fmt.Sprintf("Expected 'Root hash consistency verified' NOT to be in logs, but got: %s", logContent))
g.Expect(strings.Contains(logContent, "empty log")).To(BeTrue(),
fmt.Sprintf("Expected 'empty log' to be in logs, but got: %s", logContent))
g.Expect(strings.Contains(logContent, "skipping write of checkpoint: size is 0")).To(BeTrue(),
fmt.Sprintf("Expected 'skipping write of checkpoint: size is 0' to be in logs, but got: %s", logContent))
}, 30*time.Second, 1*time.Second).Should(Succeed(),
"Monitor log should be empty and not contain root hash consistency verification")
})
Expand Down
57 changes: 14 additions & 43 deletions test/e2e/rekor_monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ import (
"github.com/securesign/operator/internal/labels"
"github.com/securesign/operator/test/e2e/support"
"github.com/securesign/operator/test/e2e/support/steps"
rekorSupport "github.com/securesign/operator/test/e2e/support/tas/rekor"
"github.com/securesign/operator/test/e2e/support/tas/trillian"
"github.com/securesign/operator/test/e2e/support/tas"
"github.com/securesign/operator/test/e2e/support/tas/securesign"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"
ctrl "sigs.k8s.io/controller-runtime/pkg/client"
)

Expand All @@ -30,58 +29,30 @@ var _ = Describe("Rekor Monitor", Ordered, func() {

var (
namespace *v1.Namespace
trillianCR *v1alpha1.Trillian
rekorCR *v1alpha1.Rekor
rekorMonitorPod v1.Pod
rekorMonitorContainer v1.Container
s *v1alpha1.Securesign
)

BeforeAll(steps.CreateNamespace(cli, func(new *v1.Namespace) {
namespace = new
}))

BeforeAll(func(ctx SpecContext) {
trillianCR = &v1alpha1.Trillian{
ObjectMeta: metav1.ObjectMeta{
Name: "test-trillian",
Namespace: namespace.Name,
s = securesign.Create(namespace.Name, "test",
securesign.WithDefaults(),
securesign.WithMonitoring(),
func(v *v1alpha1.Securesign) {
v.Spec.Rekor.Monitoring.TLog.Enabled = true
v.Spec.Rekor.Monitoring.TLog.Interval = metav1.Duration{Duration: time.Second * 10}
},
Spec: v1alpha1.TrillianSpec{
Db: v1alpha1.TrillianDB{Create: ptr.To(true)},
},
}
Expect(cli.Create(ctx, trillianCR)).To(Succeed())

By("Waiting for Trillian to be ready")
trillian.Verify(ctx, cli, namespace.Name, trillianCR.Name, true)
)
})

BeforeAll(func(ctx SpecContext) {
rekorCR = &v1alpha1.Rekor{
ObjectMeta: metav1.ObjectMeta{
Name: "test-rekor-monitor",
Namespace: namespace.Name,
},
Spec: v1alpha1.RekorSpec{
Monitoring: v1alpha1.MonitoringWithTLogConfig{
MonitoringConfig: v1alpha1.MonitoringConfig{
Enabled: true,
},
TLog: v1alpha1.TlogMonitoring{
Enabled: true,
Interval: metav1.Duration{Duration: time.Minute * 10},
},
},
Trillian: v1alpha1.TrillianService{
Address: fmt.Sprintf("trillian-logserver.%s.svc.cluster.local", namespace.Name),
Port: ptr.To(int32(8091)),
},
},
}
Expect(cli.Create(ctx, rekorCR)).To(Succeed())

By("Waiting for Rekor to be ready")
rekorSupport.Verify(ctx, cli, namespace.Name, rekorCR.Name, true)
Expect(cli.Create(ctx, s)).To(Succeed())
By("Waiting for all TAS components to be ready")
tas.VerifyAllComponents(ctx, cli, s, true)
})

Describe("Monitor Pod Deployment", func() {
Expand Down Expand Up @@ -123,7 +94,7 @@ var _ = Describe("Rekor Monitor", Ordered, func() {
updated := &v1alpha1.Rekor{}
err := cli.Get(ctx, types.NamespacedName{
Namespace: namespace.Name,
Name: rekorCR.Name,
Name: s.Name,
}, updated)
g.Expect(err).ToNot(HaveOccurred())

Expand Down