diff --git a/CHANGELOG.md b/CHANGELOG.md index e033ce907bf89..e97fc97f88e72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ Changes should still be described appropriately in JIRA/doc input pages, for inc - ROX-30100: Incorrect defaults for admission controller related configuration options in "roxctl sensor generate" have been fixed. The admission controller will be deployed and configured for policy evaluation and enforcement as well as image scanning, out of the box - without requiring a user to specify command line options to "roxctl sensor generate". +- ROX-30034,ROX-29995,ROX-29996: Support for two new admission controller configuration related options in roxctl sensor generate + - `--admission-controller-enforcement` defaults to true. If set to false, admission controller webhook will be + configured to not enforce policies on any admission review request. + - `--admission-controller-fail-on-error` defaults to false, which means admission controller webhook will fail open. + If set to true, the admission controller webhook will fail closed i.e. the review request will be blocked in case of timeouts or errors. ### Removed Features diff --git a/central/cluster/datastore/datastore_impl.go b/central/cluster/datastore/datastore_impl.go index d7307c38e7363..d7cf40770f55d 100644 --- a/central/cluster/datastore/datastore_impl.go +++ b/central/cluster/datastore/datastore_impl.go @@ -1052,6 +1052,10 @@ func configureFromHelmConfig(cluster *storage.Cluster, helmConfig *storage.Compl cluster.AdmissionControllerEvents = staticConfig.GetAdmissionControllerEvents() cluster.TolerationsConfig = staticConfig.GetTolerationsConfig().CloneVT() cluster.SlimCollector = staticConfig.GetSlimCollector() + cluster.AdmissionControllerFailOnError = false + if features.AdmissionControllerConfig.Enabled() { + cluster.AdmissionControllerFailOnError = staticConfig.GetAdmissionControllerFailureOnError() + } } func (ds *datastoreImpl) collectClusters(ctx context.Context) ([]*storage.Cluster, error) { diff --git a/central/clusters/deployer.go b/central/clusters/deployer.go index 0218938767d75..b74ff0b4c9224 100644 --- a/central/clusters/deployer.go +++ b/central/clusters/deployer.go @@ -169,6 +169,7 @@ func getBaseMetaValues(c *storage.Cluster, versions version.Versions, scannerSli ScanInline: c.GetDynamicConfig().GetAdmissionControllerConfig().GetScanInline(), AdmissionControllerEnabled: c.GetDynamicConfig().GetAdmissionControllerConfig().GetEnabled(), AdmissionControlEnforceOnUpdates: c.GetDynamicConfig().GetAdmissionControllerConfig().GetEnforceOnUpdates(), + AdmissionControllerFailOnError: c.AdmissionControllerFailOnError, ReleaseBuild: buildinfo.ReleaseBuild, EnablePodSecurityPolicies: false, diff --git a/central/graphql/resolvers/generated.go b/central/graphql/resolvers/generated.go index 657cad4337f01..986202394315e 100644 --- a/central/graphql/resolvers/generated.go +++ b/central/graphql/resolvers/generated.go @@ -270,6 +270,7 @@ func registerGeneratedTypes(builder generator.SchemaBuilder) { utils.Must(builder.AddType("Cluster", []string{ "admissionController: Boolean!", "admissionControllerEvents: Boolean!", + "admissionControllerFailOnError: Boolean!", "admissionControllerUpdates: Boolean!", "centralApiEndpoint: String!", "collectionMethod: CollectionMethod!", @@ -1360,6 +1361,7 @@ func registerGeneratedTypes(builder generator.SchemaBuilder) { utils.Must(builder.AddType("StaticClusterConfig", []string{ "admissionController: Boolean!", "admissionControllerEvents: Boolean!", + "admissionControllerFailureOnError: Boolean!", "admissionControllerUpdates: Boolean!", "centralApiEndpoint: String!", "collectionMethod: CollectionMethod!", @@ -4033,6 +4035,11 @@ func (resolver *clusterResolver) AdmissionControllerEvents(ctx context.Context) return value } +func (resolver *clusterResolver) AdmissionControllerFailOnError(ctx context.Context) bool { + value := resolver.data.GetAdmissionControllerFailOnError() + return value +} + func (resolver *clusterResolver) AdmissionControllerUpdates(ctx context.Context) bool { value := resolver.data.GetAdmissionControllerUpdates() return value @@ -14776,6 +14783,11 @@ func (resolver *staticClusterConfigResolver) AdmissionControllerEvents(ctx conte return value } +func (resolver *staticClusterConfigResolver) AdmissionControllerFailureOnError(ctx context.Context) bool { + value := resolver.data.GetAdmissionControllerFailureOnError() + return value +} + func (resolver *staticClusterConfigResolver) AdmissionControllerUpdates(ctx context.Context) bool { value := resolver.data.GetAdmissionControllerUpdates() return value diff --git a/generated/api/v1/cluster_service.swagger.json b/generated/api/v1/cluster_service.swagger.json index 1cae632886a0e..9baaa27108976 100644 --- a/generated/api/v1/cluster_service.swagger.json +++ b/generated/api/v1/cluster_service.swagger.json @@ -353,8 +353,12 @@ "items": { "type": "string" } + }, + "admissionControllerFailOnError": { + "type": "boolean" } - } + }, + "title": "Next tag: 33" }, "UpgradeProcessStatusUpgradeProcessType": { "type": "string", @@ -574,8 +578,12 @@ "items": { "type": "string" } + }, + "admissionControllerFailOnError": { + "type": "boolean" } - } + }, + "title": "Next tag: 33" }, "storageClusterCertExpiryStatus": { "type": "object", @@ -944,6 +952,9 @@ }, "admissionControllerEvents": { "type": "boolean" + }, + "admissionControllerFailureOnError": { + "type": "boolean" } }, "description": "The difference between Static and Dynamic cluster config is that Static values are not sent over the Central to Sensor gRPC connection. They are used, for example, to generate manifests that can be used to set up the Secured Cluster's k8s components. They are *not* dynamically reloaded." diff --git a/generated/storage/cluster.pb.go b/generated/storage/cluster.pb.go index 821a692c3523c..e102ccb073152 100644 --- a/generated/storage/cluster.pb.go +++ b/generated/storage/cluster.pb.go @@ -1052,19 +1052,20 @@ func (x *TolerationsConfig) GetDisabled() bool { // The difference between Static and Dynamic cluster config is that Static values are not sent over the Central to Sensor gRPC connection. They are used, for example, to generate manifests that can be used to set up the Secured Cluster's k8s components. They are *not* dynamically reloaded. type StaticClusterConfig struct { - state protoimpl.MessageState `protogen:"open.v1"` - Type ClusterType `protobuf:"varint,1,opt,name=type,proto3,enum=storage.ClusterType" json:"type,omitempty"` - MainImage string `protobuf:"bytes,2,opt,name=main_image,json=mainImage,proto3" json:"main_image,omitempty"` - CentralApiEndpoint string `protobuf:"bytes,3,opt,name=central_api_endpoint,json=centralApiEndpoint,proto3" json:"central_api_endpoint,omitempty"` - CollectionMethod CollectionMethod `protobuf:"varint,4,opt,name=collection_method,json=collectionMethod,proto3,enum=storage.CollectionMethod" json:"collection_method,omitempty"` - CollectorImage string `protobuf:"bytes,5,opt,name=collector_image,json=collectorImage,proto3" json:"collector_image,omitempty"` - AdmissionController bool `protobuf:"varint,6,opt,name=admission_controller,json=admissionController,proto3" json:"admission_controller,omitempty"` - AdmissionControllerUpdates bool `protobuf:"varint,7,opt,name=admission_controller_updates,json=admissionControllerUpdates,proto3" json:"admission_controller_updates,omitempty"` - TolerationsConfig *TolerationsConfig `protobuf:"bytes,8,opt,name=tolerations_config,json=tolerationsConfig,proto3" json:"tolerations_config,omitempty"` - SlimCollector bool `protobuf:"varint,9,opt,name=slim_collector,json=slimCollector,proto3" json:"slim_collector,omitempty"` - AdmissionControllerEvents bool `protobuf:"varint,10,opt,name=admission_controller_events,json=admissionControllerEvents,proto3" json:"admission_controller_events,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type ClusterType `protobuf:"varint,1,opt,name=type,proto3,enum=storage.ClusterType" json:"type,omitempty"` + MainImage string `protobuf:"bytes,2,opt,name=main_image,json=mainImage,proto3" json:"main_image,omitempty"` + CentralApiEndpoint string `protobuf:"bytes,3,opt,name=central_api_endpoint,json=centralApiEndpoint,proto3" json:"central_api_endpoint,omitempty"` + CollectionMethod CollectionMethod `protobuf:"varint,4,opt,name=collection_method,json=collectionMethod,proto3,enum=storage.CollectionMethod" json:"collection_method,omitempty"` + CollectorImage string `protobuf:"bytes,5,opt,name=collector_image,json=collectorImage,proto3" json:"collector_image,omitempty"` + AdmissionController bool `protobuf:"varint,6,opt,name=admission_controller,json=admissionController,proto3" json:"admission_controller,omitempty"` + AdmissionControllerUpdates bool `protobuf:"varint,7,opt,name=admission_controller_updates,json=admissionControllerUpdates,proto3" json:"admission_controller_updates,omitempty"` + TolerationsConfig *TolerationsConfig `protobuf:"bytes,8,opt,name=tolerations_config,json=tolerationsConfig,proto3" json:"tolerations_config,omitempty"` + SlimCollector bool `protobuf:"varint,9,opt,name=slim_collector,json=slimCollector,proto3" json:"slim_collector,omitempty"` + AdmissionControllerEvents bool `protobuf:"varint,10,opt,name=admission_controller_events,json=admissionControllerEvents,proto3" json:"admission_controller_events,omitempty"` + AdmissionControllerFailureOnError bool `protobuf:"varint,11,opt,name=admission_controller_failure_on_error,json=admissionControllerFailureOnError,proto3" json:"admission_controller_failure_on_error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StaticClusterConfig) Reset() { @@ -1167,6 +1168,13 @@ func (x *StaticClusterConfig) GetAdmissionControllerEvents() bool { return false } +func (x *StaticClusterConfig) GetAdmissionControllerFailureOnError() bool { + if x != nil { + return x.AdmissionControllerFailureOnError + } + return false +} + // The difference between Static and Dynamic cluster config is that Dynamic values are sent over the Central to Sensor gRPC connection. This has the benefit of allowing for "hot reloading" of values without restarting Secured cluster components. type DynamicClusterConfig struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1385,6 +1393,7 @@ func (x *SensorDeploymentIdentification) GetK8SNodeName() string { return "" } +// Next tag: 33 type Cluster struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" search:"Cluster ID,hidden,store" sql:"pk,type(uuid)"` // @gotags: search:"Cluster ID,hidden,store" sql:"pk,type(uuid)" @@ -1411,12 +1420,13 @@ type Cluster struct { // most_recent_sensor_id is the current or most recent identification of a successfully connected sensor (if any). MostRecentSensorId *SensorDeploymentIdentification `protobuf:"bytes,26,opt,name=most_recent_sensor_id,json=mostRecentSensorId,proto3" json:"most_recent_sensor_id,omitempty"` // For internal use only. - AuditLogState map[string]*AuditLogFileState `protobuf:"bytes,28,rep,name=audit_log_state,json=auditLogState,proto3" json:"audit_log_state,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - InitBundleId string `protobuf:"bytes,29,opt,name=init_bundle_id,json=initBundleId,proto3" json:"init_bundle_id,omitempty"` - ManagedBy ManagerType `protobuf:"varint,30,opt,name=managed_by,json=managedBy,proto3,enum=storage.ManagerType" json:"managed_by,omitempty"` - SensorCapabilities []string `protobuf:"bytes,31,rep,name=sensor_capabilities,json=sensorCapabilities,proto3" json:"sensor_capabilities,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + AuditLogState map[string]*AuditLogFileState `protobuf:"bytes,28,rep,name=audit_log_state,json=auditLogState,proto3" json:"audit_log_state,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + InitBundleId string `protobuf:"bytes,29,opt,name=init_bundle_id,json=initBundleId,proto3" json:"init_bundle_id,omitempty"` + ManagedBy ManagerType `protobuf:"varint,30,opt,name=managed_by,json=managedBy,proto3,enum=storage.ManagerType" json:"managed_by,omitempty"` + SensorCapabilities []string `protobuf:"bytes,31,rep,name=sensor_capabilities,json=sensorCapabilities,proto3" json:"sensor_capabilities,omitempty"` + AdmissionControllerFailOnError bool `protobuf:"varint,32,opt,name=admission_controller_fail_on_error,json=admissionControllerFailOnError,proto3" json:"admission_controller_fail_on_error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Cluster) Reset() { @@ -1618,6 +1628,13 @@ func (x *Cluster) GetSensorCapabilities() []string { return nil } +func (x *Cluster) GetAdmissionControllerFailOnError() bool { + if x != nil { + return x.AdmissionControllerFailOnError + } + return false +} + type ClusterCertExpiryStatus struct { state protoimpl.MessageState `protogen:"open.v1"` SensorCertExpiry *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=sensor_cert_expiry,json=sensorCertExpiry,proto3" json:"sensor_cert_expiry,omitempty"` @@ -2641,7 +2658,7 @@ const file_storage_cluster_proto_rawDesc = "" + "\x0edisable_bypass\x18\x04 \x01(\bR\rdisableBypass\x12,\n" + "\x12enforce_on_updates\x18\x05 \x01(\bR\x10enforceOnUpdates\"/\n" + "\x11TolerationsConfig\x12\x1a\n" + - "\bdisabled\x18\x01 \x01(\bR\bdisabled\"\xa8\x04\n" + + "\bdisabled\x18\x01 \x01(\bR\bdisabled\"\xfa\x04\n" + "\x13StaticClusterConfig\x12(\n" + "\x04type\x18\x01 \x01(\x0e2\x14.storage.ClusterTypeR\x04type\x12\x1d\n" + "\n" + @@ -2654,7 +2671,8 @@ const file_storage_cluster_proto_rawDesc = "" + "\x12tolerations_config\x18\b \x01(\v2\x1a.storage.TolerationsConfigR\x11tolerationsConfig\x12%\n" + "\x0eslim_collector\x18\t \x01(\bR\rslimCollector\x12>\n" + "\x1badmission_controller_events\x18\n" + - " \x01(\bR\x19admissionControllerEvents\"\xd5\x01\n" + + " \x01(\bR\x19admissionControllerEvents\x12P\n" + + "%admission_controller_failure_on_error\x18\v \x01(\bR!admissionControllerFailureOnError\"\xd5\x01\n" + "\x14DynamicClusterConfig\x12b\n" + "\x1badmission_controller_config\x18\x01 \x01(\v2\".storage.AdmissionControllerConfigR\x19admissionControllerConfig\x12+\n" + "\x11registry_override\x18\x02 \x01(\tR\x10registryOverride\x12,\n" + @@ -2673,7 +2691,7 @@ const file_storage_cluster_proto_rawDesc = "" + "\rapp_namespace\x18\x03 \x01(\tR\fappNamespace\x12(\n" + "\x10app_namespace_id\x18\x04 \x01(\tR\x0eappNamespaceId\x122\n" + "\x15app_serviceaccount_id\x18\x05 \x01(\tR\x13appServiceaccountId\x12\"\n" + - "\rk8s_node_name\x18\x06 \x01(\tR\vk8sNodeName\"\xb1\v\n" + + "\rk8s_node_name\x18\x06 \x01(\tR\vk8sNodeName\"\xfd\v\n" + "\aCluster\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12(\n" + @@ -2701,7 +2719,8 @@ const file_storage_cluster_proto_rawDesc = "" + "\x0einit_bundle_id\x18\x1d \x01(\tR\finitBundleId\x123\n" + "\n" + "managed_by\x18\x1e \x01(\x0e2\x14.storage.ManagerTypeR\tmanagedBy\x12/\n" + - "\x13sensor_capabilities\x18\x1f \x03(\tR\x12sensorCapabilities\x1a9\n" + + "\x13sensor_capabilities\x18\x1f \x03(\tR\x12sensorCapabilities\x12J\n" + + "\"admission_controller_fail_on_error\x18 \x01(\bR\x1eadmissionControllerFailOnError\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a\\\n" + diff --git a/generated/storage/cluster_vtproto.pb.go b/generated/storage/cluster_vtproto.pb.go index 4bf9b59d4e615..56cb1ecb84ed2 100644 --- a/generated/storage/cluster_vtproto.pb.go +++ b/generated/storage/cluster_vtproto.pb.go @@ -235,6 +235,7 @@ func (m *StaticClusterConfig) CloneVT() *StaticClusterConfig { r.TolerationsConfig = m.TolerationsConfig.CloneVT() r.SlimCollector = m.SlimCollector r.AdmissionControllerEvents = m.AdmissionControllerEvents + r.AdmissionControllerFailureOnError = m.AdmissionControllerFailureOnError if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -339,6 +340,7 @@ func (m *Cluster) CloneVT() *Cluster { r.MostRecentSensorId = m.MostRecentSensorId.CloneVT() r.InitBundleId = m.InitBundleId r.ManagedBy = m.ManagedBy + r.AdmissionControllerFailOnError = m.AdmissionControllerFailOnError if rhs := m.Labels; rhs != nil { tmpContainer := make(map[string]string, len(rhs)) for k, v := range rhs { @@ -1051,6 +1053,9 @@ func (this *StaticClusterConfig) EqualVT(that *StaticClusterConfig) bool { if this.AdmissionControllerEvents != that.AdmissionControllerEvents { return false } + if this.AdmissionControllerFailureOnError != that.AdmissionControllerFailureOnError { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1267,6 +1272,9 @@ func (this *Cluster) EqualVT(that *Cluster) bool { return false } } + if this.AdmissionControllerFailOnError != that.AdmissionControllerFailOnError { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -2389,6 +2397,16 @@ func (m *StaticClusterConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.AdmissionControllerFailureOnError { + i-- + if m.AdmissionControllerFailureOnError { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } if m.AdmissionControllerEvents { i-- if m.AdmissionControllerEvents { @@ -2717,6 +2735,18 @@ func (m *Cluster) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.AdmissionControllerFailOnError { + i-- + if m.AdmissionControllerFailOnError { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x80 + } if len(m.SensorCapabilities) > 0 { for iNdEx := len(m.SensorCapabilities) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.SensorCapabilities[iNdEx]) @@ -4055,6 +4085,9 @@ func (m *StaticClusterConfig) SizeVT() (n int) { if m.AdmissionControllerEvents { n += 2 } + if m.AdmissionControllerFailureOnError { + n += 2 + } n += len(m.unknownFields) return n } @@ -4252,6 +4285,9 @@ func (m *Cluster) SizeVT() (n int) { n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) } } + if m.AdmissionControllerFailOnError { + n += 3 + } n += len(m.unknownFields) return n } @@ -6004,6 +6040,26 @@ func (m *StaticClusterConfig) UnmarshalVT(dAtA []byte) error { } } m.AdmissionControllerEvents = bool(v != 0) + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdmissionControllerFailureOnError", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AdmissionControllerFailureOnError = bool(v != 0) default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -7591,6 +7647,26 @@ func (m *Cluster) UnmarshalVT(dAtA []byte) error { } m.SensorCapabilities = append(m.SensorCapabilities, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 32: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdmissionControllerFailOnError", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AdmissionControllerFailOnError = bool(v != 0) default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -10903,6 +10979,26 @@ func (m *StaticClusterConfig) UnmarshalVTUnsafe(dAtA []byte) error { } } m.AdmissionControllerEvents = bool(v != 0) + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdmissionControllerFailureOnError", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AdmissionControllerFailureOnError = bool(v != 0) default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -12570,6 +12666,26 @@ func (m *Cluster) UnmarshalVTUnsafe(dAtA []byte) error { } m.SensorCapabilities = append(m.SensorCapabilities, stringValue) iNdEx = postIndex + case 32: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdmissionControllerFailOnError", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AdmissionControllerFailOnError = bool(v != 0) default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/image/templates/helm/stackrox-secured-cluster/values.yaml.htpl b/image/templates/helm/stackrox-secured-cluster/values.yaml.htpl index 8b1157f4d4ecf..9e92c27158344 100644 --- a/image/templates/helm/stackrox-secured-cluster/values.yaml.htpl +++ b/image/templates/helm/stackrox-secured-cluster/values.yaml.htpl @@ -15,17 +15,29 @@ image: main: [< required "" .MainRegistry >] collector: [< required "" .CollectorRegistry >] +admissionControl: + [<- if .AdmissionControllerFailOnError >] + failurePolicy: Fail + [<- else >] + failurePolicy: Ignore + [<- end >] + config: collectionMethod: [< default "CORE_BPF" .CollectionMethod >] admissionControl: - createService: [< default false .AdmissionController >] - listenOnUpdates: [< default false .AdmissionControlListenOnUpdates >] + createService: [< default true .AdmissionController >] + listenOnUpdates: [< default true .AdmissionControlListenOnUpdates >] + [<- if eq .ClusterType "OPENSHIFT_CLUSTER" >] listenOnEvents: [< default false .AdmissionControlListenOnEvents >] - enableService: [< default false .AdmissionControllerEnabled >] - enforceOnUpdates: [< default false .AdmissionControlEnforceOnUpdates >] - scanInline: [< default false .ScanInline >] + [<- else >] + listenOnEvents: [< default true .AdmissionControlListenOnEvents >] + [<- end >] + enableService: [< default true .AdmissionControllerEnabled >] + enforceOnUpdates: [< default true .AdmissionControlEnforceOnUpdates >] + scanInline: [< default true .ScanInline >] disableBypass: [< default false .DisableBypass >] timeout: [< default 10 .TimeoutSeconds >] + registryOverride: disableTaintTolerations: [< default false (not .TolerationsEnabled ) >] createUpgraderServiceAccount: [< default false .CreateUpgraderSA >] diff --git a/pkg/helm/charts/meta.go b/pkg/helm/charts/meta.go index fae8de88c38fd..b6866897e4ad3 100644 --- a/pkg/helm/charts/meta.go +++ b/pkg/helm/charts/meta.go @@ -52,6 +52,7 @@ type MetaValues struct { ScanInline bool AdmissionControllerEnabled bool AdmissionControlEnforceOnUpdates bool + AdmissionControllerFailOnError bool ReleaseBuild bool TelemetryEnabled bool TelemetryKey string diff --git a/proto/storage/cluster.proto b/proto/storage/cluster.proto index dae50f2012459..292aebe2dc7c1 100644 --- a/proto/storage/cluster.proto +++ b/proto/storage/cluster.proto @@ -110,6 +110,7 @@ message StaticClusterConfig { TolerationsConfig tolerations_config = 8; bool slim_collector = 9; bool admission_controller_events = 10; + bool admission_controller_failure_on_error = 11; } // The difference between Static and Dynamic cluster config is that Dynamic values are sent over the Central to Sensor gRPC connection. This has the benefit of allowing for "hot reloading" of values without restarting Secured cluster components. @@ -140,6 +141,7 @@ message SensorDeploymentIdentification { string k8s_node_name = 6; } +//Next tag: 33 message Cluster { string id = 1; // @gotags: search:"Cluster ID,hidden,store" sql:"pk,type(uuid)" string name = 2; // @gotags: search:"Cluster,store" sql:"unique" @@ -178,6 +180,7 @@ message Cluster { ManagerType managed_by = 30; repeated string sensor_capabilities = 31; + bool admission_controller_fail_on_error = 32; } enum ManagerType { diff --git a/proto/storage/proto.lock b/proto/storage/proto.lock index bf1a6d32e4e10..86f29cc4adcba 100644 --- a/proto/storage/proto.lock +++ b/proto/storage/proto.lock @@ -1987,6 +1987,11 @@ "id": 10, "name": "admission_controller_events", "type": "bool" + }, + { + "id": 11, + "name": "admission_controller_failure_on_error", + "type": "bool" } ] }, @@ -2194,6 +2199,11 @@ "name": "sensor_capabilities", "type": "string", "is_repeated": true + }, + { + "id": 32, + "name": "admission_controller_fail_on_error", + "type": "bool" } ], "maps": [ diff --git a/roxctl/maincommand/command_tree_debug.yaml b/roxctl/maincommand/command_tree_debug.yaml index cc46ae0804e9c..eec17efd32141 100644 --- a/roxctl/maincommand/command_tree_debug.yaml +++ b/roxctl/maincommand/command_tree_debug.yaml @@ -2024,6 +2024,8 @@ sensor: - admission-controller-disable-bypass - admission-controller-enforce-on-creates - admission-controller-enforce-on-updates + - admission-controller-enforcement + - admission-controller-fail-on-error - admission-controller-listen-on-creates - admission-controller-listen-on-updates - admission-controller-scan-inline @@ -2062,6 +2064,8 @@ sensor: - admission-controller-disable-bypass - admission-controller-enforce-on-creates - admission-controller-enforce-on-updates + - admission-controller-enforcement + - admission-controller-fail-on-error - admission-controller-listen-on-creates - admission-controller-listen-on-updates - admission-controller-scan-inline @@ -2101,6 +2105,8 @@ sensor: - admission-controller-disable-bypass - admission-controller-enforce-on-creates - admission-controller-enforce-on-updates + - admission-controller-enforcement + - admission-controller-fail-on-error - admission-controller-listen-on-creates - admission-controller-listen-on-updates - admission-controller-scan-inline diff --git a/roxctl/maincommand/command_tree_release.yaml b/roxctl/maincommand/command_tree_release.yaml index 8f211dbe788b3..3506c34c919de 100644 --- a/roxctl/maincommand/command_tree_release.yaml +++ b/roxctl/maincommand/command_tree_release.yaml @@ -1985,6 +1985,8 @@ sensor: - admission-controller-disable-bypass - admission-controller-enforce-on-creates - admission-controller-enforce-on-updates + - admission-controller-enforcement + - admission-controller-fail-on-error - admission-controller-listen-on-creates - admission-controller-listen-on-updates - admission-controller-scan-inline @@ -2023,6 +2025,8 @@ sensor: - admission-controller-disable-bypass - admission-controller-enforce-on-creates - admission-controller-enforce-on-updates + - admission-controller-enforcement + - admission-controller-fail-on-error - admission-controller-listen-on-creates - admission-controller-listen-on-updates - admission-controller-scan-inline @@ -2062,6 +2066,8 @@ sensor: - admission-controller-disable-bypass - admission-controller-enforce-on-creates - admission-controller-enforce-on-updates + - admission-controller-enforcement + - admission-controller-fail-on-error - admission-controller-listen-on-creates - admission-controller-listen-on-updates - admission-controller-scan-inline diff --git a/roxctl/sensor/generate/generate.go b/roxctl/sensor/generate/generate.go index 625430e7412d5..0fb0c4a58e946 100644 --- a/roxctl/sensor/generate/generate.go +++ b/roxctl/sensor/generate/generate.go @@ -28,12 +28,12 @@ const ( warningCentralEnvironmentError = "It was not possible to retrieve Central's runtime environment information: %v. Will use fallback defaults for " + mainImageRepository + " setting." - warningAdmissionControllerListenOnCreatesSet = `The --admission-controller-listen-on-creates flag has been deprecated and will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` - warningAdmissionControllerListenOnUpdatesSet = `The --admission-controller-listen-on-updates flag has been deprecated and will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` - warningAdmissionControllerScanInlineSet = `The --admission-controller-scan-inline flag has been deprecated and will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` - warningAdmissionControllerEnforceOnCreatesSet = `The --admission-controller-enforce-on-creates flag has been deprecated and will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` - warningAdmissionControllerEnforceOnUpdatesSet = `The --admission-controller-enforce-on-updates flag has been deprecated and will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` - warningAdmissionControllerTimeoutSet = `The --admission-controller-timeout flag has been deprecated and will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` + warningAdmissionControllerListenOnCreatesSet = `The --admission-controller-listen-on-creates will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` + warningAdmissionControllerListenOnUpdatesSet = `The --admission-controller-listen-on-updates will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` + warningAdmissionControllerScanInlineSet = `The --admission-controller-scan-inline will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` + warningAdmissionControllerEnforceOnCreatesSet = `The --admission-controller-enforce-on-creates flag will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` + warningAdmissionControllerEnforceOnUpdatesSet = `The --admission-controller-enforce-on-updates flag will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` + warningAdmissionControllerTimeoutSet = `The --admission-controller-timeout flag will be removed in future versions of roxctl. It will be ignored from version 4.9 onwards.` ) type sensorGenerateCommand struct { @@ -54,9 +54,10 @@ type sensorGenerateCommand struct { func defaultCluster() *storage.Cluster { return &storage.Cluster{ - AdmissionController: true, - AdmissionControllerEvents: true, - AdmissionControllerUpdates: true, + AdmissionController: true, + AdmissionControllerEvents: true, + AdmissionControllerUpdates: true, + AdmissionControllerFailOnError: false, TolerationsConfig: &storage.TolerationsConfig{ Disabled: false, }, @@ -66,6 +67,7 @@ func defaultCluster() *storage.Cluster { ScanInline: true, DisableBypass: false, EnforceOnUpdates: true, + TimeoutSeconds: 0, }, }, } @@ -107,6 +109,15 @@ func (s *sensorGenerateCommand) fullClusterCreation() error { common.LogInfoPsp(s.env.Logger(), s.enablePodSecurityPolicies) + acc := s.cluster.GetDynamicConfig().GetAdmissionControllerConfig() + if acc != nil { + // This ensures the new --admission-controller-enforcement flag value "wins". The Enabled value is + // used in admission controller business logic as "enforce on creates". The line below ensures we have + // enforcement "on" for both operations, or "off" for both, in line with the new design based on + // customer expectations. + acc.Enabled = acc.EnforceOnUpdates + } + id, err := s.createCluster(ctx, service) // If the error is not explicitly AlreadyExists or it is AlreadyExists AND continueIfExists isn't set // then return an error @@ -215,6 +226,12 @@ func Command(cliEnvironment environment.Environment) *cobra.Command { c.PersistentFlags().BoolVar(&ac.EnforceOnUpdates, "admission-controller-enforce-on-updates", true, "Dynamic enable for enforcing on object updates in the admission controller.") utils.Must(c.PersistentFlags().MarkDeprecated("admission-controller-enforce-on-updates", warningAdmissionControllerEnforceOnUpdatesSet)) + c.PersistentFlags().BoolVar(&generateCmd.cluster.AdmissionControllerFailOnError, "admission-controller-fail-on-error", false, "Fail the admission review request in case of errors or timeouts in request evaluation.") + c.PersistentFlags().BoolVar(&ac.EnforceOnUpdates, "admission-controller-enforcement", true, "Enforce security policies on the admission review request.") + + c.MarkFlagsMutuallyExclusive("admission-controller-enforce-on-creates", "admission-controller-enforcement") + c.MarkFlagsMutuallyExclusive("admission-controller-enforce-on-updates", "admission-controller-enforcement") + flags.AddTimeoutWithDefault(c, 5*time.Minute) c.AddCommand(k8s(generateCmd))