Skip to content

Commit f603869

Browse files
authored
feat(openbaocluster): add audit file storage (#483)
1 parent daf6a5c commit f603869

49 files changed

Lines changed: 2052 additions & 25 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/v1alpha1/openbaocluster_types.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ const (
6969
// ConditionACMECacheReady indicates whether the shared ACME cache PVC is ready for use
7070
// when the configured topology requires or uses a shared ACME cache.
7171
ConditionACMECacheReady ConditionType = "ACMECacheReady"
72+
// ConditionAuditFileStorageReady indicates whether the shared audit file storage PVC
73+
// is ready for file audit devices and mounted by the workload StatefulSets.
74+
ConditionAuditFileStorageReady ConditionType = "AuditFileStorageReady"
7275
// ConditionGatewayIntegrationReady indicates whether the operator can verify
7376
// the referenced Gateway and GatewayClass integration contract for the chosen
7477
// Gateway API mode.
@@ -236,6 +239,53 @@ type ACMESharedCacheConfig struct {
236239
StorageClassName *string `json:"storageClassName,omitempty"`
237240
}
238241

242+
// AuditFileStorageMode controls how the operator provides shared filesystem storage for file audit logs.
243+
// +kubebuilder:validation:Enum=ManagedPVC;ExistingPVC
244+
type AuditFileStorageMode string
245+
246+
const (
247+
// AuditFileStorageModeManagedPVC instructs the operator to create a dedicated RWX PVC.
248+
AuditFileStorageModeManagedPVC AuditFileStorageMode = "ManagedPVC"
249+
// AuditFileStorageModeExistingPVC instructs the operator to mount an existing RWX PVC.
250+
AuditFileStorageModeExistingPVC AuditFileStorageMode = "ExistingPVC"
251+
)
252+
253+
// AuditFileStorageConfig configures the shared filesystem integration point for file audit devices.
254+
//
255+
// The operator mounts the selected PVC into each OpenBao Pod. Each Pod uses a
256+
// pod-specific subPath under the same PVC so all Pods can render the same audit
257+
// file path while collectors can mount the PVC read-only and read per-Pod audit
258+
// files from the backing directories. This storage is intended as a collector
259+
// handoff and replay buffer, not as the authoritative compliance archive.
260+
// +kubebuilder:validation:XValidation:rule="self.mode != 'ManagedPVC' || !has(self.existingClaimName) || size(self.existingClaimName) == 0",message="auditFileStorage.existingClaimName is only supported when mode is ExistingPVC"
261+
// +kubebuilder:validation:XValidation:rule="self.mode != 'ExistingPVC' || size(self.existingClaimName) > 0",message="auditFileStorage.existingClaimName is required when mode is ExistingPVC"
262+
// +kubebuilder:validation:XValidation:rule="self.mode != 'ExistingPVC' || !has(self.size) || size(self.size) == 0",message="auditFileStorage.size is only supported when mode is ManagedPVC"
263+
// +kubebuilder:validation:XValidation:rule="self.mode != 'ExistingPVC' || !has(self.storageClassName) || size(self.storageClassName) == 0",message="auditFileStorage.storageClassName is only supported when mode is ManagedPVC"
264+
// +kubebuilder:validation:XValidation:rule="self.mode != 'ManagedPVC' || size(self.size) > 0",message="auditFileStorage.size is required when mode is ManagedPVC"
265+
// +kubebuilder:validation:XValidation:rule="!has(self.mountPath) || (self.mountPath.startsWith('/') && self.mountPath != '/')",message="auditFileStorage.mountPath must be an absolute path and must not be /"
266+
type AuditFileStorageConfig struct {
267+
// Mode selects whether the operator creates a dedicated RWX PVC or mounts an existing one.
268+
Mode AuditFileStorageMode `json:"mode"`
269+
// ExistingClaimName is the name of a pre-created RWX PVC in the same namespace.
270+
// Required when Mode is ExistingPVC.
271+
// +kubebuilder:validation:MinLength=1
272+
// +optional
273+
ExistingClaimName string `json:"existingClaimName,omitempty"`
274+
// Size is the requested capacity for the managed audit file storage PVC.
275+
// Required when Mode is ManagedPVC.
276+
// +kubebuilder:validation:MinLength=1
277+
// +optional
278+
Size string `json:"size,omitempty"`
279+
// StorageClassName is an optional StorageClass for the managed audit file storage PVC.
280+
// +optional
281+
StorageClassName *string `json:"storageClassName,omitempty"`
282+
// MountPath is where the audit file storage PVC is mounted in OpenBao Pods.
283+
// File audit device paths must be under this path when auditFileStorage is configured.
284+
// +kubebuilder:default=/openbao/audit
285+
// +optional
286+
MountPath string `json:"mountPath,omitempty"`
287+
}
288+
239289
// TLSConfig captures TLS configuration for an OpenBaoCluster.
240290
type TLSConfig struct {
241291
// Enabled controls whether TLS is enabled for the cluster.
@@ -2015,6 +2065,10 @@ type OpenBaoClusterSpec struct {
20152065
// +listType=map
20162066
// +listMapKey=path
20172067
Audit []AuditDevice `json:"audit,omitempty"`
2068+
// AuditFileStorage configures a shared filesystem integration point for file audit devices.
2069+
// When configured, file audit device paths must be under auditFileStorage.mountPath.
2070+
// +optional
2071+
AuditFileStorage *AuditFileStorageConfig `json:"auditFileStorage,omitempty"`
20182072
// Plugins configures declarative plugins for the OpenBao cluster.
20192073
// See: https://openbao.org/docs/configuration/plugins/
20202074
// +optional

api/v1alpha1/zz_generated.deepcopy.go

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

charts/openbao-operator/crds/openbao.org_openbaoclusters.yaml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,65 @@ spec:
186186
x-kubernetes-list-map-keys:
187187
- path
188188
x-kubernetes-list-type: map
189+
auditFileStorage:
190+
description: |-
191+
AuditFileStorage configures a shared filesystem integration point for file audit devices.
192+
When configured, file audit device paths must be under auditFileStorage.mountPath.
193+
properties:
194+
existingClaimName:
195+
description: |-
196+
ExistingClaimName is the name of a pre-created RWX PVC in the same namespace.
197+
Required when Mode is ExistingPVC.
198+
minLength: 1
199+
type: string
200+
mode:
201+
description: Mode selects whether the operator creates a dedicated
202+
RWX PVC or mounts an existing one.
203+
enum:
204+
- ManagedPVC
205+
- ExistingPVC
206+
type: string
207+
mountPath:
208+
default: /openbao/audit
209+
description: |-
210+
MountPath is where the audit file storage PVC is mounted in OpenBao Pods.
211+
File audit device paths must be under this path when auditFileStorage is configured.
212+
type: string
213+
size:
214+
description: |-
215+
Size is the requested capacity for the managed audit file storage PVC.
216+
Required when Mode is ManagedPVC.
217+
minLength: 1
218+
type: string
219+
storageClassName:
220+
description: StorageClassName is an optional StorageClass for
221+
the managed audit file storage PVC.
222+
type: string
223+
required:
224+
- mode
225+
type: object
226+
x-kubernetes-validations:
227+
- message: auditFileStorage.existingClaimName is only supported when
228+
mode is ExistingPVC
229+
rule: self.mode != 'ManagedPVC' || !has(self.existingClaimName)
230+
|| size(self.existingClaimName) == 0
231+
- message: auditFileStorage.existingClaimName is required when mode
232+
is ExistingPVC
233+
rule: self.mode != 'ExistingPVC' || size(self.existingClaimName)
234+
> 0
235+
- message: auditFileStorage.size is only supported when mode is ManagedPVC
236+
rule: self.mode != 'ExistingPVC' || !has(self.size) || size(self.size)
237+
== 0
238+
- message: auditFileStorage.storageClassName is only supported when
239+
mode is ManagedPVC
240+
rule: self.mode != 'ExistingPVC' || !has(self.storageClassName)
241+
|| size(self.storageClassName) == 0
242+
- message: auditFileStorage.size is required when mode is ManagedPVC
243+
rule: self.mode != 'ManagedPVC' || size(self.size) > 0
244+
- message: auditFileStorage.mountPath must be an absolute path and
245+
must not be /
246+
rule: '!has(self.mountPath) || (self.mountPath.startsWith(''/'')
247+
&& self.mountPath != ''/'')'
189248
backup:
190249
description: Backup configures scheduled backups for the cluster.
191250
properties:

config/crd/bases/openbao.org_openbaoclusters.yaml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,65 @@ spec:
185185
x-kubernetes-list-map-keys:
186186
- path
187187
x-kubernetes-list-type: map
188+
auditFileStorage:
189+
description: |-
190+
AuditFileStorage configures a shared filesystem integration point for file audit devices.
191+
When configured, file audit device paths must be under auditFileStorage.mountPath.
192+
properties:
193+
existingClaimName:
194+
description: |-
195+
ExistingClaimName is the name of a pre-created RWX PVC in the same namespace.
196+
Required when Mode is ExistingPVC.
197+
minLength: 1
198+
type: string
199+
mode:
200+
description: Mode selects whether the operator creates a dedicated
201+
RWX PVC or mounts an existing one.
202+
enum:
203+
- ManagedPVC
204+
- ExistingPVC
205+
type: string
206+
mountPath:
207+
default: /openbao/audit
208+
description: |-
209+
MountPath is where the audit file storage PVC is mounted in OpenBao Pods.
210+
File audit device paths must be under this path when auditFileStorage is configured.
211+
type: string
212+
size:
213+
description: |-
214+
Size is the requested capacity for the managed audit file storage PVC.
215+
Required when Mode is ManagedPVC.
216+
minLength: 1
217+
type: string
218+
storageClassName:
219+
description: StorageClassName is an optional StorageClass for
220+
the managed audit file storage PVC.
221+
type: string
222+
required:
223+
- mode
224+
type: object
225+
x-kubernetes-validations:
226+
- message: auditFileStorage.existingClaimName is only supported when
227+
mode is ExistingPVC
228+
rule: self.mode != 'ManagedPVC' || !has(self.existingClaimName)
229+
|| size(self.existingClaimName) == 0
230+
- message: auditFileStorage.existingClaimName is required when mode
231+
is ExistingPVC
232+
rule: self.mode != 'ExistingPVC' || size(self.existingClaimName)
233+
> 0
234+
- message: auditFileStorage.size is only supported when mode is ManagedPVC
235+
rule: self.mode != 'ExistingPVC' || !has(self.size) || size(self.size)
236+
== 0
237+
- message: auditFileStorage.storageClassName is only supported when
238+
mode is ManagedPVC
239+
rule: self.mode != 'ExistingPVC' || !has(self.storageClassName)
240+
|| size(self.storageClassName) == 0
241+
- message: auditFileStorage.size is required when mode is ManagedPVC
242+
rule: self.mode != 'ManagedPVC' || size(self.size) > 0
243+
- message: auditFileStorage.mountPath must be an absolute path and
244+
must not be /
245+
rule: '!has(self.mountPath) || (self.mountPath.startsWith(''/'')
246+
&& self.mountPath != ''/'')'
188247
backup:
189248
description: Backup configures scheduled backups for the cluster.
190249
properties:

docs/architecture/operator-invariants.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,19 @@ Related reading: <SiteLink docId="security/fundamentals/profiles">Security Profi
153153
rows={[
154154
{
155155
cells: [
156-
'Gateway, ACME, and API-server assumptions surface as explicit conditions.',
156+
'Gateway, ACME, audit storage, and API-server assumptions surface as explicit conditions.',
157157
'Environment and controller dependencies should become visible status contracts before they become runtime failures.',
158-
'`GatewayIntegrationReady`, `ACMEIntegrationReady`, `ACMECacheReady`, and `APIServerNetworkReady` conditions.',
158+
'`GatewayIntegrationReady`, `ACMEIntegrationReady`, `ACMECacheReady`, `AuditFileStorageReady`, and `APIServerNetworkReady` conditions.',
159159
],
160160
emphasis: 'recommended',
161161
},
162+
{
163+
cells: [
164+
'Audit file storage stays an explicit integration point.',
165+
'The operator can mount and validate the handoff PVC, but retention, tamper resistance, and collection pipelines belong to the surrounding platform.',
166+
'`spec.auditFileStorage`, `spec.audit`, status readiness, and workload mount guardrails.',
167+
],
168+
},
162169
{
163170
cells: [
164171
'Backup and restore identity stays separate from the main workload identity.',
@@ -169,7 +176,7 @@ Related reading: <SiteLink docId="security/fundamentals/profiles">Security Profi
169176
]}
170177
/>
171178

172-
Related reading: <SiteLink docId="reference/status-and-events">Status and Events</SiteLink> and <SiteLink docId="user-guide/openbaocluster/operations/backups">Configure Backups</SiteLink>.
179+
Related reading: <SiteLink docId="reference/status-and-events">Status and Events</SiteLink>, <SiteLink docId="user-guide/openbaocluster/configuration/observability">Observability</SiteLink>, and <SiteLink docId="user-guide/openbaocluster/operations/backups">Configure Backups</SiteLink>.
173180

174181
## Lifecycle safety invariants
175182

docs/architecture/workload-managers.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ This keeps change-coupling lower: config rendering, service exposure, ServiceAcc
113113
columns={['Manager', 'Owns', 'Primary writes', 'Why it stays separate']}
114114
rows={[
115115
{
116-
cells: ['Bootstrap manager', 'Rendered config, self-init surfaces, unseal prerequisites, and related validation.', 'ConfigMap surfaces, static unseal Secret when applicable, self-init ConfigMap, and shared-cache PVC setup.', 'Config and bootstrap prerequisites change for different reasons than networking or StatefulSet lifecycle.'],
116+
cells: ['Bootstrap manager', 'Rendered config, self-init surfaces, unseal prerequisites, and related validation.', 'ConfigMap surfaces, static unseal Secret when applicable, self-init ConfigMap, shared-cache PVC setup, and managed audit file storage PVC setup.', 'Config and bootstrap prerequisites change for different reasons than networking or StatefulSet lifecycle.'],
117117
emphasis: 'recommended',
118118
},
119119
{
@@ -139,6 +139,7 @@ The bootstrap manager prepares everything the workload needs before the Stateful
139139
- generate the static unseal Secret when that seal mode is selected
140140
- validate unseal prerequisites and related secret references
141141
- prepare ACME shared-cache storage when that mode requires it
142+
- prepare managed audit file storage PVCs when file audit handoff storage is configured
142143

143144
### Networking manager
144145

@@ -166,6 +167,7 @@ The workload manager owns the StatefulSet-facing contract:
166167
- steady-state read-replica StatefulSet lifecycle and safe drain or delete behavior
167168
- PodDisruptionBudget reconciliation
168169
- rollout triggers from rendered config or certificate hash changes
170+
- audit file storage volume and mount wiring for voter and read-replica StatefulSets
169171
- single-replica bootstrap and later scale-out after initialization
170172
- revision-scoped workload resources used by blue/green and rollout-safe updates
171173
- read-first or restore-safe operational ordering delegated by the app layer for rolling upgrades, blue-green, and restore

0 commit comments

Comments
 (0)