From 1d0d2c95f61455cef535504060cce55a6b5d1ad1 Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Fri, 18 Nov 2022 18:14:53 +0100 Subject: [PATCH 1/3] CLI Usage: authorino [command] Available Commands: completion Generate the autocompletion script for the specified shell help Help about any command server Run the authorization server version Prints the Authorino version info --- Dockerfile | 2 +- Makefile | 2 +- go.mod | 4 +- go.sum | 2 + main.go | 243 ++++++++++++++++++++++++++++++++--------------------- 5 files changed, 156 insertions(+), 97 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4b36b81c..74c8f041 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,4 +14,4 @@ WORKDIR / COPY --from=builder /workspace/authorino . USER 1001 -ENTRYPOINT ["/authorino"] +ENTRYPOINT ["/authorino", "server"] diff --git a/Makefile b/Makefile index 5f10f2b3..b1f57e3a 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,7 @@ manifests: controller-gen kustomize ## Generates the manifests in $PROJECT_DIR/i controller-gen crd:crdVersions=v1 rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=install/crd output:rbac:artifacts:config=install/rbac && kustomize build install > $(AUTHORINO_MANIFESTS) run: generate manifests ## Runs the application against the Kubernetes cluster configured in ~/.kube/config - go run -ldflags "-X main.version=$(VERSION)" ./main.go + go run -ldflags "-X main.version=$(VERSION)" ./main.go server build: generate ## Builds the manager binary CGO_ENABLED=0 GO111MODULE=on go build -a -ldflags "-X main.version=$(VERSION)" -o bin/authorino main.go diff --git a/go.mod b/go.mod index 2798e95f..ab328163 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,8 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/open-policy-agent/opa v0.43.1 github.com/prometheus/client_golang v1.12.2 + github.com/spf13/cobra v1.5.0 + github.com/spf13/pflag v1.0.5 github.com/tidwall/gjson v1.14.0 go.uber.org/zap v1.19.1 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd @@ -59,6 +61,7 @@ require ( github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -72,7 +75,6 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/cast v1.4.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/vektah/gqlparser/v2 v2.4.6 // indirect diff --git a/go.sum b/go.sum index ec7bd2ab..082a9570 100644 --- a/go.sum +++ b/go.sum @@ -681,6 +681,7 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= @@ -1030,6 +1031,7 @@ github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= diff --git a/main.go b/main.go index 5b9dfbf3..caa847c8 100644 --- a/main.go +++ b/main.go @@ -20,7 +20,6 @@ import ( "crypto/sha256" "crypto/tls" "encoding/hex" - "flag" "fmt" "net" "net/http" @@ -28,14 +27,7 @@ import ( "strconv" "time" - envoy_auth "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - healthpb "google.golang.org/grpc/health/grpc_health_v1" - - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - + "github.com/go-logr/logr" api "github.com/kuadrant/authorino/api/v1beta1" "github.com/kuadrant/authorino/controllers" "github.com/kuadrant/authorino/pkg/evaluators" @@ -45,6 +37,14 @@ import ( "github.com/kuadrant/authorino/pkg/metrics" "github.com/kuadrant/authorino/pkg/service" + envoy_auth "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + healthpb "google.golang.org/grpc/health/grpc_health_v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -55,6 +55,27 @@ import ( ) const ( + flagWatchNamespace = "watch-namespace" + flagWatchedAuthConfigLabelSelector = "auth-config-label-selector" + flagWatchedSecretLabelSelector = "secret-label-selector" + flagLogLevel = "log-level" + flagLogMode = "log-mode" + flagTimeout = "timeout" + flagExtAuthGRPCPort = "ext-auth-grpc-port" + flagExtAuthHTTPPort = "ext-auth-http-port" + flagTLSCertPath = "tls-cert" + flagTLSCertKeyPath = "tls-cert-key" + flagOIDCHTTPPort = "oidc-http-port" + flagOIDCTLSCertPath = "oidc-tls-cert" + flagOIDCTLSCertKeyPath = "oidc-tls-cert-key" + flagEvaluatorCacheSize = "evaluator-cache-size" // in megabytes + flagDeepMetricsEnabled = "deep-metrics-enabled" + flagMetricsAddr = "metrics-addr" + flagHealthProbeAddr = "health-probe-addr" + flagEnableLeaderElection = "enable-leader-election" + flagMaxHttpRequestBodySize = "max-http-request-body-size" // in bytes + + // [DEPRECATED] use command-line flags instead envWatchNamespace = "WATCH_NAMESPACE" envWatchedAuthConfigLabelSelector = "AUTH_CONFIG_LABEL_SELECTOR" envWatchedSecretLabelSelector = "SECRET_LABEL_SELECTOR" @@ -72,102 +93,128 @@ const ( envDeepMetricsEnabled = "DEEP_METRICS_ENABLED" envMaxHttpRequestBodySize = "MAX_HTTP_REQUEST_BODY_SIZE" // in bytes - flagMetricsAddr = "metrics-addr" - flagHealthProbeAddr = "health-probe-addr" - flagEnableLeaderElection = "enable-leader-election" - - defaultWatchNamespace = "" - defaultWatchedAuthConfigLabelSelector = "" - defaultWatchedSecretLabelSelector = "authorino.kuadrant.io/managed-by=authorino" - defaultLogLevel = "info" - defaultLogMode = "production" - defaultTimeout = "0" - defaultExtAuthGRPCPort = "50051" - defaultExtAuthHTTPPort = "5001" - defaultTLSCertPath = "" - defaultTLSCertKeyPath = "" - defaultOIDCHTTPPort = "8083" - defaultOIDCTLSCertPath = "" - defaultOIDCTLSCertKeyPath = "" - defaultEvaluatorCacheSize = "1" - defaultDeepMetricsEnabled = "false" - defaultMetricsAddr = ":8080" - defaultHealthProbeAddr = ":8081" - defaultEnableLeaderElection = false - defaultMaxHttpRequestBodySize = "8192" // 8KB - gRPCMaxConcurrentStreams = 10000 leaderElectionIDSuffix = "authorino.kuadrant.io" ) var ( - watchNamespace = fetchEnv(envWatchNamespace, defaultWatchNamespace) - watchedAuthConfigLabelSelector = fetchEnv(envWatchedAuthConfigLabelSelector, defaultWatchedAuthConfigLabelSelector) - watchedSecretLabelSelector = fetchEnv(envWatchedSecretLabelSelector, defaultWatchedSecretLabelSelector) - logLevel = fetchEnv(envLogLevel, defaultLogLevel) - logMode = fetchEnv(envLogMode, defaultLogMode) - timeout, _ = strconv.Atoi(fetchEnv(envTimeout, defaultTimeout)) - timeoutMs = time.Duration(timeout) * time.Millisecond - extAuthGRPCPort = fetchEnv(envExtAuthGRPCPort, defaultExtAuthGRPCPort) - extAuthHTTPPort = fetchEnv(envExtAuthHTTPPort, defaultExtAuthHTTPPort) - tlsCertPath = fetchEnv(envTLSCertPath, defaultTLSCertPath) - tlsCertKeyPath = fetchEnv(envTLSCertKeyPath, defaultTLSCertKeyPath) - oidcHTTPPort = fetchEnv(envOIDCHTTPPort, defaultOIDCHTTPPort) - oidcTLSCertPath = fetchEnv(envOIDCTLSCertPath, defaultOIDCTLSCertPath) - oidcTLSCertKeyPath = fetchEnv(envOIDCTLSCertKeyPath, defaultOIDCTLSCertKeyPath) - metadataCacheSize = fetchEnv(envEvaluatorCacheSize, defaultEvaluatorCacheSize) - deepMetricEnabled = fetchEnv(envDeepMetricsEnabled, defaultDeepMetricsEnabled) - maxHttpRequestBodySize, _ = strconv.ParseInt(fetchEnv(envMaxHttpRequestBodySize, defaultMaxHttpRequestBodySize), 10, 64) - - scheme = runtime.NewScheme() - logOpts = log.Options{Level: log.ToLogLevel(logLevel), Mode: log.ToLogMode(logMode)} - logger = log.NewLogger(logOpts).WithName("authorino") - + // ldflags version string + + // option flags + watchNamespace string + watchedAuthConfigLabelSelector string + watchedSecretLabelSelector string + logLevel string + logMode string + timeout int + extAuthGRPCPort int + extAuthHTTPPort int + tlsCertPath string + tlsCertKeyPath string + oidcHTTPPort int + oidcTLSCertPath string + oidcTLSCertKeyPath string + evaluatorCacheSize int + deepMetricsEnabled bool + metricsAddr string + healthProbeAddr string + enableLeaderElection bool + maxHttpRequestBodySize int64 + + defaultWatchNamespace = fetchEnv(envWatchNamespace, "") + defaultWatchedAuthConfigLabelSelector = fetchEnv(envWatchedAuthConfigLabelSelector, "") + defaultWatchedSecretLabelSelector = fetchEnv(envWatchedSecretLabelSelector, "authorino.kuadrant.io/managed-by=authorino") + defaultLogLevel = fetchEnv(envLogLevel, "info") + defaultLogMode = fetchEnv(envLogMode, "production") + defaultTimeout, _ = strconv.Atoi(fetchEnv(envTimeout, 0)) + defaultExtAuthGRPCPort, _ = strconv.Atoi(fetchEnv(envExtAuthGRPCPort, 50051)) + defaultExtAuthHTTPPort, _ = strconv.Atoi(fetchEnv(envExtAuthHTTPPort, 5001)) + defaultTLSCertPath = fetchEnv(envTLSCertPath, "") + defaultTLSCertKeyPath = fetchEnv(envTLSCertKeyPath, "") + defaultOIDCHTTPPort, _ = strconv.Atoi(fetchEnv(envOIDCHTTPPort, 8083)) + defaultOIDCTLSCertPath = fetchEnv(envOIDCTLSCertPath, "") + defaultOIDCTLSCertKeyPath = fetchEnv(envOIDCTLSCertKeyPath, "") + defaultEvaluatorCacheSize, _ = strconv.Atoi(fetchEnv(envEvaluatorCacheSize, 1)) // 1 Mb + defaultDeepMetricsEnabled, _ = strconv.ParseBool(fetchEnv(envDeepMetricsEnabled, false)) + defaultMetricsAddr = ":8080" + defaultHealthProbeAddr = ":8081" + defaultEnableLeaderElection = false + defaultMaxHttpRequestBodySize, _ = strconv.ParseInt(fetchEnv(envMaxHttpRequestBodySize, 8192), 10, 64) // 8 Kb + + scheme = runtime.NewScheme() + + logger logr.Logger ) func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(api.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme +} - log.SetLogger(logger, logOpts) +func main() { + cmdRoot := &cobra.Command{ + Use: "authorino", + Short: "Authorino is a Kubernetes-native authorization server.", + } + + cmdServer := &cobra.Command{ + Use: "server", + Short: "Runs the authorization server", + Run: run, + } + + cmdServer.PersistentFlags().StringVar(&watchNamespace, flagWatchNamespace, defaultWatchNamespace, "Kubernetes namespace to watch") + cmdServer.PersistentFlags().StringVar(&watchedAuthConfigLabelSelector, flagWatchedAuthConfigLabelSelector, defaultWatchedAuthConfigLabelSelector, "Kubernetes label selector to filter AuthConfig resources to watch") + cmdServer.PersistentFlags().StringVar(&watchedSecretLabelSelector, flagWatchedSecretLabelSelector, defaultWatchedSecretLabelSelector, "Kubernetes label selector to filter Secret resources to watch") + cmdServer.PersistentFlags().StringVar(&logLevel, flagLogLevel, defaultLogLevel, "Log level") + cmdServer.PersistentFlags().StringVar(&logMode, flagLogMode, defaultLogMode, "Log mode") + cmdServer.PersistentFlags().IntVar(&timeout, flagTimeout, defaultTimeout, "Server timeout - in milliseconds") + cmdServer.PersistentFlags().IntVar(&extAuthGRPCPort, flagExtAuthGRPCPort, defaultExtAuthGRPCPort, "Port number of authorization server - gRPC interface") + cmdServer.PersistentFlags().IntVar(&extAuthHTTPPort, flagExtAuthHTTPPort, defaultExtAuthHTTPPort, "Port number of authorization server - raw HTTP interface") + cmdServer.PersistentFlags().StringVar(&tlsCertPath, flagTLSCertPath, defaultTLSCertPath, "Path to the public TLS server certificate file in the file system - authorization server") + cmdServer.PersistentFlags().StringVar(&tlsCertKeyPath, flagTLSCertKeyPath, defaultTLSCertKeyPath, "Path to the private TLS server certificate key file in the file system - authorization server") + cmdServer.PersistentFlags().IntVar(&oidcHTTPPort, flagOIDCHTTPPort, defaultOIDCHTTPPort, "Port number of OIDC Discovery server for Festival Wristband tokens") + cmdServer.PersistentFlags().StringVar(&oidcTLSCertPath, flagOIDCTLSCertPath, defaultOIDCTLSCertPath, "Path to the public TLS server certificate file in the file system - Festival Wristband OIDC Discovery server") + cmdServer.PersistentFlags().StringVar(&oidcTLSCertKeyPath, flagOIDCTLSCertKeyPath, defaultOIDCTLSCertKeyPath, "Path to the private TLS server certificate key file in the file system - Festival Wristband OIDC Discovery server") + cmdServer.PersistentFlags().IntVar(&evaluatorCacheSize, flagEvaluatorCacheSize, defaultEvaluatorCacheSize, "Cache size of each Authorino evaluator if enabled in the AuthConfig - in megabytes") + cmdServer.PersistentFlags().BoolVar(&deepMetricsEnabled, flagDeepMetricsEnabled, defaultDeepMetricsEnabled, "Enable deep metrics at the level of each evaluator when requested in the AuthConfig, exported by the metrics server") + cmdServer.PersistentFlags().StringVar(&metricsAddr, flagMetricsAddr, defaultMetricsAddr, "The network address the metrics endpoint binds to") + cmdServer.PersistentFlags().StringVar(&healthProbeAddr, flagHealthProbeAddr, defaultHealthProbeAddr, "The network address the health probe endpoint binds to") + cmdServer.PersistentFlags().BoolVar(&enableLeaderElection, flagEnableLeaderElection, defaultEnableLeaderElection, "Enable leader election for status updater - ensures only one instance of Authorino tries to update the status of reconciled resources") + cmdServer.PersistentFlags().Int64Var(&maxHttpRequestBodySize, flagMaxHttpRequestBodySize, defaultMaxHttpRequestBodySize, "Maximum size of the body of requests accepted in the raw HTTP interface of the authorization server - in bytes") + + cmdVersion := &cobra.Command{ + Use: "version", + Short: "Prints the Authorino version info", + Run: printVersion, + } - evaluators.EvaluatorCacheSize, _ = strconv.Atoi(metadataCacheSize) - metrics.DeepMetricsEnabled, _ = strconv.ParseBool(deepMetricEnabled) + cmdRoot.AddCommand(cmdServer, cmdVersion) + + if err := cmdRoot.Execute(); err != nil { + fmt.Println("error: ", err) + os.Exit(1) + } } -func main() { - var metricsAddr, healthProbeAddr string - var enableLeaderElection bool - flag.StringVar(&metricsAddr, flagMetricsAddr, defaultMetricsAddr, "The address the metric endpoint binds to.") - flag.StringVar(&healthProbeAddr, flagHealthProbeAddr, defaultHealthProbeAddr, "The address the health probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, flagEnableLeaderElection, defaultEnableLeaderElection, "Enable leader election for status updater. Ensures only one instance of Authorino tries to update the status of reconciled resources.") - flag.Parse() +func run(cmd *cobra.Command, _ []string) { + logOpts := log.Options{Level: log.ToLogLevel(logLevel), Mode: log.ToLogMode(logMode)} + logger = log.NewLogger(logOpts).WithName("authorino") + log.SetLogger(logger, logOpts) logger.Info("booting up authorino", "version", version) - logger.V(1).Info("setting up with options", - envWatchNamespace, watchNamespace, - envWatchedAuthConfigLabelSelector, watchedAuthConfigLabelSelector, - envWatchedSecretLabelSelector, watchedSecretLabelSelector, - envLogLevel, logLevel, - envLogMode, logMode, - envTimeout, timeout, - envExtAuthGRPCPort, extAuthGRPCPort, - envExtAuthHTTPPort, extAuthHTTPPort, - envTLSCertPath, tlsCertPath, - envTLSCertKeyPath, tlsCertKeyPath, - envOIDCHTTPPort, oidcHTTPPort, - envOIDCTLSCertPath, oidcTLSCertPath, - envOIDCTLSCertKeyPath, oidcTLSCertKeyPath, - envEvaluatorCacheSize, metadataCacheSize, - envDeepMetricsEnabled, deepMetricEnabled, - flagMetricsAddr, metricsAddr, - flagHealthProbeAddr, healthProbeAddr, - flagEnableLeaderElection, enableLeaderElection, - ) + var flags []interface{} + cmd.PersistentFlags().VisitAll(func(flag *pflag.Flag) { + flags = append(flags, flag.Name, flag.Value.String()) + }) + + logger.V(1).Info("setting up with options", flags...) + + evaluators.EvaluatorCacheSize = evaluatorCacheSize + metrics.DeepMetricsEnabled = deepMetricsEnabled managerOptions := ctrl.Options{ Scheme: scheme, @@ -319,7 +366,7 @@ func startExtAuthServerGRPC(authConfigIndex index.Index) { grpcServer := grpc.NewServer(grpcServerOpts...) - envoy_auth.RegisterAuthorizationServer(grpcServer, &service.AuthService{Index: authConfigIndex, Timeout: timeoutMs}) + envoy_auth.RegisterAuthorizationServer(grpcServer, &service.AuthService{Index: authConfigIndex, Timeout: timeoutMs()}) healthpb.RegisterHealthServer(grpcServer, &service.HealthService{}) grpc_prometheus.Register(grpcServer) grpc_prometheus.EnableHandlingTimeHistogram() @@ -335,14 +382,14 @@ func startExtAuthServerGRPC(authConfigIndex index.Index) { } func startExtAuthServerHTTP(authConfigIndex index.Index) { - startHTTPService("auth", extAuthHTTPPort, service.HTTPAuthorizationBasePath, tlsCertPath, tlsCertKeyPath, service.NewAuthService(authConfigIndex, timeoutMs, maxHttpRequestBodySize)) + startHTTPService("auth", extAuthHTTPPort, service.HTTPAuthorizationBasePath, tlsCertPath, tlsCertKeyPath, service.NewAuthService(authConfigIndex, timeoutMs(), maxHttpRequestBodySize)) } func startOIDCServer(authConfigIndex index.Index) { startHTTPService("oidc", oidcHTTPPort, service.OIDCBasePath, oidcTLSCertPath, oidcTLSCertKeyPath, &service.OidcService{Index: authConfigIndex}) } -func startHTTPService(name, port, basePath, tlsCertPath, tlsCertKeyPath string, handler http.Handler) { +func startHTTPService(name string, port int, basePath, tlsCertPath, tlsCertKeyPath string, handler http.Handler) { lis, err := listen(port) if err != nil { @@ -383,23 +430,31 @@ func startHTTPService(name, port, basePath, tlsCertPath, tlsCertKeyPath string, }() } -func listen(port string) (net.Listener, error) { - if p, err := strconv.Atoi(port); err != nil || p == 0 { +func listen(port int) (net.Listener, error) { + if port == 0 { return nil, nil } - if lis, err := net.Listen("tcp", ":"+port); err != nil { + if lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err != nil { return nil, err } else { return lis, nil } } -func fetchEnv(key string, def string) string { +func fetchEnv(key string, def interface{}) string { val, ok := os.LookupEnv(key) if !ok { - return def + return fmt.Sprint(def) } else { return val } } + +func timeoutMs() time.Duration { + return time.Duration(timeout) * time.Millisecond +} + +func printVersion(_ *cobra.Command, _ []string) { + fmt.Println("Authorino", version) +} From e7670843ecd1b2595e52a2736a839597c1545daf Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Mon, 21 Nov 2022 12:24:41 +0100 Subject: [PATCH 2/3] Fetch env var without explicit conversion (generically-typed) --- main.go | 34 ++++++++++++++-------------- pkg/utils/envvar.go | 33 +++++++++++++++++++++++++++ pkg/utils/envvar_test.go | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 pkg/utils/envvar.go create mode 100644 pkg/utils/envvar_test.go diff --git a/main.go b/main.go index caa847c8..e6097be3 100644 --- a/main.go +++ b/main.go @@ -24,7 +24,6 @@ import ( "net" "net/http" "os" - "strconv" "time" "github.com/go-logr/logr" @@ -36,6 +35,7 @@ import ( "github.com/kuadrant/authorino/pkg/log" "github.com/kuadrant/authorino/pkg/metrics" "github.com/kuadrant/authorino/pkg/service" + "github.com/kuadrant/authorino/pkg/utils" envoy_auth "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" @@ -122,25 +122,25 @@ var ( enableLeaderElection bool maxHttpRequestBodySize int64 - defaultWatchNamespace = fetchEnv(envWatchNamespace, "") - defaultWatchedAuthConfigLabelSelector = fetchEnv(envWatchedAuthConfigLabelSelector, "") - defaultWatchedSecretLabelSelector = fetchEnv(envWatchedSecretLabelSelector, "authorino.kuadrant.io/managed-by=authorino") - defaultLogLevel = fetchEnv(envLogLevel, "info") - defaultLogMode = fetchEnv(envLogMode, "production") - defaultTimeout, _ = strconv.Atoi(fetchEnv(envTimeout, 0)) - defaultExtAuthGRPCPort, _ = strconv.Atoi(fetchEnv(envExtAuthGRPCPort, 50051)) - defaultExtAuthHTTPPort, _ = strconv.Atoi(fetchEnv(envExtAuthHTTPPort, 5001)) - defaultTLSCertPath = fetchEnv(envTLSCertPath, "") - defaultTLSCertKeyPath = fetchEnv(envTLSCertKeyPath, "") - defaultOIDCHTTPPort, _ = strconv.Atoi(fetchEnv(envOIDCHTTPPort, 8083)) - defaultOIDCTLSCertPath = fetchEnv(envOIDCTLSCertPath, "") - defaultOIDCTLSCertKeyPath = fetchEnv(envOIDCTLSCertKeyPath, "") - defaultEvaluatorCacheSize, _ = strconv.Atoi(fetchEnv(envEvaluatorCacheSize, 1)) // 1 Mb - defaultDeepMetricsEnabled, _ = strconv.ParseBool(fetchEnv(envDeepMetricsEnabled, false)) + defaultWatchNamespace = utils.EnvVar(envWatchNamespace, "") + defaultWatchedAuthConfigLabelSelector = utils.EnvVar(envWatchedAuthConfigLabelSelector, "") + defaultWatchedSecretLabelSelector = utils.EnvVar(envWatchedSecretLabelSelector, "authorino.kuadrant.io/managed-by=authorino") + defaultLogLevel = utils.EnvVar(envLogLevel, "info") + defaultLogMode = utils.EnvVar(envLogMode, "production") + defaultTimeout = utils.EnvVar(envTimeout, 0) + defaultExtAuthGRPCPort = utils.EnvVar(envExtAuthGRPCPort, 50051) + defaultExtAuthHTTPPort = utils.EnvVar(envExtAuthHTTPPort, 5001) + defaultTLSCertPath = utils.EnvVar(envTLSCertPath, "") + defaultTLSCertKeyPath = utils.EnvVar(envTLSCertKeyPath, "") + defaultOIDCHTTPPort = utils.EnvVar(envOIDCHTTPPort, 8083) + defaultOIDCTLSCertPath = utils.EnvVar(envOIDCTLSCertPath, "") + defaultOIDCTLSCertKeyPath = utils.EnvVar(envOIDCTLSCertKeyPath, "") + defaultEvaluatorCacheSize = utils.EnvVar(envEvaluatorCacheSize, 1) // 1 Mb + defaultDeepMetricsEnabled = utils.EnvVar(envDeepMetricsEnabled, false) defaultMetricsAddr = ":8080" defaultHealthProbeAddr = ":8081" defaultEnableLeaderElection = false - defaultMaxHttpRequestBodySize, _ = strconv.ParseInt(fetchEnv(envMaxHttpRequestBodySize, 8192), 10, 64) // 8 Kb + defaultMaxHttpRequestBodySize = utils.EnvVar(envMaxHttpRequestBodySize, int64(8192)) // 8 Kb scheme = runtime.NewScheme() diff --git a/pkg/utils/envvar.go b/pkg/utils/envvar.go new file mode 100644 index 00000000..a61ee1ec --- /dev/null +++ b/pkg/utils/envvar.go @@ -0,0 +1,33 @@ +package utils + +import ( + "os" + "reflect" + "strconv" +) + +type envVar interface { + string | int | int64 | bool +} + +func EnvVar[T envVar](key string, def T) T { + val, ok := os.LookupEnv(key) + if !ok { + return def + } else { + switch reflect.ValueOf(def).Kind() { + case reflect.String: + return any(val).(T) + case reflect.Int: + v, _ := strconv.Atoi(val) + return any(v).(T) + case reflect.Int64: + v, _ := strconv.ParseInt(val, 10, 64) + return any(v).(T) + case reflect.Bool: + v, _ := strconv.ParseBool(val) + return any(v).(T) + } + return any(nil).(T) + } +} diff --git a/pkg/utils/envvar_test.go b/pkg/utils/envvar_test.go new file mode 100644 index 00000000..83354460 --- /dev/null +++ b/pkg/utils/envvar_test.go @@ -0,0 +1,48 @@ +package utils + +import ( + "os" + "testing" + + "gotest.tools/assert" +) + +func TestFetchEnvVarString(t *testing.T) { + os.Setenv("AUTHORINO_TEST_ENV_VAR", "val") + defer os.Unsetenv("AUTHORINO_TEST_ENV_VAR") + + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR", "def"), "val") + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR_OTHER", "def"), "def") +} + +func TestFetchEnvVarInt(t *testing.T) { + os.Setenv("AUTHORINO_TEST_ENV_VAR", "123") + defer os.Unsetenv("AUTHORINO_TEST_ENV_VAR") + + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR", 456), 123) + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR_OTHER", 456), 456) +} + +func TestFetchEnvVarInt64(t *testing.T) { + os.Setenv("AUTHORINO_TEST_ENV_VAR", "123") + defer os.Unsetenv("AUTHORINO_TEST_ENV_VAR") + + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR", int64(456)), int64(123)) + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR_OTHER", int64(456)), int64(456)) +} + +func TestFetchEnvVarBool(t *testing.T) { + os.Setenv("AUTHORINO_TEST_ENV_VAR", "true") + defer os.Unsetenv("AUTHORINO_TEST_ENV_VAR") + + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR", false), true) + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR_OTHER", false), false) +} + +func TestFetchEnvVarInvalid(t *testing.T) { + os.Setenv("AUTHORINO_TEST_ENV_VAR", "NaN") + defer os.Unsetenv("AUTHORINO_TEST_ENV_VAR") + + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR", 456), 0) + assert.Equal(t, EnvVar("AUTHORINO_TEST_ENV_VAR_OTHER", 456), 456) +} From bff3d02ae8d1bf241e9cd9513d966d3456cfdd9d Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Mon, 21 Nov 2022 15:33:13 +0100 Subject: [PATCH 3/3] refactoring: CLI command flags reorganised with less constant and variable declarations --- main.go | 96 ++++++++++++--------------------------------------------- 1 file changed, 19 insertions(+), 77 deletions(-) diff --git a/main.go b/main.go index e6097be3..a0634df5 100644 --- a/main.go +++ b/main.go @@ -55,44 +55,6 @@ import ( ) const ( - flagWatchNamespace = "watch-namespace" - flagWatchedAuthConfigLabelSelector = "auth-config-label-selector" - flagWatchedSecretLabelSelector = "secret-label-selector" - flagLogLevel = "log-level" - flagLogMode = "log-mode" - flagTimeout = "timeout" - flagExtAuthGRPCPort = "ext-auth-grpc-port" - flagExtAuthHTTPPort = "ext-auth-http-port" - flagTLSCertPath = "tls-cert" - flagTLSCertKeyPath = "tls-cert-key" - flagOIDCHTTPPort = "oidc-http-port" - flagOIDCTLSCertPath = "oidc-tls-cert" - flagOIDCTLSCertKeyPath = "oidc-tls-cert-key" - flagEvaluatorCacheSize = "evaluator-cache-size" // in megabytes - flagDeepMetricsEnabled = "deep-metrics-enabled" - flagMetricsAddr = "metrics-addr" - flagHealthProbeAddr = "health-probe-addr" - flagEnableLeaderElection = "enable-leader-election" - flagMaxHttpRequestBodySize = "max-http-request-body-size" // in bytes - - // [DEPRECATED] use command-line flags instead - envWatchNamespace = "WATCH_NAMESPACE" - envWatchedAuthConfigLabelSelector = "AUTH_CONFIG_LABEL_SELECTOR" - envWatchedSecretLabelSelector = "SECRET_LABEL_SELECTOR" - envLogLevel = "LOG_LEVEL" - envLogMode = "LOG_MODE" - envTimeout = "TIMEOUT" - envExtAuthGRPCPort = "EXT_AUTH_GRPC_PORT" - envExtAuthHTTPPort = "EXT_AUTH_HTTP_PORT" - envTLSCertPath = "TLS_CERT" - envTLSCertKeyPath = "TLS_CERT_KEY" - envOIDCHTTPPort = "OIDC_HTTP_PORT" - envOIDCTLSCertPath = "OIDC_TLS_CERT" - envOIDCTLSCertKeyPath = "OIDC_TLS_CERT_KEY" - envEvaluatorCacheSize = "EVALUATOR_CACHE_SIZE" // in megabytes - envDeepMetricsEnabled = "DEEP_METRICS_ENABLED" - envMaxHttpRequestBodySize = "MAX_HTTP_REQUEST_BODY_SIZE" // in bytes - gRPCMaxConcurrentStreams = 10000 leaderElectionIDSuffix = "authorino.kuadrant.io" ) @@ -122,26 +84,6 @@ var ( enableLeaderElection bool maxHttpRequestBodySize int64 - defaultWatchNamespace = utils.EnvVar(envWatchNamespace, "") - defaultWatchedAuthConfigLabelSelector = utils.EnvVar(envWatchedAuthConfigLabelSelector, "") - defaultWatchedSecretLabelSelector = utils.EnvVar(envWatchedSecretLabelSelector, "authorino.kuadrant.io/managed-by=authorino") - defaultLogLevel = utils.EnvVar(envLogLevel, "info") - defaultLogMode = utils.EnvVar(envLogMode, "production") - defaultTimeout = utils.EnvVar(envTimeout, 0) - defaultExtAuthGRPCPort = utils.EnvVar(envExtAuthGRPCPort, 50051) - defaultExtAuthHTTPPort = utils.EnvVar(envExtAuthHTTPPort, 5001) - defaultTLSCertPath = utils.EnvVar(envTLSCertPath, "") - defaultTLSCertKeyPath = utils.EnvVar(envTLSCertKeyPath, "") - defaultOIDCHTTPPort = utils.EnvVar(envOIDCHTTPPort, 8083) - defaultOIDCTLSCertPath = utils.EnvVar(envOIDCTLSCertPath, "") - defaultOIDCTLSCertKeyPath = utils.EnvVar(envOIDCTLSCertKeyPath, "") - defaultEvaluatorCacheSize = utils.EnvVar(envEvaluatorCacheSize, 1) // 1 Mb - defaultDeepMetricsEnabled = utils.EnvVar(envDeepMetricsEnabled, false) - defaultMetricsAddr = ":8080" - defaultHealthProbeAddr = ":8081" - defaultEnableLeaderElection = false - defaultMaxHttpRequestBodySize = utils.EnvVar(envMaxHttpRequestBodySize, int64(8192)) // 8 Kb - scheme = runtime.NewScheme() logger logr.Logger @@ -165,25 +107,25 @@ func main() { Run: run, } - cmdServer.PersistentFlags().StringVar(&watchNamespace, flagWatchNamespace, defaultWatchNamespace, "Kubernetes namespace to watch") - cmdServer.PersistentFlags().StringVar(&watchedAuthConfigLabelSelector, flagWatchedAuthConfigLabelSelector, defaultWatchedAuthConfigLabelSelector, "Kubernetes label selector to filter AuthConfig resources to watch") - cmdServer.PersistentFlags().StringVar(&watchedSecretLabelSelector, flagWatchedSecretLabelSelector, defaultWatchedSecretLabelSelector, "Kubernetes label selector to filter Secret resources to watch") - cmdServer.PersistentFlags().StringVar(&logLevel, flagLogLevel, defaultLogLevel, "Log level") - cmdServer.PersistentFlags().StringVar(&logMode, flagLogMode, defaultLogMode, "Log mode") - cmdServer.PersistentFlags().IntVar(&timeout, flagTimeout, defaultTimeout, "Server timeout - in milliseconds") - cmdServer.PersistentFlags().IntVar(&extAuthGRPCPort, flagExtAuthGRPCPort, defaultExtAuthGRPCPort, "Port number of authorization server - gRPC interface") - cmdServer.PersistentFlags().IntVar(&extAuthHTTPPort, flagExtAuthHTTPPort, defaultExtAuthHTTPPort, "Port number of authorization server - raw HTTP interface") - cmdServer.PersistentFlags().StringVar(&tlsCertPath, flagTLSCertPath, defaultTLSCertPath, "Path to the public TLS server certificate file in the file system - authorization server") - cmdServer.PersistentFlags().StringVar(&tlsCertKeyPath, flagTLSCertKeyPath, defaultTLSCertKeyPath, "Path to the private TLS server certificate key file in the file system - authorization server") - cmdServer.PersistentFlags().IntVar(&oidcHTTPPort, flagOIDCHTTPPort, defaultOIDCHTTPPort, "Port number of OIDC Discovery server for Festival Wristband tokens") - cmdServer.PersistentFlags().StringVar(&oidcTLSCertPath, flagOIDCTLSCertPath, defaultOIDCTLSCertPath, "Path to the public TLS server certificate file in the file system - Festival Wristband OIDC Discovery server") - cmdServer.PersistentFlags().StringVar(&oidcTLSCertKeyPath, flagOIDCTLSCertKeyPath, defaultOIDCTLSCertKeyPath, "Path to the private TLS server certificate key file in the file system - Festival Wristband OIDC Discovery server") - cmdServer.PersistentFlags().IntVar(&evaluatorCacheSize, flagEvaluatorCacheSize, defaultEvaluatorCacheSize, "Cache size of each Authorino evaluator if enabled in the AuthConfig - in megabytes") - cmdServer.PersistentFlags().BoolVar(&deepMetricsEnabled, flagDeepMetricsEnabled, defaultDeepMetricsEnabled, "Enable deep metrics at the level of each evaluator when requested in the AuthConfig, exported by the metrics server") - cmdServer.PersistentFlags().StringVar(&metricsAddr, flagMetricsAddr, defaultMetricsAddr, "The network address the metrics endpoint binds to") - cmdServer.PersistentFlags().StringVar(&healthProbeAddr, flagHealthProbeAddr, defaultHealthProbeAddr, "The network address the health probe endpoint binds to") - cmdServer.PersistentFlags().BoolVar(&enableLeaderElection, flagEnableLeaderElection, defaultEnableLeaderElection, "Enable leader election for status updater - ensures only one instance of Authorino tries to update the status of reconciled resources") - cmdServer.PersistentFlags().Int64Var(&maxHttpRequestBodySize, flagMaxHttpRequestBodySize, defaultMaxHttpRequestBodySize, "Maximum size of the body of requests accepted in the raw HTTP interface of the authorization server - in bytes") + cmdServer.PersistentFlags().StringVar(&watchNamespace, "watch-namespace", utils.EnvVar("WATCH_NAMESPACE", ""), "Kubernetes namespace to watch") + cmdServer.PersistentFlags().StringVar(&watchedAuthConfigLabelSelector, "auth-config-label-selector", utils.EnvVar("AUTH_CONFIG_LABEL_SELECTOR", ""), "Kubernetes label selector to filter AuthConfig resources to watch") + cmdServer.PersistentFlags().StringVar(&watchedSecretLabelSelector, "secret-label-selector", utils.EnvVar("SECRET_LABEL_SELECTOR", "authorino.kuadrant.io/managed-by=authorino"), "Kubernetes label selector to filter Secret resources to watch") + cmdServer.PersistentFlags().StringVar(&logLevel, "log-level", utils.EnvVar("LOG_LEVEL", "info"), "Log level") + cmdServer.PersistentFlags().StringVar(&logMode, "log-mode", utils.EnvVar("LOG_MODE", "production"), "Log mode") + cmdServer.PersistentFlags().IntVar(&timeout, "timeout", utils.EnvVar("TIMEOUT", 0), "Server timeout - in milliseconds") + cmdServer.PersistentFlags().IntVar(&extAuthGRPCPort, "ext-auth-grpc-port", utils.EnvVar("EXT_AUTH_GRPC_PORT", 50051), "Port number of authorization server - gRPC interface") + cmdServer.PersistentFlags().IntVar(&extAuthHTTPPort, "ext-auth-http-port", utils.EnvVar("EXT_AUTH_HTTP_PORT", 5001), "Port number of authorization server - raw HTTP interface") + cmdServer.PersistentFlags().StringVar(&tlsCertPath, "tls-cert", utils.EnvVar("TLS_CERT", ""), "Path to the public TLS server certificate file in the file system - authorization server") + cmdServer.PersistentFlags().StringVar(&tlsCertKeyPath, "tls-cert-key", utils.EnvVar("TLS_CERT_KEY", ""), "Path to the private TLS server certificate key file in the file system - authorization server") + cmdServer.PersistentFlags().IntVar(&oidcHTTPPort, "oidc-http-port", utils.EnvVar("OIDC_HTTP_PORT", 8083), "Port number of OIDC Discovery server for Festival Wristband tokens") + cmdServer.PersistentFlags().StringVar(&oidcTLSCertPath, "oidc-tls-cert", utils.EnvVar("OIDC_TLS_CERT", ""), "Path to the public TLS server certificate file in the file system - Festival Wristband OIDC Discovery server") + cmdServer.PersistentFlags().StringVar(&oidcTLSCertKeyPath, "oidc-tls-cert-key", utils.EnvVar("OIDC_TLS_CERT_KEY", ""), "Path to the private TLS server certificate key file in the file system - Festival Wristband OIDC Discovery server") + cmdServer.PersistentFlags().IntVar(&evaluatorCacheSize, "evaluator-cache-size", utils.EnvVar("EVALUATOR_CACHE_SIZE", 1), "Cache size of each Authorino evaluator if enabled in the AuthConfig - in megabytes") + cmdServer.PersistentFlags().BoolVar(&deepMetricsEnabled, "deep-metrics-enabled", utils.EnvVar("DEEP_METRICS_ENABLED", false), "Enable deep metrics at the level of each evaluator when requested in the AuthConfig, exported by the metrics server") + cmdServer.PersistentFlags().StringVar(&metricsAddr, "metrics-addr", ":8080", "The network address the metrics endpoint binds to") + cmdServer.PersistentFlags().StringVar(&healthProbeAddr, "health-probe-addr", ":8081", "The network address the health probe endpoint binds to") + cmdServer.PersistentFlags().BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for status updater - ensures only one instance of Authorino tries to update the status of reconciled resources") + cmdServer.PersistentFlags().Int64Var(&maxHttpRequestBodySize, "max-http-request-body-size", utils.EnvVar("MAX_HTTP_REQUEST_BODY_SIZE", int64(8192)), "Maximum size of the body of requests accepted in the raw HTTP interface of the authorization server - in bytes") cmdVersion := &cobra.Command{ Use: "version",