ポッドコンテナー内から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など)を使用していますか?
ロバートベイリー

Vagrant / CoreOS ... iは最終的にAWS / CoreOSに移動します
tslater 2015年

どこか$KUBERNETES_SERVICE_HOST$KUBERNETES_PORT_443_TCP_PORT変数から来ますか?
ruediste 2017年

このガイドは、サービスアカウント、ロール、ロールバインディングのdeveloper.ibm.com/recipes/tutorials/…で101にとってすばらしいものであることがわかりました。最後のセクションでは、ポッド内で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
エヤルレビン

6
このcurlコマンドは安全にapiserverに接続しないため(中間者がベアラートークンを傍受できるようにするため)、ポッドとapiserverの間のネットワークが完全に信頼されている場合にのみ使用する必要があります。そうでない場合は、--cacertcurlにフラグを渡して、curlがapiserverによって提示された証明書を検証するようにする必要があります。
Robert Bailey

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 2017年

74

すべてのポッドには、apiserverへのアクセスを許可するサービスアカウントが自動的に適用されます。サービスアカウントは、ベアラートークンの形式でクライアント認証情報と、apiserverによって提示された証明書に署名するために使用された認証局証明書の両方を提供します。これらの2つの情報を使用すると、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とトークンの両方がサービスアカウントに存在するためには、レプリケーションコントローラーの--root-ca-file=起動時に引数を指定する必要があることに注意してください。(これは、ほとんどのkubernetesインストーラーで自動的に処理されます)。詳細については、こちらのディスカッションを参照してください:github.com/kubernetes/kubernetes/issues/10265
JKnight

7
名前空間が異なるポッドからAPIサーバーにアクセスしていました。したがってhttps://kubernetes.default/、ホストとして使用しなければなり
ませんでした

公式ホストはkubernetes.default.svckubernetes.io / docs / tasks / access
Martin

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コードを使用してポッド内から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サーバーへのアクセスに「デフォルトのサービスアカウント」を使用します。

したがって、APIサーバーで認証するために、「ca cert」と「default service account token」も渡す必要があります。

証明書ファイルは、ポッド内の次の場所に保存されています:/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ですが、他のバージョンでも動作するはずです^ ^


上記は、Webhookまたはその他のRBACが有効になっている場合は正しいです。これは特に当てはまります> k8sの1.2
ドクトロブリビオン

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.