Skip to content

Commit f1b47f0

Browse files
committed
feat: log and store redacted machine config diffs
Change the RedactedClusterMachineConfig controller to also compute diffs between each config change and store them in a new resource. Additionally, log this diff and include its creation in the audit logs. Clean up old diffs with both size (count) and time-based retention. Include these diffs in the support bundles. The resource ID follows the following pattern: `<machine-id>-<timestamp>`, e.g., `34bafa44-e994-4911-9c1a-609cccefee93-2025-07-04T19:05:40.181Z`. Signed-off-by: Utku Ozdemir <[email protected]>
1 parent a7ac637 commit f1b47f0

File tree

16 files changed

+967
-246
lines changed

16 files changed

+967
-246
lines changed

client/api/omni/specs/omni.pb.go

Lines changed: 195 additions & 148 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/api/omni/specs/omni.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,3 +1356,7 @@ message InfraProviderCombinedStatusSpec {
13561356

13571357
Health health = 4;
13581358
}
1359+
1360+
message MachineConfigDiffSpec {
1361+
string diff = 1;
1362+
}

client/api/omni/specs/omni_vtproto.pb.go

Lines changed: 173 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package omni
6+
7+
import (
8+
"github.com/cosi-project/runtime/pkg/resource"
9+
"github.com/cosi-project/runtime/pkg/resource/meta"
10+
"github.com/cosi-project/runtime/pkg/resource/protobuf"
11+
"github.com/cosi-project/runtime/pkg/resource/typed"
12+
13+
"github.com/siderolabs/omni/client/api/omni/specs"
14+
"github.com/siderolabs/omni/client/pkg/omni/resources"
15+
)
16+
17+
// NewMachineConfigDiff creates a new MachineConfigDiff resource.
18+
func NewMachineConfigDiff(id resource.ID) *MachineConfigDiff {
19+
return typed.NewResource[MachineConfigDiffSpec, MachineConfigDiffExtension](
20+
resource.NewMetadata(resources.DefaultNamespace, MachineConfigDiffType, id, resource.VersionUndefined),
21+
protobuf.NewResourceSpec(&specs.MachineConfigDiffSpec{}),
22+
)
23+
}
24+
25+
const (
26+
// MachineConfigDiffType is the type of the MachineConfigDiff resource.
27+
// tsgen:MachineConfigDiffType
28+
MachineConfigDiffType = resource.Type("MachineConfigDiffs.omni.sidero.dev")
29+
)
30+
31+
// MachineConfigDiff is the diff between two redacted machine configurations.
32+
type MachineConfigDiff = typed.Resource[MachineConfigDiffSpec, MachineConfigDiffExtension]
33+
34+
// MachineConfigDiffSpec wraps specs.MachineConfigDiffSpec.
35+
type MachineConfigDiffSpec = protobuf.ResourceSpec[specs.MachineConfigDiffSpec, *specs.MachineConfigDiffSpec]
36+
37+
// MachineConfigDiffExtension provides auxiliary methods for MachineConfigDiff resource.
38+
type MachineConfigDiffExtension struct{}
39+
40+
// ResourceDefinition implements [typed.Extension] interface.
41+
func (MachineConfigDiffExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
42+
return meta.ResourceDefinitionSpec{
43+
Type: MachineConfigDiffType,
44+
DefaultNamespace: resources.DefaultNamespace,
45+
}
46+
}

client/pkg/omni/resources/omni/omni.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func init() {
5858
registry.MustRegisterResource(KubernetesUpgradeManifestStatusType, &KubernetesUpgradeManifestStatus{})
5959
registry.MustRegisterResource(KubernetesUpgradeStatusType, &KubernetesUpgradeStatus{})
6060
registry.MustRegisterResource(KubernetesVersionType, &KubernetesVersion{})
61+
registry.MustRegisterResource(MachineConfigDiffType, &MachineConfigDiff{})
6162
registry.MustRegisterResource(MachineLabelsType, &MachineLabels{})
6263
registry.MustRegisterResource(MachineType, &Machine{})
6364
registry.MustRegisterResource(MachineClassType, &MachineClass{})

frontend/src/api/omni/specs/omni.pb.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,4 +892,8 @@ export type InfraProviderCombinedStatusSpec = {
892892
description?: string
893893
icon?: string
894894
health?: InfraProviderCombinedStatusSpecHealth
895+
}
896+
897+
export type MachineConfigDiffSpec = {
898+
diff?: string
895899
}

frontend/src/api/resources.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export const ClusterMachineStatusLabelNodeName = "omni.sidero.dev/node-name";
162162
export const ExtensionsConfigurationLabel = "omni.sidero.dev/root-configuration";
163163
export const MachineType = "Machines.omni.sidero.dev";
164164
export const MachineClassType = "MachineClasses.omni.sidero.dev";
165+
export const MachineConfigDiffType = "MachineConfigDiffs.omni.sidero.dev";
165166
export const MachineConfigGenOptionsType = "MachineConfigGenOptions.omni.sidero.dev";
166167
export const MachineExtensionsType = "MachineExtensions.omni.sidero.dev";
167168
export const MachineExtensionsStatusType = "MachineExtensionsStatuses.omni.sidero.dev";

internal/backend/grpc/support.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"k8s.io/client-go/kubernetes"
2929

3030
"github.com/siderolabs/omni/client/api/omni/management"
31+
"github.com/siderolabs/omni/client/pkg/omni/resources/infra"
3132
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
3233
"github.com/siderolabs/omni/client/pkg/omni/resources/siderolink"
3334
"github.com/siderolabs/omni/client/pkg/omni/resources/system"
@@ -318,6 +319,18 @@ func (s *managementServer) collectClusterResources(ctx context.Context, cluster
318319
rt: omni.DiscoveryAffiliateDeleteTaskType,
319320
listOptions: clusterQuery,
320321
},
322+
{
323+
rt: omni.MachineConfigDiffType,
324+
listOptions: clusterQuery,
325+
},
326+
{
327+
rt: infra.InfraMachineType,
328+
listOptions: clusterQuery,
329+
},
330+
{
331+
rt: infra.InfraMachineStatusType,
332+
listOptions: clusterQuery,
333+
},
321334
}
322335

323336
machineIDs := map[string]struct{}{}

internal/backend/runtime/omni/audit/data.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@ const (
2121

2222
// Data contains the audit data.
2323
type Data struct {
24-
NewUser *NewUser `json:"new_user,omitempty"`
25-
Machine *Machine `json:"machine,omitempty"`
26-
MachineLabels *MachineLabels `json:"machine_labels,omitempty"`
27-
AccessPolicy *AccessPolicy `json:"access_policy,omitempty"`
28-
Cluster *Cluster `json:"cluster,omitempty"`
29-
MachineSet *MachineSet `json:"machine_set,omitempty"`
30-
MachineSetNode *MachineSetNode `json:"machine_set_node,omitempty"`
31-
ConfigPatch *ConfigPatch `json:"config_patch,omitempty"`
32-
TalosAccess *TalosAccess `json:"talos_access,omitempty"`
33-
K8SAccess *K8SAccess `json:"k8s_access,omitempty"`
34-
Session Session `json:"session,omitempty"`
24+
NewUser *NewUser `json:"new_user,omitempty"`
25+
Machine *Machine `json:"machine,omitempty"`
26+
MachineLabels *MachineLabels `json:"machine_labels,omitempty"`
27+
AccessPolicy *AccessPolicy `json:"access_policy,omitempty"`
28+
Cluster *Cluster `json:"cluster,omitempty"`
29+
MachineSet *MachineSet `json:"machine_set,omitempty"`
30+
MachineSetNode *MachineSetNode `json:"machine_set_node,omitempty"`
31+
ConfigPatch *ConfigPatch `json:"config_patch,omitempty"`
32+
MachineConfigDiff *MachineConfigDiff `json:"machine_config_diff,omitempty"`
33+
TalosAccess *TalosAccess `json:"talos_access,omitempty"`
34+
K8SAccess *K8SAccess `json:"k8s_access,omitempty"`
35+
Session Session `json:"session,omitempty"`
3536
}
3637

3738
// Session contains information about the current session.
@@ -111,6 +112,12 @@ type ConfigPatch struct {
111112
Data string `json:"data,omitempty"`
112113
}
113114

115+
// MachineConfigDiff struct contains information about the machine configuration diff.
116+
type MachineConfigDiff struct {
117+
ID resource.ID `json:"id,omitempty"`
118+
Diff string `json:"diff,omitempty"`
119+
}
120+
114121
// TalosAccess struct contains information about the access to the Talos node.
115122
type TalosAccess struct {
116123
FullMethodName string `json:"full_method_name,omitempty"`

internal/backend/runtime/omni/audit/hooks/hooks.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ func Init(a *audit.Log) {
7070
audit.ShouldLogUpdate(a, configPatchUpdate, audit.WithInternalAgent())
7171
audit.ShouldLogUpdateWithConflicts(a, configPatchUpdate, audit.WithInternalAgent())
7272
audit.ShouldLogDestroy(a, omni.ConfigPatchType, configPatchDestroy, audit.WithInternalAgent())
73+
74+
audit.ShouldLogCreate(a, machineConfigDiffCreate, audit.WithInternalAgent())
7375
}
7476

7577
func publicKeyCreate(_ context.Context, data *audit.Data, res *auth.PublicKey, _ ...state.CreateOption) error {
@@ -389,6 +391,15 @@ func configPatchDestroy(_ context.Context, data *audit.Data, ptr resource.Pointe
389391
return nil
390392
}
391393

394+
func machineConfigDiffCreate(_ context.Context, data *audit.Data, res *omni.MachineConfigDiff, _ ...state.CreateOption) error {
395+
initPtrField(&data.MachineConfigDiff)
396+
397+
data.MachineConfigDiff.ID = res.Metadata().ID()
398+
data.MachineConfigDiff.Diff = res.TypedSpec().Value.Diff
399+
400+
return nil
401+
}
402+
392403
func initPtrField[T any](v **T) {
393404
if *v == nil {
394405
*v = new(T)

0 commit comments

Comments
 (0)