1
0
mirror of https://github.com/coreos/prometheus-operator.git synced 2026-02-05 06:45:27 +01:00

chore: check operator's permissions on status

This commit ensures that the operator's Service Account has the expected
permissions to manage status subresources when the
`StatusForConfigurationResources` feature gate is enabled.

Signed-off-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
Simon Pasquier
2025-10-13 10:33:39 +02:00
parent e564daadae
commit 2c160ddd69
6 changed files with 157 additions and 20 deletions

View File

@@ -197,6 +197,47 @@ func parseFlags(fs *flag.FlagSet) {
_ = fs.Parse(os.Args[1:])
}
// checkStatusSubresourcePermissions returns true when the operator has the
// required permissions to update the status subresource of the provided
// configuration resources.
func checkStatusSubresourcePermissions(
ctx context.Context,
logger *slog.Logger,
kclient kubernetes.Interface,
gvrs []schema.GroupVersionResource,
) bool {
ok := true
for _, gvr := range gvrs {
allowed, errs, err := k8sutil.IsAllowed(
ctx,
kclient.AuthorizationV1().SelfSubjectAccessReviews(),
cfg.Namespaces.AllowList.Slice(),
k8sutil.ResourceAttribute{
Group: gvr.Group,
Version: gvr.Version,
Resource: fmt.Sprintf("%s/status", gvr.Resource),
Verbs: []string{"update"},
},
)
if err != nil {
ok = false
logger.Error("failed to check permissions on status subresource", "err", err, "resource", gvr.String())
continue
}
if allowed {
continue
}
ok = false
for _, reason := range errs {
logger.Error("missing permission on status subresource", "reason", reason, "resource", gvr.String())
}
}
return ok
}
func run(fs *flag.FlagSet) int {
parseFlags(fs)
@@ -391,6 +432,25 @@ func run(fs *flag.FlagSet) int {
var po *prometheuscontroller.Operator
if prometheusSupported {
if cfg.Gates.Enabled(operator.StatusForConfigurationResourcesFeature) {
if !checkStatusSubresourcePermissions(
ctx,
logger,
kclient,
[]schema.GroupVersionResource{
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.ServiceMonitorName),
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.PodMonitorName),
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.ProbeName),
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.PrometheusRuleName),
},
) {
cancel()
return 1
}
promControllerOptions = append(promControllerOptions, prometheuscontroller.WithConfigResourceStatus())
}
po, err = prometheuscontroller.New(ctx, restConfig, cfg, logger, r, promControllerOptions...)
if err != nil {
logger.Error("instantiating prometheus controller failed", "err", err)
@@ -453,6 +513,24 @@ func run(fs *flag.FlagSet) int {
var pao *prometheusagentcontroller.Operator
if prometheusAgentSupported {
if cfg.Gates.Enabled(operator.StatusForConfigurationResourcesFeature) {
if !checkStatusSubresourcePermissions(
ctx,
logger,
kclient,
[]schema.GroupVersionResource{
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.ServiceMonitorName),
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.PodMonitorName),
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.ProbeName),
},
) {
cancel()
return 1
}
promAgentControllerOptions = append(promAgentControllerOptions, prometheusagentcontroller.WithConfigResourceStatus())
}
pao, err = prometheusagentcontroller.New(ctx, restConfig, cfg, logger, r, promAgentControllerOptions...)
if err != nil {
logger.Error("instantiating prometheus-agent controller failed", "err", err)
@@ -489,6 +567,11 @@ func run(fs *flag.FlagSet) int {
var ao *alertmanagercontroller.Operator
if alertmanagerSupported {
if cfg.Gates.Enabled(operator.StatusForConfigurationResourcesFeature) {
// TODO: check permissions when implementing the AlertmanagerConfig status subresource.
alertmanagerControllerOptions = append(alertmanagerControllerOptions, alertmanagercontroller.WithConfigResourceStatus())
}
ao, err = alertmanagercontroller.New(ctx, restConfig, cfg, logger, r, alertmanagerControllerOptions...)
if err != nil {
logger.Error("instantiating alertmanager controller failed", "err", err)
@@ -525,6 +608,22 @@ func run(fs *flag.FlagSet) int {
var to *thanoscontroller.Operator
if thanosRulerSupported {
if cfg.Gates.Enabled(operator.StatusForConfigurationResourcesFeature) {
if !checkStatusSubresourcePermissions(
ctx,
logger,
kclient,
[]schema.GroupVersionResource{
monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.PrometheusRuleName),
},
) {
cancel()
return 1
}
thanosControllerOptions = append(thanosControllerOptions, thanoscontroller.WithConfigResourceStatus())
}
to, err = thanoscontroller.New(ctx, restConfig, cfg, logger, r, thanosControllerOptions...)
if err != nil {
logger.Error("instantiating thanos controller failed", "err", err)

View File

@@ -121,6 +121,14 @@ func WithStorageClassValidation() ControllerOption {
}
}
// WithConfigResourceStatus tells that the controller can manage the status of
// configuration resources.
func WithConfigResourceStatus() ControllerOption {
return func(o *Operator) {
o.configResourcesStatusEnabled = true
}
}
// New creates a new controller.
func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger *slog.Logger, r prometheus.Registerer, options ...ControllerOption) (*Operator, error) {
logger = logger.With("component", controllerName)
@@ -166,7 +174,6 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
Annotations: c.Annotations,
Labels: c.Labels,
},
configResourcesStatusEnabled: c.Gates.Enabled(operator.StatusForConfigurationResourcesFeature),
}
for _, opt := range options {
opt(o)

View File

@@ -29,20 +29,21 @@ import (
// FinalizerSyncer holds the configuration and dependencies
// required to perform finalizer synchronization.
type FinalizerSyncer struct {
mdClient metadata.Interface
gvr schema.GroupVersionResource
configResourcesStatusEnabled bool
mdClient metadata.Interface
gvr schema.GroupVersionResource
disabled bool
}
func NewFinalizerSyncer(
mdClient metadata.Interface,
gvr schema.GroupVersionResource,
configResourcesStatusEnabled bool,
) *FinalizerSyncer {
func NewFinalizerSyncer(mdClient metadata.Interface, gvr schema.GroupVersionResource) *FinalizerSyncer {
return &FinalizerSyncer{
mdClient: mdClient,
gvr: gvr,
configResourcesStatusEnabled: configResourcesStatusEnabled,
mdClient: mdClient,
gvr: gvr,
}
}
func NewNoopFinalizerSyncer() *FinalizerSyncer {
return &FinalizerSyncer{
disabled: true,
}
}
@@ -52,7 +53,7 @@ func NewFinalizerSyncer(
// Returns true if the finalizer was added, otherwise false.
// The second return value indicates any error encountered during the operation.
func (s *FinalizerSyncer) Sync(ctx context.Context, p metav1.Object, deletionInProgress bool, statusCleanup func() error) (bool, error) {
if !s.configResourcesStatusEnabled {
if s.disabled {
return false, nil
}

View File

@@ -123,6 +123,14 @@ func WithStorageClassValidation() ControllerOption {
}
}
// WithConfigResourceStatus tells that the controller can manage the status of
// configuration resources.
func WithConfigResourceStatus() ControllerOption {
return func(o *Operator) {
o.configResourcesStatusEnabled = true
}
}
// New creates a new controller.
func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger *slog.Logger, r prometheus.Registerer, options ...ControllerOption) (*Operator, error) {
logger = logger.With("component", controllerName)
@@ -163,7 +171,7 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
controllerID: c.ControllerID,
newEventRecorder: c.EventRecorderFactory(client, controllerName),
configResourcesStatusEnabled: c.Gates.Enabled(operator.StatusForConfigurationResourcesFeature),
finalizerSyncer: operator.NewFinalizerSyncer(mdClient, monitoringv1alpha1.SchemeGroupVersion.WithResource(monitoringv1alpha1.PrometheusAgentName), c.Gates.Enabled(operator.StatusForConfigurationResourcesFeature)),
finalizerSyncer: operator.NewNoopFinalizerSyncer(),
}
o.metrics.MustRegister(
o.reconciliations,
@@ -172,6 +180,10 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
opt(o)
}
if o.configResourcesStatusEnabled {
o.finalizerSyncer = operator.NewFinalizerSyncer(mdClient, monitoringv1alpha1.SchemeGroupVersion.WithResource(monitoringv1alpha1.PrometheusAgentName))
}
o.promInfs, err = informers.NewInformersForResource(
informers.NewMonitoringInformerFactories(
c.Namespaces.PrometheusAllowList,

View File

@@ -144,6 +144,14 @@ func WithoutUnmanagedConfiguration() ControllerOption {
}
}
// WithConfigResourceStatus tells that the controller can manage the status of
// configuration resources.
func WithConfigResourceStatus() ControllerOption {
return func(o *Operator) {
o.configResourcesStatusEnabled = true
}
}
// New creates a new controller.
func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger *slog.Logger, r prometheus.Registerer, opts ...ControllerOption) (*Operator, error) {
logger = logger.With("component", controllerName)
@@ -190,16 +198,19 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
metrics: operator.NewMetrics(r),
reconciliations: &operator.ReconciliationTracker{},
controllerID: c.ControllerID,
newEventRecorder: c.EventRecorderFactory(client, controllerName),
retentionPoliciesEnabled: c.Gates.Enabled(operator.PrometheusShardRetentionPolicyFeature),
configResourcesStatusEnabled: c.Gates.Enabled(operator.StatusForConfigurationResourcesFeature),
finalizerSyncer: operator.NewFinalizerSyncer(mdClient, monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.PrometheusName), c.Gates.Enabled(operator.StatusForConfigurationResourcesFeature)),
controllerID: c.ControllerID,
newEventRecorder: c.EventRecorderFactory(client, controllerName),
retentionPoliciesEnabled: c.Gates.Enabled(operator.PrometheusShardRetentionPolicyFeature),
finalizerSyncer: operator.NewNoopFinalizerSyncer(),
}
for _, opt := range opts {
opt(o)
}
if o.configResourcesStatusEnabled {
o.finalizerSyncer = operator.NewFinalizerSyncer(mdClient, monitoringv1.SchemeGroupVersion.WithResource(monitoringv1.PrometheusName))
}
o.metrics.MustRegister(o.reconciliations)
o.promInfs, err = informers.NewInformersForResource(

View File

@@ -112,6 +112,14 @@ func WithStorageClassValidation() ControllerOption {
}
}
// WithConfigResourceStatus tells that the controller can manage the status of
// configuration resources.
func WithConfigResourceStatus() ControllerOption {
return func(o *Operator) {
o.configResourcesStatusEnabled = true
}
}
// New creates a new controller.
func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger *slog.Logger, r prometheus.Registerer, options ...ControllerOption) (*Operator, error) {
logger = logger.With("component", controllerName)
@@ -151,7 +159,6 @@ func New(ctx context.Context, restConfig *rest.Config, c operator.Config, logger
Labels: c.Labels,
LocalHost: c.LocalHost,
},
configResourcesStatusEnabled: c.Gates.Enabled(operator.StatusForConfigurationResourcesFeature),
}
for _, opt := range options {
opt(o)