新版的dashboard在安全方面下了不少功夫,也提供了多种认证方式。以下就踩过的坑来进行一下介绍。

dashboard官方文档:

https://github.com/kubernetes/dashboard/wiki

Installation

dashboard有两个发行版本,offical和deployment. 这里使用offical版本。

dashboard的安装文档中提到了3中方式:
1. quick setup
快速安装,但是只能通过kubectl proxy的方式使用本机地址(localhost,127.0.0.1)来进行登录。
2. recommended setup
常规安装,可以通过NodePortingress的方式访问。
3. alternative setup
采用http协议访问,出于安全性考虑,就没使用这个了。

快速安装和常规安装几乎一模一样,唯一不同的是采用常规安装的时候,需要先生成dashboard的服务器端证书,然后通过configMap挂载到dashboard容器中。

第一步,生成证书:

mkdir certs && cd certs

openssl genrsa -out dashboard.key 2048

openssl req -new -key dashboard.key -out dashboard.csr -config dashboard-csr.conf

openssl x509 -req -in dashboard.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out dashboard.crt -days 1000 -extensions v3_ext -extfile dashboard-csr.conf

dashboard-csr.conf 文件内容如下:

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = CN
L = SZ
O = Fonsview
CN = 172.16.6.79

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = kubernetes-dashboard
DNS.2 = kubernetes-dashboard.kube-system
DNS.3 = kubernetes-dashboard.kube-system.svc
DNS.4 = kubernetes-dashboard.kube-system.svc.cluster
DNS.5 = kubernetes-dashboard.kube-system.svc.cluster.local
DNS.6 = dashboard.k8s.fonsview.com
IP.1 = 172.16.6.79
IP.2 = 172.16.6.47
IP.3 = 172.16.6.249

[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names

这里我直接使用了kubernetes 里面的ca证书,用浏览器访问的时候会提示该网站证书不可靠. 官方推荐是去Let’s Encrypt 网站中生成自己的证书。

将创建好的证书,添加到Secret中.

kubectl create secret generic kubernetes-dashboard-certs --from-file=./certs -n kube-system

下载kubernetes-dashboard.yaml

修改kubernetes-dashboard的yaml文件:

kind: Deployment
apiVersion: apps/v1beta2
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: kubernetes-dashboard
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
    spec:
      containers:
      - name: kubernetes-dashboard
        image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.8.0
        ports:
        - containerPort: 8443
          protocol: TCP
        args:
          # - --auto-generate-certificates
          - --tls-key-file=dashboard.key
          - --tls-cert-file=dashboard.crt
          - --authentication-mode=basic
          # Uncomment the following line to manually specify Kubernetes API server Host
          # If not specified, Dashboard will attempt to auto discover the API server and connect
          # to it. Uncomment only if the default does not work.
          # - --apiserver-host=http://my-address:port
        volumeMounts:
        - name: kubernetes-dashboard-certs
          mountPath: /certs
          # Create on-disk volume to store exec logs
        - mountPath: /tmp
          name: tmp-volume
        livenessProbe:
          httpGet:
            scheme: HTTPS
            path: /
            port: 8443
          initialDelaySeconds: 30
          timeoutSeconds: 30
      volumes:
      - name: kubernetes-dashboard-certs
        secret:
          secretName: kubernetes-dashboard-certs
      - name: tmp-volume
        emptyDir: {}
      serviceAccountName: kubernetes-dashboard
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule

添加--tls-key-file--tls-cert-file.

如果要采用用户名和密码的认证形式,需要加上--authentication-mode=basic。 默认是使用token认证。

Note: 这里要注意证书的路径

然后执行

kubectl apply -f kubernetes-dashboard.yaml

不出意外的话,可以用命令看到pod能正常启动:

[root@walker-1 kubernetes]# kubectl get po -o wide --namespace=kube-system | grep dashboard
kubernetes-dashboard-68b6699b8-mrvfl         1/1       Running   0          5s        192.168.187.202   walker-1.novalocal

访问dashboard

修改dashboard的service, 改为NodePort的访问形式

[root@walker-1 kubernetes]# kubectl describe svc kubernetes-dashboard -n kube-system
Name:                     kubernetes-dashboard
Namespace:                kube-system
Labels:                   k8s-app=kubernetes-dashboard
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"k8s-app":"kubernetes-dashboard"},"name":"kubernetes-dashboard","namespace":...
Selector:                 k8s-app=kubernetes-dashboard
Type:                     NodePort
IP:                       10.103.175.251
Port:                     <unset>  443/TCP
TargetPort:               8443/TCP
NodePort:                 <unset>  32723/TCP
Endpoints:                192.168.187.202:8443
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

至此就可以通过 https://<nodeip>:<nodeport> 的方式来访问dashboard了

image

官网上还提及了通过apiserver和kubectl proxy 的方式来访问页面。据个人实际使用,kubectl proxy默认监听127.0.0.1。只能通过本地地址去访问。当然可以绑定到其他地址,但是页面无法进行登录操作。这在文档中有描述:

NOTE: Dashboard should not be exposed publicly using kubectl proxy command as it only allows HTTP connection. For domains other than localhost and 127.0.0.1 it will not be possible to sign in. Nothing will happen after clicking Sign in button on login page.

通过apiserver端口来访问时,会出现403权限问题。提示是以匿名用户身份访问的,权限拒绝。但是要让浏览器支持提供身份请求显然不现实,所以也放弃了。

为用户授权

如果使用token的认证方式来登录,也是可行的。不过需要为service account添加合适的权限。如果想直接跳过认证,那么默认是以kubernetes-dashboard的service account账户来访问。如果不做配置,kubernetes-dashboard 只能访问很少一部分资源。官方文档中提供了将所有权限赋予kubernetes-dashboard的配置。

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system

将用户绑定到 cluster-admin权限组。这样一来kubernetes-dashboard就能访问平台所有资源。这样做很方便,但有安全风险,不建议。

token认证方案已经很好了,但是大佬们显然更倾向使用账户+密码的方式认证。具体配置步骤如下:

  1. 在dashboard的deployment配置中,添加 --authentication-mode=basic
  2. 修改apiserver的配置,在启动参数中添加密码文件、ABAC认证以及指定ABAC策略文件。

    • 编辑密码文件
      密码文件的格式如下:
password,user,uid,"group1, group2..."

详情可参考:https://kubernetes.io/docs/admin/authentication/#static-password-file

为了方便起见,我创建了/etc/kubernetes/dashboard 文件夹

[root@walker-1 ~]# cd /etc/kubernetes/dashboard/
[root@walker-1 dashboard]# cat dashboard.basic 
password,walker,123123,system:authenticated

Note: 一定要为用户添加system:authenticated组,否则默认为system:unauthenticated组,用户被视为匿名用户,丧失访问权限。

  • 编辑ABAC策略文件
[root@walker-1 dashboard]# cat dashboard-abac.json 
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "walker", "namespace": "*", "resource": "*", "apiGroup": "*"}}

这里把所有权限放开给walker用户。

有关ABAC认证参考:https://kubernetes.io/docs/admin/authorization/abac/

Note: 策略文件中的用户名要和密码文件对应。

  • 修改apiserver配置
apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --service-cluster-ip-range=10.96.0.0/12
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --enable-bootstrap-token-auth=true
    - --admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota
    - --advertise-address=172.16.6.47
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --insecure-port=0
    - --requestheader-username-headers=X-Remote-User
    - --requestheader-extra-headers-prefix=X-Remote-Extra-
    - --requestheader-allowed-names=front-proxy-client
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    - --allow-privileged=true
    - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
    - --secure-port=6443
    - --requestheader-group-headers=X-Remote-Group
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --authorization-mode=Node,RBAC,ABAC
    - --authorization-policy-file=/etc/kubernetes/dashboard/dashboard-abac.json
    - --basic-auth-file=/etc/kubernetes/dashboard/dashboard.basic
    - --etcd-servers=http://walker-1:2379,http://walker-2:2379,http://walker-4:2379
    image: gcr.io/google_containers/kube-apiserver-amd64:v1.8.1
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 127.0.0.1
        path: /healthz
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 15
      timeoutSeconds: 15
    name: kube-apiserver
    resources:
      requests:
        cpu: 250m
    volumeMounts:
    - mountPath: /etc/kubernetes/pki
      name: k8s-certs
      readOnly: true
    - mountPath: /etc/kubernetes/dashboard
      name: k8s-dashboard
      readOnly: true
    - mountPath: /etc/ssl/certs
      name: ca-certs
      readOnly: true
    - mountPath: /etc/pki
      name: ca-certs-etc-pki
      readOnly: true
  hostNetwork: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki
      type: DirectoryOrCreate
    name: k8s-certs
  - hostPath:
      path: /etc/kubernetes/dashboard
      type: DirectoryOrCreate
    name: k8s-dashboard
  - hostPath:
      path: /etc/ssl/certs
      type: DirectoryOrCreate
    name: ca-certs
  - hostPath:
      path: /etc/pki
      type: DirectoryOrCreate
    name: ca-certs-etc-pki
status: {}

添加了ABAC认证方式,--authorization-policy-file以及--basic-auth-file。将/etc/kubernetes/dashboard 挂载到容器中。

  1. 重启apiserver, 使用添加的用户进行访问。
    先使用一个错误的密码试试认证有没有生效:

image

在使用正确密码登录:

image

至此密码认证方式配置完毕。

Logo

开源、云原生的融合云平台

更多推荐