精华内容
下载资源
问答
  • 2021-11-14 20:33:54

    1 介紹

    k8s安全02–云安全工具与安全运行时k8s安全03–云安全工具 kube-bench & OPA 介绍了云安全常见的工具, 本文继续上述两篇文章,介绍 k8s 中 apiserver相关的安全配置。

    2 安全配置

    2.1 配置 insecure-port

    k8s 集群中可以通过配置api-server 启动命令的–insecure-port=0 来配置api-server 的本地端口安全。
    docs/concepts/security/controlling-access

    root@kmaster:/home/xg# sed -e '/insecure-port/s/^/#/g' -i /etc/kubernetes/manifests/kube-apiserver.yaml
    root@kmaster:/home/xg# cat /etc/kubernetes/manifests/kube-apiserver.yaml |grep inse
    #    - --insecure-port=0
    
    root@kmaster:/home/xg# kube-bench
    ...
    [PASS] 1.2.15 Ensure that the admission control plugin NamespaceLifecycle is set (Scored)
    [FAIL] 1.2.16 Ensure that the admission control plugin PodSecurityPolicy is set (Scored)
    [PASS] 1.2.17 Ensure that the admission control plugin NodeRestriction is set (Scored)
    [PASS] 1.2.18 Ensure that the --insecure-bind-address argument is not set (Scored)
    [FAIL] 1.2.19 Ensure that the --insecure-port argument is set to 0 (Scored)
    [PASS] 1.2.20 Ensure that the --secure-port argument is not set to 0 (Scored)
    ...
    

    2.2 RBAC

    创建role 并通过rolebinding来绑定
    Using RBAC Authorization

    1. 创建 role
    $ vim limitonerole.yaml 
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: prod-a
      name: limitone
    rules:
    - apiGroups: [""] # "" indicates the core API group
      resources: ["pods"]
      verbs: ["get", "watch", "delete"]
    rolebind
    
    $ kubectl auth reconcile -f limitonerole.yaml
    $ kubectl -n prod-a get role
    
    2. 创建RoleBinding
    $ vim limitonebind.yaml 
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: manage-pods
      namespace: prod-a
    subjects:
    - kind: User
      name: paul
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: limitone 
      apiGroup: rbac.authorization.k8s.io
    
    $ kubectl auth reconcile -f limitonebind.yaml
    $ kubectl -n prod-a get rolebindings.rbac.authorization.k8s.io
    

    2.3 Service Accounts

    創建SA, 並設置到pod配置中
    Configure Service Accounts for Pods

    1. 创建 pod
    $ vim simplepod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: simple-pod
      namespace: prod-b
    spec:
      containers:
      - name: simple
        image: nginx
        
    $ kubectl apply -f simplepod.yaml
    
    2. 两个ns 的pod 都无法访问pod 信息
    $ kubectl -n prod-b get pod simple-pod -oyaml|grep serviceaccount
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    
    # root@simple-pod:/# curl https://kubernetes.default:443/api/v1 --insecure
    {
      "kind": "Status",
      "apiVersion": "v1",
      "metadata": {
        
      },
      "status": "Failure",
      "message": "forbidden: User \"system:anonymous\" cannot get path \"/api/v1\"",
      "reason": "Forbidden",
      "details": {
        
      },
      "code": 403
    }
    
    # export TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    # curl -H "Authorization: Bearer $TOKEN" https://kubernetes.default:443/api/v1 --insecure
    {
      "kind": "APIResourceList",
      "groupVersion": "v1",
      "resources": [
        {
          "name": "bindings",
          "singularName": "",
          "namespaced": true,
          "kind": "Binding",
          "verbs": [
            "create"
          ]
        },
    ......
        {
          "name": "services/status",
          "singularName": "",
          "namespaced": true,
          "kind": "Service",
          "verbs": [
            "get",
            "patch",
            "update"
          ]
        }
      ]
    }
    
    # curl -H "Authorization: Bearer $TOKEN" https://kubernetes.default:443/api/v1/namespaces/default/pods/ --insecure
    {
      "kind": "Status",
      "apiVersion": "v1",
      "metadata": {
        
      },
      "status": "Failure",
      "message": "pods is forbidden: User \"system:serviceaccount:prod-b:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
      "reason": "Forbidden",
      "details": {
        "kind": "pods"
      },
      "code": 403
    }
    
    $ kubectl -n prod-b get sa default  -o yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      creationTimestamp: "2021-11-11T13:37:49Z"
      name: default
      namespace: prod-b
      resourceVersion: "488820"
      uid: 942370fb-f114-4ad5-a41c-402de7e9ea08
    secrets:
    - name: default-token-4w7mh
    
    4. 一个ns配置sa,且设置pod权限,另外 一个保持不便
    $ vim prodbSA.yaml 
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: simple-sa
      namespace: prod-b
    secrets:
    $ kubectl create -f prodbSA.yaml 
    serviceaccount/simple-sa created
    
    $ vim SArole.yaml 
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: prod-b
      name: sa-role
    rules:
    - apiGroups: [""] 
      resources: ["pods"]
      verbs: ["list"]
    $ kubectl create -f SArole.yaml 
    role.rbac.authorization.k8s.io/sa-role created
    
    $ vim SArolebind.yaml 
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: sa-role-bind
      namespace: prod-b
    subjects:
    - kind: ServiceAccount
      name: simple-sa
      namespace: prod-b
    roleRef:
      kind: Role
      name: sa-role
      apiGroup: rbac.authorization.k8s.io
    $ kubectl create -f SArolebind.yaml 
    rolebinding.rbac.authorization.k8s.io/sa-role-bind created  
    
    5. 设置pod权限的可以正常访问pod 信息
    再 pod 中新增上述新建的SA simple-sa
    $ vim simplepod.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: simple-pod
      namespace: prod-b
    spec:
      serviceAccountName: simple-sa
      containers:
      - name: simple
        image: nginx
    
    $ kubectl delete -f simplepod.yaml
    pod "simple-pod" deleted
    $ kubectl create -f simplepod.yaml
    pod/simple-pod created
    
    $ kubectl -n prod-b exec -it simple-pod -- bash
    # export TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
    # curl -H "Authorization: Bearer $TOKEN" https://192.168.2.11:6443/api/v1/namespaces/default/pods/ --insecure
    {
      "kind": "Status",
      "apiVersion": "v1",
      "metadata": {
        
      },
      "status": "Failure",
      "message": "pods is forbidden: User \"system:serviceaccount:prod-b:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
      "reason": "Forbidden",
      "details": {
        "kind": "pods"
      },
      "code": 403
    }
    #  curl -H "Authorization: Bearer $TOKEN" https://192.168.2.11:6443/api/v1/namespaces/prod-b/pods/ --insecure
    {
      "kind": "PodList",
      "apiVersion": "v1",
      "metadata": {
        "resourceVersion": "490779"
      },
      "items": [
        {
          "metadata": {
            "name": "simple-pod",
            "namespace": "prod-b",
            "uid": "32b61feb-c3d6-48d7-9d84-ce3445d691ce",
            "resourceVersion": "490723",
    ......
                "ready": true,
                "restartCount": 0,
                "image": "nginx:latest",
                "imageID": "docker-pullable://nginx@sha256:dfef797ddddfc01645503cef9036369f03ae920cac82d344d58b637ee861fda1",
                "containerID": "docker://467ebc051442f7eb319a2da968f8340d019a2cdf9d794966d89320af055ef5e0",
                "started": true
              }
            ],
            "qosClass": "BestEffort"
          }
        }
      ]
    }
    

    2.4 Researching Pod Security Policies

    docs/concepts/policy/pod-security-policy/
    PodSecurityPolicy-对不同的用户和组分配不同的PodSecurityPolicy

    限制pods使用指定的目录

    Which policy would I use to limit pods using hostPath to a directory, such as /data and all subdirectories?

    $ vim psp01.yaml 
    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: allowed-host-paths
    spec:
      fsGroup: 
        rule: RunAsAny
      seLinux: 
        rule: RunAsAny
      runAsUser:
        rule: RunAsAny
      supplementalGroups:
        rule: RunAsAny
      allowedHostPaths:
        - pathPrefix: "/home"
          readOnly: true
    
    $ kubectl -n prod-a  apply -f psp01.yaml 
    Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
    podsecuritypolicy.policy/allowed-host-paths created
    

    控制pod 的网络

    man-pages/man7/capabilities.7.html
    2. Which policy and what YAML stanza with CAP_xx would be used if you want to allow a pod from fully controlling the node’s networking?

    $ vim psp02.yaml 
    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: allowed-capabilities
    spec:
      allowedCapabilities: 
        - CAP_NET_ADMIN
    ......
    

    配置 allowedUnsafeSysctls

    If a developer requires known unsafe sysctls, such as what high-performance computing may require, what yaml would you need to put into the pod spec to allow it?

    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: allowed-unsafe-sysctls
    spec:
      allowedUnsafeSysctls: 
        - kernel.msg*
    ......
    

    2.5 Enable Pod Security Policies

    1. 新建 PodSecurityPolicy
    vim nopriv.yaml
    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: no-priv
    spec:
      privileged: false
      runAsUser:
        rule: MustRunAsNonRoot
      seLinux:
        rule: RunAsAny
      fsGroup:
        rule: RunAsAny
      supplementalGroups:
        rule: RunAsAny
      volumes:
      - '*'
    
    $ kubectl apply -f nopriv.yaml 
    Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
    podsecuritypolicy.policy/no-priv created
    
    2. 新建普通的pod,可以正常新建
    $ kubectl create deployment busybox --image=busybox:1.32 -- sleep infinity
    
    3. 配置 PodSecurityPolicy,使其生效
    vim /etc/kubernetes/manifests/kube-apiserver.yaml
    ...
    - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
    ...
    
    4. 新建busybox2, 并查看报错信息,发现其受到 PodSecurityPolicy 限制
    $ kubectl create deployment busybox2 --image=busybox:1.32 -- sleep infinity
    $ kubectl get deploy
    NAME       READY   UP-TO-DATE   AVAILABLE   AGE
    busybox    1/1     1            1           13m
    busybox2   0/1     0            0           11s
    $ kubectl describe rs busybox2-648559c4d4
    $Events:
      Type     Reason        Age                From                   Message
      ----     ------        ----               ----                   -------
      Warning  FailedCreate  8s (x14 over 49s)  replicaset-controller  Error creating: pods "busybox2-648559c4d4-" is forbidden: PodSecurityPolicy: unable to admit pod: []
    
    5. 取消 PodSecurityPolicy 配置和 psp 策略后,可以正常新建服务
    $ /etc/kubernetes/manifests/kube-apiserver.yaml 中去掉PodSecurityPolicy
    - --enable-admission-plugins=NodeRestriction  
    kubectl delete psp no-priv
    $ kubectl create deployment busybox2 --image=busybox:1.32 -- sleep infinity
    $ kubectl get pod
    NAME                        READY   STATUS    RESTARTS   AGE
    busybox-6b8867777d-gs4qj    1/1     Running   0          34m
    busybox2-648559c4d4-7lcpb   1/1     Running   0          5s
    

    2.6 Enabling API Server Auditing

    # vim /etc/kubernetes/simple-policy.yaml
    apiVersion: audit.k8s.io/v1
    kind: Policy
    rules:
    - level: Metadata
    
    # vim /etc/kubernetes/manifests/kube-apiserver.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.2.11:6443
      creationTimestamp: null
      labels:
        component: kube-apiserver
        tier: control-plane
      name: kube-apiserver
      namespace: kube-system
    spec:
      containers:
      - command:
        - kube-apiserver
        ...
        - --audit-log-maxage=7
        - --audit-log-maxbackup=2
        - --audit-log-maxsize=50
        - --audit-log-path=/var/log/audit.log
        - --audit-policy-file=/etc/kubernetes/simple-policy.yaml
        ...
        image: registry.aliyuncs.com/google_containers/kube-apiserver:v1.21.4
        ...
        volumeMounts:
        - mountPath: /etc/kubernetes/simple-policy.yaml
          name: audit
          readOnly: true
        - mountPath: /var/log/audit.log
          name: audit-log
          readOnly: false
        ...
      hostNetwork: true
      priorityClassName: system-node-critical
      volumes:
      - hostPath:
          path: /etc/kubernetes/simple-policy.yaml
          type: File
        name: audit
      - hostPath:
          path: /var/log/audit.log
          type: FileOrCreate
        name: audit-log
      ...
    status: {}
    

    更新后 api-server 就正常重启:

    root@kmaster:/home/xg# docker ps |grep apiserver
    797c8636f865   cef7457710b1                                          "kube-apiserver --ad…"   38 seconds ago   Up 38 seconds             k8s_kube-apiserver_kube-apiserver-kmaster_kube-system_0e9626cb6a8df5c71073e401abc687eb_0
    14f4304feef2   registry.aliyuncs.com/google_containers/pause:3.4.1   "/pause"                 38 seconds ago   Up 38 seconds             k8s_POD_kube-apiserver-kmaster_kube-system_0e9626cb6a8df5c71073e401abc687eb_0
    

    发现持续出现审计日志:

    root@kmaster:/home/xg# tail -n 3 /var/log/audit.log
    {"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"6c71e531-c823-4c86-b0b1-0c8d20f77400","stage":"ResponseComplete","requestURI":"/apis/crd.projectcalico.org/v1/clusterinformations/default","verb":"get","user":{"username":"system:serviceaccount:kube-system:calico-kube-controllers","uid":"1346c03c-7aa9-48d1-b6eb-ca5356f9e75d","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"],"extra":{"authentication.kubernetes.io/pod-name":["calico-kube-controllers-58497c65d5-rlz7x"],"authentication.kubernetes.io/pod-uid":["63c1d7ca-0426-40db-9161-aa46b3ebddf3"]}},"sourceIPs":["10.224.189.2"],"userAgent":"Go-http-client/2.0","objectRef":{"resource":"clusterinformations","name":"default","apiGroup":"crd.projectcalico.org","apiVersion":"v1"},"responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-11-09T00:02:41.779246Z","stageTimestamp":"2021-11-09T00:02:41.793716Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"calico-kube-controllers\" of ClusterRole \"calico-kube-controllers\" to ServiceAccount \"calico-kube-controllers/kube-system\""}}
    {"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"f080f4c4-49cf-458b-902b-05409fbf6206","stage":"RequestReceived","requestURI":"/healthz?timeout=32s","verb":"get","user":{"username":"system:serviceaccount:kube-system:calico-kube-controllers","uid":"1346c03c-7aa9-48d1-b6eb-ca5356f9e75d","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"],"extra":{"authentication.kubernetes.io/pod-name":["calico-kube-controllers-58497c65d5-rlz7x"],"authentication.kubernetes.io/pod-uid":["63c1d7ca-0426-40db-9161-aa46b3ebddf3"]}},"sourceIPs":["10.224.189.2"],"userAgent":"kube-controllers/v0.0.0 (linux/amd64) kubernetes/$Format","requestReceivedTimestamp":"2021-11-09T00:02:41.794590Z","stageTimestamp":"2021-11-09T00:02:41.794590Z"}
    {"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"f080f4c4-49cf-458b-902b-05409fbf6206","stage":"ResponseComplete","requestURI":"/healthz?timeout=32s","verb":"get","user":{"username":"system:serviceaccount:kube-system:calico-kube-controllers","uid":"1346c03c-7aa9-48d1-b6eb-ca5356f9e75d","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"],"extra":{"authentication.kubernetes.io/pod-name":["calico-kube-controllers-58497c65d5-rlz7x"],"authentication.kubernetes.io/pod-uid":["63c1d7ca-0426-40db-9161-aa46b3ebddf3"]}},"sourceIPs":["10.224.189.2"],"userAgent":"kube-controllers/v0.0.0 (linux/amd64) kubernetes/$Format","responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2021-11-09T00:02:41.794590Z","stageTimestamp":"2021-11-09T00:02:41.795889Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"system:discovery\" of ClusterRole \"system:discovery\" to Group \"system:authenticated\""}}
    

    ls 可以发现会快速产生大量日志,因此实际中需要做rotate,此处暂时直接关闭

    查看审计日志量:
    root@kmaster:/home/xg# ls -lh /var/log/audit.log
    -rw-r--r-- 1 root root 7.9M Nov  9 00:04 /var/log/audit.log
    
    关闭审计操作:
    # vim /etc/kubernetes/manifests/kube-apiserver.yaml 
    #    - --audit-policy-file=/etc/kubernetes/simple-policy.yaml # 注釋掉該行
    
    再次查看發現已經沒有生成审计日志了:
    root@kmaster:/home/xg# ls -lh /var/log/audit.log
    -rw-r--r-- 1 root root 7.9M Nov  9 00:04 /var/log/audit.log
    root@kmaster:/home/xg# ls -lh /var/log/audit.log
    -rw-r--r-- 1 root root 13M Nov  9 00:07 /var/log/audit.log
    root@kmaster:/home/xg# ls -lh /var/log/audit.log
    -rw-r--r-- 1 root root 13M Nov  9 00:07 /var/log/audit.log
    

    复杂一點的审计功能:

    # vim /etc/kubernetes/moderate-policy.yaml
    apiVersion: audit.k8s.io/v1 
    kind: Policy
    omitStages:
      - "RequestReceived"
    rules:
      - level: RequestResponse
        resources:
        - group: ""
          resources: ["pods"]
      - level: Metadata
        resources:
        - group: ""
          resources: ["pods/log", "pods/status"]
      - level: Metadata
        userGroups: ["system:authenticated"]
        nonResourceURLs:
        - "/api*" 
        - "/version"
      - level: Request
        resources:
        - group: "" 
          resources: ["configmaps"]
        namespaces: ["kube-system"]
      - level: Metadata
        resources:
        - group: "" 
          resources: ["secrets", "configmaps"]
        omitStages:
          - "RequestReceived"
    # vim /etc/kubernetes/manifests/kube-apiserver.yaml 
    ...
      volumes:
      - hostPath:
          path: /etc/kubernetes/moderate-policy.yaml # simple-policy.yaml
          type: File
        name: audit
    

    2.7 Encrypting Secrets

    1. 創建 secret
    $ kubectl create secret generic first -n default  --from-literal=firstkey=first
    secret/first created
    
    2. 查看 secret
    $ kubectl get secrets first -oyaml
    apiVersion: v1
    data:
      firstkey: Zmlyc3Q=
    kind: Secret
    metadata:
      creationTimestamp: "2021-11-09T23:50:29Z"
    ...
    
    3. 使用base64 檢查加密的值
    $ echo "Zmlyc3Q="| base64 --decode 
    first
    
    4. 在etcd 中查看secret
    4.1 獲取 etcd 相關的配置
    # grep etcd /etc/kubernetes/manifests/kube-apiserver.yaml
        - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
        - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
        - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
        - --etcd-servers=https://127.0.0.1:2379
    4.2 在etcd 中查看數據信息
    # docker cp 56f5b:/usr/local/bin/etcdctl /usr/bin
    # ETCDCTL_API=3 etcdctl --endpoints https://192.168.2.11:2379 \
    --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    --cert=/etc/kubernetes/pki/etcd/server.crt \
    --key=/etc/kubernetes/pki/etcd/server.key \
    get /registry/secrets/default/first
    輸出:
    k8s
    
    v1Secret�
    �
    first�default"*$1245c445-cec6-4fc9-b774-24a399af74522Œ��z�c
    kubectl-createUpdate�vŒ��FieldsV1:1
    /{"f:data":{".":{},"f:firstkey":{}},"f:type":{}}
    firstkeyfirst�Opaque�"
    
    5. 生成随机base64字符串
    $ head -c 32 /dev/urandom | base64
    GRLTglCQMgwNoq0Or5OjuC2rSrt6j4P7hgDY5sGCuJY=
    
    6. 配置yaml
    vim encryptionconfig.yaml 
    apiVersion: apiserver.config.k8s.io/v1
    kind: EncryptionConfiguration
    name: newsetup
    resources:
      - resources:
        - secrets
        providers:
        - aescbc:
            keys:
            - name: firstkey
              secret: GRLTglCQMgwNoq0Or5OjuC2rSrt6j4P7hgDY5sGCuJY=
        - identity: {}
    
    7. 拷贝配置
    cp encryptionconfig.yaml /etc/kubernetes/pki/
    
    8. kube-apiserver 中追加 --encryption-provider-config 配置
    vim /etc/kubernetes/manifests/kube-apiserver.yaml
    ...
        - --feature-gates=RemoveSelfLink=false
        - --encryption-provider-config=/etc/kubernetes/pki/encryptionconfig.yaml # add this
        image: registry.aliyuncs.com/google_containers/kube-apiserver:v1.21.4
    ...
    
    9. 创建新secret
    $ kubectl create secret generic second -n default --from-literal=secondkey=second
    secret/second created
    
    10. 在etcd 中查看second
    # ETCDCTL_API=3 etcdctl --endpoints https://192.168.2.11:2379 \
    --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    --cert=/etc/kubernetes/pki/etcd/server.crt \
    --key=/etc/kubernetes/pki/etcd/server.key \
    get /registry/secrets/default/second
    /registry/secrets/default/second
    k8s:enc:aescbc:v1:firstkey:cK+ˣP�
    <�6'��6�m�1'E��[i�B�GGg�$(��n�+�n9�ԭ>����s�߫��j��G��z����"�=
                                                              �zē���� �AVO�6��d'"�Ш����=0X�5TU�K�
    QA3�.��'7��GU�龭ցQۮ� ���>���{�Q��
                                     �	�',6FH�H�_�K��������I�-�:����Y�G�r�J�y���_;�g�qh�jTS44R<���w ��
    
    11. 重新新建所有的secret,並确认first也被创建且加密了
    $ kubectl get secrets --all-namespaces -o json | kubectl replace -f -
    
    12. 查看first
    # ETCDCTL_API=3 etcdctl --endpoints https://192.168.2.11:2379 \
    ...
    get /registry/secrets/default/first
    /registry/secrets/default/first
    k8s:enc:aescbc:v1:firstkey:r�yg��JX���ި����r�Y�w�p�������қ
                                                             �]8���X��8O�:}�o���6�,��_�����D�������x
    �DG���\Ć��|�w�"[w{�Ni���?44��.�˔E�*��a�� ��9z<=9H�zC�4�����CɎ�f-�k
    z;ݺ����/�A9k�ptЙ����U���V���bHܙlǍ�g �1�
                             �~�
    可見first已經被加密了
    

    3 注意事项

    1. 当前k8s 版本已经支持到1.22.xx 版本, 本文基于1.22.1 版本做实验,如果版本不匹配,那么最好更新到1.22.xx版本, 以下为笔者从1.21升级到1.22的方法
      kmaster:
      # apt-mark unhold kubeadm kubectl kubelet 
      # apt-get update && apt-get install -y kubeadm=1.22.1-00 kubelet=1.22.1-00 kubectl=1.22.1-00
      # kubeadm upgrade apply v1.22.1
      
      knode01:
      # apt-mark unhold kubeadm kubectl kubelet
      # kubeadm upgrade node
      

    4 说明

    docs/concepts/security
    concepts/security/overview/

    更多相关内容
  • apiserver-builder-alpha 除非绝对需要apiserver-aggregation,否则建议您使用而不是apiserver-builder来构建Kubernetes API。 Kubebuilder使用CRD构建API,并解决了apiserver-builder的局限性和反馈。 Apiserver ...
  • 注意:将此软件包打包或k8s.io/sample-apiserver为k8s.io/sample-apiserver 。 目的 如果要构建用于API聚合的扩展API服务器,或构建独立的Kubernetes风格的API服务器,则可以使用此代码。 但是,请考虑其他两个...
  • kube-apiserver_v1.15.3.tar

    2019-09-20 12:17:16
    k8s.gcr.io/kube-apiserver:v1.15.3镜像tar包,使用 docker load --input kube-apiserver_v1.15.3.tar 进行导入
  • kubernetes的k8s.gcr.io/kube-apiserver:v1.17.3镜像包,版本为v1.17.3。文件是kube-controller-manager_v_1_17.3.tar
  • apiextensions-apiserver 实现: : 它提供了用于注册CustomResourceDefinitions的API。 目的 该API服务器提供CustomResourceDefinitions的实现,该实现作为kube-apiserver服务器包含在kube-apiserver 。 兼容性 ...
  • kube-apiserver-amd64_v1.9.3.tarkube-apiserver-amd64_v1.9.3.tar
  • API Server简介

    千次阅读 2020-12-05 17:05:54
    API Server简介 一、API Server简介 1.1 API Server功能 k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。 kubernetes API ...

     

    一、API Server简介

    1.1 API Server功能

    k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。

     

    kubernetes API Server的功能

    1. 提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更);

    2. 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd);

    3. 提供准入控制的功能;

    4. 拥有完备的集群安全机制.

     

    集群功能模块之间的通信

    kubernetes API Server作为集群的核心,负责集群各功能模块之间的通信,集群内各个功能模块通过API Server将信息存入etcd,当需要获取和操作这些数据时,通过API Server提供的REST接口(GET\LIST\WATCH方法)来实现,从而实现各模块之间的信息交互

     

    1. kubelet与API Server交互

    每个Node节点上的kubelet定期就会调用API Server的REST接口报告自身状态,API Server接收这些信息后,将节点状态信息更新到etcd中。kubelet也通过API Server的Watch接口监听Pod信息,从而对Node机器上的POD进行管理。

    1. kube-controller-manager与API Server交互

    kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口,实时监控Node的信息,并做相应处理。他们通过API Server提供的接口实时监控整个集群里的每一个资源对象的当前状态,当发生各种故障导致系统状态发生变化,这些controller会尝试将系统从“现有装态”修正到“期望状态”。

    1. kube-scheduler与API Server交互

    Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后,它会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。

    1.2 访问APIServer

    k8s通过kube-apiserver这个进程提供服务,该进程运行在单个k8s-master节点上。默认有两个端口

    1.2.1 本地端口

    该端口用于接收HTTP请求;

    该端口默认值为8080,可以通过API Server的启动参数“--insecure-port”的值来修改默认值;

    默认的IP地址为“localhost”,可以通过启动参数“--insecure-bind-address”的值来修改该IP地址;

    非认证或授权的HTTP请求通过该端口访问API Server。

    1.2.2 安全端口

    该端口默认值为6443,可通过启动参数“--secure-port”的值来修改默认值;

    默认IP地址为非本地(Non-Localhost)网络端口,通过启动参数“--bind-address”设置该值;

    该端口用于接收HTTPS请求;

    用于基于Tocken文件或客户端证书及HTTP Base的认证;

    用于基于策略的授权;

    默认不启动HTTPS安全访问控制。

    1.2.3 kubectl客户端

    命令行工具kubectl客户端,通过命令行参数转换为对API Server的REST API调用,并将调用结果输出。

    命令格式:kubectl [command] [options]

    1.2.4 Kubectl Proxy

    Kubectl Proxy代理程序既能作为API Server的反向代理,也能作为普通客户端访问API Server的代理。通过master节点的8080端口来启动该代理程序。

    本质上kubectl proxy为访问kubernetes apiserver的REST api充当反向代理角色,这里反向代理的作用与通常意义上的反向代理作用相同,比如提供统一入口进行访问控制、监控、管理,在代理中管理后端,在代理中进行认证等。当然可以不经过kubectl proxy反向代理直接访问kubernetes apiserver的REST api,但是需要手动管理kubernetes apiserver的地址、手动获取token、手动将token加请到请求的头部,相对来说要繁琐而已。

    实验一

    kubectl proxy --port=8080 &

    1.2.5 编程方式调用

    使用场景:

    1. 运行在Pod里的用户进程调用kubernetes API,通常用来实现分布式集群搭建的目标。
    2. 开发基于kubernetes的管理平台,比如调用kubernetes API来完成Pod、Service、RC等资源对象的图形化创建和管理界面。可以使用kubernetes提供的Client Library。

    官方支持的 Kubernetes 客户端库:

    语言

    客户端库

    Go

    github.com/kubernetes/client-go/

    Python

    github.com/kubernetes-client/python/

    Java

    github.com/kubernetes-client/java

    dotnet

    github.com/kubernetes-client/csharp

    JavaScript

    github.com/kubernetes-client/javascript

     

    二、API版本

    为了消除字段或重组资源表示形式,Kubernetes 支持多个 API 版本,每个版本在不同的 API 路径下。例如:/api/v1或者/apis/extensions/v1beta1。

    版本是在 API 级别而非资源或字段级别配置的:

    1. 确保 API 呈现出清晰一致的系统资源和行为视图。
    2. 对生命周期结束的API 和/或实验性 API 的访问控制。

    2.1 API级别

    Alpha:

      • 版本名称包含alpha(例如,v1alpha1)。
      • 该软件可能包含错误。启用功能可能会暴露错误。默认情况下,功能可能被禁用。
      • 对功能的支持随时可能被删除,但不另行通知。
      • 在以后的软件版本中,API 可能会以不兼容的方式更改,亦不另行通知。
      • 由于存在更高的错误风险和缺乏长期支持,建议仅在短期测试集群中使用该软件。

    Beta:

      • 版本名称包含beta(例如,v2beta3)。
      • 该软件已经过充分测试。启用功能被认为是安全的。默认情况下启用功能。
      • 尽管细节可能会发生变更,对应功能不会被废弃。
      • 在随后的 Beta 或稳定版本中,对象的模式和/或语义可能会以不兼容的方式更改。发生这种情况时,将提供迁移说明。迁移时可能需要删除、编辑和重新创建 API 对象。编辑过程可能需要一些思考。对于依赖该功能的应用程序,可能需要停机。
      • 该软件仅建议用于非关键业务用途,因为在后续版本中可能会发生不兼容的更改。如果您有多个可以独立升级的群集,则可以放宽此限制。

    稳定版:

      • 版本名称为vX,其中X为整数。
      • 功能特性的稳定版本会持续出现在许多后续版本的发行软件中。

    2.2 API组

    API 组使扩展Kubernetes API更容易。API组在REST路径和序列化对象的 apiVersion 字段中指定。

    当前,有几个正在使用的 API 组:

    1. *core*(也称为 *legacy*)组,它位于 REST 路径/api/v1上,未指定为 apiVersion 字段的一部分,例如apiVersion: v1。
    2. 特定名称的组位于 REST 路径/apis/$GROUP_NAME/$VERSION下,并使用apiVersion:$GROUP_NAME/$VERSION(例如,apiVersion:batch/v1)。您可以在Kubernetes API 参考 中找到受支持的 API Group 的完整列表。

    有两种途径来使用自定义资源扩展 API,分别是:

    1. CustomResourceDefinition提供基本的 CRUD 需求。
    2. 聚合器(Aggregator)具有完整的 Kubernetes API 语义,用以实现用户自己的 apiserver。

    kubernetes的 Aggregated API是什么呢?它是允许k8s的开发人员编写一个自己的服务,可以把这个服务注册到k8s的api里面,这样,就像k8s自己的api一样,你的服务只要运行在k8s集群里面,k8s 的Aggregate通过service名称就可以转发到你写的service里面去了。

     

    2.3启用API组

    默认情况下,某些资源和 API 组处于启用状态。您可以通过设置--runtime-config来启用或禁用它们。

    --runtime-config接受逗号分隔的值。例如:要禁用batch/v1,请配置--runtime-config=batch/v1=false;要启用batch/2alpha1,请配置--runtime-config=batch/v2alpha1。该标志接受描述apiserver的运行时配置的以逗号分隔的key=value对集合。

    启用或禁用组或资源时,需要重新启动 apiserver 和控制器管理器以刷新--runtime-config的更改。

     

    三、API访问控制

    可以使用kubectl客户端库方式对REST API的访问,Kubernetes的普通账户和Service帐户都可以实现授权访问API。API的请求会经过多个阶段的访问控制才会被接受处理,其中包含认证、授权以及准入控制(Admission Control)等。如下图所示:

    需要注意:认证授权过程只存在HTTPS形式的API中。也就是说,如果客户端使用HTTP连接到kube-apiserver,是不会进行认证授权的。所以说,可以这么设置,在集群内部组件间通信使用HTTP,集群外部就使用HTTPS,这样既增加了安全性,也不至于太复杂。

    3.1. 认证

    开启TLS时,所有的请求首先需要认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。如果认证成功,则用户的username会传入授权模块做进一步授权验证;对于认证失败的请求则返回HTTP 401。

    当TLS建立时,HTTP请求会进行身份认证步骤,如图中步骤1,集群管理器将apiserver配置为运行一个或多个认证器模块。

    认证模块包含客户端证书,密码、Plain Tokens、Bootstrap Tokens、JWT Tokens(used for service accounts)。

    我们可以指定多个认证模块,每个认证模块都会按顺序进行,直到其中一个成功。

    3.1.1. kubernetes账户

    所有Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。

    普通账户是假定被外部或独立服务管理的,由管理员分配keys,用户像使用Keystone或google账号一样,被存储在包含usernames和passwords的list的文件里。

    需要注意:在Kubernetes中不能通过API调用将普通用户添加到集群中

    Kubernetes只专注于做应用编排,其他的功能则提供接口集成,除了认证和授权,我们发现网络、存储也都如此。

    这样做的好处也显而易见,用户账户信息与Kubernetes集群松耦合,便于集成企业已有的身份认证系统,如AD、LADP、Keycloak等。

    相比之下,Service Accounts是由Kubernetes API管理的帐户。它们被绑定到特定的命名空间,并由APIserver自动创建或通过API调用手动创建。Service Accounts与存储为Secrets的一组证书相关联,这些凭据被挂载到pod中,以便集群进程与Kubernetes API通信。

    • 普通帐户是针对(人)用户的,服务账户针对Pod进程。
    • 普通帐户是全局性。在集群所有namespaces中,名称具有惟一性。
    • 通常,群集的普通帐户可以与企业数据库同步,新的普通帐户创建需要特殊权限。服务账户创建目的是更轻量化,允许集群用户为特定任务创建服务账户。
    • 普通帐户和服务账户的审核注意事项不同。
    • 对于复杂系统的配置包,可以包括对该系统的各种组件的服务账户的定义。

     

    3.1.2 静态密码认证

    静态密码是最简单的认证方式,只需要在api-server启动时指定使用的密码本路径即可,通过配置-Basic-authfile=file选项实现,Basic认证凭证一直有效,并且如果没有重新启动API Server,密码将无法更改。

    Basic Authentication文件csv也是格式文件,且必须包含:password, user, uid。在Kubernetes 1.6+版本中,可以指定一个可选的第四列,使用逗号来分隔group名,如果有多个组,必须使用双引号(“)。参考以下示例:

    password,user,uid,"group1,group2,group3"

    当从http客户端使用Basic Authentication时,API Server需要在请求头加入Basic BASE64ENCODED(USER:PASSWORD)。

    通过静态密码的唯一优势是简单,其缺点也是非常明显:

    1. 静态密码是明文,非常不安全,还有可能被暴力破解。
    2. 非常不灵活,增加或者删除用户,必须手动修改静态密码文件并重启所有的api-server服务。

    这种方式在实际场景中很少被使用,不建议生产环境使用。

     

    3.1.3 x509证书认证

    对称加密和非对称加密

    1. 对称加密

    对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥,作为私钥。

    常见的对称加密算法:DES,AES,3DES等等。

    2. 非对称加密

    非对称加密指的是:加密和解密使用不同的秘钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。私钥加密的信息,只有公钥才能解密。

    常见的非对称加密算法:RSA,ECC

    3. 区别

    对称加密算法相比非对称加密算法来说,加解密的效率要高得多。但是缺陷在于对于秘钥的管理上,以及在非安全信道中通讯时,密钥交换的安全性不能保障。所以在实际的网络环境中,会将两者混合使用.

    双向TLS认证

    https://upload-images.jianshu.io/upload_images/3437040-5e8d79e001ff5118.png

    • 浏览器发送一个连接请求给安全服务器。
    • 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。
    • 客户浏览器检查服务器送过来的证书是否是由自己信赖的CA中心(如沃通CA)所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续。
    • 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。
    • 服务器要求客户发送客户自己的证书。收到后,服务器验证客户的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得用户的公钥。
    • 客户浏览器告诉服务器自己所能够支持的通讯对称密码方案。
    • 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。
    • 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
    • ⑨ 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。
    • ⑩ 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的。

    双向认证则是需要服务端与客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些。SSL单向认证只要求站点部署了ssl证书就行,任何用户都可以去访问(IP被限制除外等),只是服务端提供了身份认证。

     

    使用API Server启动时配置–client-ca-file = SOMEFILE选项来启用客户端证书认证。引用的文件必须包含,提交给API Server的客户端证书的证书颁发机构。如果客户端提交的证书通过,通用名称(common name)将被用作请求的用户名。

    x509认证是默认开启的认证方式,api-server启动时会指定ca证书以及ca私钥,只要是通过ca签发的客户端x509证书,则可认为是可信的客户端。

        kubectl 如何认证? 获取$HOME/config

    在kubectl config中会有两个证书,分别为certificate-authority证书和client-certificate证书。client-certificate用于客户端认证,这显而易见。

     

    在使用client-certificate客户端证书认证时,CN(commom Name)对应Kubernetes的User,O(organization)对应Kubernetes的Group。

     

    签发客户端证书有两种方式,一种是基于CA根证书签发证书,另一个种是发起CSR(Certificate Signing Requests)请求。

    1) 使用CA根证书签发客户端证书

    实验二:

    openssl genrsa -out cat.key 2048

    openssl req -new -key cat.key -out cat.csr -subj "/CN= cat "

    openssl x509 -req -in cat.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out cat.crt -days 365 #基于CSR文件签发x509证书

    kubectl config set-credentials cat --client-certificate= cat.crt  --client-key= cat.key  --embed-certs=true

    kubectl config view

    kubectl config set-context cat@cluster.local --cluster=cluster.local --user=cat

    kubectl config use-context cat@cluster.local

     

    2)通过CSR签发证书

    前面通过CA签发证书需要有CA的私钥,其实Kubernetes可以直接发起CSR请求。

    首先创建一个CSR请求,CN为test-csr,O为int32bit,即User为test-csr,Group为int32bbit。

    openssl req -new -newkey rsa:4096 \
      -nodes -keyout test-csr.key \
      -out test-csr.csr -subj "/CN=test-csr/O=int32bit"

    声明一个CSR Resource:

    apiVersion: certificates.k8s.io/v1beta1
    kind: CertificateSigningRequest
    metadata:
      name: test-csr
    spec:
      groups:
      - int32bit
      request: ... # 这里填test-csr.csr内容并转化为base64
      usages:
      - client auth

    创建该资源:

    # kubectl apply -f test-csr.yaml
    certificatesigningrequest.certificates.k8s.io/test-csr created
    # kubectl get csr
    NAME       AGE   REQUESTOR          CONDITION
    test-csr   4s    kubernetes-admin   Pending

    此时CSR的状态为Pending,通过kubectl certificate approve命令签发证书:

    # kubectl certificate approve test-csr
    certificatesigningrequest.certificates.k8s.io/test-csr approved
    # kubectl get csr
    NAME       AGE   REQUESTOR          CONDITION
    test-csr   2m    kubernetes-admin   Approved,Issued

    此时CSR显示已经完成签发,可以读取证书内容:

    # kubectl get csr test-csr -o jsonpath='{.status.certificate}' | base64 -d
    -----BEGIN CERTIFICATE-----
    MIIEDTCCAvWgAwIBAgIUB9dVsj34xnQ8m5KUQwpdblWapNcwDQYJKoZIhvcNAQEL
    ...
    yvfz8hcwrhQc6APpmZcBnil7iyzia3tnztQjoyaZ0cjC
    -----END CERTIFICATE-----

    查看证书部分摘要信息:

    # kubectl get csr test-csr -o jsonpath='{.status.certificate}' \
      | base64 -d \
      | openssl x509  -noout  \
      -subject  -issuer
    subject=O = int32bit, CN = test-csr
    issuer=CN = kubernetes

    使用x509证书认证的问题

    使用x509证书相对静态密码来说显然会更安全,只要证书不泄露,可以认为是无懈可击的。但是虽然颁发证书容易,目前却没有很好的方案注销证书。想想如果某个管理员离职,该如何回收他的权限和证书。有人说,证书轮转不就解决了吗?但这也意味着需要重新颁发其他所有证书,非常麻烦。

    所以使用x509证书认证适用于Kubernetes内部组件之间认证,普通用户认证并不推荐通过证书的形式进行认证。

    3.1.4 令牌认证

    通过一个不记名令牌 (Bear Token) 来识别用户是一种相对安全又被各种客户端广泛支持的认证策略。不记名令牌,代表着对某种资源,以某种身份访问的权利,无论是谁,任何获取该令牌的访问者,都被认为具有了相应的身份和访问权限。配合成熟的令牌授予机构,不记名令牌非常适于在生产环境中严肃使用。身份令牌(ID Token)就是一种形式的不记名令牌,它本身记录着一个权威认证机构对用户身份的认证声明,同时还可以包含对这个用户授予了哪些权限的声明,像极了古代官员佩戴的腰牌。Kubernetes 接受和识别的正是这种 ID Token。

    1)静态令牌认证

    静态token认证和静态密码原理几乎完全一样,唯一不同的是静态token通过token-auth-file指定token文件,认证时头部格式为Authorization: Bearer ${Token},而静态密码通过basic-auth-file指定密码文件,认证头部为Basic base64encode(${username}:${password}),本质都是一样的。

    因此其优点和缺点也和静态密码完全一样,这里不再赘述。

    2)Bootstrap Token认证

    前面提到的静态token在运行时是固定不变的,并且不会在Kubernetes集群中存储,意味着除非修改静态文件并重启服务,token不会改变。

    而bootstrap token则是由Kubernetes动态生成的,通过Secret形式存储,并且具有一定的生命周期,一旦过期就会失效。

    启用参数:--enable-bootstrap-token-auth=true

    为了简便我们使用kubeadm生成一个token:

    Kubeadm token create

    Kubeadm token list

    kubectl get clusterrolebinding | grep boot

    kubectl get secret bootstrap-token-${TOKEN_ID} –n kube-system

    过期的token会自动删除secret

     

     

    Token有两个部分组成,由.分割,前面部分为Token ID,后面部分为Token Secret。Token默认TTL为一天,对应的group system:bootstrappers:kubeadm:default-node-token,对应User为system:bootstrap:${Token ID}。

    kubeadm创建一个Token会对应在Kubernetes的kube-system namespace创建一个secret,secret名为bootstrap-token-${TOKEN_ID}。

    授权: ClusterRoleBinding kubeadm:get-nodes

    这种token主要用于临时授权使用,比如kubeadm初始化集群时会生成一个bootstrap token,这个token具有创建certificatesigningrequests权限,从而新Node能够发起CSR请求,请求客户端证书。

    3) service account token认证

    service account是Kubernetes唯一由自己管理的账号实体,意味着service account可以通过Kubernetes创建,不过这里的service account并不是直接和User关联的,service account是namespace作用域,而User是全cluster唯一。service account会对应一个虚拟User,User名为system:serviceaccount:${namespace}:${sa_name},比如在default namespace的test service account,则对应的虚拟User为system:serviceaccount:default:test。

     

    和前面的bootstrap一样,service account也是使用Bearer Token认证的,不过和前面的Token不一样的是service account是基于JWT(JSON Web Token)认证机制,JWT原理和x509证书认证其实有点类似,都是通过CA根证书进行签名和校验,只是格式不一样而已,JWT由三个部分组成,每个部分由.分割,三个部分依次如下:

    1. Header(头部): Token的元数据,如alg表示签名算法,typ表示令牌类型,一般为JWT,kid表示Token ID等。
    2. Payload(负载): 实际存放的用户凭证数据,如iss表示签发人,sub签发对象,exp过期时间等。
    3. Signature(签名):基于alg指定的算法生成的数字签名,为了避免被篡改和伪造。

    为了便于HTTP传输,JWT Token在传递过程中会转成Base64URL编码,其中Base64URL相对我们常用的Base64编码不同的是=被省略、+替换成-,/替换成_,这么做的原因是因为这些字符在URL里面有特殊含义,更多关于JWT的介绍可参考阮一峰的JSON Web Token 入门教程

    JWT Token的颁发机构为kubernetes/serviceaccount,颁发对象为SA对应的虚拟用户system:serviceaccount:default:test,除此之外还存储着其他的SA信息,如SA name、namespace、uuid等。这里需要注意的是我们发现JWT Token中没有exp字段,即意味着只要这个SA存在,这个Token就是永久有效的。

    kubectl create sa {SA_NAME}

    通过如下方式配置kubeconfig:

    TOKEN_NAME=$(kubectl get serviceaccounts ${SA_NAME} -o jsonpath={.secrets[0].name})

    TOKEN=$(kubectl get secret "${TOKEN_NAME}" -o jsonpath={.data.token} | base64 -d)

    kubectl config set-credentials "${USERNAME}" --token="$TOKEN"

    为了验证test-sa,在刚刚创建的int32bit-rolebinding的subjects增加了ServiceAccount test-sa。

    Service account除了可以用于集群外认证外,其还有一个最大的特点是可以通过Pod.spec.serviceAccountName把token attach到Pod中。

    此时Kubernetes会自动把SA的Token通过volume的形式挂载到/run/secrets/kubernetes.io/serviceaccount目录上,从而Pod可以读取token调用Kubernetes API.

    如何在Pod自动添加ServiceAccount:

    通过 Admission Controller插件来实现对pod修改,它是apiserver的一部分。创建或更新pod时会同步进行修改pod。当插件处于激活状态(在大多数发行版中都默认情况)创建或修改pod时,会按以下操作执行:

    1.如果pod没有设置ServiceAccount,则将ServiceAccount设置为default。

    2.确保pod引用的ServiceAccount存在,否则将会拒绝请求。

    3.如果pod不包含任何ImagePullSecrets,则将ServiceAccount的ImagePullSecrets会添加到pod中。

    4.为包含API访问的Token的pod添加了一个volume。

    5.把volumeSource添加到安装在pod的每个容器中,挂载在/var/run/secrets/kubernetes.io/serviceaccount。

    service account token的管理:Token Controller

    TokenController作为controller-manager的一部分运行。异步行为:

    1. 观察serviceAccount的创建,并创建一个相应的Secret 来允许API访问。
    2. 观察serviceAccount的删除,并删除所有相应的ServiceAccountToken Secret
    3. 观察secret 添加,并确保关联的ServiceAccount存在,并在需要时向secret 中添加一个Token。
    4. 观察secret 删除,并在需要时对应 ServiceAccount 的关联

    需要使用--service-account-private-key-file 参数选项将Service Account 密匙(key)文件传递给controller-manager中的Token controller。key用于 Service Account Token签名。同样,也需要使用--service-account-key-file 参数选项将相应的(public key)公匙传递给kube-apiserver ,公钥用于在认证期间验证Token。

     

    针对一些需要和Kubernetes API交互的应用非常有用,比如coredns就需要监控endpoints、services的变化,因此关联了coredns SA,coredns又关联了system:coredns clusterrole。flannel需要监控pods以及nodes变化同样关联了flannel SA。

    到这里为止,service account可能是Kubernetes目前最完美的认证方案了,既能支持集群外的客户端认证,又支持集群内的Pod关联授权。

    但事实上,service account并不是设计用来给普通user认证的,而是给集群内部服务使用的。目前虽然token是永久有效的,但未来会改成使用动态token的方式,参考官方设计设计文档Bound Service Account Tokens,此时如果kubectl客户端认证则需要频繁更新token。

    除此之外,SA虽然能够对应一个虚拟User,但不支持自定义Group,在授权体系中不够灵活。另外也不支持客户端高级认证功能,比如MFA、SSO等。

    3.1.1.5 集成外部认证系统

    前面已经介绍过Kubernetes集成简单的静态用户文件以及x509证书认证,Kubernetes最强大的功能是支持集成第三方Id Provider(IdP),主流的如AD、LADP以及OpenStack Keystone等,毕竟专业的人做专业的事。

    Kubernetes 的认证策略有很多种(请参考 Kubernetes Authentication Strategy),其中,通过一个不记名令牌 (Bear Token) 来识别用户是一种相对安全又被各种客户端广泛支持的认证策略。不记名令牌,代表着对某种资源,以某种身份访问的权利,无论是谁,任何获取该令牌的访问者,都被认为具有了相应的身份和访问权限。配合成熟的令牌授予机构,不记名令牌非常适于在生产环境中严肃使用。身份令牌(ID Token)就是一种形式的不记名令牌,它本身记录着一个权威认证机构对用户身份的认证声明,同时还可以包含对这个用户授予了哪些权限的声明,像极了古代官员佩戴的腰牌。Kubernetes 接受和识别的正是这种 ID Token。

    由上可知,想得到 ID Token,首先要经过某个权威机构的一套身份认证流程,OpenID Connect 简称 OIDC 就是这样一套认证、授予 ID Token 的协议。OIDC 是 OAuth2 协议的一种扩展,目前在各大主流厂牌的云服务中都被广泛支持和使用,例如 IBM IAM Service、Google Accounts、Azure Active Directory 等。

     

    Kubernetes 使用 OIDC Token 的认证流程

    Kubernetes 使用 OIDC 进行身份认证的流程,比上面介绍的 OAuth2 授权流程要简单不少。在整个过程中, Kubernetes 既作为资源(Resource)服务器,又作为用户代理 User-Agent 存在,但它并不提供引导用户到 Auth Server 进行认证的功能,相反,它要求用户先自行获取 ID Token,然后在访问 Kubernetes API Server 的时候直接提供 ID Token。因此,整个过程中,Kubernetes 其实不需要真正和 Authentication Server 发生任何交互。整个认证流程如下图 2 所示:

    1. 某个 Kubernetes Client 想访问 Kubernetes API。
    2. 用户先自行向 Auth Server (例如 KeyCloak 或 Google Accounts) 认证自己。
    3. 拿到 id_token、refresh_token。
    4. 用户把 token 配置到需要访问 Kubernetes api 的 client application 中(如 kubectl 或 dashboard)。
    5. Kubernetes Client 就可以使用 tokens 以用户的身份访问 Kubernetes API 了。

    那么问题来了,如果 Kubernetes 不和 Auth Server 发生交互的话,它怎么鉴定这些 Token 是合法的用户 token 呢?这里我们可以参考一下 Kubernetes Authentication OIDC Tokens 官方文档,其中它分 9 个步骤更详细描述了从获取 token 到在 kubectl 中使用它们进行访问的流程。其中绝大部分都被上图抽象概括,这里我们重点关注一下步骤 5:

    5.The API server will make sure the JWT signature is valid by checking against the certificate named in the configuration.

    能够认证 token 的合法性的关键在于,所有 JWT token 都被其颁发 Auth Service 进行了数字签名,我们只需在 Kubernetes API Server 中配置上我们所信任的这个 Auth Server 的证书(Certificate),并用它来验证收到的 id_token 中的签名是否合法,就可以验证 token 的真实性。使用这种基于 PKI 的验证机制,在配置完成后,认证过程中 Kubernetes 就无需和 Auth Server 有任何交互。

     

    3.2 授权

    Kubernetes使用API server授权API请求。它根据策略来评估所有请求属性,是否给于通过。

    (Kubernetes使用API server,访问控制和依赖特定资源对象的策略由(Admission Controllers)准入控制器处理。)

    当配置多个授权模块时,会按顺序检查每个模块,如果有任何模块授权通过,则继续执行下一步的请求。如果所有模块拒绝,则该请求授权失败(返回HTTP 403)。

    Kubernetes只对以下的API请求属性进行检查:

    • user-认证期间提供的user字符串
    • group - 认证用户所属的组名列表
    • “extra”- 由认证层提供的任意字符串键到字符串值的映射
    • API- 指示请求是否为API resource
    • Request path- 到其他非request端点的路径,如/api或/healthz。
    • API request verb- API verbs get,list,create,update,patch,watch,proxy,redirect,delete,和deletecollection用于请求resource。要确定resource API端点的请求verbs 。
    • HTTP request verb- HTTP verbs get,post,put,和delete用于非资源请求
    • Resource-被访问(仅用于resource请求)的resource的ID或名字- *对于使用resource的请求get,update,patch,和delete,必须提供resource名称。
    • Subresource- 正在访问的subresource (仅用于请求resource)
    • Namespace- 正在访问对象的命名空间(仅针对命名空间的请求资源)
    • API group- 正在访问的API组(仅用于请求资源)。空字符串指定核心API

     

    策略中需要包含一个flag,来指定你的策略包含的哪种授权模块:

    使用以下flags:

    • ---authorization-mode=ABAC 基于属性的访问控制(ABAC)模式允许使用本地文件配置策略。
    • ---authorization-mode=RBAC 基于角色的访问控制(RBAC)模式允许使用Kubernetes API创建和存储策略。
    • ---authorization-mode=WebhookWebHook 是一种HTTP回调模式,允许使用远程REST管理授权。
    • ---authorization-mode=AlwaysDeny flag 阻止所有请求。仅使用此flag进行测试。
    • ---authorization-mode=AlwaysAllow 此标志允许所有请求。只有在不需要API请求授权的情况下才能使用此标志。
    • 可以选择多个授权模块。如果其中一种模式是AlwaysAllow,则覆盖其他模式,并允许所有的API请求。

    3.2.1 Node授权

    Node授权是一种特殊授权模式,专门授权由kubelet访问的API请求。

    Node授权器允许kubelet执行的API操作包括:

    读:

    • services
    • endpoints
    • nodes
    • pods
    • secrets, configmaps, persistent volume claims and persistent volumes related to pods bound to the kubelet’s node

    写:

    • Node和Node status(启用NodeRestriction准入插件限制kubelet仅修改当前的Node)
    • Pod和Pod status(启用NodeRestriction准入插件限制kubelet仅修改与当前绑定的pod)
    • events

    Auth-related

    • read/write access to the certificationsigningrequests API for TLS bootstrapping
    • the ability to create tokenreviews and subjectaccessreviews for delegated authentication/authorization checks

    在以后的版本中,Node授权器支持添加或删除的权限。

    为获得Node授权器的授权,kubelet需要使用system:nodes组中的用户名system:node:<nodeName>。

    启用Node授权器方法:apiserver --authorization-mode=Node。

    为了限制kubelets能够写入的API对象,可以启动--admission-control=...,NodeRestriction,...准入(admission)插件。

    3.2.2 ABAC模式

    基于属性的访问控制(ABAC)定义了访问控制范例,通过将属性组合在一起的策略来授予用户访问权限。ABAC策略可以使用任何类型的属性(用户属性,资源属性,对象,环境属性等)。

    使用ABAC模式指定策略文件:--authorization-policy-file=SOME_FILENAME。

    文件格式是JSON, one JSON object per line

    每一行都是一个“policy 对象”,policy对象具有以下属性:

    • Versioning 属性:
      • apiVersion,字符串类型; 有效值为“abac.authorization.kubernetes.io/v1beta1”。允许版本控制和对策略格式进行转换。
      • kind,字符串类型:有效值为“Policy”。允许版本控制和对策略格式进行转换。
    • spec 属性:
      • Subject-matching 属性:
        • user,字符串类型;
        • group,字符串类型;
      • Resource-matching 属性:
        • apiGroup,字符串类型; 一个API Group。
          • 例如: extensions
          • 通配符:*匹配所有API Group。
        • namespace,字符串类型;一个(namespace)命名空间
          • 例如: kube-system
          • 通配符:*匹配所有资源请求。
        • resource,字符串类型;  资源类型
          • 例如: pods
          • 通配符:*匹配所有资源请求。
      • Non-resource-matching 属性:
        • nonResourcePath,字符串类型; non-resource request paths。
          • 例如:/version 或 /apis
          • 通配符:
            • 匹配所有non-resource 请求。
            • /foo/* matches all subpaths of /foo/
      • readonly,boolean类型,如果为true,表示该策略仅用于操作get,list和watch。
      • 授权方法:
    • 属性设置为"*"将匹配所有属性值。
    • 检查属性的元组以匹配策略文件中的每个策略。如果有一行匹配了请求属性,则请求被授权(但可能会在稍后的认证中失败)。
    • 要允许认证过的用户执行操作,请将Group属性设置"system:authenticated"。
    • 要允许未认证的用户执行操作,请将Group属性设置"system:unauthenticated"。
    • 要允许用户执行任何操作,请编写一个策略,使用apiGroup,namespace,resource和nonResourcePath属性设置为"*"。

    示例:

    Alice对所有资源进行操作

    {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}}

    Kubelet可以读取任何pod:

    {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "pods", "readonly": true}}

    Kubelet可以读/写事件:

    {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "events"}}

     

    Bob可以在namespace“projectCaribou”中读取pod:

    {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}

    3.2.3 RBAC模式

    基于角色的访问控制(“RBAC”)使用“rbac.authorization.k8s.io”API 组来实现授权控制,允许管理员通过Kubernetes API动态配置策略。

    启用RBAC:

    apiserver --authorization-mode=RBAC。

    RBAC API声明了四个最高级别的类型(本文介绍),RBAC 的授权策略可以利用 kubectl 或者 Kubernetes API 直接进行配置。RBAC 可以授权给用户,让用户有权进行授权管理,这样就无需接触节点,直接进行授权管理。RBAC 在 Kubernetes 中被映射为 API 资源和操作。

    Role 和 ClusterRole

    Role是一系列的权限的集合,例如一个Role可以包含读取 Pod 的权限和列出 Pod 的权限, ClusterRole 跟 Role 类似,但是可以在集群中全局使用。

    Role只能授予单个namespace 中资源的访问权限。以下是Role“default”namespace 中的示例,用于授予对pod的访问权限:

    kind: Role

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      namespace: default

      name: pod-reader

    rules:

    - apiGroups: [""] # "" indicates the core API group

      resources: ["pods"]

      verbs: ["get", "watch", "list"]

    ClusterRole授权 >= Role授予(与Role类似),但ClusterRole属于集群级别对象:

    • 集群范围(cluster-scoped)的资源访问控制(如:节点访问权限)
    • 非资源类型(如“/ healthz”)
    • 所有namespaces 中的namespaced 资源(如 pod)

    ClusterRole示例:

     

    kind: ClusterRole

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      # "namespace" omitted since ClusterRoles are not namespaced

      name: secret-reader

    rules:

    - apiGroups: [""]

      resources: ["secrets"]

      verbs: ["get", "watch", "list"]

    RoleBinding和ClusterRoleBinding

     

    RoleBinding是将Role中定义的权限授予给用户或用户组。它包含一个subjects列表(users,groups ,service accounts),并引用该Role。RoleBinding在某个namespace 内授权,ClusterRoleBinding适用在集群范围内使用。

    RoleBinding可以引用相同namespace下定义的Role。以下的RoleBinding在“default”namespace中将“pod-reader”Role授予用户“jane”。将允许“jane”在“default”namespace中读取pod权限。

    # This role binding allows "jane" to read pods in the "default" namespace.

    kind: RoleBinding

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      name: read-pods

      namespace: default

    subjects:

    - kind: User

      name: jane

      apiGroup: rbac.authorization.k8s.io

    roleRef:

      kind: Role

      name: pod-reader

      apiGroup: rbac.authorization.k8s.io

    RoleBinding还可以引用ClusterRole。将允许管理员为整个集群定义一组通用Role,然后在不同namespace中使用RoleBinding引用。

     

    # This role binding allows "dave" to read secrets in the "development" namespace.

    kind: RoleBinding

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      name: read-secrets

      namespace: development # This only grants permissions within the "development" namespace.

    subjects:

    - kind: User

      name: dave

      apiGroup: rbac.authorization.k8s.io

    roleRef:

      kind: ClusterRole

      name: secret-reader

      apiGroup: rbac.authorization.k8s.io

    ClusterRoleBinding可以用于集群中所有命名空间中授予权限。以下ClusterRoleBinding允许组“manager”中的任何用户在任何命名空间中读取secrets。

    kind: ClusterRoleBinding

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      name: read-secrets-global

    subjects:

    - kind: Group

      name: manager

      apiGroup: rbac.authorization.k8s.io

    roleRef:

      kind: ClusterRole

      name: secret-reader

      apiGroup: rbac.authorization.k8s.io

    子资源的授权

    大多数资源由name字符串的形式表示,例如“pod”。然而,一些Kubernetes API 涉及“子资源”,例如Pod的logs ,pod log endpoint 的URL:

    GET /api/v1/namespaces/{namespace}/pods/{name}/log

    在这种情况下,“pod”是namespace中资源,“log”是pod的子资源,这种情况要在RBAC角色中表示,可以使用斜杠来划分资源和子资源。如下例子:

    kind: Role

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      namespace: default

      name: pod-and-pod-logs-reader

    rules:

    - apiGroups: [""]

      resources: ["pods", "pods/log"]

      verbs: ["get", "list"]

    资源也可以通过resourceNames列表的某些请求的资源名称来引用。如下例子:

    kind: Role

    apiVersion: rbac.authorization.k8s.io/v1beta1

    metadata:

      namespace: default

      name: configmap-updater

    rules:

    - apiGroups: [""]

      resources: ["configmap"]

      resourceNames: ["my-configmap"]

      verbs: ["update", "get"]

    需要注意如果设置了resourceNames,那么verbs不能指定为list、watch、create或deletecollection。

    Role 示例

    允许在核心API Group中读取“pods”资源:

    rules:

    - apiGroups: [""]

      resources: ["pods"]

      verbs: ["get", "list", "watch"]

    允许在“extensions”和“apps”API Group中读/写“deployments”:

    rules:

    - apiGroups: ["extensions", "apps"]

      resources: ["deployments"]

      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

    允许读取 “Pod” 和 读/写 “jobs”:

    rules:

    - apiGroups: [""]

      resources: ["pods"]

      verbs: ["get", "list", "watch"]

    - apiGroups: ["batch", "extensions"]

      resources: ["jobs"]

      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

    允许读取名称为 “my-config” 的 ConfigMap:

    rules:

    - apiGroups: [""]

      resources: ["configmaps"]

      resourceNames: ["my-config"]

      verbs: ["get"]

    允许读取核心 Group中资源“Node”(Node属于集群范围,则必须将ClusterRole绑定ClusterRoleBinding):

    rules:

    - apiGroups: [""]

      resources: ["nodes"]

      verbs: ["get", "list", "watch"]

    允许非资源型“/ healthz”和所有子路径进行 “GET”和“POST”请求:(必须将ClusterRole绑定ClusterRoleBinding):

    rules:

    - nonResourceURLs: ["/healthz", "/healthz/*"] # '*' in a nonResourceURL is a suffix glob match

      verbs: ["get", "post"]

    Referring to Subjects

     

    RoleBinding或ClusterRoleBinding可以将Role绑定到主体subjects。Subjects 可以是groups、users和service accounts。

    Role Binding 示例

    适合一个名为“alice@example.com”的用户:

    subjects:

    - kind: User

      name: "alice@example.com"

      apiGroup: rbac.authorization.k8s.io

    适合一个名为“frontend-admins”的Group:

    subjects:

    - kind: Group

      name: "frontend-admins"

      apiGroup: rbac.authorization.k8s.io

    适合kube-system Namespace中的默认ServiceAccount:

    subjects:

    - kind: ServiceAccount

      name: default

      namespace: kube-system

    适合“qa”Namespace中的所有ServiceAccount:

    subjects:

    - kind: Group

      name: system:serviceaccounts:qa

      apiGroup: rbac.authorization.k8s.io

    适合集群中所有ServiceAccount:

    subjects:

    - kind: Group

      name: system:serviceaccounts

      apiGroup: rbac.authorization.k8s.io

    适合所有经过认证的用户(1.5版本以上):

    subjects:

    - kind: Group

      name: system:authenticated

      apiGroup: rbac.authorization.k8s.io

    适合所有未经认证的用户(1.5版本以上):

    subjects:

    - kind: Group

      name: system:unauthenticated

      apiGroup: rbac.authorization.k8s.io              

    适合所有用户(1.5版本以上):

    subjects:

    - kind: Group

      name: system:authenticated

      apiGroup: rbac.authorization.k8s.io

    - kind: Group

      name: system:unauthenticated

      apiGroup: rbac.authorization.k8s.io

     

    默认Role和 Role Bindings

     

    API Server会创建一组默认的ClusterRole和ClusterRoleBinding对象。其中许多都是system:前缀,表示这些资源属于系统基础组件。修改这些资源对象可能会引起一些未知错误。例如:是system:nodeClusterRole,此角色定义了kubelet的权限,如果角色被修改,将会引起kubelet无法工作。

    Auto-reconciliation

    在每次启动时,API Server会更新默认的cluster roles ,并更新默认ClusterRoleBinding各个角色绑定主体,这使集群能够修复某些意外修改情况。

    User-facing Roles

     

    一些不以system:为前缀的角色是面向用户的Role 。它们包括超级用户Role (cluster-admin),ClusterRoleBindings (cluster-status),以及特定namespaces中授权的 RoleBinding( admin,edit,view )

    cluster-admin

    Allows super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself.

     

    Admin

    Allows admin access, intended to be granted within a namespace using a RoleBinding. If used in a RoleBinding, allows read/write access to most resources in a namespace, including the ability to create roles and rolebindings within the namespace. It does not allow write access to resource quota or to the namespace itself.

    Edit
    Allows read/write access to most objects in a namespace. It does not allow viewing or modifying roles or rolebindings

    View:

    Allows read-only access to see most objects in a namespace. It does not allow viewing roles or rolebindings. It does not allow viewing secrets, since those are escalating

    Default ClusterRole

    Default ClusterRoleBinding

    Description

    cluster-admin

    system:masters group

    Allows super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself.

    admin

    None

    Allows admin access, intended to be granted within a namespace using a RoleBinding. If used in a RoleBinding, allows read/write access to most resources in a namespace, including the ability to create roles and rolebindings within the namespace. It does not allow write access to resource quota or to the namespace itself.

    edit

    None

    Allows read/write access to most objects in a namespace. It does not allow viewing or modifying roles or rolebindings

    view

    None

    Allows read-only access to see most objects in a namespace. It does not allow viewing roles or rolebindings. It does not allow viewing secrets, since those are escalating

    Default ClusterRole

    Default ClusterRoleBinding

    Description

    cluster-admin

    system:masters group

    Allows super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself.

     

     

     

     

     

    Core Component Roles

    Default ClusterRole

    Default ClusterRoleBinding

    Description

    system:kube-scheduler

    system:kube-scheduler user

    Allows access to the resources required by the kube-scheduler component.

    system:kube-controller-manager

    system:kube-controller-manager user

    Allows access to the resources required by the kube-controller-manager component. The permissions required by individual control loops are contained in the controller roles.

    system:node

    system:nodes group (deprecated in 1.7)

    Allows access to resources required by the kubelet component, including read access to all secrets, and write access to all pods. As of 1.7, use of the [Node authorizer](/docs/admin/authorization/node/) and [NodeRestriction admission plugin](/docs/admin/admission-controllers#NodeRestriction) is recommended instead of this role, and allow granting API access to kubelets based on the pods scheduled to run on them. As of 1.7, when the `Node` authorization mode is enabled, the automatic binding to the `system:nodes` group is not created.

    system:node-proxier

    system:kube-proxy user

    Allows access to the resources required by the kube-proxy component

    Default ClusterRole

    Default ClusterRoleBinding

    Description

    system:kube-scheduler

    system:kube-scheduler user

    Allows access to the resources required by the kube-scheduler component.

     

     

    3.3 准入控制

    准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数,在对kubernetes api服务器的请求过程中,先经过认证授权后,执行准入操作,在对目标对象进行操作。这个准入插件代码在apiserver中,而且必须被编译到二进制文件中才能被执行。

    在对集群进行请求时,每个准入控制插件都按顺序运行,只有全部插件都通过的请求才会进入系统,如果序列中的任何插件拒绝请求,则整个请求将被拒绝,并返回错误信息。

    在某些情况下,为了适用于应用系统的配置,准入逻辑可能会改变目标对象。此外,准入逻辑也会改变请求操作的一部分相关资源。

    运行准入控制插件

    旧版本:在kubernetes apiserver中有一个flag:admission_control,他的值为一串用逗号连接起、有序的准入模块列表,设置后,就可在对象操作前执行一定顺序的准入模块调用。

    Kubernetes 1.10之后的版本, --admission-control 已经废弃,建议使用 --enable-admission-plugins --disable-admission-plugins 指定需要打开或者关闭的 Admission Controller。 同时用户指定的顺序并不影响实际 Admission Controllers 的执行顺序,对用户来讲非常友好。

    在1.18版本中默认启动的插件:

    NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota

     

    AlwaysAdmit

    结束所有的请求。

    AlwaysPullImages

    该插件修改每个新的Pod,强制pull最新镜像,这在多租户群集中非常有用,以便私有镜像只能由拥有授权凭据的用户使用。

    AlwaysDeny

    拒绝所有请求,一般用于测试。

    DenyExecOnPrivileged(已弃用)

    该插件将拦截所有请求。如果pod有一个privileged container,将只执行这个pod中的命令。
    如果自己的集群支持privileged container,自己又希望限制用户在这些privileged container上执行命令,那么强烈推荐使用它。

    此功能已合并到DenyEscalatingExec中。

    DenyEscalatingExec

    禁止privileged container的exec和attach操作。

    ImagePolicyWebhook

    通过webhook决定image策略,需要同时配置--admission-control=ImagePolicyWebhook,配置文件格式如下。

    ServiceAccount

    该插件将serviceAccounts 实现了自动化。如果打算使用Kubernetes ServiceAccount对象,那么强烈建议使用此插件。

    SecurityContextDeny

    该插件会将使用了 SecurityContext的pod中定义的选项全部失效 。

    ResourceQuota

    该插件将会观察传入的所有请求,并确保它不会违反ResourceQuota对象中枚举的任何限制Namespace。如果在Kubernetes Deployment中使用了ResourceQuota对象,则必须使用此插件来约束Container。

    更多详细信息,请参阅resourceQuota design docexample of Resource Quota

    推荐在Admission Control参数列表中,这个插件排最后一个。

    LimitRanger

    该插件将会观察传入的所有请求,并确保它不会违反LimitRanger对象中枚举的任何限制Namespace,如果在Kubernetes Deployment中使用了LimitRanger对象,则必须使用此插件。LimitRanger还可使用Apply将default资源请求不指定任何的Pods; 目前LimitRanger对Default Namespace中的所有pod应用要求0.1 CPU

    更多详细信息,请参阅limitRange design docexample of Limit Range 。

    InitialResources(试验)

    根据镜像的历史使用记录,为容器设置默认资源请求和limits。

    更多详细信息,参考 InitialResouces proposal

    NamespaceLifecycle

    该插件确保处于Termination状态的Namespace不再接收新的对象创建请求,并拒绝请求不存在的Namespace。该插件还可以防止删除系统保留的Namespace:default,kube-system,kube-public。

    DefaultStorageClass

    该插件将观察PersistentVolumeClaim,并自动设置默认的Storage Class。

    当没有配置默认Storage Class时,此插件不会执行任何操作。当有多个Storage Class被标记为默认值时,它也将拒绝任何创建,管理员必须重新访问StorageClass对象,并且只标记一个作为默认值。此插件不用于PersistentVolumeClaim的更新,仅用于创建。

    更多详细信息,参考persistent volume

    DefaultTolerationSeconds

    该插件设置Pod的默认forgiveness toleration为5分钟。

    PodSecurityPolicy

    该插件用于创建和修改pod,使用Pod Security Policies时需要开启。

    当 Kubernetes <1.6.0版本时,API服务器需要启用扩展名/ v1beta1 / podsecuritypolicy API扩展组(--runtime-config=extensions/v1beta1/podsecuritypolicy=true)。

    更多信息,请参考Pod Security Policy documentation

    NodeRestriction

    此插件限制kubelet修改Node和Pod对象,这样的kubelets只允许修改绑定到Node的Pod API对象,以后版本可能会增加额外的限制。

    限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源(仅适用于v1.7+)

     

     

     

     

     

     

     

    参考文献:

    1.Kubernetes API Server官方文档

    http://docs.kubernetes.org.cn/27.html

    2. SSL双向认证和SSL单向认证的流程和区别

    https://www.cnblogs.com/bluestorm/p/10571989.html

    3. 浅聊Kubernetes的各种认证策略以及适用场景

    https://zhuanlan.zhihu.com/p/97797321

    4. openssl 证书请求和自签名命令req详解

    https://www.cnblogs.com/gordon0918/p/5409286.html

    5. Https原理及流程

    https://www.jianshu.com/p/14cd2c9d2cd2

    6. Kubernetes 必须掌握技能之 RBAC

    https://zhuanlan.zhihu.com/p/97793056

    7. 使用kubectl访问Kubernetes集群时的身份验证和授权

    https://blog.csdn.net/luanpeng825485697/article/details/83955721

    8. kubernetes中kubeconfig的用法

    https://www.cnblogs.com/charlieroro/p/8489515.html

    9.为 Kubernetes 搭建支持 OpenId Connect 的身份认证系统

    https://developer.ibm.com/zh/articles/cl-lo-openid-connect-kubernetes-authentication/

    10. kubernetes新建自定义用户(新cluster 用户名)

    https://blog.csdn.net/wt334502157/article/details/102822348

    11.kubernetes proxy简介

    https://blog.csdn.net/dkfajsldfsdfsd/article/details/80981780

    12.accessing-the-rest-api

    https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#directly-

    13. Kubernetes 准入控制 Admission Controller 介绍

    https://www.codercto.com/a/27364.html

     

    展开全文
  • 深入理解Kube-APIServer

    千次阅读 2022-01-18 15:34:26
    kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能 • 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等 • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API ...

    k8s环境-Test
    平台:腾讯云-TKE
    在这里插入图片描述

    API Server

    kube-apiserver是Kubernetes最重要的核心组件之一,主要提供以下的功能
    • 提供集群管理的REST API接口,包括认证授权、数据校验以及集群状态变更等
    • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd)

    访问控制概览

    Kubernetes API的每个请求都会经过多阶段的访问控制之后才会被接受,这包括认证、授权以及准入控制(Admission Control)等。
    在这里插入图片描述

    apiserver本身是一个rust server,首先要有一个http handler来处理不同版本的请求,接收到请求之后要做认证、鉴权,然后到转变,对应两个webhook(可以自定义开发,在到达mutating步骤时,apiserver会校验有没有对应的webhook,有的话则会被调用,改变对象的值webhook会进行回转),接下来到schema步骤,apiserver会继续校验这个对象是不是有效的(主要是k8s内嵌的逻辑),

    访问控制细节

    在这里插入图片描述

    红色箭头为整个apiserver细节调用链:
    首先会做request-timeout的检查,然后做认证相关的校验,接下来到audit,主要记录k8s的日志审计(谁在哪个时间点修改了对象?)
    inpersonation(不太常用),在请求的handler里边模拟用户请求(a用户代替b用户)
    max-in-flight(用作限流),可以设置多少个请求发到apiserver,但是还没有返回,可以理解为在整个调用过程中设置上限值
    authorization 做鉴权
    kube-aggregator(抽象为多个apiserver汇总),本身是一个api gateway,大概可以理解为它可以分配多个apiserver来进行任务处理,把其中的一部分请求转到其他apiserver做处理
    resource handler,首先会解码——》做准入——》校验——》存储etcd中

    认证

    开启TLS时,所有的请求都需要首先认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。如果认证成功,则用户的username会传入授权模块做进一步授权验证;而对于认证失败的请求则返回HTTP 401。

    认证插件

    X509证书
    • 使用X509客户端证书只需要API Server启动时配置–client-ca-file=SOMEFILE。在证书认证时,其CN域用作用户名,而组织机构域则用作group名。

    静态Token文件
    • 使用静态Token文件认证只需要API Server启动时配置–token-auth-file=SOMEFILE。
    • 该文件为csv格式,每行至少包括三列token,username,user id,
    token,user,uid,"group1,group2,group3”
    参考资料:https://github.com/cncamp/101/blob/master/module6/basic-auth/static-token.csv

    ## Static token
    ### Put static-token to target folder
    
    mkdir -p /etc/kubernetes/auth
    cp static-token /etc/kubernetes/auth
    
    ### Backup your orginal apiserver
    
    cp /etc/kubernetes/manifests/kube-apiserver.yaml ~/kube-apiserver.yaml
    
    ### Override your kube-apiserver with the one with static-token config
    
    cp ./kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml
    
    ### Get kubernetes object with static token
    
    curl https://192.168.34.2:6443/api/v1/namespaces/default -H "Authorization: Bearer cncamp-token" -k
    

    引导Token
    • 为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型, 称作 启动引导令牌(Bootstrap Token)。
    • 这些令牌以 Secret 的形式保存在 kube-system 名字空间中,可以被动态管理和创建。
    • 控制器管理器包含的 TokenCleaner 控制器能够在启动引导令牌过期时将其删除。
    • 在使用kubeadm部署Kubernetes时,可通过kubeadm token list命令查询。

    静态密码文件
    • 需要API Server启动时配置–basic-auth-file=SOMEFILE,文件格式为csv,每行至少三列password, user, uid,后面是可选的group名
    password,user,uid,"group1,group2,group3”

    ServiceAccount
    • ServiceAccount是Kubernetes自动生成的,并会自动挂载到容器的/run/secrets/kubernetes.io/serviceaccount目录中。
    创建ns默认都会创建一个,自动会mount到容器里边。

    ~]# kubectl get sa -oyaml
    apiVersion: v1
    items:
    - apiVersion: v1
      kind: ServiceAccount
      metadata:
        creationTimestamp: "2022-01-06T12:12:13Z"
        name: default
        namespace: default
        resourceVersion: "383"
        selfLink: /api/v1/namespaces/default/serviceaccounts/default
        uid: ba297c44-2a92-4c17-9db2-9e804e76d4b1
      secrets:
      - name: default-token-zj56s	#同时k8s会创建一个secret
    kind: List
    metadata:
      resourceVersion: ""
      selfLink: ""
    
    ~]# kubectl get secret default-token-zj56s -oyaml
    。。。
    这个文件中会带有ns、ca文件、token,是apiserver给颁发的
    
    echo "token的值" |base64 -d 
    是一个标准的gwt token,apiserver颁发的——》解码
    用这个token文件去访问apiserver,就会知道是哪个用户访问的?
    
    1、当开发k8s组件时,例如写operator,理论上要监听集群apiserver来获取数据,有没有权限读/写 完全要基于身份
    2、团队希望每个人有自己的sa,来单独做调试
    

    在这里插入图片描述

    OpenID
    • OAuth 2.0的认证机制

    Webhook 令牌身份认证
    • --authentication-token-webhook-config-file 指向一个配置文件,其中描述 如何访问远程的 Webhook 服务。
    • --authentication-token-webhook-cache-ttl 用来设定身份认证决定的缓存时间。 默认时长为 2 分钟。

    匿名请求
    • 如果使用AlwaysAllow以外的认证模式,则匿名请求默认开启,但可用–anonymous-auth=false禁止匿名请求。

    基于webhook的认证服务集成

    参考资料:https://github.com/cncamp/101/tree/master/module6/authn-webhook

    构建符合Kubernetes规范的认证服务
    需要依照Kubernetes规范,构建认证服务,用来认证tokenreview request
    认证服务需要满足如下Kubernetes的规范

    URL: https://authn.example.com/authenticate
    Method: POST
    Input:
    Output:
    

    在这里插入图片描述

    鉴权

    授权主要是用于对集群资源的访问控制,通过检查请求包含的相关属性值,与相对应的访问策略相比较,API请求必须满足某些策略才能被处理。跟认证类似,Kubernetes也支持多种授权机制,并支持同时开启多个授权插件(只要有一个验证通过即可)。如果授权成功,则用户的请求会发送到准入控制模块做进一步的请求验证;对于授权失败的请求则返回HTTP 403。

    Kubernetes授权仅处理以下的请求属性:
    • user, group, extra
    • API、请求方法(如get、post、update、patch和delete)和请求路径(如/api) • 请求资源和子资源
    • Namespace
    • API Group
    目前,Kubernetes支持以下授权插件:
    • ABAC
    • RBAC
    • Webhook
    • Node

    RBAC vs ABAC

    ABAC(Attribute Based Access Control)本来是不错的概念,但是在 Kubernetes 中的实现比较难于管理和理解,而且需要对 Master 所在节点的 SSH 和文件系统权限,要使得对授权的变更成功生效,还需要重新启动 API Server。
    而 RBAC 的授权策略可以利用 kubectl 或者 Kubernetes API 直接进行配置。RBAC 可以授权给用户,让用户有权进行授权管理,这样就可以无需接触节点,直接进行授权管理。RBAC 在 Kubernetes 中被映射为 API 资源和操作。
    在这里插入图片描述
    在这里插入图片描述

    k8s设计了一系列对象,例如:Role(代表角色),里边定义了一些resources资源和verb(动作),称为一组对象的操作权限聚合成一个角色,subject(抽象为主体)分为user(外部用户)和serviceaccount(内部用户)两种,subject和role通过rolebinding产生关联,最终rbac的定位是谁对哪些对象做什么样的操作;
    clusterrole和role的区别:
    有时候角色(clusterrole)是一个全局的,role跟namespace是关联的,可以在某一个ns下创建role,clusterrole在整个集群下可以授权给其他用户权限,带clusterrole均为全局性的。

    专业术语:
    Role(角色)是一系列权限的集合,例如一个角色可以包含读取 Pod 的权限和列出 Pod 的权限。
    Role只能用来给某个特定namespace中的资源作鉴权,对多namespace和集群级的资源或者是非资源类的API(如/healthz)使用ClusterRole。
    在这里插入图片描述

    binding

    在这里插入图片描述

    账户/组的管理

    角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。
    它包含若干 主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。

    组的概念:

    • 当与外部认证系统对接时,用户信息(UserInfo)可包含Group信息,授权可针对用户群组
    • 当对ServiceAccount授权时,Group代表某个Namespace下的所有ServiceAccount
      在这里插入图片描述

    针对群租授权

    在这里插入图片描述

    规划系统角色

    User
    • 管理员
    所有资源的所有权限??
    • 普通用户
    是否有该用户创建的namespace下的所有object的操作权限?
    对其他用户的namespace资源是否可读,是否可写?
    SystemAccount
    • SystemAccount是开发者(kubernetes developer或者domain developer)创建应用后,应用于apiserver通讯需要的身份
    • 用户可以创建自定的ServiceAccount,kubernetes也为每个namespace创建default ServiceAccount
    • Default ServiceAccount通常需要给定权限以后才能对apiserver做写操作

    实现方案

    在cluster创建时,创建自定义的role,比如namespace-creator
    Namespace-creator role定义用户可操作的对象和对应的读写操作。
    创建自定义的namespace admission controller
    • 当namespace创建请求被处理时,获取当前用户信息并annotate到namespace
    创建RBAC controller
    • Watch namespace的创建事件
    • 获取当前namespace的创建者信息
    • 在当前namespace创建rolebinding对象,并将namespace-creator 角色和用户绑定

    与权限相关的其他最佳实践

    ClusterRole是非namespace绑定的,针对整个集群生效
    通常需要创建一个管理员角色,并且绑定给开发运营团队成员
    ThirdPartyResource和CustomResourceDefinition是全局资源,普通用户创建
    ThirdPartyResource以后,需要管理员授予相应权限后才能真正操作该对象
    针对所有的角色管理,建议创建spec,用源代码驱动

    • 虽然可以通过edit操作来修改权限,但后期会导致权限管理混乱,可能会有很多临时创建出来的角色和角色绑定对象,重复绑定某一个资源权限
      权限是可以传递的,用户A可以将其对某对象的某操作,抽取成一个权限,并赋给用户B防止海量的角色和角色绑定对象,因为大量的对象会导致鉴权效率低,同时给apiserver增加负担
      ServiceAccount也需要授权的,否则你的component可能无法操作某对象
      Tips:SSH到master节点通过insecure port访问apiserver可绕过鉴权,当需要做管理操作又没有权限时可以使用(不推荐)

    运营过程中出现的陷阱

    在这里插入图片描述

    准入

    准入控制

    为资源增加自定义属性

    • 作为多租户集群方案中的一环,我们需要在namespace的准入控制中,获取用户信息,并将用户信息更新的namespace的annotation
      只有当namespace中有有效用户信息时,我们才可以在namespace创建时,自动绑定用户权限,namespace即可使用。
      在这里插入图片描述
    • 准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数。不同于授权和认证只关心请求的用户和操作,准入控制还处理请求的内容,并且仅对创建、更新、删除或连接(如代理)等有效,而对读操作无效
    • 准入控制支持同时开启多个插件,它们依次调用,只有全部插件都通过的请求才可以放过进入系统。

    准入控制插件

    AlwaysAdmit: 接受所有请求。
    AlwaysPullImages: 总是拉取最新镜像。在多租户场景下非常有用。
    DenyEscalatingExec: 禁止特权容器的exec和attach操作。
    ImagePolicyWebhook: 通过webhook决定image策略,需要同时配置–admission-controlconfig-file
    ServiceAccount:自动创建默认ServiceAccount,并确保Pod引用的ServiceAccount已经存在
    SecurityContextDeny:拒绝包含非法SecurityContext配置的容器

    ResourceQuota:限制Pod的请求不会超过配额,需要在namespace中创建一个ResourceQuota对象
    LimitRanger:为Pod设置默认资源请求和限制,需要在namespace中创建一个LimitRange对 象
    InitialResources:根据镜像的历史使用记录,为容器设置默认资源请求和限制
    NamespaceLifecycle:确保处于termination状态的namespace不再接收新的对象创建请求,并拒绝请求不存在的namespace
    DefaultStorageClass:为PVC设置默认StorageClass
    DefaultTolerationSeconds:设置Pod的默认forgiveness toleration为5分钟
    PodSecurityPolicy:使用Pod Security Policies时必须开启
    NodeRestriction:限制kubelet仅可访问node、endpoint、pod、service以及secret、
    configmap、PV和PVC等相关的资源

    准入控制插件的开发

    除默认的准入控制插件以外,Kubernetes预留了准入控制插件的扩展点,用户可自定义准入控制插件实现自定义准入功能
    MutatingWebhookConfiguration:变形插件,支持对准入对象的修改
    ValidatingWebhookConfiguration:校验插件,只能对准入对象合法性进行校验,不能修改

    在这里插入图片描述

    配额管理

    背景:资源有限,如何限定某个用户有多少资源?

    方案:

    • 预定义每个Namespace的ResourceQuota,并把spec保存为configmap
      • 用户可以创建多少个Pod
        • BestEffortPod
        • QoSPod
      • 用户可以创建多少个service
      • 用户可以创建多少个ingress
      • 用户可以创建多少个service VIP
    • 创建ResourceQuota Controller
      • 监控namespace创建事件,当namespace创建时,在该namespace创建对应的ResourceQuota 对象
    • apiserver中开启ResourceQuota的admission plugin

    实践操作

    场景:在认证、授权之后使用webhook来做准入控制。
    ~]# git clone https://github.com/cncamp/admission-controller-webhook-demo.git
    [root@VM-0-16-centos ~]# kubectl get mutatingwebhookconfiguration
    NAME                       WEBHOOKS   AGE
    base-operator              3          16d
    cert-manager-webhook-new   1          16d
    cluster-transformer        2          16d
    courier                    4          16d
    metis                      8          16d
    spark-webhook-config       1          16d
    ti-admission-webhook       6          16d
    validateimage              1          16d
    vpa-webhook-config         1          16d
    warlock                    1          16d
    
    [root@VM-0-16-centos ~/p_ywcheng/admission-controller-webhook-demo]# bash deploy.sh 
    Generating TLS keys ...
    Generating a 2048 bit RSA private key
    ...................................................+++
    ...............+++
    writing new private key to 'ca.key'
    -----
    Generating RSA private key, 2048 bit long modulus
    .........+++
    ................................................+++
    e is 65537 (0x10001)
    Signature ok
    subject=/CN=webhook-server.webhook-demo.svc
    Getting CA Private Key
    Creating Kubernetes objects ...
    namespace/webhook-demo created
    secret/webhook-server-tls created
    deployment.apps/webhook-server created
    service/webhook-server created
    mutatingwebhookconfiguration.admissionregistration.k8s.io/demo-webhook created
    The webhook server has been deployed and configured!
    
    kubectl get mutatingwebhookconfiguration.admissionregistration.k8s.io/demo-webhook -oyaml
    .....
    caBundle参数:相信webhook启的https证书
        service:
          name: webhook-server
          namespace: webhook-demo
          path: /mutate
          port: 443
    .....
    kubectl get svc -nwebhook-demo
    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    webhook-server   ClusterIP   10.106.194.34   <none>        443/TCP   4m56s
    
    kubectl get deploy/webhook-server -nwebhook-demo
    NAME             READY   UP-TO-DATE   AVAILABLE   AGE
    webhook-server   1/1     1            1           27m
    
    kubectl get pod -nwebhook-demo
    NAME                             READY   STATUS    RESTARTS   AGE
    webhook-server-988f9f4f9-gcc9z   1/1     Running   0          27m
    
    #测试访问webhook-demo
    curl https://10.106.194.34/mutate -k
    invalid method GET, only POST requests are allowed
    #说明已经开启了mutatingwebhook
    
    kubectl create -f examples/pod-with-defaults.yaml
    kubectl get po  pod-with-defaults -oyaml
    kubectl logs -f pod-with-defaults
    

    在这里插入图片描述

    Pod启动失败!
     kubectl get pod nginx-demo -oyaml
      securityContext:
        runAsNonRoot: true
        runAsUser: 1234		#需要以userid为1234的用户来运行此程序
    

    在这里插入图片描述

    限流

    计数器固定窗口算法

    在这里插入图片描述

    计数器滑动窗口算法

    在这里插入图片描述

    漏斗算法

    在这里插入图片描述

    令牌桶算法

    在这里插入图片描述

    APIServer中的限流

    max-requests-inflight: 在给定时间内的最大 non-mutating 请求数
    max-mutating-requests-inflight: 在给定时间内的最大 mutating 请求数,调整 apiserver 的流控 qos
    代码
    staging/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go:WithMaxInFlightLimit()
    在这里插入图片描述

    传统限流方法的局限性

    在这里插入图片描述

    API Priority and Fairness

    k8s 1.18以后 组件:顾忌到公平和优先级
    在这里插入图片描述
    在这里插入图片描述
    flowschema用来定义一个个flow,prioritylevelconfiguration定义队列优先级

    实践分析

    ➜ ~ kubectl get flowschema
    NAME                           PRIORITYLEVEL     MATCHINGPRECEDENCE   DISTINGUISHERMETHOD   AGE   MISSINGPL
    exempt(豁免)                         exempt            1                    <none>                66d   False
    probes(健康检测)                         exempt            2                    <none>                66d   False
    system-leader-election         leader-election   100                  ByUser                66d   False
    workload-leader-election       leader-election   200                  ByUser                66d   False
    system-node-high               node-high         400                  ByUser                66d   False
    system-nodes                   system            500                  ByUser                66d   False
    kube-controller-manager        workload-high     800                  ByNamespace           66d   False
    kube-scheduler                 workload-high     800                  ByNamespace           66d   False
    kube-system-service-accounts   workload-high     900                  ByNamespace           66d   False
    service-accounts               workload-low      9000                 ByUser                66d   False
    global-default                 global-default    9900                 ByUser                66d   False
    catch-all(以上都没有占到的话才用)                      catch-all         10000                ByUser                66d   False
    
    ➜ ~ kubectl get flowschema service-accounts -oyaml
    apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
    kind: FlowSchema	#如何定义一个flow
    metadata:
      annotations:
        apf.kubernetes.io/autoupdate-spec: "true"
      creationTimestamp: "2021-12-10T09:11:25Z"
      generation: 1
      name: service-accounts
      resourceVersion: "66"
      uid: 2bb0d2a3-563c-4d7b-b4c4-53cd708c258b
    spec:
      distinguisherMethod:	#标识一个flow的唯一性
        type: ByUser	#类型为byuser,不同的service-account flow是不一样的
      matchingPrecedence: 9000	#规则的优先级,数字越小优先级越高
      priorityLevelConfiguration:	#这个flow请求最终由哪个队列去处理
        name: workload-low
      rules:	#规则,什么样的操作会被限流
      - nonResourceRules:
        - nonResourceURLs:	#例如:kubectl get ns default -v 9获得的结果:/api/v1/namespaces/cyw
          - '*'
          verbs:
          - '*'
        resourceRules:
        - apiGroups:
          - '*'
          clusterScope: true
          namespaces:
          - '*'
          resources:
          - '*'
          verbs:
          - '*'
        subjects:
        - group:
            name: system:serviceaccounts
          kind: Group
    status:
      conditions:
      - lastTransitionTime: "2021-12-10T09:11:25Z"
        message: This FlowSchema references the PriorityLevelConfiguration object named
          "workload-low" and it exists
        reason: Found
        status: "False"
        type: Dangling
    
    查看当前集群所有的优先队列
    ➜ ~ kubectl get PriorityLevelConfiguration
    NAME              TYPE      ASSUREDCONCURRENCYSHARES   QUEUES   HANDSIZE   QUEUELENGTHLIMIT   AGE
    catch-all         Limited   5                          <none>   <none>     <none>             66d
    exempt            Exempt    <none>                     <none>   <none>     <none>             66d
    global-default    Limited   20                         128      6          50                 66d
    leader-election   Limited   10                         16       4          50                 66d
    node-high         Limited   40                         64       6          50                 66d
    system            Limited   30                         64       6          50                 66d
    workload-high     Limited   40                         128      6          50                 66d
    workload-low      Limited   100                        128      6          50                 66d
    
    ➜ ~ kubectl get PriorityLevelConfiguration workload-low -oyaml
    apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
    kind: PriorityLevelConfiguration
    metadata:
      annotations:
        apf.kubernetes.io/autoupdate-spec: "true"
      creationTimestamp: "2021-12-10T09:11:25Z"
      generation: 1
      name: workload-low
      resourceVersion: "21"
      uid: b8110060-368b-45e1-981c-31891e259d6a
    spec:
      limited:
        assuredConcurrencyShares: 100
        limitResponse:
          queuing:
            handSize: 6
            queueLengthLimit: 50
            queues: 128
          type: Queue
      type: Limited
    status: {}
    
    
    ➜ ~ kubectl get flowschema exempt -oyaml
    apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
    kind: FlowSchema
    metadata:
      annotations:
        apf.kubernetes.io/autoupdate-spec: "true"
      creationTimestamp: "2021-12-10T09:11:25Z"
      generation: 1
      name: exempt
      resourceVersion: "61"
      uid: 89953d28-4f0a-4949-bbbd-b14c26082664
    spec:
      matchingPrecedence: 1		#优先级最高的
      priorityLevelConfiguration:
        name: exempt
      rules:
      - nonResourceRules:
        - nonResourceURLs:
          - '*'
          verbs:
          - '*'
        resourceRules:
        - apiGroups:
          - '*'
          clusterScope: true
          namespaces:
          - '*'
          resources:
          - '*'
          verbs:
          - '*'
        subjects:
        - group:
            name: system:masters	#这个角色具备豁免权
          kind: Group
    status:
      conditions:
      - lastTransitionTime: "2021-12-10T09:11:25Z"
        message: This FlowSchema references the PriorityLevelConfiguration object named
          "exempt" and it exists
        reason: Found
        status: "False"
        type: Dangling
    
    ➜ ~ kubectl get priorityLevelConfiguration exempt  -oyaml
    apiVersion: flowcontrol.apiserver.k8s.io/v1beta1
    kind: PriorityLevelConfiguration
    metadata:
      annotations:
        apf.kubernetes.io/autoupdate-spec: "true"
      creationTimestamp: "2021-12-10T09:11:25Z"
      generation: 1
      name: exempt
      resourceVersion: "26"
      uid: 0b9fd349-384b-4fad-8e03-795aacb50c38
    spec:
      type: Exempt	#对于最重要的请求,都会豁免
    status: {}
    

    概念

    在这里插入图片描述

    优先级

    在这里插入图片描述

    排队

    在这里插入图片描述

    豁免请求

    某些特别重要的请求不受制于此特性施加的任何限制。这些豁免可防止不当的流控配置完全禁用API 服务器。

    默认配置

    在这里插入图片描述
    在这里插入图片描述

    PriorityLevelConfiguration

    一个 PriorityLevelConfiguration 表示单个隔离类型。
    每个 PriorityLevelConfigurations 对未完成的请求数有各自的限制,对排队中的请求数也有限制。
    在这里插入图片描述

    FlowSchema

    FlowSchema 匹配一些入站请求,并将它们分配给优先级。
    每个入站请求都会对所有 FlowSchema 测试是否匹配, 首先从 matchingPrecedence 数值最低的匹配开始(我们认为这是逻辑上匹配度最高), 然后依次进行,直到首个匹配出现。
    在这里插入图片描述

    调试

    在这里插入图片描述

    ~ kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels
    PriorityLevelName, ActiveQueues, IsIdle, IsQuiescing, WaitingRequests, ExecutingRequests
    workload-high,     0,            true,   false,       0,               0
    workload-low,      0,            true,   false,       0,               0
    catch-all,         0,            true,   false,       0,               0
    exempt,            <none>,       <none>, <none>,      <none>,          <none>
    global-default,    0,            true,   false,       0,               0
    leader-election,   0,            true,   false,       0,               0
    node-high,         0,            true,   false,       0,               0
    system,            0,            true,   false,       0,               0
    
    #集群所有队列查看~ kubectl get --raw /debug/api_priority_and_fairness/dump_queues
    PriorityLevelName, Index,  PendingRequests, ExecutingRequests, VirtualStart
    exempt,            <none>, <none>,          <none>,            <none>
    global-default,    0,      0,               0,                 0.0000
    global-default,    1,      0,               0,                 0.0000
    global-default,    2,      0,               0,                 0.0000
    global-default,    3,      0,               0,                 0.0000
    global-default,    4,      0,               0,                 0.0000
    global-default,    5,      0,               0,                 0.0000
    global-default,    6,      0,               0,                 0.0000
    global-default,    7,      0,               0,                 0.0000
    global-default,    8,      0,               0,                 0.0000
    global-default,    9,      0,               0,                 0.0000
    global-default,    10,     0,               0,                 0.0000
    global-default,    11,     0,               0,                 0.0000
    global-default,    12,     0,               0,                 0.0000
    global-default,    13,     0,               0,                 0.0000
    
    #集群所有等待的请求队列~ kubectl get --raw /debug/api_priority_and_fairness/dump_requests
    PriorityLevelName, FlowSchemaName, QueueIndex, RequestIndexInQueue, FlowDistingsher, ArriveTime
    #当前为空
    

    高可用APIServer

    构建高可用的多副本apiserver

    apiserver是无状态的Rest Server
    无状态所以方便Scale Up/down

    负载均衡

    • 在多个apiserver实例之上,配置负载均衡
    • 证书可能需要加上Loadbalancer VIP重新生成

    预留充足的CPU、内存资源

    随着集群中节点数量不断增多,APIServer对CPU和内存的开销也不断增大。过少的CPU资源会降低其处理效率,过少的内存资源会导致Pod被OOMKilled,直接导致服务不可用。在规划APIServer资源时,不能仅看当下需求,也要为未来预留充分。

    善用速率限制(RateLimit)

    APIServer的参数“–max-requests-inflight”和“–max-mutating-requests-inflight”支持在给定时间内限制并行处理读请求(包括Get、List和Watch操作)和写请求(包括Create、Delete、Update和Patch操作)的最大数量。当APIServer接收到的请求超过这两个参数设定的值时,再接收到的请求将会被直接拒绝。通过速率限制机制,可以有效地控制APIServer内存的使用。如果该值配置过低,会经常出现请求超过限制的错误,如果配置过高,则APIServer可能会因为占用过多内存而被强制终止,因此需要根据实际的运行环境,结合实时用户请求数量和APIServer的资源配置进行调优。

    客户端在接收到拒绝请求的返回值后,应等待一段时间再发起重试,无间隔的重试会加重APIServer的压力,导致性能进一步降低。针对并行处理请求数的过滤颗粒度太大,在请求数量比较多的场景,重要的消息可能会被拒绝掉,自1.18版本开始,社区引入了优先级和公平保证(Priority and Fairness)功能,以提供更细粒度地客户端请求控制。该功能支持将不同用户或不同类型的请求进行优先级归类,保证高优先级的请求总是能够更快得到处理,从而不受低优先级请求的影响。

    设置合适的缓存大小

    APIServer与etcd之间基于gRPC协议进行通信,gRPC协议保证了二者在大规模集群中的数据高速传输。gRPC基于连接复用的HTTP/2协议,即针对相同分组的对象,APIServer和etcd之间共享相同的TCP连接,不同请求由不同的stream传输。

    一个HTTP/2连接有其stream配额 ,配额的大小限制了能支持的并发请求。APIServer提供了集群对象的缓存机制,当客户端发起查询请求时,APIServer默认会将其缓存直接返回给客户端。缓存区大小可以通过参数“–watch-cache-sizes”设置。针对访问请求比较多的对象,适当设置缓存的大小,极大降低对etcd的访问频率,节省了网络调用,降低了对etcd集群的读写压力,从
    而提高对象访问的性能。

    但是APIServer也是允许客户端忽略缓存的,例如客户端请求中ListOption中没有设置resourceVersion,这时APIServer直接从etcd拉取最新数据返回给客户端。客户端应尽量避免此操作,应在ListOption中设置resourceVersion为0,APIServer则将从缓存里面读取数据,而不会直接访问etcd。

    客户端尽量使用长连接

    当查询请求的返回数据较大且此类请求并发量较大时,容易引发TCP链路的阻塞,导致其他查询操作超时。因此基于Kubernetes开发组件时,例如某些DaemonSet和Controller,如果要查询某类对象,应尽量通过长连接ListWatch监听对象变更,避免全量从APIServer获取资源。如果在同一应用程序中,如果有多个Informer监听APIServer资源变化,可以将这些Informer合并,减少和APIServer的长连接数,从而降低对APIServer的压力。

    如何访问APIServer

    对外部客户(user/client/admin),永远只通过LoadBalancer访问
    只有当负载均衡出现故障时,管理员才切换到apiserver IP进行管理
    内部客户端,优先访问cluster IP?(是否一定如此?)
    在这里插入图片描述

    搭建多租户的Kubernetes集群

    在这里插入图片描述

    认证

    在这里插入图片描述

    注册APIService

    在这里插入图片描述

    apimachinery

    回顾GKV
    Group
    Kind
    Version

    • Internel version 和External version
    • 版本转换

    如何定义Group

    在这里插入图片描述

    定义对象类型 types.go

    List
    单一对象数据结构

    • TypeMeta
    • ObjectMeta
    • Spec
    • Status

    代码生成Tags

    在这里插入图片描述

    实现etcd storage

    在这里插入图片描述

    创建和更新对象时的业务逻辑-Strategy

    在这里插入图片描述

    subresource

    在这里插入图片描述

    注册APIGroup

    在这里插入图片描述

    代码生成

    在这里插入图片描述
    https://github.com/kubernetes/code-generator

    hack/update-codegen.sh

    在这里插入图片描述

    APIServer代码

    https://cncamp.notion.site/kube-apiserver-10d5695cbbb14387b60c6d622005583d

    展开全文
  • 则创建此目录 添加/usr/local/apiserver-builder/bin到您的路径 export PATH=$PATH:/usr/local/apiserver-builder/bin 运行apiserver-boot -h 初始化项目 完成 apiserver-boot 安装后,可通过如下命令来初始化一个 ...

    作者

    张鹏,腾讯云容器产品工程师,拥有多年云原生项目开发落地经验。目前主要负责腾讯云 TKE 云原生 AI 产品的开发工作。

    谢远东,腾讯高级工程师,Kubeflow Member、Fluid(CNCF Sandbox) 核心开发者,负责腾讯云 TKE 在 AI 场景的研发和支持工作。

    概述

    随着 Kubernetes 的日趋成熟,越来越多的公司、企业开始使用 K8s 来构建自己的云原生平台,基于 kubernetes 良好的扩展性以及成熟稳定的架构,你可以快速部署并管理自己的云原生应用。

    目前我们也在基于 kubernetes 打造一个云原生 AI 平台(我们称它为:SKAI),该平台具备极致弹性多云兼容性高易用可观测性可复现性的特点,旨在利用云原生的思想和技术,为 AI 场景的数据处理、模型训练、模型上线推理等需求构建弹性可扩展的系统架构,从而提升资源利用率。

    为了使我们的平台更加的云原生,我们没有选择常用的 web 框架来构建 API 服务,而是使用 kubernetes 扩展来构建整个平台,这样使我们的平台能更好的和 kubernetes 融合,可以无缝适配任何基于 k8s 的多云混合云环境。

    为什么选择 Aggregated APIServer?

    选择独立 API 还是 Aggregated APIServer ?

    尽管使用 gin、go-restful 等 go 语言 web 框架可以轻易地构建出一个稳定的 API 接口服务,但以 kubernetes 原生的方式构建 API 接口服务还是有很多优势,例如:

    • 能利用 kubernetes 原生的认证、授权、准入等机制,有更高的开发效率;
    • 能更好的和 K8s 系统融合,借助 K8s 生态更快的推广自己的产品,方便用户上手;
    • 借助于 K8s 成熟的 API 工具及规范,构建出的 API 接口更加规范整齐;

    但是在很多场景下,我们还是不能确定到底使用聚合 API(Aggregated APIServer)还是独立 API 来构建我们的服务,官方为我们提供了两种选择的对比;如果你不能确定使用聚合 API 还是独立 API,下面的表格或许对你有帮助:

    考虑 API 聚合的情况优选独立 API 的情况
    你在开发新的 API你已经有一个提供 API 服务的程序并且工作良好
    你希望可以是使用 kubectl 来读写你的新资源类别不要求 kubectl 支持
    你希望在 Kubernetes UI (如仪表板)中和其他内置类别一起查看你的新资源类别不需要 Kubernetes UI 支持
    你希望复用 Kubernetes API 支持特性你不需要这类特性
    你有意愿取接受 Kubernetes 对 REST 资源路径所作的格式限制,例如 API 组和名字空间。(参阅 API 概述你需要使用一些特殊的 REST 路径以便与已经定义的 REST API 保持兼容
    你的 API 是声明式的你的 API 不符合声明式模型
    你的资源可以自然地界定为集群作用域或集群中某个名字空间作用域集群作用域或名字空间作用域这种二分法很不合适;你需要对资源路径的细节进行控制

    首先我们希望我们的 SKAI 平台能更好的和 k8s 结合,并且它是一个声明式的 API,尽可能的复用 Kubernets API 的特性,显然聚合 API 对我们来说更加适合。

    选择 CRDs 还是 Aggregated APIServer?

    除了聚合 API,官方还提供了另一种方式以实现对标准 kubernetes API 接口的扩展:CRD(Custom Resource Definition ),能达到与聚合 API 基本一样的功能,而且更加易用,开发成本更小,但相较而言聚合 API 则更为灵活。针对这两种扩展方式如何选择,官方也提供了相应的参考。

    通常,如果存在以下情况,CRD 可能更合适:

    • 定制资源的字段不多;
    • 你在组织内部使用该资源或者在一个小规模的开源项目中使用该资源,而不是在商业产品中使用; 聚合 API 可提供更多的高级 API 特性,也可对其他特性进行定制;例如,对存储层进行定制、对 protobuf 协议支持、对 logs、patch 等操作支持。

    两种方式的核心区别是定义 api-resource 的方式不同。在 Aggregated APIServer 方式中,api-resource 是通过代码向 API 注册资源类型,而 Custom Resource 是直接通过 yaml 文件向 API 注册资源类型。

    简单来说就是 CRD 是让 kube-apiserver 认识更多的对象类别(Kind),Aggregated APIServer 是构建自己的 APIServer 服务。虽然 CRD 更简单,但是缺少更多的灵活性,更详细的 CRDs 与 Aggregated API 的对比可参考官方文档

    对于我们而言,我们希望使用更多的高级 API 特性,例如 "logs" 或 "exec",而不仅仅局限于 CRUD ,所以我们最终选择了 Aggregated APIServer 。

    APIServer 扩展的基本原理

    kube-apiserver 作为整个 Kubernetes 集群操作 etcd 的唯一入口,负责 Kubernetes 各资源的认证&鉴权,校验以及 CRUD 等操作,提供 RESTful APIs,供其它组件调用:

    kube-apiserver 其实包含三种 APIServer:

    • AggregatorServer:负责处理 apiregistration.k8s.io 组下的 APIService 资源请求,同时将来自用户的请求拦截转发给 Aggregated APIServer(AA);
    • KubeAPIServer:负责对请求的一些通用处理,包括:认证、鉴权以及各个内建资源(pod, deployment,service)的 REST 服务等;
    • ApiExtensionsServer:负责 CustomResourceDefinition(CRD)apiResources 以及 apiVersions 的注册,同时处理 CRD 以及相应 CustomResource(CR)的REST请求(如果对应 CR 不能被处理的话则会返回404),也是 apiserver Delegation 的最后一环;

    三个 APIServer 通过 delegation 的关系关联,在 kube-apiserver 初始化创建的过程中,首先创建的是 APIExtensionsServer,它的 delegationTarget 是一个空的 Delegate,即什么都不做,继而将 APIExtensionsServer 的 GenericAPIServer,作为 delegationTarget 传给了 KubeAPIServer,创建出了 KubeAPIServer,再然后,将 kubeAPIServer 的 GenericAPIServer 作为 delegationTarget 传给了 AggregatorServer,创建出了 AggregatorServer,所以他们之间 delegation 的关系为: Aggregator -> KubeAPIServer -> APIExtensions,如下图所示:

    如何快速构建 Aggregated APIServer?

    虽然官方提供了一个 sample-apiserver,我们可以参考实现自己的 Aggregated APIServer。但完全手工编写太过复杂,也不便于后期维护,我们最终选择了官方推荐的工具 apiserver-builder,apiserver-builder 可以帮助我们快速创建项目骨架,并且使用 apiserver-builder 构建的项目目录结构比较清晰,更利于后期维护。

    安装 apiserver-builder 工具

    通过 Go Get 安装

    $ GO111MODULE=on go get sigs.k8s.io/apiserver-builder-alpha/cmd/apiserver-boot

    通过安装包安装

    • 下载最新版本
    • 解压到 /usr/local/apiserver-builder/
    • 如果此目录不存在,则创建此目录
    • 添加/usr/local/apiserver-builder/bin到您的路径 export PATH=$PATH:/usr/local/apiserver-builder/bin
    • 运行apiserver-boot -h

    初始化项目

    完成 apiserver-boot 安装后,可通过如下命令来初始化一个 Aggregated APIServer 项目:

    $ mkdir skai-demo
    $ cd skai-demo 
    $ apiserver-boot init repo --domain skai.io

    执行后会生成如下目录:

    .
    ├── BUILD.bazel
    ├── Dockerfile
    ├── Makefile
    ├── PROJECT
    ├── WORKSPACE
    ├── bin
    ├── cmd
    │   ├── apiserver
    │   │   └── main.go
    │   └── manager
    │       └── main.go -> ../../main.go
    ├── go.mod
    ├── hack
    │   └── boilerplate.go.txt
    ├── main.go
    └── pkg
        └── apis
            └── doc.go
    • hack 目录存放自动脚本
    • cmd/apiserver 是 aggregated server的启动入口
    • cmd/manager 是 controller 的启动入口
    • pkg/apis 存放 CR 相关的结构体定义,会在下一步自动生成

    生成自定义资源

    $ apiserver-boot create group version resource --group animal --version v1alpha1 --kind Cat --non-namespaced=false
    Create Resource [y/n]
    y
    Create Controller [y/n]
    n

    可根据自己的需求选择是否生成 Controller,我们这里暂时选择不生成, 对于需要通过 namespace 隔离的 resource 需要增加 --non-namespaced=false 的参数,默认都是 true。

    执行完成后代码结构如下:

    └── pkg
        └── apis
            ├── animal
            │   ├── doc.go
            │   └── v1alpha1
            │       ├── cat_types.go
            │       ├── doc.go
            │       └── register.go
            └── doc.go

    可以看到在 pkg/apis 下生成了 animal 的 group 并在 v1alpha1 版本下新增了 cat_types.go 文件,此文件包含了我们资源的基础定义,我们在 spec 中增加字段定义,并在已经实现的 Validate 方法中完成基础字段的校验。

    // Cat
    // +k8s:openapi-gen=true
    type Cat struct {
            metav1.TypeMeta   `json:",inline"`
            metav1.ObjectMeta `json:"metadata,omitempty"`
            Spec   CatSpec   `json:"spec,omitempty"`
            Status CatStatus `json:"status,omitempty"`
    }
    // CatSpec defines the desired state of Cat
    type CatSpec struct {
        Name string `json:"name"`
    }
    func (in *Cat) Validate(ctx context.Context) field.ErrorList {
        allErrs := field.ErrorList{}
        if len(in.Spec.Name) == 0 {
            allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "name"), in.Spec.Name, "must be specify"))
        }
        return allErrs
    }

    部署运行

    完成以上步骤,你其实已经拥有一个完整的 Aggregated APIServer,接下来我们试着将它运行起来;apiserver-boot 本身提供了两种运行模式:in-cluster、local; local 模式下只作为单独的 API 服务部署在本地方便做调试,过于简单这里不做过多介绍,主要关注一下 in-cluster 模式;in-cluster 可以将你的 Aggregated APIServer 部署在任何 K8s 集群中,例如:minikube,腾讯 TKE,EKS 等,我们这里使用 EKS 集群作为演示。

    创建EKS集群&配置好本地kubeconfig

    执行部署命令 ;

    $ apiserver-boot run in-cluster --image=xxx/skai.io/skai-demo:0.0.1 --name=skai-demo --namespace=default

    在执行部署命令过程中,apiserver-boot 主要帮我们做了如下几件事情:

    • 自动生成 APIServer Dockerfile 文件;
    • 通过 APIServer Dockerfile 构建服务镜像,并将镜像推送到指定仓库;
    • 在config目录下生成 CA 及其他 APIServer 部署需要的证书文件;
    • 在config目录下生成 APIServer 部署需要的 Deployment、Service、APIService、ServiceAccount 等 yaml 文件;
    • 将上一步生成的 yaml 文件部署到集群中;

    功能验证

    确认 Resource 注册成功

    $ kubectl api-versions |grep animal
    animal.skai.io/v1alpha1

    确认 Aggregated APIServer 能正常工作

    $ kubectl get apiservice v1alpha1.animal.skai.io 
    NAME                      SERVICE             AVAILABLE   AGE
    v1alpha1.animal.skai.io   default/skai-demo   True        19h

    创建并查看新增的 Resource

    创建

    $ cat lucky.yaml
    apiVersion: animal.skai.io/v1alpha1
    kind: Cat
    metadata:
      name: mycat
      namespace: default
    spec:
      name: lucky
    # 创建自定义 resource
    $ kubectl apply -f lucky.yaml

    查找

    # 查找自定义 resource 列表
    $ kubectl get cat
    NAME    CREATED AT
    mycat   2021-11-17T09:08:10Z
    # 查找自定义资源详情
    $ kubectl get cat mycat -oyaml
    apiVersion: animal.skai.io/v1alpha1
    kind: Cat
    metadata:
      annotations:
        kubectl.kubernetes.io/last-applied-configuration: |
          {"apiVersion":"animal.skai.io/v1alpha1","kind":"Cat","metadata":{"annotations":{},"name":"mycat"},"spec":{"name":"lucky"}}
      creationTimestamp: "2021-11-17T09:08:10Z"
      name: mycat
      resourceVersion: "17"
      uid: 98af0905-f01d-4042-bad3-71b96c0919f4
    spec:
      name: lucky
    status: {}

    总结

    本文从实战角度出发介绍我们开发 SKAI 平台过程中选择 Aggregated API 的原因,以及 kube-apisever 的扩展原理,最后介绍了 apiserver-builder 工具,并演示如何一步一步构建起自己的 Aggregated API,并将它部署到 EKS 集群中。希望该篇 Aggregated APIServer 最佳实践可以帮助即将使用 K8s API 扩展来构建云原生应用的开发者。

    关于我们

    更多关于云原生的案例和知识,可关注同名【腾讯云原生】公众号~

    福利:

    ①公众号后台回复【手册】,可获得《腾讯云原生路线图手册》&《腾讯云原生最佳实践》~

    ②公众号后台回复【系列】,可获得《15个系列100+篇超实用云原生原创干货合集》,包含Kubernetes 降本增效、K8s 性能优化实践、最佳实践等系列。

    【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

    展开全文
  • Kubernetes安装系列之Master-Apiserver安装

    千次阅读 2019-03-23 21:03:44
    这篇文章整理以下Master节点的apiserver的安装与设定方法,本文以脚本的方式进行固化,内容仍然放在github的easypack上。
  • kubernetes扩展apiserver实现分析

    千次阅读 2020-04-25 20:27:23
    Kubernetes提供了丰富的扩展功能,如果需要实现自定义的资源,通过有两种方式CRD与Aggregation API。相对于CRD扩展API功能更丰富,可以实现单独的存储。今天来聊一聊,k8s是如果实现扩展api,它们直接又是如何协作的...
  • Kubernetes(k8s)API Server详解

    千次阅读 2021-10-31 13:02:52
    文章目录一、概述二、K8s REST API 设计思想三、API 访问1)kubectl 命令行访问方式2...k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。
  • ApiServer的主要功能是 对k8s集群的资源进行CRUD操作,所有的对k8s集群的操作必须通过ApiServerApiServer通过对外提供restful类型的接口向外发布服务;内部kubectl命令也是通过ApiServer执行。其实ApiServer是通过...
  • K8S安装(二) kube-apiserver组件安装

    千次阅读 2020-05-28 21:42:59
    根据架构图,我们的apiserver部署在hdss7-21和hdss7-22上: 首先在hdss7-200上申请证书并拷贝到21和22上: 创建证书文件: # cd /opt/certs # vi client-csr.json { "CN": "k8s-node", "hosts": [ ], ...
  • 客户端请求API Server过程 客户端 --> API Server(识别用户是否有通过api server执行操作的权限)  api Server识别内容:  user: username,uid  group: 用户组  extra: 字段,提供额外信息 客户端请求的API...
  • api服务器 用于服务Venturemark grpc api的守护程序。... helm -n infra install apiserver ./hlm/apiserver --set "apiserver.replica=1" --set "image.tag=f8585a447ff9f226afbfc41b30f100eec3875b07" grpcur
  • kubernetes apiserver限流方案

    千次阅读 2020-11-11 14:24:35
    为了防止突发流量影响apiserver可用性,k8s支持多种限流配置,包括: MaxInFlightLimit,server级别整体限流 Client限流 EventRateLimit, 限制event APF,更细力度的限制配置 MaxInFlightLimit MaxInFlightLimit限...
  • kubernetes-kube-apiserver进程源码分析

    千次阅读 2019-02-17 20:22:30
    kubernetes API server是由kube-apiserver进程实现的,它运行在kubernetes的管理节点—master上并对外提供kubernetes Restful API服务,它提供的主要是与集群管理相关的API服务,例如校验pod、services、replication...
  • Kubernetes集群安全:Api Server认证

    千次阅读 2018-11-11 20:26:13
    Kubernetes提供了三种级别的客户端认证方式: ... ... ...HTTP Token认证和Http Basic认证是相对简单的认证方式,Kubernetes的各组件与Api Server的通信方式仍然是HTTPS,但不再使用CA数字证书。 ...
  • kube-apiserver到3节点 证书制作

    千次阅读 2019-06-18 12:51:52
    使用kubeadm部署k8s集群03-扩容kube-apiserver到3节点 2018/1/3 扩容 kube-apiserver 到 3 节点 配置 kube-apiserver.yaml 分析 kube-apiserver 依赖的证书 为新节点生成专属证书 下发证书到对应的节点 确认...
  • kube-apiserver 配置参数解读(kubernets version 1.12.0) 下面是kube-apiserverversion 1.12.0的所有配置,其中高亮加粗的是我认为需要注意的Flag。 Flag Comments --admission-control-config-file ...
  • 重启 kube-apiserver 组件 重启三个 Master 服务器中全部 kube-apiserver 组件: $ systemctl daemon-reload && systemctl restart kube-apiserver 重启 Metrics Server 应用 查看已有的 metrics server 的 ...
  • kubernetes 简介:API Server 简介

    万次阅读 2017-02-10 16:34:54
    http://cizixs.com/2016/11/07/kubernetes-intro-api-server 简介 ...这篇文章是整个系统的第二篇,上一篇文章讲解了 kubelet 的功能和...API Server 负责和 etcd 交互(其他组件不会直接操作 etcd,只有 API Serv
  • k8s-apiserver工作原理

    千次阅读 2020-06-16 07:25:00
    公众号关注「SY技术小站」设为「星标」,每天带你分享技术与生活!API Serverkube-apiserver 是 Kubernetes 最重要的核心组件之一,主要提供以下的功能提供...
  • 前面一篇文章中介绍了Kubernetes和Prometheus进行集成的常见方式,这篇文章结合具体的示例介绍一下如何监控Kubernetes的Api Server
  • k8s二进制安装-5,安装kube-apiserver

    千次阅读 2021-02-17 09:20:16
    下载kubernetes 二进制文件 cd /usr/local/src/ ...tar xzf kubernetes-server-linux-amd64.tar.gz kubernetes cd kubernetes/server/bin...cp kube-apiserver kube-controller-manager kube-scheduler kubectl /opt/kuber
  • 如何使用curl访问k8s的apiserver

    千次阅读 2019-06-24 16:24:13
    apiserver有三种级别的客户端认证方式 1,HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式 2,HTTP Token认证:通过一个Token来识别合法用户 3,HTTP Base认证:通过用户名+密码的认证方式 通常的运维...
  • K8S:无法正常开启 Kube-apiserver

    千次阅读 2021-04-16 15:39:16
    文章目录K8S:无法正常开启 Kube-apiserver①报错现象②解决过程 K8S:无法正常开启 Kube-apiserver ①报错现象 环境:K8S 单节点二进制部署 主机 IP 组件 master01 192.168.126.11 kube-apiserver、kube-...
  • Kubernetes 之APIServer组件简介

    万次阅读 2018-08-21 11:20:30
    API Server简介 k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。 kubernetes API Server的功能: 提供了集群管理的REST API接口...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 807,532
精华内容 323,012
关键字:

apiserver