Skip to content

Commit 6c87ebf

Browse files
committed
Remove kube-rbac-proxy dependency & adopt controller-runtime native auth for metric
1 parent 6c4cd79 commit 6c87ebf

33 files changed

+1311
-280
lines changed

.github/workflows/test-e2e.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: E2E Tests
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test-e2e:
9+
name: Run on Ubuntu
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Clone the code
13+
uses: actions/checkout@v4
14+
15+
- name: Setup Go
16+
uses: actions/setup-go@v5
17+
with:
18+
go-version-file: go.mod
19+
20+
- name: Install the latest version of kind
21+
run: |
22+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
23+
chmod +x ./kind
24+
sudo mv ./kind /usr/local/bin/kind
25+
26+
- name: Verify kind installation
27+
run: kind version
28+
29+
- name: Running Test e2e
30+
run: |
31+
go mod tidy
32+
make test-e2e

Makefile

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ vet: ## Run go vet against code.
6262
test: manifests generate fmt vet setup-envtest ## Run tests.
6363
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
6464

65+
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
66+
# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally.
67+
# CertManager is installed by default; skip with:
68+
# - CERT_MANAGER_INSTALL_SKIP=true
69+
KIND_CLUSTER ?= ipam
70+
71+
.PHONY: setup-test-e2e
72+
setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist
73+
@command -v $(KIND) >/dev/null 2>&1 || { \
74+
echo "Kind is not installed. Please install Kind manually."; \
75+
exit 1; \
76+
}
77+
$(KIND) create cluster --name $(KIND_CLUSTER)
78+
79+
.PHONY: test-e2e
80+
test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind.
81+
KIND_CLUSTER=$(KIND_CLUSTER) go test ./test/e2e/ -v -ginkgo.v
82+
$(MAKE) cleanup-test-e2e
83+
84+
.PHONY: cleanup-test-e2e
85+
cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests
86+
@$(KIND) delete cluster --name $(KIND_CLUSTER)
87+
6588
.PHONY: add-license
6689
add-license: addlicense ## Add license headers to all go files.
6790
find . -name '*.go' -exec $(ADDLICENSE) -f hack/license-header.txt {} +
@@ -96,7 +119,7 @@ run: manifests generate fmt vet ## Run a controller from your host.
96119
# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.
97120
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
98121
.PHONY: docker-build
99-
docker-build: test ## Build docker image with the manager.
122+
docker-build: ## Build docker image with the manager.
100123
docker build -t ${IMG} .
101124

102125
.PHONY: docker-push
@@ -158,6 +181,7 @@ $(LOCALBIN):
158181

159182
## Tool Binaries
160183
KUBECTL ?= kubectl
184+
KIND ?= kind
161185
KUSTOMIZE ?= $(LOCALBIN)/kustomize
162186
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
163187
ENVTEST ?= $(LOCALBIN)/setup-envtest

cmd/main.go

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
package main
55

66
import (
7+
"crypto/tls"
78
"flag"
89
"os"
10+
"path/filepath"
911

1012
"github.com/ironcore-dev/ipam/internal/webhook/v1alpha1"
1113

@@ -19,8 +21,10 @@ import (
1921
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2022
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
2123
ctrl "sigs.k8s.io/controller-runtime"
24+
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
2225
"sigs.k8s.io/controller-runtime/pkg/healthz"
2326
"sigs.k8s.io/controller-runtime/pkg/log/zap"
27+
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
2428
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
2529

2630
ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1"
@@ -41,13 +45,28 @@ func init() {
4145

4246
func main() {
4347
var metricsAddr string
48+
var secureMetrics bool
49+
var metricsCertPath, metricsCertName, metricsCertKey string
50+
var enableHTTP2 bool
4451
var enableLeaderElection bool
4552
var probeAddr string
46-
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
53+
var tlsOpts []func(*tls.Config)
54+
55+
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
56+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
57+
flag.BoolVar(&secureMetrics, "metrics-secure", true,
58+
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
59+
flag.StringVar(&metricsCertPath, "metrics-cert-path", "",
60+
"The directory that contains the metrics server certificate.")
61+
flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
62+
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
63+
flag.BoolVar(&enableHTTP2, "enable-http2", false,
64+
"If set, HTTP/2 will be enabled for the metrics server")
4765
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
4866
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
4967
"Enable leader election for controller manager. "+
5068
"Enabling this will ensure there is only one active controller manager.")
69+
5170
opts := zap.Options{
5271
Development: true,
5372
}
@@ -56,11 +75,72 @@ func main() {
5675

5776
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
5877

78+
// if the enable-http2 flag is false (the default), http/2 should be disabled
79+
// due to its vulnerabilities. More specifically, disabling http/2 will
80+
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
81+
// Rapid Reset CVEs. For more information see:
82+
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
83+
// - https://github.com/advisories/GHSA-4374-p667-p6c8
84+
disableHTTP2 := func(c *tls.Config) {
85+
setupLog.Info("disabling http/2")
86+
c.NextProtos = []string{"http/1.1"}
87+
}
88+
89+
if !enableHTTP2 {
90+
tlsOpts = append(tlsOpts, disableHTTP2)
91+
}
92+
93+
// Create watchers for metrics and webhooks certificates
94+
var metricsCertWatcher *certwatcher.CertWatcher
95+
96+
// Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
97+
// More info:
98+
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/metrics/server
99+
// - https://book.kubebuilder.io/reference/metrics.html
100+
metricsServerOptions := metricsserver.Options{
101+
BindAddress: metricsAddr,
102+
SecureServing: secureMetrics,
103+
TLSOpts: tlsOpts,
104+
}
105+
106+
if secureMetrics {
107+
// FilterProvider is used to protect the metrics endpoint with authn/authz.
108+
// These configurations ensure that only authorized users and service accounts
109+
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
110+
// https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/metrics/filters#WithAuthenticationAndAuthorization
111+
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
112+
}
113+
114+
// If the certificate is not specified, controller-runtime will automatically
115+
// generate self-signed certificates for the metrics server. While convenient for development and testing,
116+
// this setup is not recommended for production.
117+
//
118+
// TODO(user): If you enable certManager, uncomment the following lines:
119+
// - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
120+
// managed by cert-manager for the metrics server.
121+
// - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
122+
if len(metricsCertPath) > 0 {
123+
setupLog.Info("Initializing metrics certificate watcher using provided certificates",
124+
"metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey)
125+
126+
var err error
127+
metricsCertWatcher, err = certwatcher.New(
128+
filepath.Join(metricsCertPath, metricsCertName),
129+
filepath.Join(metricsCertPath, metricsCertKey),
130+
)
131+
if err != nil {
132+
setupLog.Error(err, "to initialize metrics certificate watcher", "error", err)
133+
os.Exit(1)
134+
}
135+
136+
metricsServerOptions.TLSOpts = append(metricsServerOptions.TLSOpts, func(config *tls.Config) {
137+
config.GetCertificate = metricsCertWatcher.GetCertificate
138+
})
139+
}
140+
59141
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
60-
Scheme: scheme,
61-
Metrics: metricsserver.Options{
62-
BindAddress: metricsAddr,
63-
},
142+
Scheme: scheme,
143+
Metrics: metricsServerOptions,
64144
HealthProbeBindAddress: probeAddr,
65145
LeaderElection: enableLeaderElection,
66146
LeaderElectionID: "f42c18d5.ironcore.dev",
@@ -122,6 +202,14 @@ func main() {
122202
}
123203
// +kubebuilder:scaffold:builder
124204

205+
if metricsCertWatcher != nil {
206+
setupLog.Info("Adding metrics certificate watcher to manager")
207+
if err := mgr.Add(metricsCertWatcher); err != nil {
208+
setupLog.Error(err, "unable to add metrics certificate watcher to manager")
209+
os.Exit(1)
210+
}
211+
}
212+
125213
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
126214
setupLog.Error(err, "unable to set up health check")
127215
os.Exit(1)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# The following manifests contain a self-signed issuer CR and a metrics certificate CR.
2+
# More document can be found at https://docs.cert-manager.io
3+
apiVersion: cert-manager.io/v1
4+
kind: Certificate
5+
metadata:
6+
name: metrics-certs # this name should match the one appeared in kustomizeconfig.yaml
7+
namespace: system
8+
spec:
9+
dnsNames:
10+
# SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
11+
# replacements in the config/default/kustomization.yaml file.
12+
- SERVICE_NAME.SERVICE_NAMESPACE.svc
13+
- SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
14+
issuerRef:
15+
kind: Issuer
16+
name: selfsigned-issuer
17+
secretName: metrics-server-cert
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# The following manifests contain a self-signed issuer CR and a certificate CR.
2+
# More document can be found at https://docs.cert-manager.io
3+
apiVersion: cert-manager.io/v1
4+
kind: Certificate
5+
metadata:
6+
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
7+
namespace: system
8+
spec:
9+
# SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
10+
# replacements in the config/default/kustomization.yaml file.
11+
dnsNames:
12+
- SERVICE_NAME.SERVICE_NAMESPACE.svc
13+
- SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
14+
issuerRef:
15+
kind: Issuer
16+
name: selfsigned-issuer
17+
secretName: webhook-server-cert

config/certmanager/certificate.yaml

Lines changed: 0 additions & 25 deletions
This file was deleted.

config/certmanager/issuer.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# The following manifest contains a self-signed issuer CR.
2+
# More information can be found at https://docs.cert-manager.io
3+
# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
4+
apiVersion: cert-manager.io/v1
5+
kind: Issuer
6+
metadata:
7+
name: selfsigned-issuer
8+
namespace: system
9+
spec:
10+
selfSigned: {}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
resources:
2-
- certificate.yaml
2+
- issuer.yaml
3+
- certificate-webhook.yaml
4+
- certificate-metrics.yaml
35

46
configurations:
57
- kustomizeconfig.yaml
Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
# This configuration is for teaching kustomize how to update name ref and var substitution
1+
# This configuration is for teaching kustomize how to update name ref substitution
22
nameReference:
33
- kind: Issuer
44
group: cert-manager.io
55
fieldSpecs:
66
- kind: Certificate
77
group: cert-manager.io
88
path: spec/issuerRef/name
9-
10-
varReference:
11-
- kind: Certificate
12-
group: cert-manager.io
13-
path: spec/commonName
14-
- kind: Certificate
15-
group: cert-manager.io
16-
path: spec/dnsNames

config/crd/kustomization.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ resources:
88
- bases/ipam.metal.ironcore.dev_networkcounters.yaml
99
#+kubebuilder:scaffold:crdkustomizeresource
1010

11-
patchesStrategicMerge:
11+
patches:
1212
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
1313
# patches here are for enabling the conversion webhook for each CRD
1414
#- patches/webhook_in_ips.yaml
1515
#+kubebuilder:scaffold:crdkustomizewebhookpatch
1616

1717
# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
1818
# patches here are for enabling the CA injection for each CRD
19-
- patches/cainjection_in_ips.yaml
19+
- path: patches/cainjection_in_ips.yaml
2020
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
2121

2222
# the following config is for teaching kustomize how to do kustomization for CRDs.

0 commit comments

Comments
 (0)