kubernetes Amazon EKS:通过python脚本生成/更新kubeconfig

1rhkuytd  于 2023-01-12  发布在  Kubernetes
关注(0)|答案(4)|浏览(164)

当使用Amazon的K8s产品EKS服务时,有时候需要将Kubernetes API和配置连接到AWS中建立的基础设施。特别是我们需要一个具有适当凭据和URL的 kubeconfig 来连接到EKS提供的k8s控制平面。
Amazon命令行工具aws为此任务提供了一个例程

aws eks update-kubeconfig --kubeconfig /path/to/kubecfg.yaml --name <EKS-cluster-name>

问题:通过Python/boto 3执行相同操作

在查看Boto API documentation时,我似乎找不到上面提到的aws例程的等价物,也许我看错了地方。

  • boto 中是否有现成的函数来实现这一点?
  • 否则,如何在python中直接处理这个问题(而不是在子进程中调用aws)?
svmlkihl

svmlkihl1#

没有方法函数可以完成这一操作,但您可以自己构建配置文件,如下所示:

# Set up the client
s = boto3.Session(region_name=region)
eks = s.client("eks")

# get cluster details
cluster = eks.describe_cluster(name=cluster_name)
cluster_cert = cluster["cluster"]["certificateAuthority"]["data"]
cluster_ep = cluster["cluster"]["endpoint"]

# build the cluster config hash
cluster_config = {
        "apiVersion": "v1",
        "kind": "Config",
        "clusters": [
            {
                "cluster": {
                    "server": str(cluster_ep),
                    "certificate-authority-data": str(cluster_cert)
                },
                "name": "kubernetes"
            }
        ],
        "contexts": [
            {
                "context": {
                    "cluster": "kubernetes",
                    "user": "aws"
                },
                "name": "aws"
            }
        ],
        "current-context": "aws",
        "preferences": {},
        "users": [
            {
                "name": "aws",
                "user": {
                    "exec": {
                        "apiVersion": "client.authentication.k8s.io/v1alpha1",
                        "command": "heptio-authenticator-aws",
                        "args": [
                            "token", "-i", cluster_name
                        ]
                    }
                }
            }
        ]
    }

# Write in YAML.
config_text=yaml.dump(cluster_config, default_flow_style=False)
open(config_file, "w").write(config_text)
eqqqjvef

eqqqjvef2#

这在https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.htmlCreate kubeconfig manually 一节中有解释,实际上是从boto 3 EKS文档中引用的。这里的manual方法与@jaxxstorm的答案非常相似,除了它没有显示你需要的python代码,但是它也没有假设heptio验证器(它显示了令牌和IAM验证器的方法)。

u5i3ibmn

u5i3ibmn3#

我遇到了同样的问题,决定将其实现为Python包,可以通过

pip install eks-token

然后简单地

from eks_token import get_token
response = get_token(cluster_name='<value>')

更多详情和示例here

ffdz8vbo

ffdz8vbo4#

Amazon的aws工具包含在python包awscli中,所以一个选择是将awscli添加为python依赖项,然后从python调用它,下面的代码假设kubectl已经安装(但是如果你愿意,你可以删除测试)。

kubeconfig取决于~/.aws/credentials

这里的一个挑战是aws生成的kubeconfig文件有一个用户部分,如下所示:

users:
- name: arn:aws:eks:someregion:1234:cluster/somecluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - --region
      - someregion
      - eks
      - get-token
      - --cluster-name
      - somecluster
      command: aws

因此,如果你把它挂载到一个容器或移动到不同的机器,你会得到这个错误,当你尝试使用它:

Unable to locate credentials. You can configure credentials by running "aws configure".

根据该用户部分,kubectl正在运行aws eks get-token,并且由于~/.aws目录不具有生成kubeconfig文件时所具有的凭据而失败。
您可以通过在您想要使用kubeconfig文件的任何地方暂存~/.aws目录来解决这个问题,但是我有一个自动化程序,它将一个单独的kubeconfig文件作为参数,所以我将修改用户部分,以包括必要的秘密作为env变量。
要知道,这使得任何人都有可能得到kubeconfig文件,使用我们包含的秘密做其他事情,这是否是一个问题将取决于你的aws用户有多大的权力。

承担角色

如果集群使用RBAC,则可能需要为kubeconfig文件指定所需的角色。下面的代码首先生成一组单独的cred,然后使用它们来生成kubeconfig文件。
角色假设有一个超时(我在下面使用12小时),所以如果您不能在令牌超时之前管理您的恶作剧,您将需要再次调用脚本。

代码

您可以生成如下文件:

pip install awscli boto3 pyyaml sh
python mkkube.py > kubeconfig

...如果将以下内容放入mkkube.py

from pathlib import Path
from tempfile import TemporaryDirectory
from time import time

import boto3
import yaml
from sh import aws, sh

aws_access_key_id = "AKREDACTEDAT"
aws_secret_access_key = "ubREDACTEDaE"
role_arn = "arn:aws:iam::1234:role/some-role"
cluster_name = "mycluster"
region_name = "someregion"

# assume a role that has access
sts = boto3.client(
    "sts",
    aws_access_key_id=aws_access_key_id,
    aws_secret_access_key=aws_secret_access_key,
)

assumed = sts.assume_role(
    RoleArn=role_arn,
    RoleSessionName="mysession-" + str(int(time())),
    DurationSeconds=(12 * 60 * 60),  # 12 hrs
)

# these will be different than the ones you started with
credentials = assumed["Credentials"]
access_key_id = credentials["AccessKeyId"]
secret_access_key = credentials["SecretAccessKey"]
session_token = credentials["SessionToken"]

# make sure our cluster actually exists
eks = boto3.client(
    "eks",
    aws_session_token=session_token,
    aws_access_key_id=access_key_id,
    aws_secret_access_key=secret_access_key,
    region_name=region_name,
)

clusters = eks.list_clusters()["clusters"]
if cluster_name not in clusters:
    raise RuntimeError(f"configured cluster: {cluster_name} not found among {clusters}")

with TemporaryDirectory() as kube:
    kubeconfig_path = Path(kube) / "config"

    # let awscli generate the kubeconfig
    result = aws(
        "eks",
        "update-kubeconfig",
        "--name",
        cluster_name,
        _env={
            "AWS_ACCESS_KEY_ID": access_key_id,
            "AWS_SECRET_ACCESS_KEY": secret_access_key,
            "AWS_SESSION_TOKEN": session_token,
            "AWS_DEFAULT_REGION": region_name,
            "KUBECONFIG": str(kubeconfig_path),
        },
    )

    # read the generated file
    with open(kubeconfig_path, "r") as f:
        kubeconfig_str = f.read()
    kubeconfig = yaml.load(kubeconfig_str, Loader=yaml.SafeLoader)

    # the generated kubeconfig assumes that upon use it will have access to
    # `~/.aws/credentials`, but maybe this filesystem is ephemeral,
    # so add the creds as env vars on the aws command in the kubeconfig
    # so that even if the kubeconfig is separated from ~/.aws it is still
    # useful
    users = kubeconfig["users"]
    for i in range(len(users)):
        kubeconfig["users"][i]["user"]["exec"]["env"] = [
            {"name": "AWS_ACCESS_KEY_ID", "value": access_key_id},
            {"name": "AWS_SECRET_ACCESS_KEY", "value": secret_access_key},
            {"name": "AWS_SESSION_TOKEN", "value": session_token},
        ]

    # write the updates to disk
    with open(kubeconfig_path, "w") as f:
        f.write(yaml.dump(kubeconfig))

    awsclipath = str(Path(sh("-c", "which aws").stdout.decode()).parent)
    kubectlpath = str(Path(sh("-c", "which kubectl").stdout.decode()).parent)
    pathval = f"{awsclipath}:{kubectlpath}"

    # test the modified file without a ~/.aws/ dir
    # this will throw an exception if we can't talk to the cluster
    sh(
        "-c",
        "kubectl cluster-info",
        _env={
            "KUBECONFIG": str(kubeconfig_path),
            "PATH": pathval,
            "HOME": "/no/such/path",
        },
    )

print(yaml.dump(kubeconfig))

相关问题