1. 程式人生 > 實用技巧 >如何用Frabic client以serviceAccount方式訪問k8s叢集

如何用Frabic client以serviceAccount方式訪問k8s叢集

一. 以ServiceAccount的方式訪問k8s叢集

k8s支援客戶端通過serviceAccount與RBAC結合的方式訪問kube-apiserver,這種方式便於靈活控制賬戶許可權

1)建立serviceAccount與對應的secret

建立serviceAccount
使用指令碼:kubernetes_add_service_account.sh在qa-k8s-2-master叢集建立serviceAccount: test-sa1

#!/bin/bash
set -e
set -o pipefail

# Add user to k8s using service account, no RBAC (must create RBAC after this script)
if [[ -z "$1" ]] || [[ -z "$2" ]]; then
 echo "usage: $0 <service_account_name> <namespace>"
 exit 1
fi

SERVICE_ACCOUNT_NAME=$1
NAMESPACE="$2"
KUBECFG_FILE_NAME="/tmp/kube/k8s-${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-conf"
TARGET_FOLDER="/tmp/kube"

create_target_folder() {
    echo -n "Creating target directory to hold files in ${TARGET_FOLDER}..."
    mkdir -p "${TARGET_FOLDER}"
    printf "done"
}

create_service_account() {
    echo -e "\\nCreating a service account in ${NAMESPACE} namespace: ${SERVICE_ACCOUNT_NAME}"
    kubectl create sa "${SERVICE_ACCOUNT_NAME}" --namespace "${NAMESPACE}"
}

get_secret_name_from_service_account() {
    echo -e "\\nGetting secret of service account ${SERVICE_ACCOUNT_NAME} on ${NAMESPACE}"
    SECRET_NAME=$(kubectl get sa "${SERVICE_ACCOUNT_NAME}" --namespace="${NAMESPACE}" -o json | jq -r .secrets[].name)
    echo "Secret name: ${SECRET_NAME}"
}

extract_ca_crt_from_secret() {
    echo -e -n "\\nExtracting ca.crt from secret..."
    kubectl get secret --namespace "${NAMESPACE}" "${SECRET_NAME}" -o json | jq \
    -r '.data["ca.crt"]' | base64 -d > "${TARGET_FOLDER}/ca.crt"
    printf "done"
}

get_user_token_from_secret() {
    echo -e -n "\\nGetting user token from secret..."
    USER_TOKEN=$(kubectl get secret --namespace "${NAMESPACE}" "${SECRET_NAME}" -o json | jq -r '.data["token"]' | base64 -d)
    printf "done"
}

set_kube_config_values() {
    context=$(kubectl config current-context)
    echo -e "\\nSetting current context to: $context"

    CLUSTER_NAME=$(kubectl config get-contexts "$context" | awk '{print $3}' | tail -n 1)
    echo "Cluster name: ${CLUSTER_NAME}"

    ENDPOINT=$(kubectl config view \
    -o jsonpath="{.clusters[?(@.name == \"${CLUSTER_NAME}\")].cluster.server}")
    echo "Endpoint: ${ENDPOINT}"

    # Set up the config
    echo -e "\\nPreparing k8s-${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-conf"
    echo -n "Setting a cluster entry in kubeconfig..."
    kubectl config set-cluster "${CLUSTER_NAME}" \
    --kubeconfig="${KUBECFG_FILE_NAME}" \
    --server="${ENDPOINT}" \
    --certificate-authority="${TARGET_FOLDER}/ca.crt" \
    --embed-certs=true

    echo -n "Setting token credentials entry in kubeconfig..."
    kubectl config set-credentials \
    "${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
    --kubeconfig="${KUBECFG_FILE_NAME}" \
    --token="${USER_TOKEN}"

    echo -n "Setting a context entry in kubeconfig..."
    kubectl config set-context \
    "${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
    --kubeconfig="${KUBECFG_FILE_NAME}" \
    --cluster="${CLUSTER_NAME}" \
    --user="${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
    --namespace="${NAMESPACE}"

    echo -n "Setting the current-context in the kubeconfig file..."
    kubectl config use-context "${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
    --kubeconfig="${KUBECFG_FILE_NAME}"
}

create_target_folder
create_service_account
get_secret_name_from_service_account
extract_ca_crt_from_secret
get_user_token_from_secret
set_kube_config_values

echo -e "\\nAll done! Test with:"
echo "KUBECONFIG=${KUBECFG_FILE_NAME} kubectl get pods"
echo "you should not have any permissions by default - you have just created the authentication part"
echo "You will need to create RBAC permissions"
KUBECONFIG=${KUBECFG_FILE_NAME} kubectl get pods

得到serviceAccount與對應secre

[root@qa-k8s-2-master ~]# bash /tmp/kubernetes_add_service_account.sh test-sa1 default
...
  
[root@qa-k8s-2-master ~]# kubectl get serviceaccount test-sa1 -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2019-06-10T09:20:55Z
  name: test-sa1
  namespace: default
  resourceVersion: "19622333"
  selfLink: /api/v1/namespaces/default/serviceaccounts/test-sa1
  uid: 0ced12b2-8b61-11e9-8839-fa163e432469
secrets:
- name: test-sa1-token-zp6vt
...
  
[root@qa-k8s-2-master ~]# kubectl get secret test-sa1-token-zp6vt -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1C......EUtLS0tLQo=
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJ........R1JMdw==
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: test-sa1
    kubernetes.io/service-account.uid: 0ced12b2-8b61-11e9-8839-fa163e432469
  creationTimestamp: 2019-06-10T09:20:55Z
  name: test-sa1-token-zp6vt
  namespace: default
  resourceVersion: "19622332"
  selfLink: /api/v1/namespaces/default/secrets/test-sa1-token-zp6vt
  uid: 0cefd45a-8b61-11e9-8839-fa163e432469
type: kubernetes.io/service-account-token

同時也會生成對應的kubeconfig檔案:

[root@qa-k8s-2-master ~]# cat /tmp/kube/k8s-test-sa1-default-conf
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJ.........LS0tLQo=
    server: https://qa-k8s-2-master:6443
  name: qa-k8s-2-master
contexts:
- context:
    cluster: qa-k8s-2-master
    namespace: default
    user: test-sa1-default-qa-k8s-2-master
  name: test-sa1-default-qa-k8s-2-master
current-context: test-sa1-default-qa-k8s-2-master
kind: Config
preferences: {}
users:
- name: test-sa1-default-qa-k8s-2-master
  user:
    as-user-extra: {}
    token: eyJhbGciOiJ....hGRLw

2)繫結clusterRole

clusterRole cluster-admin擁有k8s叢集中所有資源的讀寫許可權,將test-sa1加入clusterRoleBinding cluster-admin的subjects中

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: 2019-01-30T10:32:45Z
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "19622865"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/cluster-admin
  uid: 619bdffa-247a-11e9-9ccb-fa163e432469
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:masters
- kind: ServiceAccount
  name: test-sa1
  namespace: default

3) kubectl使用test-sa1訪問k8s叢集

指定KUBECONFIG為k8s-test-sa1-default-conf,則可以在任意機器上訪問qa-k8s-2-master叢集

[root@qa-k8s-1-master ~]# scp qa-k8s-2-master:/tmp/kube/k8s-test-sa1-default-conf /tmp/
...
  
[root@qa-k8s-1-master ~]# KUBECONFIG=/tmp/k8s-test-sa1-default-conf kubectl get node
NAME             STATUS    ROLES     AGE       VERSION
10.189.108.144   Ready     <none>    105d      1.9.8.4
10.189.108.145   Ready     <none>    130d      1.9.8.4
10.189.108.146   Ready     <none>    130d      1.9.8.4

4)Java客戶端訪問示例

String k8sEntryPoint = "https://10.199.175.66:6443";
ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(k8sEntryPoint)
      .withRequestTimeout(REQUEST_TIMEOUT).withConnectionTimeout(CONNECTION_TIMEOUT);
 
Config config = configBuilder.build();
config.setCaCertData("LS0tLS1CRUdJTiB....BVEUtLS0tLQo=");
config.setOauthToken("eyJhb......V0TGd_hGRLw");
 
OkHttpClient httpClient = HttpClientUtils.createHttpClient(config);
httpClient.dispatcher().setMaxRequests(MAX_REQUEST);
httpClient.dispatcher().setMaxRequestsPerHost(MAX_REQUEST);
KubernetesClient client = new DefaultKubernetesClient(httpClient, config);
 
NodeList nodeList = client.nodes().list();
for (Node node : nodeList.getItems()) {
    System.out.println(node.getMetadata().getName())
}