Skip to content

Commit cf8c812

Browse files
committed
add admission webhook
1 parent a4eaa33 commit cf8c812

37 files changed

Lines changed: 631 additions & 52 deletions

.github/workflows/build-and-test.yaml

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,39 @@ jobs:
111111
packages: write
112112
id-token: write
113113
uses: gardener/cc-utils/.github/workflows/helmchart-ocm.yaml@master
114+
strategy:
115+
matrix:
116+
args:
117+
- name: gardener-extension-shoot-traefik
118+
dir: charts/gardener-extension-shoot-traefik
119+
oci-repository: charts/gardener/extensions
120+
ocm-mappings:
121+
- ref: ocm-resource:gardener-extension-shoot-traefik.repository
122+
attribute: image.repository
123+
- ref: ocm-resource:gardener-extension-shoot-traefik.tag
124+
attribute: image.tag
125+
- name: admission-shoot-traefik-application
126+
dir: charts/gardener-extension-admission-traefik/charts/application
127+
oci-repository: charts/gardener/extensions
128+
ocm-mappings:
129+
- ref: ocm-resource:gardener-extension-shoot-traefik.repository
130+
attribute: image.repository
131+
- ref: ocm-resource:gardener-extension-shoot-traefik.tag
132+
attribute: image.tag
133+
- name: admission-shoot-traefik-runtime
134+
dir: charts/gardener-extension-admission-traefik/charts/runtime
135+
oci-repository: charts/gardener/extensions
136+
ocm-mappings:
137+
- ref: ocm-resource:gardener-extension-shoot-traefik.repository
138+
attribute: image.repository
139+
- ref: ocm-resource:gardener-extension-shoot-traefik.tag
140+
attribute: image.tag
114141
with:
115-
name: gardener-extension-shoot-traefik
116-
dir: charts
142+
name: ${{ matrix.args.name }}
143+
dir: ${{ matrix.args.dir }}
117144
oci-registry: ${{ needs.prepare.outputs.oci-registry }}
118-
oci-repository: charts/gardener/extensions
119-
ocm-mappings: |
120-
[
121-
{"ref": "ocm-resource:gardener-extension-shoot-traefik.repository", "attribute": "image.repository"},
122-
{"ref": "ocm-resource:gardener-extension-shoot-traefik.tag", "attribute": "image.tag"}
123-
]
145+
oci-repository: ${{ matrix.args.oci-repository }}
146+
ocm-mappings: ${{ toJSON(matrix.args.ocm-mappings) }}
124147

125148
build-only:
126149
if: inputs.mode == ''

Makefile

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,18 @@ generate-operator-extension: ## Generate operator extension example resources.
232232

233233
.PHONY: check-helm
234234
check-helm: ## Lint helm charts and validate rendered templates.
235-
@$(GO_TOOL) helm lint $(SRC_ROOT)/charts
236-
@$(GO_TOOL) helm template $(SRC_ROOT)/charts | \
235+
@$(GO_TOOL) helm lint $(SRC_ROOT)/charts/gardener-extension-shoot-traefik
236+
@$(GO_TOOL) helm template $(SRC_ROOT)/charts/gardener-extension-shoot-traefik | \
237+
$(GO_TOOL) kubeconform \
238+
$(KUBECONFORM_OPTS) \
239+
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'
240+
@$(GO_TOOL) helm lint $(SRC_ROOT)/charts/gardener-extension-admission-traefik/charts/runtime
241+
@$(GO_TOOL) helm template $(SRC_ROOT)/charts/gardener-extension-admission-traefik/charts/runtime | \
242+
$(GO_TOOL) kubeconform \
243+
$(KUBECONFORM_OPTS) \
244+
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'
245+
@$(GO_TOOL) helm lint $(SRC_ROOT)/charts/gardener-extension-admission-traefik/charts/application
246+
@$(GO_TOOL) helm template $(SRC_ROOT)/charts/gardener-extension-admission-traefik/charts/application | \
237247
$(GO_TOOL) kubeconform \
238248
$(KUBECONFORM_OPTS) \
239249
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'
@@ -260,22 +270,34 @@ kind-load-image: ## Load extension images to target cluster.
260270

261271
.PHONY: helm-load-chart
262272
helm-load-chart: ## Load helm chart to local registry.
263-
@$(GO_TOOL) helm package $(SRC_ROOT)/charts --version $(VERSION)
273+
@$(GO_TOOL) helm package $(SRC_ROOT)/charts/gardener-extension-shoot-traefik --version $(VERSION)
264274
@$(GO_TOOL) helm push --plain-http $(EXTENSION_NAME)-$(VERSION).tgz oci://$(LOCAL_REGISTRY)/helm-charts
265275
@rm -f $(EXTENSION_NAME)-$(VERSION).tgz
276+
@$(GO_TOOL) helm package $(SRC_ROOT)/charts/gardener-extension-admission-traefik/charts/runtime --version $(VERSION)
277+
@$(GO_TOOL) helm push --plain-http admission-traefik-runtime-$(VERSION).tgz oci://$(LOCAL_REGISTRY)/helm-charts
278+
@rm -f admission-traefik-runtime-$(VERSION).tgz
279+
@$(GO_TOOL) helm package $(SRC_ROOT)/charts/gardener-extension-admission-traefik/charts/application --version $(VERSION)
280+
@$(GO_TOOL) helm push --plain-http admission-traefik-application-$(VERSION).tgz oci://$(LOCAL_REGISTRY)/helm-charts
281+
@rm -f admission-traefik-application-$(VERSION).tgz
266282

267283
.PHONY: update-version-tags
268284
update-version-tags: ## Update version tags in helm charts and example resources based on VERSION file.
269285
@env version=$(VERSION) \
270-
$(GO_TOOL) yq -i '.version = env(version)' $(SRC_ROOT)/charts/Chart.yaml
286+
$(GO_TOOL) yq -i '.version = env(version)' $(SRC_ROOT)/charts/gardener-extension-shoot-traefik/Chart.yaml
271287
@env image=$(IMAGE) tag=$(VERSION) \
272-
$(GO_TOOL) yq -i '(.image.repository = env(image)) | (.image.tag = env(tag))' $(SRC_ROOT)/charts/values.yaml
288+
$(GO_TOOL) yq -i '(.image.repository = env(image)) | (.image.tag = env(tag))' $(SRC_ROOT)/charts/gardener-extension-shoot-traefik/values.yaml
273289
@env oci_charts=$(LOCAL_REGISTRY)/helm-charts/$(EXTENSION_NAME):$(VERSION) \
274290
$(GO_TOOL) yq -i '.helm.ociRepository.ref = env(oci_charts)' $(SRC_ROOT)/examples/dev-setup/controllerdeployment.yaml
275291
@env oci_charts=$(LOCAL_REGISTRY)/helm-charts/$(EXTENSION_NAME):$(VERSION) \
276292
$(GO_TOOL) yq -i '.spec.deployment.extension.helm.ociRepository.ref = env(oci_charts)' $(SRC_ROOT)/examples/operator-extension/base/extension.yaml
293+
@env oci_charts=$(LOCAL_REGISTRY)/helm-charts/admission-traefik-runtime:$(VERSION) \
294+
$(GO_TOOL) yq -i '.spec.deployment.admission.runtimeCluster.helm.ociRepository.ref = env(oci_charts)' $(SRC_ROOT)/examples/operator-extension/base/extension.yaml
295+
@env oci_charts=$(LOCAL_REGISTRY)/helm-charts/admission-traefik-application:$(VERSION) \
296+
$(GO_TOOL) yq -i '.spec.deployment.admission.virtualCluster.helm.ociRepository.ref = env(oci_charts)' $(SRC_ROOT)/examples/operator-extension/base/extension.yaml
277297
@env image=$(IMAGE) tag=$(VERSION) \
278298
$(GO_TOOL) yq -i '(.spec.deployment.extension.values.image.repository = env(image)) | (.spec.deployment.extension.values.image.tag = env(tag))' $(SRC_ROOT)/examples/operator-extension/patches/extension.yaml
299+
@env image=$(IMAGE) tag=$(VERSION) \
300+
$(GO_TOOL) yq -i '(.spec.deployment.admission.runtimeCluster.values.image.repository = env(image)) | (.spec.deployment.admission.runtimeCluster.values.image.tag = env(tag))' $(SRC_ROOT)/examples/operator-extension/patches/extension.yaml
279301

280302
deploy deploy-operator: export IMAGE=$(LOCAL_REGISTRY)/extensions/$(EXTENSION_NAME)
281303

README.md

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ The `gardener-extension-shoot-traefik` deploys Traefik ingress controller to Gar
55
## Features
66

77
- **Traefik Ingress Controller**: Deploys Traefik v3.x as the ingress controller in shoot clusters
8-
- **Admission Webhook**: Validates that Traefik extension is only enabled for shoots with purpose "evaluation"
8+
- **Admission Webhook**: Validates that Traefik extension is only enabled for shoots with purpose "evaluation". Deployed as a separate admission controller using the same binary with the `webhook` subcommand.
99
- **ManagedResource**: Uses Gardener's ManagedResource mechanism for deployment and lifecycle management
1010
- **Configurable**: Supports custom Traefik image, replicas, and ingress class configuration
1111

@@ -119,6 +119,57 @@ kubectl -n kube-system port-forward deployment/traefik 9000:9000
119119

120120
Then open `http://localhost:9000/dashboard/` in your browser (the trailing `/` is required).
121121

122+
## Admission Controller
123+
124+
The extension includes an admission controller that validates Shoot resources to ensure
125+
the Traefik extension can only be enabled for shoots with `purpose: evaluation`.
126+
127+
The admission controller is deployed as a separate component using the same binary
128+
(`extension-traefik webhook`) and has its own Helm charts under
129+
`charts/gardener-extension-admission-traefik/`. Following the Gardener extension
130+
convention, it consists of two sub-charts:
131+
132+
- **`charts/runtime/`** — Deployed in the runtime cluster. Contains the Deployment,
133+
Service, RBAC, VPA, and PodDisruptionBudget resources for the webhook server.
134+
- **`charts/application/`** — Deployed in the virtual garden cluster. Contains the
135+
ClusterRole, ClusterRoleBinding, and ServiceAccount needed for the webhook to
136+
access Shoot resources.
137+
138+
### Deployment via Gardener Operator
139+
140+
When deploying via `gardener-operator`, the admission controller is automatically
141+
deployed alongside the extension. The `Extension` resource (from group
142+
`operator.gardener.cloud/v1alpha1`) specifies both the extension and the admission
143+
deployment:
144+
145+
```yaml
146+
apiVersion: operator.gardener.cloud/v1alpha1
147+
kind: Extension
148+
metadata:
149+
name: gardener-extension-shoot-traefik
150+
spec:
151+
deployment:
152+
admission:
153+
runtimeCluster:
154+
helm:
155+
ociRepository:
156+
ref: <registry>/admission-shoot-traefik-runtime:<version>
157+
virtualCluster:
158+
helm:
159+
ociRepository:
160+
ref: <registry>/admission-shoot-traefik-application:<version>
161+
extension:
162+
helm:
163+
ociRepository:
164+
ref: <registry>/gardener-extension-shoot-traefik:<version>
165+
resources:
166+
- kind: Extension
167+
type: shoot-traefik
168+
```
169+
170+
See [`examples/operator-extension/`](./examples/operator-extension/) for a
171+
complete example.
172+
122173
## Development
123174

124175
In order to build a binary of the extension, you can use the following command.
@@ -194,9 +245,9 @@ The `deploy-operator` target takes care of the following.
194245

195246
1. Builds a Docker image of the extension
196247
2. Loads the image into the `kind` cluster nodes
197-
3. Packages the Helm charts and pushes them to the local registry
248+
3. Packages the Helm charts (extension + admission) and pushes them to the local registry
198249
4. Deploys the `Extension` (from group `operator.gardener.cloud/v1alpha1`) to
199-
the _runtime_ cluster
250+
the _runtime_ cluster, which includes the admission controller configuration
200251

201252
Verify that we have successfully created the
202253
`Extension` (from group `operator.gardener.cloud/v1alpha1`) resource.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Patterns to ignore when building packages.
2+
.DS_Store
3+
# Common VCS dirs
4+
.git/
5+
.gitignore
6+
.bzr/
7+
.bzrignore
8+
.hg/
9+
.hgignore
10+
.svn/
11+
# Common backup files
12+
*.swp
13+
*.bak
14+
*.tmp
15+
*.orig
16+
*~
17+
# Various IDEs
18+
.project
19+
.idea/
20+
*.tmproj
21+
.vscode/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: v1
2+
description: A Helm chart to deploy the gardener-extension-admission-traefik application related resources
3+
name: admission-traefik-application
4+
version: 0.1.0
5+
sources:
6+
- https://github.com/gardener/gardener-extension-shoot-traefik
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{{- define "name" -}}
2+
gardener-extension-admission-traefik
3+
{{- end -}}
4+
5+
{{- define "labels.app.key" -}}
6+
app.kubernetes.io/name
7+
{{- end -}}
8+
{{- define "labels.app.value" -}}
9+
{{ include "name" . }}
10+
{{- end -}}
11+
12+
{{- define "labels" -}}
13+
{{ include "labels.app.key" . }}: {{ include "labels.app.value" . }}
14+
app.kubernetes.io/instance: {{ .Release.Name }}
15+
{{- end -}}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: {{ include "name" . }}
6+
labels:
7+
{{ include "labels" . | indent 4 }}
8+
rules:
9+
- apiGroups:
10+
- core.gardener.cloud
11+
resources:
12+
- shoots
13+
verbs:
14+
- get
15+
- list
16+
- watch
17+
- apiGroups:
18+
- ""
19+
resources:
20+
- namespaces
21+
verbs:
22+
- get
23+
- list
24+
- watch
25+
- apiGroups:
26+
- admissionregistration.k8s.io
27+
resources:
28+
- validatingwebhookconfigurations
29+
verbs:
30+
- create
31+
- get
32+
- list
33+
- watch
34+
- apiGroups:
35+
- admissionregistration.k8s.io
36+
resources:
37+
- validatingwebhookconfigurations
38+
resourceNames:
39+
- {{ include "name" . }}
40+
verbs:
41+
- patch
42+
- update
43+
- delete
44+
---
45+
apiVersion: rbac.authorization.k8s.io/v1
46+
kind: ClusterRoleBinding
47+
metadata:
48+
name: {{ include "name" . }}
49+
labels:
50+
{{ include "labels" . | indent 4 }}
51+
roleRef:
52+
apiGroup: rbac.authorization.k8s.io
53+
kind: ClusterRole
54+
name: {{ include "name" . }}
55+
subjects:
56+
{{- if .Values.gardener.virtualCluster.serviceAccount.name }}
57+
- kind: ServiceAccount
58+
name: {{ required ".Values.gardener.virtualCluster.serviceAccount.name is required" .Values.gardener.virtualCluster.serviceAccount.name }}
59+
namespace: {{ required ".Values.gardener.virtualCluster.serviceAccount.namespace is required" .Values.gardener.virtualCluster.serviceAccount.namespace }}
60+
{{- else }}
61+
- kind: ServiceAccount
62+
name: {{ include "name" . }}
63+
namespace: {{ .Release.Namespace }}
64+
{{- end }}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{{- if and .Values.gardener.virtualCluster.enabled ( not .Values.gardener.virtualCluster.serviceAccount.name ) }}
2+
apiVersion: v1
3+
kind: ServiceAccount
4+
metadata:
5+
name: {{ include "name" . }}
6+
namespace: {{ .Release.Namespace }}
7+
labels:
8+
{{ include "labels" . | indent 4 }}
9+
{{- end }}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
gardener:
2+
virtualCluster:
3+
enabled: true
4+
serviceAccount: {}
5+
# name: gardener-extension-admission-traefik
6+
# namespace: kube-system
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Patterns to ignore when building packages.
2+
.DS_Store
3+
# Common VCS dirs
4+
.git/
5+
.gitignore
6+
.bzr/
7+
.bzrignore
8+
.hg/
9+
.hgignore
10+
.svn/
11+
# Common backup files
12+
*.swp
13+
*.bak
14+
*.tmp
15+
*.orig
16+
*~
17+
# Various IDEs
18+
.project
19+
.idea/
20+
*.tmproj
21+
.vscode/

0 commit comments

Comments
 (0)