Làm cách nào để truy cập api Kubernetes từ bên trong vùng chứa nhóm?


118

Tôi đã từng có thể uốn tóc

https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1beta3/namespaces/default/

là URL cơ sở của tôi, nhưng trong kubernetes 0.18.0, nó cho tôi "trái phép". Điều kỳ lạ là nếu tôi sử dụng địa chỉ IP bên ngoài của máy API ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/), nó vẫn hoạt động tốt.


Bạn đang chạy cụm của mình ở đâu (GCE, AWS, v.v.) và sử dụng hệ điều hành cơ bản nào (debian, CoreOS, v.v.)?
Robert Bailey

Vagrant / CoreOS ... cuối cùng tôi sẽ chuyển nó sang AWS / CoreOS
tslater

Các $KUBERNETES_SERVICE_HOST$KUBERNETES_PORT_443_TCP_PORTbiến đến từ đâu?
ruediste

Tôi thấy hướng dẫn này thật tuyệt vời cho 101 tài khoản dịch vụ, vai trò và liên kết vai trò developer.ibm.com/recipes/tutorials/… . Phần cuối cùng nêu chi tiết cách chúng tôi có thể truy cập biểu mẫu API k8 trong các nhóm.
viv

Câu trả lời:


132

Trong tài liệu chính thức, tôi tìm thấy điều này:

https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod

Rõ ràng tôi đã thiếu mã thông báo bảo mật mà tôi không cần trong phiên bản Kubernetes trước đó. Từ đó, tôi nghĩ ra giải pháp đơn giản hơn là chạy proxy hoặc cài đặt golang trên vùng chứa của mình. Hãy xem ví dụ này để lấy thông tin, từ api, cho vùng chứa hiện tại:

KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" \
      https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME

Tôi cũng sử dụng bao gồm một nhị phân đơn giản, jq ( http://stedolan.github.io/jq/download/ ), để phân tích cú pháp json để sử dụng trong các tập lệnh bash.


5
Đối với các cụm gần đây được triển khai, bạn có thể muốn thay đổi v1beta3đểv1
Eyal Levin

6
Lưu ý rằng lệnh curl này sẽ kết nối không an toàn với apiserver (khiến người trung gian có thể chặn mã thông báo mang tên), vì vậy bạn chỉ nên sử dụng nó nếu mạng giữa pod và apiserver được tin cậy hoàn toàn. Nếu không, bạn nên chuyển --cacertcờ để cuộn lại để curl xác thực chứng chỉ do apiserver trình bày.
Robert Bailey

1
Tôi đã phải sử dụng KUBERNETES_SERVICE_HOST=kubernetes.default, $KUBERNETES_443_TCP_PORT=443NAMESPACE == $ (</ var / run / secret / kubernetes.io / serviceaccount / namespace) . The URL was kubernetes.default: 443 / api / v1 / namespaces / $ NAMESPACE / pods /… '. Lưu ý rằng phiên bản API được đặt thành v1 thay vì v1beta3 và không gian tên mặc định được thay thế bằng $ NAMESPACE.
ruediste

74

Mỗi nhóm đều có một tài khoản dịch vụ được áp dụng tự động cho phép nhóm đó truy cập apiserver. Tài khoản dịch vụ cung cấp cả thông tin đăng nhập của khách hàng, dưới dạng mã thông báo mang và chứng chỉ của tổ chức phát hành chứng chỉ được sử dụng để ký chứng chỉ do apiserver trình bày. Với hai phần thông tin này, bạn có thể tạo một kết nối an toàn, được xác thực tới apisever mà không cần sử dụng curl -k(aka curl --insecure):

curl -v --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/

2
Cần lưu ý rằng để cacert và mã thông báo đều tồn tại trong tài khoản dịch vụ, bộ điều khiển sao chép phải được cung cấp một --root-ca-file=đối số khi bắt đầu. (điều này được xử lý tự động trong hầu hết các trình cài đặt kubernetes). Xem cuộc thảo luận tại đây để biết thêm chi tiết: github.com/kubernetes/kubernetes/issues/10265
JKnight

7
Tôi đang truy cập máy chủ API từ một nhóm có không gian tên khác. Vì vậy, tôi phải sử dụng https://kubernetes.default/làm máy chủ lưu trữ
ruediste

Máy chủ chính thức được kubernetes.default.svcghi lại tại kubernetes.io/docs/tasks/access-application-cluster/…
Martin Tapp

17

Sử dụng ứng dụng Python kubernetes ..

from kubernetes import client, config

config.load_incluster_config()
v1_core = client.CoreV1Api()

1
Cảm ơn! Đây là một repo nhỏ với một ví dụ, dựa trên câu trả lời của bạn, để giúp bạn chơi với mã này đơn giản hơn.
Omer Levi Hevroni

10

phiên bản wget:

KUBE_TOKEN=$(</var/run/secrets/kubernetes.io/serviceaccount/token)    
wget -vO- --ca-certificate /var/run/secrets/kubernetes.io/serviceaccount/ca.crt  --header "Authorization: Bearer $KUBE_TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME

6

Phụ lục quan trọng nhất đối với các chi tiết đã được đề cập ở trên là nhóm mà bạn đang cố gắng truy cập máy chủ API phải có khả năng RBAC để làm như vậy.

Mỗi thực thể trong hệ thống k8s được xác định bởi một tài khoản dịch vụ (giống như tài khoản người dùng đang được sử dụng cho người dùng). Dựa trên khả năng của RBAC, mã thông báo tài khoản dịch vụ (/var/run/secrets/kubernetes.io/serviceaccount/token) được điền. Các liên kết kube-api (ví dụ: pykube) có thể lấy mã thông báo này làm đầu vào khi tạo kết nối với các máy chủ kube-api. Nếu nhóm có khả năng RBAC phù hợp, nhóm sẽ có thể thiết lập kết nối với máy chủ kube-api.


5

Tôi đã gặp phải sự cố này khi cố gắng truy cập API từ bên trong một nhóm bằng cách sử dụng Go Code. Dưới đây là những gì tôi đã triển khai để làm cho nó hoạt động, nếu ai đó gặp câu hỏi này cũng muốn sử dụng Go.

Ví dụ sử dụng tài nguyên nhóm mà bạn nên sử dụng client-gothư viện nếu bạn đang làm việc với các đối tượng kubernetes bản địa. Mã này hữu ích hơn cho những người làm việc với CustomResourceDefintions.

serviceHost := os.GetEnv("KUBERNETES_SERVICE_HOST")
servicePort := os.GetEnv("KUBERNETES_SERVICE_PORT")
apiVersion := "v1" // For example
namespace := default // For example
resource := "pod" // For example
httpMethod := http.MethodGet // For Example

url := fmt.Sprintf("https://%s:%s/apis/%s/namespaces/%s/%s", serviceHost, servicePort, apiVersion, namespace, resource)

u, err := url.Parse(url)
if err != nil {
  panic(err)
}
req, err := http.NewRequest(httpMethod, u.String(), bytes.NewBuffer(payload))
if err != nil {
    return err
}

caToken, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
    panic(err) // cannot find token file
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(caToken)))

caCertPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
if err != nil {
    return panic(err) // Can't find cert file
}
caCertPool.AppendCertsFromPEM(caCert)

client := &http.Client{
  Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
        RootCAs: caCertPool,
    },
  },
}

resp, err := client.Do(req)
if err != nil {
    log.Printf("sending helm deploy payload failed: %s", err.Error())
    return err
}
defer resp.Body.Close()

// Check resp.StatusCode
// Check resp.Status

4

Từ bên trong pod, máy chủ api kubernetes có thể được truy cập trực tiếp trên " https: //kubernetes.default ". Theo mặc định, nó sử dụng "tài khoản dịch vụ mặc định" để truy cập máy chủ api.

Vì vậy, chúng tôi cũng cần chuyển "ca cert" và "mã thông báo tài khoản dịch vụ mặc định" để xác thực với máy chủ api.

tệp chứng chỉ được lưu trữ tại vị trí sau bên trong pod: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

và mã thông báo tài khoản dịch vụ mặc định tại: /var/run/secrets/kubernetes.io/serviceaccount/token

Bạn có thể sử dụng ứng dụng khách nodejs kubbernetes godaddy .

let getRequestInfo = () => {
    return {
        url: "https://kubernetes.default",
        ca:   fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt').toString(),
        auth: {
            bearer: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token').toString(),
        },
        timeout: 1500
    };
}

let initK8objs = () =>{
    k8obj = getRequestInfo();
    k8score = new Api.Core(k8obj),
    k8s = new Api.Api(k8obj);
}


3

Tôi đã gặp sự cố auth tương tự trên GKE trong đó tập lệnh python đột nhiên ném ra các ngoại lệ. Giải pháp phù hợp với tôi là cấp quyền cho nhóm thông qua vai trò

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: fabric8-rbac
subjects:
  - kind: ServiceAccount
  # Reference to upper's `metadata.name`
  name: default
  # Reference to upper's `metadata.namespace`
  namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

để biết thêm thông tin nhập mô tả liên kết tại đây




0
curl -v -cacert <path to>/ca.crt --cert <path to>/kubernetes-node.crt --key <path to>/kubernetes-node.key https://<ip:port>

Phiên bản k8s của tôi là 1.2.0 và trong các phiên bản khác, nó cũng phải hoạt động ^ ^


Ở trên là chính xác nếu bạn đã bật webhook hoặc một số RBAC khác. Điều này đặc biệt đúng> 1.2 k8s
doktoroblivion

0

This is from the Kubernetes Đang hoạt động book.

Bạn cần phải chăm sóc xác thực . Bản thân máy chủ API cho biết bạn không được phép truy cập nó, vì nó không biết bạn là ai .

Để xác thực, bạn cần có mã xác thực. May mắn thay, mã thông báo được cung cấp thông qua Bí mật mã thông báo mặc định đã đề cập trước đó và được lưu trữ trong tệp mã thông báo trong tập tin bí mật.

Bạn sẽ sử dụng mã thông báo để truy cập máy chủ API . Đầu tiên, tải mã thông báo vào một biến môi trường:

root@myhome:/# TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

Mã thông báo hiện được lưu trữ trong biến môi trường TOKEN . Bạn có thể sử dụng nó khi gửi yêu cầu đến máy chủ API:

root@curl:/# curl -H "Authorization: Bearer $TOKEN"  https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME
   {  "paths": 
      [    
        "/api",    
        "/api/v1",   
        "/apis",    
        "/apis/apps",    
        "/apis/apps/v1beta1",    
        "/apis/authorization.k8s.io",        
         ...    
        "/ui/",    
        "/version"  
      ]
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.