From a227e6457b581d4f1f1d79f16ca9b7baad8f38c0 Mon Sep 17 00:00:00 2001 From: Mengqi Yu Date: Thu, 6 Dec 2018 12:49:40 -0800 Subject: [PATCH] :sparkles: scaffold auth proxy --- cmd/init_project.go | 7 +- pkg/scaffold/manager/cmd.go | 4 +- pkg/scaffold/project/kustomize.go | 17 ++++- .../project/kustomize_auth_proxy_patch.go | 67 +++++++++++++++++++ pkg/scaffold/resource/authproxyrole.go | 57 ++++++++++++++++ pkg/scaffold/resource/authproxyrolebinding.go | 56 ++++++++++++++++ pkg/scaffold/resource/authproxyservice.go | 64 ++++++++++++++++++ test/project/cmd/manager/main.go | 4 +- .../project/config/default/kustomization.yaml | 17 ++++- .../default/manager_auth_proxy_patch.yaml | 24 +++++++ test/project/config/rbac/auth_proxy_role.yaml | 13 ++++ .../config/rbac/auth_proxy_role_binding.yaml | 12 ++++ .../config/rbac/auth_proxy_service.yaml | 20 ++++++ 13 files changed, 357 insertions(+), 5 deletions(-) create mode 100644 pkg/scaffold/project/kustomize_auth_proxy_patch.go create mode 100644 pkg/scaffold/resource/authproxyrole.go create mode 100644 pkg/scaffold/resource/authproxyrolebinding.go create mode 100644 pkg/scaffold/resource/authproxyservice.go create mode 100644 test/project/config/default/manager_auth_proxy_patch.yaml create mode 100644 test/project/config/rbac/auth_proxy_role.yaml create mode 100644 test/project/config/rbac/auth_proxy_role_binding.yaml create mode 100644 test/project/config/rbac/auth_proxy_service.yaml diff --git a/cmd/init_project.go b/cmd/init_project.go index 8b431a2f7f3..ae0f2cbf0b3 100644 --- a/cmd/init_project.go +++ b/cmd/init_project.go @@ -35,6 +35,7 @@ import ( "sigs.k8s.io/kubebuilder/pkg/scaffold/input" "sigs.k8s.io/kubebuilder/pkg/scaffold/manager" "sigs.k8s.io/kubebuilder/pkg/scaffold/project" + "sigs.k8s.io/kubebuilder/pkg/scaffold/resource" ) func newInitProjectCmd() *cobra.Command { @@ -143,7 +144,11 @@ func (o *projectOptions) runInit() { &project.GitIgnore{}, &project.Kustomize{}, &project.KustomizeImagePatch{}, - &project.KustomizePrometheusMetricsPatch{}) + &project.KustomizePrometheusMetricsPatch{}, + &project.KustomizeAuthProxyPatch{}, + &resource.AuthProxyService{}, + &resource.AuthProxyRole{}, + &resource.AuthProxyRoleBinding{}) if err != nil { log.Fatal(err) } diff --git a/pkg/scaffold/manager/cmd.go b/pkg/scaffold/manager/cmd.go index 95e097f1eea..3246e7e8b62 100644 --- a/pkg/scaffold/manager/cmd.go +++ b/pkg/scaffold/manager/cmd.go @@ -57,6 +57,8 @@ import ( ) func main() { + var metricsAddr string + flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") flag.Parse() logf.SetLogger(logf.ZapLogger(false)) log := logf.Log.WithName("entrypoint") @@ -71,7 +73,7 @@ func main() { // Create a new Cmd to provide shared dependencies and start components log.Info("setting up manager") - mgr, err := manager.New(cfg, manager.Options{}) + mgr, err := manager.New(cfg, manager.Options{MetricsBindAddress: metricsAddr}) if err != nil { log.Error(err, "unable to set up overall controller manager") os.Exit(1) diff --git a/pkg/scaffold/project/kustomize.go b/pkg/scaffold/project/kustomize.go index 74e0bf4ea68..176f9e88871 100644 --- a/pkg/scaffold/project/kustomize.go +++ b/pkg/scaffold/project/kustomize.go @@ -74,10 +74,25 @@ resources: - ../rbac/rbac_role.yaml - ../rbac/rbac_role_binding.yaml - ../manager/manager.yaml + # Comment the following 3 lines if you want to disable + # the auth proxy (https://github.com/brancz/kube-rbac-proxy) + # which protects your /metrics endpoint. +- ../rbac/auth_proxy_service.yaml +- ../rbac/auth_proxy_role.yaml +- ../rbac/auth_proxy_role_binding.yaml patches: - manager_image_patch.yaml -- manager_prometheus_metrics_patch.yaml + # Protect the /metrics endpoint by putting it behind auth. + # Only one of manager_auth_proxy_patch.yaml and + # manager_prometheus_metrics_patch.yaml should be enabled. +- manager_auth_proxy_patch.yaml + # If you want your controller-manager to expose the /metrics + # endpoint w/o any authn/z, uncomment the following line and + # comment manager_auth_proxy_patch.yaml. + # Only one of manager_auth_proxy_patch.yaml and + # manager_prometheus_metrics_patch.yaml should be enabled. +#- manager_prometheus_metrics_patch.yaml vars: - name: WEBHOOK_SECRET_NAME diff --git a/pkg/scaffold/project/kustomize_auth_proxy_patch.go b/pkg/scaffold/project/kustomize_auth_proxy_patch.go new file mode 100644 index 00000000000..c165ff9206a --- /dev/null +++ b/pkg/scaffold/project/kustomize_auth_proxy_patch.go @@ -0,0 +1,67 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package project + +import ( + "path/filepath" + + "sigs.k8s.io/kubebuilder/pkg/scaffold/input" +) + +var _ input.File = &KustomizeAuthProxyPatch{} + +// KustomizeAuthProxyPatch scaffolds the patch file for enabling +// prometheus metrics for manager Pod. +type KustomizeAuthProxyPatch struct { + input.Input +} + +// GetInput implements input.File +func (c *KustomizeAuthProxyPatch) GetInput() (input.Input, error) { + if c.Path == "" { + c.Path = filepath.Join("config", "default", "manager_auth_proxy_patch.yaml") + } + c.TemplateBody = kustomizeAuthProxyPatchTemplate + c.Input.IfExistsAction = input.Error + return c.Input, nil +} + +var kustomizeAuthProxyPatchTemplate = `# This patch inject a sidecar container which is a HTTP proxy for the controller manager, +# it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + image: quay.io/brancz/kube-rbac-proxy:v0.4.0 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=10" + ports: + - containerPort: 8443 + name: https + - name: manager + args: + - "--metrics-addr=127.0.0.1:8080" +` diff --git a/pkg/scaffold/resource/authproxyrole.go b/pkg/scaffold/resource/authproxyrole.go new file mode 100644 index 00000000000..94c1d69ca84 --- /dev/null +++ b/pkg/scaffold/resource/authproxyrole.go @@ -0,0 +1,57 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resource + +import ( + "path/filepath" + + "sigs.k8s.io/kubebuilder/pkg/scaffold/input" +) + +var _ input.File = &AuthProxyRole{} + +// AuthProxyRole scaffolds the config/rbac/auth_proxy_role.yaml file +type AuthProxyRole struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (r *AuthProxyRole) GetInput() (input.Input, error) { + if r.Path == "" { + r.Path = filepath.Join("config", "rbac", "auth_proxy_role.yaml") + } + r.TemplateBody = proxyRoleTemplate + return r.Input, nil +} + +var proxyRoleTemplate = `apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: proxy-role +rules: +- apiGroups: ["authentication.k8s.io"] + resources: + - tokenreviews + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: + - subjectaccessreviews + verbs: ["create"] +` diff --git a/pkg/scaffold/resource/authproxyrolebinding.go b/pkg/scaffold/resource/authproxyrolebinding.go new file mode 100644 index 00000000000..9ec5ba61197 --- /dev/null +++ b/pkg/scaffold/resource/authproxyrolebinding.go @@ -0,0 +1,56 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resource + +import ( + "path/filepath" + + "sigs.k8s.io/kubebuilder/pkg/scaffold/input" +) + +var _ input.File = &AuthProxyRoleBinding{} + +// AuthProxyRoleBinding scaffolds the config/rbac/auth_proxy_role_binding_rbac.yaml file +type AuthProxyRoleBinding struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (r *AuthProxyRoleBinding) GetInput() (input.Input, error) { + if r.Path == "" { + r.Path = filepath.Join("config", "rbac", "auth_proxy_role_binding.yaml") + } + r.TemplateBody = proxyRoleBindinggTemplate + return r.Input, nil +} + +var proxyRoleBindinggTemplate = `apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: default + namespace: system +` diff --git a/pkg/scaffold/resource/authproxyservice.go b/pkg/scaffold/resource/authproxyservice.go new file mode 100644 index 00000000000..7e08d236613 --- /dev/null +++ b/pkg/scaffold/resource/authproxyservice.go @@ -0,0 +1,64 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resource + +import ( + "path/filepath" + + "sigs.k8s.io/kubebuilder/pkg/scaffold/input" +) + +var _ input.File = &AuthProxyService{} + +// AuthProxyService scaffolds the config/rbac/auth_proxy_role.yaml file +type AuthProxyService struct { + input.Input + + // Resource is a resource in the API group + Resource *Resource +} + +// GetInput implements input.File +func (r *AuthProxyService) GetInput() (input.Input, error) { + if r.Path == "" { + r.Path = filepath.Join("config", "rbac", "auth_proxy_service.yaml") + } + r.TemplateBody = AuthProxyServiceTemplate + return r.Input, nil +} + +var AuthProxyServiceTemplate = `apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/port: "8443" + prometheus.io/scheme: https + prometheus.io/scrape: "true" + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" +` diff --git a/test/project/cmd/manager/main.go b/test/project/cmd/manager/main.go index 1ab2ad83f54..bf62879789d 100644 --- a/test/project/cmd/manager/main.go +++ b/test/project/cmd/manager/main.go @@ -31,6 +31,8 @@ import ( ) func main() { + var metricsAddr string + flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") flag.Parse() logf.SetLogger(logf.ZapLogger(false)) log := logf.Log.WithName("entrypoint") @@ -45,7 +47,7 @@ func main() { // Create a new Cmd to provide shared dependencies and start components log.Info("setting up manager") - mgr, err := manager.New(cfg, manager.Options{}) + mgr, err := manager.New(cfg, manager.Options{MetricsBindAddress: metricsAddr}) if err != nil { log.Error(err, "unable to set up overall controller manager") os.Exit(1) diff --git a/test/project/config/default/kustomization.yaml b/test/project/config/default/kustomization.yaml index 3bb22473649..8557b373c63 100644 --- a/test/project/config/default/kustomization.yaml +++ b/test/project/config/default/kustomization.yaml @@ -21,10 +21,25 @@ resources: - ../rbac/rbac_role.yaml - ../rbac/rbac_role_binding.yaml - ../manager/manager.yaml + # Comment the following 3 lines if you want to disable + # the auth proxy (https://github.com/brancz/kube-rbac-proxy) + # which protects your /metrics endpoint. +- ../rbac/auth_proxy_service.yaml +- ../rbac/auth_proxy_role.yaml +- ../rbac/auth_proxy_role_binding.yaml patches: - manager_image_patch.yaml -- manager_prometheus_metrics_patch.yaml + # Protect the /metrics endpoint by putting it behind auth. + # Only one of manager_auth_proxy_patch.yaml and + # manager_prometheus_metrics_patch.yaml should be enabled. +- manager_auth_proxy_patch.yaml + # If you want your controller-manager to expose the /metrics + # endpoint w/o any authn/z, uncomment the following line and + # comment manager_auth_proxy_patch.yaml. + # Only one of manager_auth_proxy_patch.yaml and + # manager_prometheus_metrics_patch.yaml should be enabled. +#- manager_prometheus_metrics_patch.yaml vars: - name: WEBHOOK_SECRET_NAME diff --git a/test/project/config/default/manager_auth_proxy_patch.yaml b/test/project/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 00000000000..eeeba7060af --- /dev/null +++ b/test/project/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,24 @@ +# This patch inject a sidecar container which is a HTTP proxy for the controller manager, +# it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + image: quay.io/brancz/kube-rbac-proxy:v0.4.0 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=10" + ports: + - containerPort: 8443 + name: https + - name: manager + args: + - "--metrics-addr=127.0.0.1:8080" diff --git a/test/project/config/rbac/auth_proxy_role.yaml b/test/project/config/rbac/auth_proxy_role.yaml new file mode 100644 index 00000000000..618f5e4177c --- /dev/null +++ b/test/project/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: proxy-role +rules: +- apiGroups: ["authentication.k8s.io"] + resources: + - tokenreviews + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: + - subjectaccessreviews + verbs: ["create"] diff --git a/test/project/config/rbac/auth_proxy_role_binding.yaml b/test/project/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 00000000000..48ed1e4b85c --- /dev/null +++ b/test/project/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/test/project/config/rbac/auth_proxy_service.yaml b/test/project/config/rbac/auth_proxy_service.yaml new file mode 100644 index 00000000000..027073f9528 --- /dev/null +++ b/test/project/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/port: "8443" + prometheus.io/scheme: https + prometheus.io/scrape: "true" + labels: + control-plane: controller-manager + controller-tools.k8s.io: "1.0" + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager + controller-tools.k8s.io: "1.0"