-
Notifications
You must be signed in to change notification settings - Fork 203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove dependency for kube-rbac-proxy and add secure-metrics feature #3833
Changes from 9 commits
7938491
ec4b7fb
3df85ba
f0dc11a
93964d0
b15c3f7
e544203
a04af18
5283762
8f243f3
99969f3
752e319
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,19 +7,21 @@ The metrics exposed fall into two groups: Azure based metrics, and reconciler me | |
|
||
## Toggling the metrics | ||
|
||
By default, metrics for ASOv2 are turned on and can be toggled by the following options: | ||
By default, secure metrics for ASOv2 are turned on and can be toggled by the following options: | ||
matthchr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- ### ASOv2 Helm Chart | ||
### ASOv2 Helm Chart | ||
|
||
While installing the Helm chart, we can turn the metrics _**on**_ and _**off**_ and set the metrics expose address using the | ||
below settings. Also, we can change the settings inside `values.yaml` file for ASOv2 Helm chart. | ||
|
||
``` | ||
--set metrics.enable=true/false (default: true) | ||
--set metrics.address=0.0.0.0:8080 (default) | ||
--set metrics.secure=true/false (default: true) | ||
--set metrics.profiling=true/false (default: false) | ||
--set metrics.address=0.0.0.0:8443 (default) | ||
``` | ||
|
||
- ### Deployment YAML | ||
### Deployment YAML | ||
|
||
In the deployment yaml, we can turn _**off**_ the metrics by omitting the `metrics-addr` flag. We can also change to use | ||
a different metrics-addr by changing the default value of that same flag. | ||
|
@@ -29,8 +31,75 @@ By default, metrics for ASOv2 are turned on and can be toggled by the following | |
containers: | ||
- args: | ||
- --metrics-addr=0.0.0.0:8080 (default) | ||
- --secure-metrics=true/false (default: true) | ||
- --profiling-metrics=true/false (default: false) | ||
``` | ||
|
||
|
||
## Scraping Metrics Securely via HTTPs using RBAC | ||
|
||
A ServiceAccount token is required to scrape metrics securely. The corresponding ServiceAccount needs permissions on the "/metrics" and "debug/pprof" paths. | ||
This can be achieved e.g. by following the [Kubernetes documentation](https://kubernetes.io/docs/concepts/cluster-administration/system-metrics/). | ||
|
||
Follow the steps below to scrape metrics securely. | ||
|
||
### ASOv2 Helm Chart | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. very minor: Could use one of the table-selector thingies here, like we do for Windows versus Linux in the installation instructions? |
||
``` | ||
--set metrics.enable=true | ||
--set metrics.secure=true | ||
--set metrics.profiling=true | ||
--set metrics.address=0.0.0.0:8443 | ||
``` | ||
|
||
### Deployment YAML | ||
``` | ||
spec: | ||
containers: | ||
- args: | ||
- --metrics-addr=0.0.0.0:8443 | ||
- --secure-metrics=true | ||
- --profiling-metrics=true | ||
``` | ||
|
||
Deploy the following RBAC configuration. This creates a role that can scrape metrics. | ||
``` | ||
cat << EOT | kubectl apply -f - | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: ClusterRole | ||
metadata: | ||
name: default-metrics | ||
rules: | ||
- nonResourceURLs: | ||
- "/metrics" | ||
- "/debug/pprof/*" | ||
verbs: | ||
- get | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: ClusterRoleBinding | ||
metadata: | ||
name: default-metrics | ||
roleRef: | ||
apiGroup: rbac.authorization.k8s.io | ||
kind: ClusterRole | ||
name: default-metrics | ||
subjects: | ||
- kind: ServiceAccount | ||
name: default | ||
namespace: default | ||
EOT | ||
``` | ||
Test locally: | ||
- Open a port-forward | ||
|
||
``` | ||
kubectl port-forward deployments/azureserviceoperator-controller-manager -n azureserviceoperator-system 8443 | ||
``` | ||
- Create a ServiceAccount token and scrape metrics | ||
``` | ||
TOKEN=$(kubectl create token default) | ||
curl https://localhost:8443/metrics --header "Authorization: Bearer $TOKEN" -k | ||
``` | ||
|
||
## Understanding the ASOv2 Metrics | ||
|
||
| Metric | Description | Label 1 | Label 2 | Label 3 | | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,14 +86,19 @@ webhook: | |
# repository). | ||
image: | ||
repository: mcr.microsoft.com/k8s/azureserviceoperator:v2.6.0 | ||
kubeRBACProxy: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1 | ||
|
||
# 'metrics' define settings for the metrics from controller. | ||
# 'address' field defines the metrics binding address on which metrics | ||
metrics: | ||
enable: true | ||
# secure controls whether metrics should be served via 'http' or 'https'. | ||
# Flagging secure as 'true' would use https | ||
# Refer to https://azure.github.io/azure-service-operator/guide/metrics/ for more information | ||
secure: true | ||
# profiling endpoints are only enabled when serving metrics securely | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: Say what profiling is (it enables /pprof endpoints), in addition to its restrictions. Though, see below about this restriction because I am not sure it is needed? |
||
profiling: false | ||
address: 0.0.0.0:{{ .Values.metrics.port }} | ||
port: 8080 | ||
port: 8443 | ||
|
||
# installCRDs configures if the operator attempts to install and manage the CRDs associated with ASO. | ||
# If the operator does not install and manage the CRDs on its own, you must manually install the appropriate | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,19 +16,23 @@ import ( | |
|
||
type Flags struct { | ||
MetricsAddr string | ||
ProfilingMetrics bool | ||
SecureMetrics bool | ||
HealthAddr string | ||
WebhookPort int | ||
WebhookCertDir string | ||
EnableLeaderElection bool | ||
CRDManagementMode string | ||
CRDPatterns string // This is a ; delimited string containing a collection of patterns | ||
CRDPatterns string // This is a ';' delimited string containing a collection of patterns | ||
PreUpgradeCheck bool | ||
} | ||
|
||
func (f Flags) String() string { | ||
return fmt.Sprintf( | ||
"MetricsAddr: %s, HealthAddr: %s, WebhookPort: %d, WebhookCertDir: %s, EnableLeaderElection: %t, CRDManagementMode: %s, CRDPatterns: %s, PreUpgradeCheck: %t", | ||
"MetricsAddr: %s, SecureMetrics: %t, ProfilingMetrics: %t, HealthAddr: %s, WebhookPort: %d, WebhookCertDir: %s, EnableLeaderElection: %t, CRDManagementMode: %s, CRDPatterns: %s, PreUpgradeCheck: %t", | ||
f.MetricsAddr, | ||
f.SecureMetrics, | ||
f.ProfilingMetrics, | ||
f.HealthAddr, | ||
f.WebhookPort, | ||
f.WebhookCertDir, | ||
|
@@ -44,6 +48,8 @@ func ParseFlags(args []string) (Flags, error) { | |
klog.InitFlags(flagSet) | ||
|
||
var metricsAddr string | ||
var profilingMetrics bool | ||
var secureMetrics bool | ||
var healthAddr string | ||
var webhookPort int | ||
var webhookCertDir string | ||
|
@@ -54,6 +60,9 @@ func ParseFlags(args []string) (Flags, error) { | |
|
||
// default here for 'MetricsAddr' is set to "0", which sets metrics to be disabled if 'metrics-addr' flag is omitted. | ||
flagSet.StringVar(&metricsAddr, "metrics-addr", "0", "The address the metric endpoint binds to.") | ||
flagSet.BoolVar(&secureMetrics, "secure-metrics", true, "Enable secure metrics. This secures the pprof and metrics endpoints via Kubernetes RBAC and HTTPS") | ||
flagSet.BoolVar(&profilingMetrics, "profiling-metrics", true, "Enable pprof metrics, only enabled in conjunction with secure-metrics. This will enable serving pprof metrics endpoints") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default should probably be false |
||
|
||
flagSet.StringVar(&healthAddr, "health-addr", "", "The address the healthz endpoint binds to.") | ||
flagSet.IntVar(&webhookPort, "webhook-port", 9443, "The port the webhook endpoint binds to.") | ||
flagSet.StringVar(&webhookCertDir, "webhook-cert-dir", "", "The directory the webhook server's certs are stored.") | ||
|
@@ -69,6 +78,7 @@ func ParseFlags(args []string) (Flags, error) { | |
|
||
return Flags{ | ||
MetricsAddr: metricsAddr, | ||
SecureMetrics: secureMetrics, | ||
HealthAddr: healthAddr, | ||
WebhookPort: webhookPort, | ||
WebhookCertDir: webhookCertDir, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ import ( | |
"context" | ||
"fmt" | ||
"math/rand" | ||
"net/http" | ||
"net/http/pprof" | ||
"os" | ||
"regexp" | ||
"time" | ||
|
@@ -31,6 +33,7 @@ import ( | |
"sigs.k8s.io/controller-runtime/pkg/controller" | ||
"sigs.k8s.io/controller-runtime/pkg/healthz" | ||
"sigs.k8s.io/controller-runtime/pkg/manager" | ||
"sigs.k8s.io/controller-runtime/pkg/metrics/filters" | ||
"sigs.k8s.io/controller-runtime/pkg/metrics/server" | ||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
"sigs.k8s.io/controller-runtime/pkg/webhook" | ||
|
@@ -131,9 +134,7 @@ func SetupControllerManager(ctx context.Context, setupLog logr.Logger, flgs Flag | |
LeaderElection: flgs.EnableLeaderElection, | ||
LeaderElectionID: "controllers-leader-election-azinfra-generated", | ||
HealthProbeBindAddress: flgs.HealthAddr, | ||
Metrics: server.Options{ | ||
BindAddress: flgs.MetricsAddr, | ||
}, | ||
Metrics: getMetricsOpts(flgs), | ||
WebhookServer: webhook.NewServer(webhook.Options{ | ||
Port: flgs.WebhookPort, | ||
CertDir: flgs.WebhookCertDir, | ||
|
@@ -253,6 +254,37 @@ func SetupControllerManager(ctx context.Context, setupLog logr.Logger, flgs Flag | |
return mgr | ||
} | ||
|
||
func getMetricsOpts(flags Flags) server.Options { | ||
var metricsOptions server.Options | ||
|
||
if !flags.SecureMetrics { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code doesn't seem right, because it doesn't return here, it falls through and then overwrites the I think you want something like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or if you want to only enable profiling if secure, put that bit into the secure bit, and/or (maybe better) add a check that secure is not off with profiling on and if so return an error and crash the pod. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah good catch. I missed return there. I'll update |
||
metricsOptions = server.Options{ | ||
BindAddress: flags.MetricsAddr, | ||
} | ||
} | ||
|
||
var pprofHandlers map[string]http.Handler | ||
if flags.ProfilingMetrics { | ||
pprofHandlers = map[string]http.Handler{ | ||
"/debug/pprof/": http.HandlerFunc(pprof.Index), | ||
"/debug/pprof/cmdline": http.HandlerFunc(pprof.Cmdline), | ||
"/debug/pprof/profile": http.HandlerFunc(pprof.Profile), | ||
"/debug/pprof/symbol": http.HandlerFunc(pprof.Symbol), | ||
"/debug/pprof/trace": http.HandlerFunc(pprof.Trace), | ||
} | ||
} | ||
|
||
metricsOptions = server.Options{ | ||
BindAddress: flags.MetricsAddr, | ||
SecureServing: true, | ||
FilterProvider: filters.WithAuthenticationAndAuthorization, | ||
// Note that pprof endpoints are meant to be sensitive and shouldn't be exposed publicly. | ||
ExtraHandlers: pprofHandlers, | ||
} | ||
|
||
return metricsOptions | ||
} | ||
|
||
func getDefaultAzureCredential(cfg config.Values, setupLog logr.Logger) (*identity.Credential, error) { | ||
tokenCred, err := getDefaultAzureTokenCredential(cfg, setupLog) | ||
if err != nil { | ||
|
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are they really turned on, given the option below says
default: false
?