From f9ad1cae78b5fc27a5bf2f17b3f9ebf7b239b3ca Mon Sep 17 00:00:00 2001 From: Johan Thomsen Date: Mon, 18 Jun 2018 13:05:01 +0200 Subject: [PATCH] nixos/kubernetes: dashboard lockdown Kubernetes dashboard currently has cluster admin permissions, which is not recommended. - Renamed option "services.kubernetes.addons.dashboard.enableRBAC" to "services.kubernetes.addons.dashboard.rbac.enable" - Added option "services.kubernetes.addons.dashboard.rbac.clusterAdmin", default = false. - Setting recommended minimal permissions for the dashboard in accordance with https://github.com/kubernetes/dashboard/wiki/Installation - Updated release note for 18.09. --- nixos/doc/manual/release-notes/rl-1809.xml | 16 ++ nixos/modules/rename.nix | 1 + .../services/cluster/kubernetes/dashboard.nix | 138 +++++++++++++++--- 3 files changed, 132 insertions(+), 23 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml index f57fd75c782d..d3062b3ea323 100644 --- a/nixos/doc/manual/release-notes/rl-1809.xml +++ b/nixos/doc/manual/release-notes/rl-1809.xml @@ -306,6 +306,22 @@ inherit (pkgs.nixos { was not used and thus has been removed. + + + The option services.kubernetes.addons.dashboard.enableRBAC + was renamed to services.kubernetes.addons.dashboard.rbac.enable. + + + + + The Kubernetes Dashboard now has only minimal RBAC permissions by default. + If dashboard cluster-admin rights are desired, + set services.kubernetes.addons.dashboard.rbac.clusterAdmin to true. + On existing clusters, in order for the revocation of privileges to take effect, + the current ClusterRoleBinding for kubernetes-dashboard must be manually removed: + kubectl delete clusterrolebinding kubernetes-dashboard + + diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 2df737452fbc..e3691843e170 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -34,6 +34,7 @@ with lib; (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "admissionControl" ] [ "services" "kubernetes" "apiserver" "enableAdmissionPlugins" ]) (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "address" ] ["services" "kubernetes" "apiserver" "bindAddress"]) (mkRemovedOptionModule [ "services" "kubernetes" "apiserver" "publicAddress" ] "") + (mkRenamedOptionModule [ "services" "kubernetes" "addons" "dashboard" "enableRBAC" ] [ "services" "kubernetes" "addons" "dashboard" "rbac" "enable" ]) (mkRenamedOptionModule [ "services" "logstash" "address" ] [ "services" "logstash" "listenAddress" ]) (mkRenamedOptionModule [ "services" "mpd" "network" "host" ] [ "services" "mpd" "network" "listenAddress" ]) (mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "listenAddress" ]) diff --git a/nixos/modules/services/cluster/kubernetes/dashboard.nix b/nixos/modules/services/cluster/kubernetes/dashboard.nix index 9c1f814b683c..6d9faada4401 100644 --- a/nixos/modules/services/cluster/kubernetes/dashboard.nix +++ b/nixos/modules/services/cluster/kubernetes/dashboard.nix @@ -8,10 +8,25 @@ in { options.services.kubernetes.addons.dashboard = { enable = mkEnableOption "kubernetes dashboard addon"; - enableRBAC = mkOption { - description = "Whether to enable role based access control is enabled for kubernetes dashboard"; - type = types.bool; - default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode; + rbac = mkOption { + description = "Role-based access control (RBAC) options"; + type = types.submodule { + + options = { + enable = mkOption { + description = "Whether to enable role based access control is enabled for kubernetes dashboard"; + type = types.bool; + default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode; + }; + + clusterAdmin = mkOption { + description = "Whether to assign cluster admin rights to the kubernetes dashboard"; + type = types.bool; + default = false; + }; + + }; + }; }; version = mkOption { @@ -202,29 +217,106 @@ in { namespace = "kube-system"; }; }; - } // (optionalAttrs cfg.enableRBAC { - kubernetes-dashboard-crb = { - apiVersion = "rbac.authorization.k8s.io/v1"; - kind = "ClusterRoleBinding"; - metadata = { - name = "kubernetes-dashboard"; - labels = { - k8s-app = "kubernetes-dashboard"; - k8s-addon = "kubernetes-dashboard.addons.k8s.io"; - "addonmanager.kubernetes.io/mode" = "Reconcile"; - }; - }; - roleRef = { - apiGroup = "rbac.authorization.k8s.io"; - kind = "ClusterRole"; - name = "cluster-admin"; - }; + } // (optionalAttrs cfg.rbac.enable + (let subjects = [{ kind = "ServiceAccount"; name = "kubernetes-dashboard"; namespace = "kube-system"; }]; - }; - }); + labels = { + k8s-app = "kubernetes-dashboard"; + k8s-addon = "kubernetes-dashboard.addons.k8s.io"; + "addonmanager.kubernetes.io/mode" = "Reconcile"; + }; + in + (if cfg.rbac.clusterAdmin then { + kubernetes-dashboard-crb = { + apiVersion = "rbac.authorization.k8s.io/v1"; + kind = "ClusterRoleBinding"; + metadata = { + name = "kubernetes-dashboard"; + inherit labels; + }; + roleRef = { + apiGroup = "rbac.authorization.k8s.io"; + kind = "ClusterRole"; + name = "cluster-admin"; + }; + inherit subjects; + }; + } + else + { + # Upstream role- and rolebinding as per: + # https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml + kubernetes-dashboard-role = { + apiVersion = "rbac.authorization.k8s.io/v1"; + kind = "Role"; + metadata = { + name = "kubernetes-dashboard-minimal"; + namespace = "kube-system"; + inherit labels; + }; + rules = [ + # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret. + { + apiGroups = [""]; + resources = ["secrets"]; + verbs = ["create"]; + } + # Allow Dashboard to create 'kubernetes-dashboard-settings' config map. + { + apiGroups = [""]; + resources = ["configmaps"]; + verbs = ["create"]; + } + # Allow Dashboard to get, update and delete Dashboard exclusive secrets. + { + apiGroups = [""]; + resources = ["secrets"]; + resourceNames = ["kubernetes-dashboard-key-holder"]; + verbs = ["get" "update" "delete"]; + } + # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. + { + apiGroups = [""]; + resources = ["configmaps"]; + resourceNames = ["kubernetes-dashboard-settings"]; + verbs = ["get" "update"]; + } + # Allow Dashboard to get metrics from heapster. + { + apiGroups = [""]; + resources = ["services"]; + resourceNames = ["heapster"]; + verbs = ["proxy"]; + } + { + apiGroups = [""]; + resources = ["services/proxy"]; + resourceNames = ["heapster" "http:heapster:" "https:heapster:"]; + verbs = ["get"]; + } + ]; + }; + + kubernetes-dashboard-rb = { + apiVersion = "rbac.authorization.k8s.io/v1"; + kind = "RoleBinding"; + metadata = { + name = "kubernetes-dashboard-minimal"; + namespace = "kube-system"; + inherit labels; + }; + roleRef = { + apiGroup = "rbac.authorization.k8s.io"; + kind = "Role"; + name = "kubernetes-dashboard-minimal"; + }; + inherit subjects; + }; + }) + )); }; }