From 0ad0895dc9609cad9e4ef48d6d5223c5d6525b25 Mon Sep 17 00:00:00 2001 From: BugFest <52962234+bugfest@users.noreply.github.com> Date: Mon, 6 Feb 2023 00:50:03 +0100 Subject: [PATCH] Implements #33 - Namespaced Support (#34) --- Makefile | 8 ++- README.md | 12 +++-- apis/config/v2/projectconfig_types.go | 3 ++ charts/tor-controller/Chart.yaml | 4 +- charts/tor-controller/README.md | 3 +- charts/tor-controller/templates/_helpers.tpl | 22 ++++++++ .../tor-controller/templates/clusterrole.yaml | 27 +++++++++- .../templates/clusterrolebinding.yaml | 22 ++++++-- .../tor-controller/templates/configmap.yaml | 3 ++ charts/tor-controller/values.yaml | 3 ++ .../controller_manager_config.yaml | 0 .../controller_manager_config_dev.yaml | 2 +- ...troller_manager_config_dev_namespaced.yaml | 20 +++++++ config/manager/{ => bases}/manager.yaml | 0 config/manager/kustomization.yaml | 6 +-- docs/DEVELOP.md | 52 +++++++++++++++++++ docs/QEMU.md | 2 +- main.go | 7 +++ 18 files changed, 178 insertions(+), 18 deletions(-) rename config/manager/{ => bases}/controller_manager_config.yaml (100%) rename config/manager/{ => bases}/controller_manager_config_dev.yaml (88%) create mode 100644 config/manager/bases/controller_manager_config_dev_namespaced.yaml rename config/manager/{ => bases}/manager.yaml (100%) diff --git a/Makefile b/Makefile index 6ea2949..79ed1bf 100644 --- a/Makefile +++ b/Makefile @@ -71,11 +71,15 @@ build: generate fmt vet ## Build manager binary. .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go -no-leader-elect --config config/manager/controller_manager_config.yaml + go run ./main.go -no-leader-elect --config config/manager/bases/controller_manager_config.yaml .PHONY: rundev rundev: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go -no-leader-elect --config config/manager/controller_manager_config_dev.yaml + go run ./main.go -no-leader-elect --config config/manager/bases/controller_manager_config_dev.yaml + +.PHONY: rundev_namespaced +rundev_namespaced: manifests generate fmt vet ## Run a controller from your host. + go run ./main.go -no-leader-elect --config config/manager/bases/controller_manager_config_dev_namespaced.yaml .PHONY: docker-build-all docker-build-all: docker-build docker-build-daemon docker-build-daemon-manager docker-build-onionbalance-manager diff --git a/README.md b/README.md index d0edf23..c18911f 100644 --- a/README.md +++ b/README.md @@ -92,12 +92,14 @@ Full changelog: [CHANGELOG](CHANGELOG.md) - Tor instance CRD supporting custom config and Client/Server/Metrics/Control ports - **v0.7.x** - Onion Service's authorized clients support +- **v0.8.x** + - Namespaced deployments Roadmap / TODO -------------- - Tor daemon management via socket (e.g: config reload) -- Manage Tor Server fingerpting (ed25519_master_id_secret_key, secret_id_key) and automatic family and nikname management +- Manage Tor Server fingerpting (ed25519_master_id_secret_key, secret_id_key) and automatic family and nickname management - Tor relays: - Non exit: Bridge, Snowflake, Middle/Guard - Exit relay: Tor Exit @@ -115,9 +117,12 @@ Using helm (recommended): --create-namespace --namespace tor-controller \ tor-controller bugfest/tor-controller -Install tor-controller directly using the manifest: +For namespaced deployments add `--set namespaced=true` to helm's command when deploying. +Check [charts/tor-controller/README.md](charts/tor-controller/README.md) for a full set of available options. - $ kubectl apply -f hack/install.yaml +Install tor-controller directly using the manifest (cluster-scoped): + + $ kubectl apply -f https://raw.githubusercontent.com/bugfest/tor-controller/master/hack/install.yaml Resources --------- @@ -599,6 +604,7 @@ Versions | 0.1.7 | 0.7.0 | 0.4.6.10 | | 0.1.8 | 0.7.1 | 0.4.6.10 | | 0.1.9 | 0.7.2 | 0.4.6.10 | +| 0.1.10 | 0.8.0 | 0.5.6.10 | References ---------- diff --git a/apis/config/v2/projectconfig_types.go b/apis/config/v2/projectconfig_types.go index 3ab9df9..eff5a76 100644 --- a/apis/config/v2/projectconfig_types.go +++ b/apis/config/v2/projectconfig_types.go @@ -47,6 +47,9 @@ type ProjectConfig struct { // +optional TorOnionbalanceManager TorOnionbalanceManagerType `json:"torOnionbalanceManager,omitempty"` + + // +optional + Namespace string `json:"namespace,omitempty"` } type TorDaemonType struct { diff --git a/charts/tor-controller/Chart.yaml b/charts/tor-controller/Chart.yaml index 71e1bcd..d815e99 100644 --- a/charts/tor-controller/Chart.yaml +++ b/charts/tor-controller/Chart.yaml @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.9 +version: 0.1.10 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.7.2" +appVersion: "0.8.0" diff --git a/charts/tor-controller/README.md b/charts/tor-controller/README.md index 4ff759d..1a4ba21 100644 --- a/charts/tor-controller/README.md +++ b/charts/tor-controller/README.md @@ -1,6 +1,6 @@ # tor-controller -![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.7.2](https://img.shields.io/badge/AppVersion-0.7.2-informational?style=flat-square) +![Version: 0.1.10](https://img.shields.io/badge/Version-0.1.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.8.0](https://img.shields.io/badge/AppVersion-0.8.0-informational?style=flat-square) Tor hidden services controller for kubernetes @@ -18,6 +18,7 @@ Tor hidden services controller for kubernetes | manager.image | object | `{"pullPolicy":"Always","repository":"quay.io/bugfest/tor-daemon-manager","tag":""}` | tor-daemon-manager image, it runs Tor client with manager | | manager.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | | nameOverride | string | `""` | | +| namespaced | bool | `false` | If enabled, permissions are restricted to the target Namespace | | nodeSelector | object | `{}` | | | onionbalance.image | object | `{"pullPolicy":"Always","repository":"quay.io/bugfest/tor-onionbalance-manager","tag":""}` | tor-onionbalance-manager image, it runs Tor client | | onionbalance.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | diff --git a/charts/tor-controller/templates/_helpers.tpl b/charts/tor-controller/templates/_helpers.tpl index 5d51300..958d6a4 100644 --- a/charts/tor-controller/templates/_helpers.tpl +++ b/charts/tor-controller/templates/_helpers.tpl @@ -60,3 +60,25 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* +Helper to dynamically create cluster-wide or namespaced roles & rolebindings +*/}} +{{- define "tor-controller.roleKind" -}} +{{- if .Values.namespaced }} +{{- "Role" }} +{{- else }} +{{- "ClusterRole" }} +{{- end }} +{{- end }} + +{{/* +Helper to dynamically create cluster-wide or namespaced roles & rolebindings +*/}} +{{- define "tor-controller.roleBindingKind" -}} +{{- if .Values.namespaced }} +{{- "RoleBinding" }} +{{- else }} +{{- "ClusterRoleBinding" }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/tor-controller/templates/clusterrole.yaml b/charts/tor-controller/templates/clusterrole.yaml index 14e2468..d782e4b 100644 --- a/charts/tor-controller/templates/clusterrole.yaml +++ b/charts/tor-controller/templates/clusterrole.yaml @@ -1,5 +1,24 @@ +--- +{{- if .Values.namespaced }} +# Namespaced deployment requires this minimal ClusterRole to read CRD's apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole +metadata: + creationTimestamp: null + name: {{ include "tor-controller.fullname" . }}-manager-crd-role +rules: + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: {{ include "tor-controller.roleKind" . }} metadata: creationTimestamp: null name: {{ include "tor-controller.fullname" . }}-manager-role @@ -60,6 +79,7 @@ rules: - patch - update - watch +{{- if not .Values.namespaced }} - apiGroups: - apiextensions.k8s.io resources: @@ -68,6 +88,7 @@ rules: - get - list - watch +{{- end }} - apiGroups: - apps resources: @@ -195,8 +216,9 @@ rules: - patch - update --- +{{- if not .Values.namespaced }} apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole +kind: {{ include "tor-controller.roleKind" . }} metadata: name: {{ include "tor-controller.fullname" . }}-metrics-reader rules: @@ -204,9 +226,10 @@ rules: - /metrics verbs: - get +{{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole +kind: {{ include "tor-controller.roleKind" . }} metadata: name: {{ include "tor-controller.fullname" . }}-proxy-role rules: diff --git a/charts/tor-controller/templates/clusterrolebinding.yaml b/charts/tor-controller/templates/clusterrolebinding.yaml index 551c436..8e7843c 100644 --- a/charts/tor-controller/templates/clusterrolebinding.yaml +++ b/charts/tor-controller/templates/clusterrolebinding.yaml @@ -1,10 +1,26 @@ +--- +{{- if .Values.namespaced }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: {{ include "tor-controller.fullname" . }}-manager-rolebinding + name: {{ include "tor-controller.fullname" . }}-manager-crd-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole + name: {{ include "tor-controller.fullname" . }}-manager-crd-role +subjects: + - kind: ServiceAccount + name: {{ include "tor-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: {{ include "tor-controller.roleBindingKind" . }} +metadata: + name: {{ include "tor-controller.fullname" . }}-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: {{ include "tor-controller.roleKind" . }} name: {{ include "tor-controller.fullname" . }}-manager-role subjects: - kind: ServiceAccount @@ -12,12 +28,12 @@ subjects: namespace: {{ .Release.Namespace }} --- apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding +kind: {{ include "tor-controller.roleBindingKind" . }} metadata: name: {{ include "tor-controller.fullname" . }}-proxy-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io - kind: ClusterRole + kind: {{ include "tor-controller.roleKind" . }} name: {{ include "tor-controller.fullname" . }}-proxy-role subjects: - kind: ServiceAccount diff --git a/charts/tor-controller/templates/configmap.yaml b/charts/tor-controller/templates/configmap.yaml index 4b8770f..aaac14f 100644 --- a/charts/tor-controller/templates/configmap.yaml +++ b/charts/tor-controller/templates/configmap.yaml @@ -22,3 +22,6 @@ data: image: "{{ .Values.manager.image.repository }}:{{ .Values.manager.image.tag | default .Chart.AppVersion }}" torOnionbalanceManager: image: "{{ .Values.onionbalance.image.repository }}:{{ .Values.onionbalance.image.tag | default .Chart.AppVersion }}" + {{- if .Values.namespaced }} + namespace: {{ .Release.Namespace }} + {{- end }} \ No newline at end of file diff --git a/charts/tor-controller/values.yaml b/charts/tor-controller/values.yaml index a3a6c6e..ed3e9a1 100644 --- a/charts/tor-controller/values.yaml +++ b/charts/tor-controller/values.yaml @@ -2,6 +2,9 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# -- If enabled, permissions are restricted to the target Namespace +namespaced: false + # -- Daemonset replica count replicaCount: 1 diff --git a/config/manager/controller_manager_config.yaml b/config/manager/bases/controller_manager_config.yaml similarity index 100% rename from config/manager/controller_manager_config.yaml rename to config/manager/bases/controller_manager_config.yaml diff --git a/config/manager/controller_manager_config_dev.yaml b/config/manager/bases/controller_manager_config_dev.yaml similarity index 88% rename from config/manager/controller_manager_config_dev.yaml rename to config/manager/bases/controller_manager_config_dev.yaml index 25ba7e0..27fc72d 100644 --- a/config/manager/controller_manager_config_dev.yaml +++ b/config/manager/bases/controller_manager_config_dev.yaml @@ -16,4 +16,4 @@ torDaemon: torDaemonManager: image: onions:5000/tor-daemon-manager:latest torOnionbalanceManager: - image: onions:5000/tor-onionbalance-manager:latest + image: onions:5000/tor-onionbalance-manager:latest \ No newline at end of file diff --git a/config/manager/bases/controller_manager_config_dev_namespaced.yaml b/config/manager/bases/controller_manager_config_dev_namespaced.yaml new file mode 100644 index 0000000..c5223ff --- /dev/null +++ b/config/manager/bases/controller_manager_config_dev_namespaced.yaml @@ -0,0 +1,20 @@ +apiVersion: config.k8s.torproject.org/v2 +kind: ProjectConfig +meta: + name: tor-controller-config +health: + healthProbeBindAddress: :8081 +metrics: + bindAddress: 127.0.0.1:8080 +webhook: + port: 9443 +leaderElection: + leaderElect: true + resourceName: 59806307.k8s.torproject.org +torDaemon: + image: onions:5000/tor-daemon:latest +torDaemonManager: + image: onions:5000/tor-daemon-manager:latest +torOnionbalanceManager: + image: onions:5000/tor-onionbalance-manager:latest +namespace: default \ No newline at end of file diff --git a/config/manager/manager.yaml b/config/manager/bases/manager.yaml similarity index 100% rename from config/manager/manager.yaml rename to config/manager/bases/manager.yaml diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 26f1829..6b4384e 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,16 +1,16 @@ resources: -- manager.yaml +- bases/manager.yaml generatorOptions: disableNameSuffixHash: true configMapGenerator: - files: - - controller_manager_config.yaml + - bases/controller_manager_config.yaml name: manager-config apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: tor-controller + newName: onions:5000/tor-controller newTag: latest diff --git a/docs/DEVELOP.md b/docs/DEVELOP.md index 2a5a2df..0876a5e 100644 --- a/docs/DEVELOP.md +++ b/docs/DEVELOP.md @@ -101,6 +101,58 @@ To deploy in a test cluster # Update helm chart README docker run --rm --volume "$(pwd)/charts:/helm-docs" -u $(id -u) jnorwood/helm-docs:latest +# Namespaced deployment + +1. Use controller's SA to impersonate its permissions + +```shell +cat < $mysa + +echo using KUBECONFIG=$mysa +export KUBECONFIG=$mysa +``` + +[Steps' source](https://stackoverflow.com/questions/47770676/how-to-create-a-kubectl-config-file-for-serviceaccount) + # Prometheus/Grafana helm repo add prometheus-community https://prometheus-community.github.io/helm-charts diff --git a/docs/QEMU.md b/docs/QEMU.md index 939b80c..77de23c 100644 --- a/docs/QEMU.md +++ b/docs/QEMU.md @@ -106,7 +106,7 @@ Docs - qemu docs: https://qemu.readthedocs.io/en/latest/system/invocation.html#hxtool-1 - alpine downloads: https://alpinelinux.org/downloads/ -- determine bin architecture: https://exceptionshub.com/determine-target-architecture-of-binary-file-in-linux-library-or-executable.html +- determine bin architecture: https://exceptionshub.com/determine-target-architecture-of-binary-file-in-linux-li ary-or-executable.html - fix blkio cgroup issue: https://www.programmerall.com/article/5933169238/ - fix alpine repos: https://github.com/alpinelinux/docker-alpine/issues/98 - fix alpine time: https://wiki.alpinelinux.org/wiki/Alpine_Linux:FAQ#Time_and_timezones diff --git a/main.go b/main.go index 7627cf5..9cd5643 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ package main import ( "flag" + "fmt" "os" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -92,6 +93,12 @@ func main() { setupLog.Info("Overriding LeaderElection (no-leader-elect)") } + // Setup namespace if running in namespaced mode + if ctrlConfig.Namespace != "" { + setupLog.Info(fmt.Sprintf("Namespaced mode. Namespace=%s", ctrlConfig.Namespace)) + options.Namespace = ctrlConfig.Namespace + } + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), options) if err != nil { setupLog.Error(err, "unable to start manager")