Updated on 2024-10-10 GMT+08:00

Service Accounts

All access requests to Kubernetes resources are processed by the API Server, regardless of whether the requests are from an external system. Therefore, the requests must be authenticated and authorized before they are sent to Kubernetes resources.

  • Authentication: authenticates user identities. Kubernetes uses different authentication rules for external and internal service accounts. For details, see Authentication and ServiceAccounts.
  • Authorization: controls users' access to resources. Role-based access control (RBAC) is used to authorize users to access resources. For details, see RBAC.
Figure 1 Authentication and authorization of the API Server

Authentication and ServiceAccounts

Kubernetes users are classified as service accounts (ServiceAccounts) and common accounts.

  • A ServiceAccount is bound to a namespace and associated with a set of credentials. When a pod is created, the token is mounted to the pod so that the pod can be called by the API server.
  • Kubernetes does not come with pre-built objects for managing common accounts. Instead, external services are used for this purpose. For example, CCE users are managed through Identity and Access Management (IAM).

ServiceAccounts in Kubernetes are resources that exist at the namespace level, just like pods and ConfigMaps. When a namespace is created, the system automatically generates a ServiceAccount named default in the namespace.

You can run the following command to check ServiceAccounts:

kubectl get sa

NAME     SECRETS   AGE
default  1         30d
  • In clusters earlier than v1.21, a token is obtained by mounting the secret of the service account to a pod. Tokens obtained this way are permanent. This approach is no longer recommended starting from version 1.21. Service accounts will stop auto creating secrets in clusters from version 1.25.

    In clusters of version 1.21 or later, you can use the TokenRequest API to obtain the token and use the projected volume to mount the token to the pod. Such tokens are valid for a fixed period. When the mounting pod is deleted, the token automatically becomes invalid. For details, see Service Account Token Security Improvement.

  • If you need a token that never expires, you can also manually manage secrets for service accounts. Although a permanent service account token can be manually created, you are advised to use a short-lived token by calling the TokenRequest API for higher security.

In clusters earlier than 1.25, a secret is automatically created for each ServiceAccount. In clusters 1.25 or later, a secret is not automatically created for each ServiceAccount. The following describes how to check the statuses of ServiceAccounts in clusters earlier than 1.25 and in clusters 1.25 or later.

  • In a cluster earlier than 1.25, run the following command to check the status of the default ServiceAccount.

    kubectl describe sa default

    If information similar to the following is displayed, the default-token-vssmw secret is automatically created for the ServiceAccount.

    Name:                  default
    Namespace:             default
    Labels:                <none>
    Annotations:           <none>
    Image pull secrets:    <none>
    Mountable secrets:     default-token-vssmw
    Tokens:                default-token-vssmw
    Events:                <none>
  • In a cluster 1.25 or later, run the following command to check the status of the default ServiceAccount.

    kubectl describe sa default

    According to the command output, no secret is automatically created for the default ServiceAccount.
    Name:                     default
    Namespace:                default 
    Labels:                   <none>
    Annotations:              <none>
    Image pull secrets:       <none>
    Mountable secrets:        <none>
    Tokens:                   <none>
    Events:                   <none>

When defining a pod, you can assign a ServiceAccount to it by specifying the account name in the file. If no account name is specified, the default ServiceAccount will be used. When receiving a request with an authentication token, the API Server uses the token to check whether the ServiceAccount associated with the client that sends the request allows the request to be executed.

Creating a ServiceAccount

  1. Take a cluster 1.29 as an example. Run the following command to create a ServiceAccount in the default namespace:

    kubectl create serviceaccount sa-example

    serviceaccount/sa-example created

    Run the following command to check whether sa-example has been created. If sa-example is displayed in the NAME column, it has been created.

    kubectl get sa

    NAME            SECRETS   AGE
    default         1         30d
    sa-example      0         2s

    Because the cluster version used in this case is later than 1.25, the ServiceAccount will not have a secret created automatically. To check if a secret was created, use the following command to view the ServiceAccount details. If the output shows none for Mountable secrets and Tokens, then no secret was automatically created for the ServiceAccount.

    kubectl describe sa sa-example

    Name:                   sa-example
    Namespace:              default
    Labels:                 <none>
    Annotations:            <none>
    Image pull secrets:     <none>
    Mountable secrets:      <none>
    Tokens:                 <none>
    Events:                 <none>

  2. In this example, manually manage the secret to obtain a token that never expires. Use the following command to manually create a secret named sa-example-token and associate it with the sa-example ServiceAccount.

    kubectl apply -f - <<EOF
    apiVersion: v1 
    kind: Secret 
    metadata:
      namespace: default   
      name: sa-example-token   
      annotations:     
        kubernetes.io/service-account.name: sa-example 
    type: kubernetes.io/service-account-token 
    EOF

  3. Check whether sa-example-token has been created. If sa-example-token is present in secrets of the default namespace, then it has been created.

    kubectl get secrets

    NAME                        TYPE                                    DATA        AGE
    default-secret              kubernetes.io/dockerconfigjson          1           6d20h
    paas.elb                    cfe/secure-opaque                       1           6d20h
    sa-example-token            kubernetes.io/service-account-token     3           16s

    Check the secret content. You can find the ca.crt, namespace, and token data.

    kubectl describe secret sa-example-token

    Name:         sa-example-token
    Namespace:    default
    Labels:       <none>
    Annotations:  kubernetes.io/service-account.name: sa-example
                  kubernetes.io/service-account.uid: 4b7d3e19-1dfe-4ee0-bb49-4e2e0c3c5e25
    
    Type:  kubernetes.io/service-account-token
    
    Data
    ====
    ca.crt:     1123 bytes
    namespace:  7 bytes
    token:      eyJhbGciOiJSU...

  4. Check whether the ServiceAccount has been associated with the new secret, meaning if the ServiceAccount has obtained the token. The command output shows that sa-example is associated with sa-example-token.

    kubectl describe sa sa-example

    Name:                 sa-example
    Namespace:            default
    Labels:               <none>
    Annotations:          <none>
    Image pull secrets:   <none>
    Mountable secrets:    <none>
    Tokens:               sa-example-token
    Events:               <none>

Using a ServiceAccount in a Pod

It is convenient to use a ServiceAccount in a pod. You only need to specify the name of the ServiceAccount. The following uses nginx:latest as an example to describe how to use a ServiceAccount in a pod.

  1. Create a description file named sa-pod.yaml. mysql.yaml is an example file name. You can rename it as required.

    vim sa-pod.yaml

    To enable the pod to use the token from the manually created secret, you must mount the secret to the container. For details about how to mount the secret, see the code in bold in the description file.

    The file content is as follows:

    apiVersion: v1
    kind: Pod
    metadata:
      name: sa-pod
    spec:
      serviceAccountName: sa-example                  #  Specify sa-example as the ServiceAccount used by the pod.
      imagePullSecrets:
      - name: default-secret
      containers:
      - image: nginx:latest
        name: container-0
        resources:
          limits:
            cpu: 100m
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:                             #  Mount the storage volume named secret-volume to the pod.
        - name: secret-volume
          readOnly: true                          #  The mounted storage volume is read-only.
          mountPath: "/etc/secret-volume"         #  Mount path of the storage volume in the container, which can be customized
      volumes:                                    #  Define a secret volume that can be used by the pod.
      - name: secret-volume                       #   Name of the secret volume, which can be customized
        secret:                                   #  Set the type of the storage volume to Secret.
          secretName: sa-example-token            #  Mount sa-example-token to the defined storage volume.

  2. Create a pod and view its details. You can see that sa-example-token is mounted to the pod. The pod uses the token for authentication.

    kubectl create -f sa-pod.yaml

    The command output is as follows:

    pod/sa-pod created

    Use the following command to check whether the pod has been created:

    kubectl get pod

    In the command output, if sa-pod is in the Running state, the pod has been created.

    NAME                     READY   STATUS              RESTARTS   AGE
    sa-pod               1/1     running             0          5s

  3. View the sa-pod details and check whether sa-example-token has been mounted to the pod.

    kubectl describe pod sa-pod

    The command output is as follows:

    ...
    Containers:
      container-0:
        Container ID:   
        Image:          nginx:latest
        Image ID:       
        Port:           <none>
        Host Port:      <none>
        State:          Waiting
          Reason:       ImagePullBackOff
        Ready:          False
        Restart Count:  0
        Limits:
          cpu:     100m
          memory:  200Mi
        Requests:
          cpu:        100m
          memory:     200Mi
        Environment:  <none>
        Mounts:
           #  The sa-example-token has been mounted to the pod, and the pod can use the token for authentication.
          /etc/secret-volume from secret-volume (ro)                                 
           #  Automatically mounted TokenRequest, which can provide a short-term token
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-2s4sw (ro)  
    ...

    You can also run the following command to view the corresponding files in the pod. (The path after cd is the same as the mount path of secret-volume.)

    kubectl exec -it sa-pod -- /bin/sh

    cd /etc/secret-volume

    ls

    The command output is as follows:

    ca.crt     namespace  token

  4. Verify that the manually created ServiceAccount token can work.

    1. In a Kubernetes cluster, a Service named kubernetes is created for the API Server by default. Pods can be accessed through this Service. After exiting the pod by pressing Ctrl+D, you can run the following command to view the detailed information about the Service:

      kubectl get svc

      The command output is as follows:

      NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
      kubernetes     ClusterIP   10.247.0.1       <none>        443/TCP          34
    2. Access the pod and check whether the pod can access pod resources in the cluster through the API Server without using the token.

      kubectl exec -it sa-pod -- /bin/sh

      curl https://10.247.0.1:443/api/v1/namespaces/default/pods

      If information similar to the following is displayed, the pod cannot directly access pod resources in the cluster through the API Server.

      curl: (60) SSL certificate problem: unable to get local issuer certificate
      More details here: https://curl.se/docs/sslcerts.html
      
      curl failed to verify the legitimacy of the server and therefore could not
      establish a secure connection to it. To learn more about this situation and
      how to fix it, please visit the web page mentioned above.
    3. Configure the environment variables of ca.crt. Add the path of ca.crt to the CURL_CA_BUNDLE environment variable, which instructs the curl command to use the certificate file as the trust anchor.

      export CURL_CA_BUNDLE = /etc/secret-volume/ca.crt

    4. Add the token content to TOKEN.

      TOKEN=$(cat /etc/secret-volume/token)

      Check whether TOKEN has been configured.

      echo $TOKEN

      If information similar to the following is displayed, the TOKEN has been configured as expected.

      eyJhbGciOiJSUzI1NiIsImtpZCI6I...
    5. Access the API Server using the configured TOKEN.

      curl -H "Authorization: Bearer $TOKEN" https://10.247.0.1:443/api/v1/namespaces/default/pods

      If information similar to the following is displayed, it means that the pod has passed authentication and the manually created ServiceAccount token is in effect. (If the API Server returns cannot get path \"/api/v1/namespaces/default/pods\"", the pod does not have the access permissions. The pod can access the API Server only after being authorized. For details about the authorization mechanism, see RBAC.)

      "kind": "PodList",
        "apiVersion": "v1",
        "metadata": {
          "resourceVersion": "13267712"
        },
        "items": [
          {
            "metadata": {
              "name": "hpa-example-77b9b446f6-nc7b6",
      ...