Як отримати доступ до api Kubernetes з контейнера стручка?


118

Я раніше вміла згортатися

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

як мою базову URL-адресу, але в kubernetes 0.18.0 він дає мені "несанкціонований". Дивна річ у тому, що якщо я використовував зовнішню IP-адресу API-машини ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/), вона працює чудово.


Де ви запускаєте кластер (GCE, AWS тощо) та використовуєте базу ОС (debian, CoreOS тощо)?
Роберт Бейлі

Vagrant / CoreOS ... я врешті-решт переміщу його до AWS / CoreOS
tslater

Звідки беруться $KUBERNETES_SERVICE_HOSTі $KUBERNETES_PORT_443_TCP_PORTзмінні?
ruediste

Я вважав, що цей посібник є дивовижним для 101 щодо облікових записів служб, ролей та зв’язків ролей developer.ibm.com/recipes/tutorials/… . В останньому розділі докладно описано, як ми можемо отримати доступ до форми API k8 в межах стручок.
viv

Відповіді:


132

В офіційній документації я знайшов таке:

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

Мабуть, мені не вистачало знака безпеки, який мені не знадобився в попередній версії Kubernetes. З цього моменту я придумав, що, на мою думку, є більш простим рішенням, ніж запуск проксі-сервера або встановлення голанг на мій контейнер. Дивіться цей приклад, який отримує інформацію з api для поточного контейнера:

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

Я також використовую простий двійковий файл jq ( http://stedolan.github.io/jq/download/ ) для розбору json для використання в bash-скриптах.


5
Для нещодавно розгорнутих кластерів, які ви можете змінити v1beta3наv1
Eyal Levin

6
Зауважте, що ця команда curl небезпечно підключатиметься до apiserver (що дозволяє людині посередині перехоплювати маркер носія), тому використовувати його слід лише у тому випадку, якщо мережа між стручком і apiserver буде повністю довірена. В іншому випадку вам слід передати --cacertпрапор, щоб згорнутися, щоб curl перевіряв сертифікат, представлений apiserver.
Роберт Бейлі

1
Я повинен був використовувати KUBERNETES_SERVICE_HOST=kubernetes.default, $KUBERNETES_443_TCP_PORT=443, NAMESPACE == $ (</ вар / біг / секрети / kubernetes.io / ServiceAccount / простір імен) . The URL was kubernetes.default: 443 / API / v1 / простір імен / $ NAMESPACE / стручки / ... `. Зауважте, що версія API встановлена ​​на v1 замість v1beta3, а простір імен за замовчуванням було замінено на $ NAMESPACE.
ruediste

74

Кожен стручок автоматично застосовується обліковий запис служби, який дозволяє йому отримати доступ до програми. Обліковий запис сервісу надає як облікові дані клієнта у вигляді маркера носія, так і сертифікат органу сертифікації, який використовувався для підпису сертифіката, представленого прикладником. За допомогою цих двох відомостей ви можете створити захищене, автентифіковане з'єднання з apisever, не використовуючи 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
Слід зазначити, що для того, щоб кацерт і маркер існували в обліковому записі служби, контролеру реплікації слід надати --root-ca-file=аргумент при його запуску. (це обробляється автоматично у більшості установців kubernetes). Дивіться тут обговорення для більш детальної інформації: github.com/kubernetes/kubernetes/isissue/10265
JKnight

7
Я звертався до сервера API із стручка з іншим простором імен. Таким чином, мені довелося використовувати https://kubernetes.default/в якості господаря
ruediste

Офіційний хост, kubernetes.default.svcяк задокументовано на сайті kubernetes.io/docs/tasks/access-application-cluster/…
Мартін Тапп

17

Використання клієнта Python kubernetes ..

from kubernetes import client, config

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

1
Дякую! Ось невеликий репо з прикладом, заснованим на вашій відповіді, щоб спростити гру з цим кодом.
Омер Леві Хевроні

10

версія 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

Найважливішим доповненням до вже згадуваних деталей є те, що струк, з якого ви намагаєтеся отримати доступ до сервера API, повинен мати можливості RBAC для цього.

Кожна сутність в системі k8s ідентифікується обліковим записом служби (наприклад, обліковий запис користувача, який використовується для користувачів). На основі можливостей RBAC заповнюється маркер облікового запису служби (/var/run/secrets/kubernetes.io/serviceaccount/token). Прив'язки kube-api (наприклад, pykube) можуть приймати цей маркер як вхід при створенні з'єднання з kube-api-серверами. Якщо струк має правильні можливості RBAC, він зможе встановити з'єднання з сервером kube-api.


5

Я зіткнувся з цією проблемою, намагаючись отримати доступ до API всередині стручка за допомогою Go Code. Нижче наведено те, що я реалізував, щоб працювати, чи хтось стикається з цим питанням, бажаючи використовувати Go.

У прикладі використовується ресурс стручка, для якого слід використовувати client-goбібліотеку, якщо ви працюєте з нативними об’єктами kubernetes. Код корисніший для тих, хто працює з 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

Зсередини поділки сервер kubernetes api може бути доступний безпосередньо на " https: //kubernetes.default ". За замовчуванням він використовує "обліковий запис служби за замовчуванням" для доступу до сервера api.

Отже, нам також потрібно передати "ca cert" та "маркер облікового запису служби за замовчуванням" для автентифікації з сервером api.

файл сертифіката зберігається в такому місці всередині стручка: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

та маркер облікового запису служби за замовчуванням за адресою: /var/run/secrets/kubernetes.io/serviceaccount/token

Ви можете використовувати клієнт 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

У мене була подібна проблема з автентичністю в GKE, де сценарії python раптом викинули винятки. Рішення, яке працювало для мене, було дати дозвіл стручкам через роль

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

для отримання додаткової інформації введіть опис посилання тут



2

Якщо ввімкнено RBAC, обліковий запис служби за замовчуванням не має дозволів.

Краще створіть окремий обліковий запис сервісу для своїх потреб і використовуйте його для створення свого стручка.

spec:
  serviceAccountName: secret-access-sa
  containers:
    ...

Це добре пояснено тут https://developer.ibm.com/recipes/tutorials/service-accounts-and-auditing-in-kubernetes/


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

Моя версія k8s становить 1.2.0, а в інших версіях вона також повинна працювати ^ ^


Сказане вище правильне, якщо у вас ввімкнено веб-кнопок або інший RBAC. Особливо це стосується> 1,2 з k8s
доктороблівіон

0

This is from the Kubernetes в дії book.

Вам потрібно подбати про автентифікацію . Сам сервер API каже, що ви не маєте права доступу до нього, оскільки він не знає, хто ви .

Для аутентифікації вам потрібен маркер аутентифікації. На щастя, маркер надається через згаданий раніше Secret-маркер за замовчуванням і зберігається у файлі маркера в секретному томі.

Ви будете використовувати маркер для доступу до сервера API . Спочатку завантажте маркер у змінну середовища:

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

Тепер маркер зберігається в змінній середовища TOKEN . Ви можете використовувати його для надсилання запитів на сервер 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"  
      ]
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.