Skip to content
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

Add support for securing the operator metrics endpoint with RBAC and TLS #7567

Merged
merged 30 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c7dbb50
WIP
naemono Feb 14, 2024
2420f8d
Final settings enabling authentication for the metrics endpoint.
naemono Feb 15, 2024
60b5b90
add servicemonitor template.
naemono Feb 15, 2024
bdf972d
Move non-cluster related roles to proper location.
naemono Feb 20, 2024
2d9f885
Remove non-cluster scoped option.
naemono Feb 20, 2024
7bf352f
Add back missing cluster role binding.
naemono Feb 20, 2024
4c6eabd
Docs for secure metrics.
naemono Feb 22, 2024
b0e8e65
Update docs for enabling secure metrics.
naemono Feb 22, 2024
21cf390
Fix all helm templating issues
naemono Feb 22, 2024
6233643
Expand fail directive
naemono Feb 23, 2024
4739249
update fail directive #2
naemono Feb 23, 2024
1db9145
fix helm if statement
naemono Feb 23, 2024
0f3ae45
Merge branch 'main' into 480-add-metrics-auth
naemono Feb 23, 2024
664cffb
Move to using 'metricsHost' instead of 'metricsBindAddress'
naemono Feb 26, 2024
6916389
Add serviceMonitor to default values.
naemono Feb 26, 2024
361ca67
WIP
naemono Feb 26, 2024
bd6f90d
Add additional information to docs.
naemono Feb 27, 2024
566f8f0
Add preceeding '-'
naemono Feb 27, 2024
e45f691
Fix all metricsports missing '-'
naemono Feb 27, 2024
7c41f51
securemode.enabled, not enable.
naemono Feb 27, 2024
1f1bacf
remove todo item.
naemono Feb 27, 2024
4348ce8
remove metrics-host from helm values, as it's not needed.
naemono Feb 27, 2024
d862223
remove secure-metrics link.
naemono Feb 27, 2024
11c1742
Updated documentation with full instructions on using custom tls cert…
naemono Mar 1, 2024
144e6f1
Update to include the whole configmap, not a script to patch it.
naemono Mar 4, 2024
119150e
Review comments
naemono Mar 5, 2024
3e35723
Review comments
naemono Mar 5, 2024
2f89b3b
Review comments.
naemono Mar 5, 2024
848e8ed
Addressing review comments
naemono Mar 5, 2024
e8eccd1
Lowercasing operator, and chart.
naemono Mar 6, 2024
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
7 changes: 6 additions & 1 deletion cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,12 @@ func Command() *cobra.Command {
cmd.Flags().Int(
operator.MetricsPortFlag,
DefaultMetricPort,
"Port to use for exposing metrics in the Prometheus format (set 0 to disable)",
"(Deprecated) Port to use for exposing metrics in the Prometheus format. (set 0 to disable. Use --metrics-bind-address instead)",
naemono marked this conversation as resolved.
Show resolved Hide resolved
)
cmd.Flags().String(
operator.MetricsBindAddressFlag,
"",
fmt.Sprintf("The address which the operator should listen on to serve metrics in the Prometheus format. Cannot be combined with %s. (set to empty to disable)", operator.MetricsPortFlag),
)
cmd.Flags().StringSlice(
operator.NamespacesFlag,
Expand Down
27 changes: 27 additions & 0 deletions deploy/eck-operator/templates/auth-proxy-service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{- if .Values.config.enableSecureMetrics }}
{{ $metricsPort := 0 }}
{{- if and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")) }}
{{ $metricsPort = int (.Values.config.metricsBindAddress | splitList ":" | last) }}
{{- else if (gt (int .Values.config.metricsPort) 0) }}
{{ $metricsPort = int .Values.config.metricsPort }}
{{- end }}
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: {{ include "eck-operator.name" . }}-metrics-service
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
helm.sh/chart: {{ include "eck-operator.chart" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
name: "{{ include "eck-operator.fullname" . }}-metrics-service"
namespace: {{ .Release.Namespace }}
spec:
ports:
- name: https
port: {{ $metricsPort }}
protocol: TCP
targetPort: metrics
selector:
{{- include "eck-operator.selectorLabels" . | nindent 4 }}
{{- end }}
25 changes: 25 additions & 0 deletions deploy/eck-operator/templates/cluster-roles.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{{- if and (not .Values.createClusterScopedResources) (.Values.config.enableSecureMetrics) -}}
{{ fail "createClusterScopedResources is required to enable secure metrics" }}
naemono marked this conversation as resolved.
Show resolved Hide resolved
{{- end }}
{{- if .Values.createClusterScopedResources -}}
---
apiVersion: rbac.authorization.k8s.io/v1
Expand Down Expand Up @@ -93,4 +96,26 @@ rules:
- apiGroups: ["logstash.k8s.elastic.co"]
resources: ["logstashes"]
verbs: ["create", "delete", "deletecollection", "patch", "update"]
{{- if and .Values.config.enableSecureMetrics }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
{{- include "eck-operator.labels" . | nindent 4 }}
name: "{{ include "eck-operator.fullname" . }}-proxy-role"
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
{{- end }}
{{- end -}}
17 changes: 16 additions & 1 deletion deploy/eck-operator/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,22 @@ metadata:
data:
eck.yaml: |-
log-verbosity: {{ int .Values.config.logVerbosity }}
metrics-port: {{ int .Values.config.metricsPort }}
{{- if (and .Values.config.enableSecureMetrics (eq (int .Values.config.metricsPort) 0) (or (eq .Values.config.metricsBindAddress "") (not (hasKey .Values.config "metricsBindAddress")))) }}
{{ fail "metricsPort or metricsBindAddress is required when enableSecureMetrics is true" }}
{{- end }}
{{- if (and .Values.config.enableSecureMetrics (gt (int .Values.config.metricsPort) 0) (or (eq .Values.config.metricsBindAddress "") (not (hasKey .Values.config "metricsBindAddress")))) }}
metrics-port: {{ add (int .Values.config.metricsPort) 1 }}
{{- else }}
metrics-port: {{ int (.Values.config.metricsBindAddress | splitList ":" | last) }}
{{- end }}
{{- if (and .Values.config.enableSecureMetrics (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress ""))) }}
{{- if .Values.config.enableSecureMetrics }}
{{ $host := .Values.config.metricsBindAddress | splitList ":" | first }}
metrics-bind-address: {{ $host }}:{{ add (int (.Values.config.metricsBindAddress | splitList ":" | last)) 1 }}
{{- else }}
metrics-bind-address: {{ int .Values.config.metricsBindAddress | splitList ":" | last }}
{{- end }}
{{- end }}
container-registry: {{ .Values.config.containerRegistry }}
naemono marked this conversation as resolved.
Show resolved Hide resolved
{{- with .Values.config.containerSuffix }}
container-suffix: {{ . }}
Expand Down
9 changes: 7 additions & 2 deletions deploy/eck-operator/templates/operator-network-policy.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{{- if .Values.softMultiTenancy.enabled -}}
{{- $kubeAPIServerIP := (required "kubeAPIServerIP is required" .Values.kubeAPIServerIP) -}}
{{- $metricsPort := int .Values.config.metricsPort -}}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
Expand Down Expand Up @@ -40,7 +39,13 @@ spec:
podSelector:
matchLabels:
common.k8s.elastic.co/type: "elasticsearch"
{{- if or .Values.webhook.enabled (gt $metricsPort 0) }}
{{- if or .Values.webhook.enabled (gt (int .Values.config.metricsPort ) 0) (and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")))}}
{{ $metricsPort := 0 }}
{{- if and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")) }}
{{ $metricsPort = int .Values.config.metricsBindAddress | splitList ":" | last }}
{{- else if (gt .Values.config.metricsPort 0) }}
{{ $metricsPort = int .Values.config.metricsPort }}
{{- end }}
ingress:
{{- if .Values.webhook.enabled }}
- ports:
Expand Down
8 changes: 5 additions & 3 deletions deploy/eck-operator/templates/podMonitor.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{{- $metricsPort := int .Values.config.metricsPort -}}
{{- if and .Values.podMonitor.enabled (gt $metricsPort 0) }}
{{- if and .Values.podMonitor.enabled .Values.config.enableSecureMetrics}}
{{ fail "podMonitor.enabled and enableSecureMetrics are mutually exclusive" }}
{{- end }}
{{- if and .Values.podMonitor.enabled (or (gt (int .Values.config.metricsPort) 0) (and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")))) }}
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
Expand Down Expand Up @@ -33,4 +35,4 @@ spec:
- {{ .Release.Namespace }}
selector:
matchLabels: {{- include "eck-operator.selectorLabels" . | nindent 6 }}
{{- end }}
{{- end }}
18 changes: 18 additions & 0 deletions deploy/eck-operator/templates/role-bindings.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{{- $operatorNSIsManaged := has .Release.Namespace .Values.managedNamespaces -}}
{{- $fullName := include "eck-operator.fullname" . -}}
{{- $svcAccount := include "eck-operator.serviceAccountName" . }}
{{- $enableSecureMetrics := and .Values.config.enableSecureMetrics -}}

{{- if not .Values.createClusterScopedResources }}
{{- range .Values.managedNamespaces }}
Expand Down Expand Up @@ -77,4 +78,21 @@ subjects:
- kind: ServiceAccount
name: {{ $svcAccount }}
namespace: {{ $.Release.Namespace }}
{{- if $enableSecureMetrics }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
{{- include "eck-operator.labels" $ | nindent 4 }}
name: "{{ include "eck-operator.fullname" . }}-proxy-rolebinding"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: "{{ include "eck-operator.fullname" . }}-proxy-role"
subjects:
- kind: ServiceAccount
name: {{ $svcAccount }}
namespace: {{ $.Release.Namespace }}
{{- end }}
{{- end }}
24 changes: 24 additions & 0 deletions deploy/eck-operator/templates/serviceMonitor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{- if and .Values.config.enableSecureMetrics }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "eck-operator.fullname" . }}
namespace: {{ ternary .Values.serviceMonitor.namespace .Release.Namespace (not (empty .Values.serviceMonitor.namespace)) }}
naemono marked this conversation as resolved.
Show resolved Hide resolved
labels: {{- include "eck-operator.labels" . | nindent 4 }}
spec:
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "eck-operator.name" . }}-metrics-service
app.kubernetes.io/instance: {{ .Release.Name }}
endpoints:
- port: https
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
{{- end }}
42 changes: 39 additions & 3 deletions deploy/eck-operator/templates/statefulset.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{{- $metricsPort := int .Values.config.metricsPort -}}
---
apiVersion: apps/v1
kind: StatefulSet
Expand Down Expand Up @@ -79,9 +78,15 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or (gt $metricsPort 0) .Values.webhook.enabled }}
{{- if or .Values.webhook.enabled (gt (int .Values.config.metricsPort) 0) (and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")))}}
{{ $metricsPort := 0 }}
{{- if and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")) }}
{{ $metricsPort = int (.Values.config.metricsBindAddress | splitList ":" | last) }}
{{- else if (gt (int .Values.config.metricsPort) 0) }}
{{ $metricsPort = int .Values.config.metricsPort }}
{{- end }}
ports:
{{- if (gt $metricsPort 0) }}
{{- if and (gt $metricsPort 0) (not .Values.config.enableSecureMetrics) }}
- containerPort: {{ .Values.config.metricsPort }}
name: metrics
protocol: TCP
Expand All @@ -104,6 +109,37 @@ spec:
{{- with .Values.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.config.enableSecureMetrics }}
{{ $metricsPort := 0 }}
{{- if and (hasKey .Values.config "metricsBindAddress") (not (eq .Values.config.metricsBindAddress "")) }}
{{ $metricsPort = int (.Values.config.metricsBindAddress | splitList ":" | last) }}
{{- else if (gt (int .Values.config.metricsPort) 0) }}
{{ $metricsPort = int .Values.config.metricsPort }}
{{- end }}
- name: kube-rbac-proxy
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.15.0
args:
- "--secure-listen-address=0.0.0.0:{{ $metricsPort }}"
- "--upstream=http://127.0.0.1:{{ add $metricsPort 1 }}/"
- "--logtostderr=true"
- "--v=0"
ports:
- containerPort: {{ $metricsPort }}
protocol: TCP
name: metrics
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 5m
memory: 64Mi
{{- end }}
volumes:
- name: conf
configMap:
Expand Down
36 changes: 35 additions & 1 deletion deploy/eck-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,43 @@ config:
# number greater than 0: Errors, warnings, information, and debug details.
logVerbosity: "0"

# metricsPort defines the port to expose operator metrics. Set to 0 to disable metrics reporting.
# metricsBindAddress defines the address which the operator should listen on to serve metrics in the Prometheus format.
#
# *Note* If this option is combined with the enableSecureMetrics option then only the port is used, the bind address is ignored
# as the operator will only listen on the localhost (127.0.0.1) interface and kube-rbac-proxy will intercept traffic
# to the metrics port.
#
# Examples follow:
# - :8080 (equivalent to 0.0.0.0:8080)
# - 0.0.0.0:8080
# - localhost:8080
metricsBindAddress: ""

# (Deprecated; Will be removed in v2.14.0) metricsPort defines the port to expose operator metrics. Set to 0 to disable metrics reporting. Use `metricsBindAddress` instead.
metricsPort: "0"

# enableSecureMetrics specifies whether to enable RBAC and TLS/HTTPs for the metrics endpoint. (Will be enabled by default in v2.14.0)
# * This option requires using a ServiceMonitor to scrape the metrics and as such is mutually exclusive with the podMonitor.enabled option.
# * This option also requires using cluster scoped resources (ClusterRole, ClusterRoleBinding) to
# grant access to the /metrics endpoint. (createClusterScopedResources: true is required)
#
# This option requires the following settings within Prometheus to function:
# 1. RBAC settings for the Prometheus instance to access the metrics endpoint.
#
# - nonResourceURLs:
# - /metrics
# verbs:
# - get
#
# 2. If using the Prometheus Operator and your Prometheus instance is not in the same namespace as the operator you will need
# the Prometheus Operator configured with the following Helm values:
#
# prometheus:
# prometheusSpec:
# serviceMonitorNamespaceSelector: {}
# serviceMonitorSelectorNilUsesHelmValues: false
naemono marked this conversation as resolved.
Show resolved Hide resolved
enableSecureMetrics: false

# containerRegistry to use for pulling Elasticsearch and other application container images.
containerRegistry: docker.elastic.co

Expand Down
2 changes: 2 additions & 0 deletions docs/advanced-topics/advanced-topics.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ endif::[]
- <<{p}-webhook-namespace-selectors>>
- <<{p}-stack-monitoring>>
- <<{p}-fips>>
- <<{p}-secure-metrics>>
--

include::openshift.asciidoc[leveloffset=+1]
Expand All @@ -29,3 +30,4 @@ include::network-policies.asciidoc[leveloffset=+1]
include::webhook-namespace-selectors.asciidoc[leveloffset=+1]
include::stack-monitoring.asciidoc[leveloffset=+1]
include::fips.asciidoc[leveloffset=+1]
include::secure-metrics.asciidoc[leveloffset=+1]
Loading