Exemple #1
0
def load_gke_config(fname: Filepath,
                    context: Optional[str],
                    disable_warnings: bool = False) -> Tuple[K8sConfig, bool]:
    """Return K8s access config for GKE cluster described in `kubeconfig`.

    Returns None if `kubeconfig` does not exist or could not be parsed.

    Inputs:
        kubconfig: str
            Name of kubeconfig file.
        context: str
            Kubeconf context. Use `None` to use default context.
        disable_warnings: bool
            Whether or not do disable GCloud warnings.

    Returns:
        Config

    """
    # Parse the kubeconfig file.
    name, user, cluster, err = load_kubeconfig(fname, context)
    if err:
        return (K8sConfig(), True)

    # Unpack the self signed certificate (Google does not register the K8s API
    # server certificate with a public CA).
    try:
        ssl_ca_cert_data = base64.b64decode(
            cluster["certificate-authority-data"])
    except KeyError:
        logit.debug(f"Context {context} in <{fname}> is not a GKE config")
        return (K8sConfig(), True)

    # Save the certificate to a temporary file. This is only necessary because
    # the requests library will need a path to the CA file - unfortunately, we
    # cannot just pass it the content.
    _, tmp = tempfile.mkstemp(text=False)
    ssl_ca_cert = Filepath(tmp)
    ssl_ca_cert.write_bytes(ssl_ca_cert_data)

    with warnings.catch_warnings(record=disable_warnings):
        try:
            cred, project_id = google.auth.default(
                scopes=['https://www.googleapis.com/auth/cloud-platform'])
            cred.refresh(google.auth.transport.requests.Request())
            token = cred.token
        except google.auth.exceptions.DefaultCredentialsError as e:
            logit.error(str(e))
            return (K8sConfig(), True)

    # Return the config data.
    logit.info("Assuming GKE cluster.")
    return K8sConfig(
        url=cluster["server"],
        token=token,
        ca_cert=ssl_ca_cert,
        client_cert=None,
        version="",
        name=cluster["name"],
    ), False
Exemple #2
0
def load_eks_config(fname: Filepath,
                    context: Optional[str],
                    disable_warnings: bool = False) -> Tuple[K8sConfig, bool]:
    """Return K8s access config for EKS cluster described in `kubeconfig`.

    Returns None if `kubeconfig` does not exist or could not be parsed.

    Inputs:
        fname: Filepath
            Kubeconfig file.
        context: str
            Kubeconf context. Use `None` to use default context.
        disable_warnings: bool
            Whether or not do disable GCloud warnings.

    Returns:
        Config

    """
    # Parse the kubeconfig file.
    name, user, cluster, err = load_kubeconfig(fname, context)
    if err:
        return (K8sConfig(), True)

    # Get a copy of all env vars. We will pass that one along to the
    # sub-process, plus the env vars specified in the kubeconfig file.
    env = os.environ.copy()

    # Unpack the self signed certificate (AWS does not register the K8s API
    # server certificate with a public CA).
    try:
        ssl_ca_cert_data = base64.b64decode(
            cluster["certificate-authority-data"])
        cmd = user["exec"]["command"]
        args = user["exec"]["args"]
        env_kubeconf = user["exec"].get("env", [])
    except KeyError:
        logit.debug(f"Context {context} in <{fname}> is not an EKS config")
        return (K8sConfig(), True)

    # Convert a None value (valid value in YAML) to an empty list of env vars.
    env_kubeconf = env_kubeconf if env_kubeconf else []

    # Save the certificate to a temporary file. This is only necessary because
    # the Requests library will need a path to the CA file - unfortunately, we
    # cannot just pass it the content.
    _, tmp = tempfile.mkstemp(text=False)
    ssl_ca_cert = Filepath(tmp)
    ssl_ca_cert.write_bytes(ssl_ca_cert_data)

    # Compile the name, arguments and env vars for the command specified in kubeconf.
    cmd_args = [cmd] + args
    env_kubeconf = {_["name"]: _["value"] for _ in env_kubeconf}
    env.update(env_kubeconf)
    logit.debug(
        f"Requesting EKS certificate: {cmd_args} with envs: {env_kubeconf}")

    # Pre-format the command for the log message.
    log_cmd = (f"kubeconf={fname} kubectx={context} "
               f"cmd={cmd_args}  env={env_kubeconf}")

    # Run the specified command to produce the access token. That program must
    # produce a YAML document on stdout that specifies the bearer token.
    try:
        out = subprocess.run(cmd_args, stdout=subprocess.PIPE, env=env)
        token = yaml.safe_load(out.stdout.decode("utf8"))["status"]["token"]
    except FileNotFoundError:
        logit.error(
            f"Could not find {cmd} application to get token ({log_cmd})")
        return (K8sConfig(), True)
    except (KeyError, yaml.YAMLError):
        logit.error(
            f"Token manifest produce by {cmd_args} is corrupt ({log_cmd})")
        return (K8sConfig(), True)
    except TypeError:
        logit.error(
            f"The YAML token produced by {cmd_args} is corrupt ({log_cmd})")
        return (K8sConfig(), True)

    # Return the config data.
    logit.info("Assuming EKS cluster.")
    return K8sConfig(
        url=cluster["server"],
        token=token,
        ca_cert=ssl_ca_cert,
        client_cert=None,
        version="",
        name=cluster["name"],
    ), False