포드 컨테이너 내에서 Kubernetes API에 액세스하려면 어떻게해야합니까?


118

나는 컬을 할 수 있었다

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

내 기본 URL로 사용하지만 kubernetes 0.18.0에서는 "승인되지 않음"을 제공합니다. 이상한 점은 API 머신 ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/) 의 외부 IP 주소를 사용하면 제대로 작동한다는 것입니다.


클러스터 (GCE, AWS 등)를 어디에서 실행하고 있으며 어떤 기본 OS (debian, CoreOS 등)를 사용하고 있습니까?
Robert Bailey

Vagrant / CoreOS ... i는 결국이를 AWS / CoreOS로 옮길 것입니다
tslater

$KUBERNETES_SERVICE_HOST$KUBERNETES_PORT_443_TCP_PORT변수의 출처는 어디 입니까?
ruediste

나는이 가이드가 서비스 계정, 역할 및 역할 바인딩에 대한 101 명에게 놀랍다는 것을 알았다 . developer.ibm.com/recipes/tutorials/… . 마지막 섹션에서는 포드 내에서 k8 API 양식에 액세스하는 방법을 자세히 설명합니다.
viv

답변:


132

공식 문서에서 다음을 발견했습니다.

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

분명히 이전 버전의 Kubernetes에서 필요하지 않은 보안 토큰이 누락되었습니다. 그로부터 프록시를 실행하거나 컨테이너에 golang을 설치하는 것보다 더 간단한 솔루션을 고안했습니다. 현재 컨테이너에 대한 정보를 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

또한 bash 스크립트에서 사용하기 위해 json을 구문 분석하기 위해 간단한 바이너리 jq ( http://stedolan.github.io/jq/download/ )를 사용합니다.


5
최근에 배치 클러스터의 경우에는 변경할 수 있습니다 v1beta3v1
Eyal 님 레빈

6
이 curl 명령은 apiserver에 안전하지 않게 연결 되므로 (중간자 (man-in-the-middle)가 전달자 토큰을 가로 챌 수 있음), 포드와 apiserver 간의 네트워크가 완전히 신뢰할 수있는 경우에만 사용해야합니다. 그렇지 않으면 --cacertcurl이 apiserver에서 제공 한 인증서의 유효성을 검사하도록 curl에 플래그를 전달해야합니다 .
로버트 베일리

1
내가 사용했다 KUBERNETES_SERVICE_HOST=kubernetes.default, $KUBERNETES_443_TCP_PORT=443네임 스페이스 == $ (<은 / var / 실행 / 비밀 / kubernetes.io / serviceaccount / 네임 스페이스) . The URL was kubernetes.default : 443 / API / V1 / 네임 스페이스 / $ NAMESPACE / 포드 / ... `. API 버전은 v1beta3 대신 v1로 설정되고 기본 네임 스페이스는 $ NAMESPACE로 대체되었습니다.
ruediste

74

모든 pod에는 apiserver에 액세스 할 수있는 서비스 계정이 자동으로 적용됩니다. 서비스 계정은 전달자 토큰 형식의 클라이언트 자격 증명과 apiserver에서 제공 한 인증서에 서명하는 데 사용 된 인증 기관 인증서를 모두 제공합니다. 이 두 가지 정보를 사용하면 curl -k(일명 curl --insecure) 을 사용하지 않고도 apisever에 대한 보안 인증 연결을 만들 수 있습니다 .

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
cacert와 token이 모두 서비스 계정에 존재하려면 --root-ca-file=시작시 복제 컨트롤러에 인수 가 제공되어야합니다 . (대부분의 kubernetes 설치 프로그램에서 자동으로 처리됩니다). 자세한 내용은 여기에서 토론을 참조하십시오. github.com/kubernetes/kubernetes/issues/10265
JKnight

7
네임 스페이스가 다른 포드에서 API 서버에 액세스했습니다. 따라서 나는 https://kubernetes.default/호스트 로 사용해야 했다
ruediste

공식 호스트는 kubernetes.io/docs/tasks/access-application-cluster/…에kubernetes.default.svc 문서화되어 있습니다.
Martin Tapp

17

Python kubernetes 클라이언트 사용 ..

from kubernetes import client, config

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

1
감사! 다음은 이 코드로 더 쉽게 플레이 할 수 있도록 답변을 기반으로 한 예제 가있는 작은 저장소 입니다.
Omer Levi Hevroni

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-servers에 연결할 때이 토큰을 입력으로 사용할 수 있습니다. 포드에 올바른 RBAC 기능이있는 경우 포드는 kube-api 서버와의 연결을 설정할 수 있습니다.


5

Go Code를 사용하여 포드 내부에서 API에 액세스하려고 할 때이 문제가 발생했습니다. 아래는 누군가 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'및 'default service account token'을 전달하여 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

Python 스크립트에서 갑자기 예외가 발생하는 GKE에서 유사한 인증 문제가 발생했습니다. 나를 위해 일한 해결책은 역할을 통해 포드에 권한을 부여하는 것이 었습니다.

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

자세한 내용을 보려면 여기에 링크 설명을 입력하십시오.




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가 활성화 된 경우 위의 내용이 정확합니다. 이것은 특히 k8s의 1.2보다 큰 사실입니다
doktoroblivion

0

This is from the 실행중인 Kubernetes book.

인증 처리가 필요 합니다 . API 서버 자체는 사용자가 누구인지 모르기 때문에 액세스 권한이 없다고 말합니다 .

인증하려면 인증 토큰 이 필요합니다 . 운 좋게도 토큰은 앞서 언급 한 기본 토큰 시크릿을 통해 제공되며 시크릿 볼륨의 토큰 파일에 저장됩니다.

당신이 사용하는거야 토큰 은 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"  
      ]
  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.