Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions manifests/0000_50_olm_02-olm-operator.serviceaccount.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ rules:
verbs: ["watch", "list", "get", "create", "update", "patch", "delete", "deletecollection", "escalate", "bind"]
- nonResourceURLs: ["*"]
verbs: ["*"]
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- security.openshift.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ rules:
verbs: ["watch", "list", "get", "create", "update", "patch", "delete", "deletecollection", "escalate", "bind"]
- nonResourceURLs: ["*"]
verbs: ["*"]
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- security.openshift.io
resources:
Expand Down
12 changes: 6 additions & 6 deletions staging/operator-lifecycle-manager/cmd/catalog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,15 @@ func (o *options) run(ctx context.Context, logger *logrus.Logger) error {
o.catalogNamespace = catalogNamespaceEnvVarValue
}

config, err := clientcmd.BuildConfigFromFlags("", o.kubeconfig)
if err != nil {
return fmt.Errorf("error configuring client: %s", err.Error())
}

listenAndServe, err := server.GetListenAndServeFunc(
server.WithLogger(logger),
server.WithTLS(&o.tlsCertPath, &o.tlsKeyPath, &o.clientCAPath),
server.WithKubeConfig(config),
server.WithDebug(o.debug),
)
if err != nil {
Expand All @@ -71,12 +77,6 @@ func (o *options) run(ctx context.Context, logger *logrus.Logger) error {
logger.Error(err)
}
}()

// create a config client for operator status
config, err := clientcmd.BuildConfigFromFlags("", o.kubeconfig)
if err != nil {
return fmt.Errorf("error configuring client: %s", err.Error())
}
configClient, err := configv1client.NewForConfig(config)
if err != nil {
return fmt.Errorf("error configuring client: %s", err.Error())
Expand Down
19 changes: 12 additions & 7 deletions staging/operator-lifecycle-manager/cmd/olm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,18 @@ func main() {
}
logger.Infof("log level %s", logger.Level)

listenAndServe, err := server.GetListenAndServeFunc(server.WithLogger(logger), server.WithTLS(tlsCertPath, tlsKeyPath, clientCAPath), server.WithDebug(*debug))
mgr, err := Manager(ctx, *debug)
if err != nil {
logger.WithError(err).Fatal("error configuring controller manager")
}
config := mgr.GetConfig()

listenAndServe, err := server.GetListenAndServeFunc(
server.WithLogger(logger),
server.WithTLS(tlsCertPath, tlsKeyPath, clientCAPath),
server.WithKubeConfig(config),
server.WithDebug(*debug),
)
if err != nil {
logger.Fatalf("Error setting up health/metric/pprof service: %v", err)
}
Expand All @@ -134,12 +145,6 @@ func main() {
}
}()

mgr, err := Manager(ctx, *debug)
if err != nil {
logger.WithError(err).Fatal("error configuring controller manager")
}
config := mgr.GetConfig()

// create a config that validates we're creating objects with labels
validatingConfig := validatingroundtripper.Wrap(config, mgr.GetScheme())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ rules:
verbs: ["watch", "list", "get", "create", "update", "patch", "delete", "deletecollection", "escalate", "bind"]
- nonResourceURLs: ["*"]
verbs: ["*"]
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
---
kind: ServiceAccount
apiVersion: v1
Expand Down
63 changes: 42 additions & 21 deletions staging/operator-lifecycle-manager/pkg/lib/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ import (
"fmt"
"net/http"
"path/filepath"
"time"

"github.com/go-logr/logr"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
"sigs.k8s.io/controller-runtime/pkg/log"
)

// Option applies a configuration option to the given config.
Expand Down Expand Up @@ -43,11 +48,18 @@ func WithDebug(debug bool) Option {
}
}

func WithKubeConfig(config *rest.Config) Option {
return func(sc *serverConfig) {
sc.kubeConfig = config
}
}

type serverConfig struct {
logger *logrus.Logger
tlsCertPath *string
tlsKeyPath *string
clientCAPath *string
kubeConfig *rest.Config
debug bool
}

Expand All @@ -62,6 +74,7 @@ func defaultServerConfig() serverConfig {
tlsCertPath: nil,
tlsKeyPath: nil,
clientCAPath: nil,
kubeConfig: nil,
logger: nil,
debug: false,
}
Expand Down Expand Up @@ -89,13 +102,40 @@ func (sc serverConfig) getListenAndServeFunc() (func() error, error) {
return nil, fmt.Errorf("both --tls-key and --tls-crt must be provided for TLS to be enabled")
}

// Create base HTTP mux with unprotected endpoints
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
profile.RegisterHandlers(mux, profile.WithTLS(tlsEnabled || !sc.debug))

// Set up authenticated metrics endpoint if kubeConfig is provided
if sc.kubeConfig != nil && tlsEnabled {
// Create authentication filter using controller-runtime
filter, err := filters.WithAuthenticationAndAuthorization(sc.kubeConfig, &http.Client{
Timeout: 30 * time.Second,
})
if err != nil {
return nil, fmt.Errorf("failed to create authentication filter: %w", err)
}

// Create authenticated metrics handler
logger := log.FromContext(context.Background())
authenticatedMetricsHandler, err := filter(logger, promhttp.Handler())
if err != nil {
return nil, fmt.Errorf("failed to wrap metrics handler with authentication: %w", err)
}

mux.Handle("/metrics", authenticatedMetricsHandler)
sc.logger.Info("Metrics endpoint configured with authentication and authorization")
} else {
// Fallback to unprotected metrics (for development/testing)
mux.Handle("/metrics", promhttp.Handler())
if sc.kubeConfig == nil {
sc.logger.Warn("No Kubernetes config provided - metrics endpoint will be unprotected")
}
}

s := http.Server{
Handler: mux,
Addr: sc.getAddress(tlsEnabled),
Expand All @@ -116,31 +156,12 @@ func (sc serverConfig) getListenAndServeFunc() (func() error, error) {
return nil, fmt.Errorf("error creating cert file watcher: %v", err)
}
csw.Run(context.Background())
certPoolStore, err := filemonitor.NewCertPoolStore(*sc.clientCAPath)
if err != nil {
return nil, fmt.Errorf("certificate monitoring for client-ca failed: %v", err)
}
cpsw, err := filemonitor.NewWatch(sc.logger, []string{filepath.Dir(*sc.clientCAPath)}, certPoolStore.HandleCABundleUpdate)
if err != nil {
return nil, fmt.Errorf("error creating cert file watcher: %v", err)
}
cpsw.Run(context.Background())

s.TLSConfig = &tls.Config{
GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
return certStore.GetCertificate(), nil
},
GetConfigForClient: func(_ *tls.ClientHelloInfo) (*tls.Config, error) {
var certs []tls.Certificate
if cert := certStore.GetCertificate(); cert != nil {
certs = append(certs, *cert)
}
return &tls.Config{
Certificates: certs,
ClientCAs: certPoolStore.GetCertPool(),
ClientAuth: tls.VerifyClientCertIfGiven,
}, nil
},
Comment on lines 119 to 143
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't obvious to me what the connection is between use of filters.WithAuthenticationAndAuthorization and removing the certPoolStore/GetConfigForClient. What's the story here?

NextProtos: []string{"http/1.1"}, // Disable HTTP/2 for security
}
return func() error {
return s.ListenAndServeTLS("", "")
Expand Down