Giter VIP home page Giter VIP logo

deno-kubernetes_client's Introduction

Deno CI

/x/kubernetes_client

This module implements several ways of sending authenticated requests to the Kubernetes API from deno scripts.

Kubernetes is a complex architechure which likes using sophisticated networking concepts, while Deno is a relatively young runtime, so there's some mismatch in capabilities. Therefor one client implementation cannot work in every case, and different Deno flags enable supporting different setups.

This library is intended as a building block. If you are unsure how to issue a specific request from your own library/code, or if your usage results in any TODO: ... error message from my code, please feel free to file a Github Issue.

Usage

Here's a basic request, listing all Pods in the default namespace. It uses the autoDetectClient() entrypoint which returns the first usable client.

Note: This example shows a manual HTTP request. To use the Kubernetes APIs more easily, consider also using /x/kubernetes_apis

import { autoDetectClient } from 'https://deno.land/x/kubernetes_client/mod.ts';
const kubernetes = await autoDetectClient();

const podList = await kubernetes.performRequest({
  method: 'GET',
  path: `/api/v1/namespaces/default/pods`,
  expectJson: true, // run JSON.parse on the response body
});
console.log(podList);

// see demo.ts for more request examples (streaming responses, etc)

To get started on local development, autoDetectClient will most likely decide to call out to your kubectl installation to make each network call. This only requires the --allow-run=kubectl Deno flag.

To use other clients, more flags are necesary. See "Client Implementations" below for more information on flags and other HTTP clients.

The kubectl client logs the issued commands if --verbose is passed to the Deno program.

Check out lib/contract.ts to see the type/API contract.

Changelog

  • v0.7.0 on 2023-08-13: Port KubectlRawRestClient over to newer Deno.Command() API. Support patching subresources & opening PodExec tunnels in KubectlRawRestClient. Obey abortSignal in more places (WebSocket tunnels, kubectl invocations). New API for swapping out the KubeConfigRestClient when auto-detecting a client.

    • v0.7.1 on 2023-09-24: Update std dependencies to /[email protected]
    • v0.7.2 on 2023-12-29: Fix WebsocketTunnel for Deno v1.38 change
  • v0.6.0 on 2023-08-08: Introduce an API for opening Kubernetes tunnels, useful for PodExec and others. Add an initial WebSocket-based tunnel client (in beta).

  • v0.5.2 on 2023-06-12: Remove IP address restriction. Deno v1.33.4 can now access IP addresses with TLS. This is important when accessing GKE clusters or similar configurations.

  • v0.5.1 on 2023-05-09: Run CI on Deno v1.26 thru v1.32. Now supports 'exec' plugins in kubeconfigs to load temporary credentials. This new feature requires Deno v1.31 or later (or Deno v1.28 with --unstable).

  • v0.5.0 on 2023-02-09: Updated deps to /[email protected] and run CI on Deno v1.22 thru v1.30. Now skips interactive permission prompts for InCluster files. Now throws an error when expectStream requests do not succeed. Authenticating with mTLS now requires Deno v1.15 or later.

  • v0.4.0 on 2022-05-21: Updated deps to /[email protected]. Now requires Deno v1.14 or later to pass typecheck.

  • v0.3.2 on 2021-11-28: Fix another regression on modern Deno, related to client certificates. Or more exactly the lack thereof when running in-cluster.

  • v0.3.1 on 2021-11-27: Fix cluster certificate authority setup in KubeConfigRestClient on Deno v1.15.0 and later.

  • v0.3.0 on 2021-08-29: Allow TLS authentication, when supported by Deno (#7). More consistently use --verbose flag (#4). Updated deps to /[email protected]. Now requires Deno v1.11 or later.

  • v0.2.4 on 2021-05-09: Clean up Deno-specific code in stream-transformers.ts. This also improves compatibility with Deno Deploy. Updated deps to /[email protected].

  • v0.2.3 on 2021-04-26: Full fix for certificate data encodings. Addresses a partial fix in v0.2.3 which introduced an InCluster regression.

  • v0.2.2 on 2021-04-21: Fix for using certificate data stored within kubeconfig. The Base64 encoding was not being respected previously.

  • v0.2.1 on 2021-03-26: Better Windows support from @jhannes. Checks for the $USERPROFILE variable as well as $HOME.

  • v0.2.0 on 2021-02-27: Rewrote KubeConfig handling and removed stable/unstable split. There's only two transport implementations now: KubectlRaw and KubeConfig.

  • v0.1.3 on 2020-12-29: Improved KubectlRaw Patch support. Now supports namespaced resources ;) and knows that subresources can't be patched.

  • v0.1.2 on 2020-12-27: Initial KubectlRaw Patch support. Also exports the Reflector implementation and plumbs the unstable Kubeconfig client more.

  • v0.1.1 on 2020-12-24: Add a generic Reflector implementation. This is useful for consuming a pairing of list & watch APIs.

  • v0.1.0 on 2020-11-16: Initial publication, with KubectlRaw and InCluster clients. Also includes ReadableStream transformers, useful for consuming watch streams.

Client Implementations

An error message is shown when no client is usable, something like this:

Error: Failed to load any possible Kubernetes clients:
  - InCluster PermissionDenied: Requires read access to "/var/run/secrets/kubernetes.io/serviceaccount/namespace", run again with the --allow-read flag
  - KubeConfig PermissionDenied: Requires env access to "KUBECONFIG", run again with the --allow-env flag
  - KubectlProxy PermissionDenied: Requires net access to "localhost:8001", run again with the --allow-net flag
  - KubectlRaw PermissionDenied: Requires run access to "kubectl", run again with the --allow-run flag

Each client has different pros and cons:

  • KubectlRawRestClient invokes kubectl --raw for every HTTP call. Excellent for development, though a couple APIs are not possible to implement.

    Flags: --allow-run=kubectl

  • KubeConfigRestClient uses Deno's fetch() to issue HTTP requests. There's a few different functions to configure it:

    • forInCluster() uses a pod's ServiceAccount to automatically authenticate. This is what is used when you deploy your script to a cluster.

      Flags: --allow-read=/var/run/secrets/kubernetes.io --allow-net=kubernetes.default.svc.cluster.local plus either --unstable or --cert=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

      Lazy flags: --allow-read --allow-net --unstable

    • forKubectlProxy() expects a kubectl proxy command to be running and talks directly to it without auth.

      This allows a full range-of-motion for development purposes regardless of the Kubernetes configuration.

      Flags: --allow-net=localhost:8001 given that kubectl proxy is already running at that URL.

    • readKubeConfig(path?, context?) (or forKubeConfig(config, context?)) tries using the given config (or $HOME/.kube/config if none is given) as faithfully as possible.

      This requires a lot of flags depending on the config file, and in some cases simply cannot work. For example https://<ip-address> server values are not currently supported by Deno, and invoking auth plugins such as gcloud aren't implemented yet, so any short-lived tokens in the kubeconfig must already be fresh. Trial & error works here :)

      Entry-level flags: --allow-env --allow-net --allow-read=$HOME/.kube

Related: API Typings

This module is only implementing the HTTP/transport part of talking to Kubernetes. You'll likely also want Typescript interfaces around actually working with Kubernetes resources.

API typings are available in a sibling project: kubernetes_apis published to /x/kubernetes_apis.

Of course, for some situations it might make sense to issue specific requests directly in which case using this client library alone might make more sense.

TODO

  • Support for kubectl proxy
  • Add filtering to Reflector implementation (e.g. by annotation)

deno-kubernetes_client's People

Contributors

danopia avatar jhannes avatar lucsoft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

deno-kubernetes_client's Issues

exec workaround?

I was wondering if there are suggestions for working around lack of exec support. I'm trying to connect to a cluster in Azure and my kube config uses the kubelogin command via exec. Any ideas?

Seems to not successfully authenticate against local kube with default config

KubeConfigRestClient.forKubeConfig(await KubeConfig.getDefaultConfig());

When I log what its loading it its correctly printing this object (all keys are correct):

PatchedKubeConfigRestClient {
  ctx: KubeConfigContext {
    context: { cluster: "docker-desktop", user: "docker-desktop" },
    cluster: {
      "certificate-authority-data": "<redacted>",
      server: "https://kubernetes.docker.internal:6443"
    },
    user: {
      "client-certificate-data": "<redacted>",
      "client-key-data": "<redacted>"
    }
  },
  httpClient: HttpClient { rid: 4 },
  defaultNamespace: "default"
}

But when I attempt to make a request it gets this error:

Error: Kubernetes says: pods is forbidden: User "system:anonymous" cannot list resource "pods" in API group "" in the namespace "example"

If I just use await autoDetectClient(); it falls back to the KubectlRawRestClient and then gives me 403 on certain apis such as exec.

Support kubectl auth plugins in `KubeConfigRestClient`

The config is already typed. Just need the implementation.

Maybe we can use Deno's new subprocess API?

Deno.Command will be stable in the next release, Deno 1.31

That's soon!

I understand that client.authentication.k8s.io involves passing JSON over stdin/stdout. It sounds like a bit of self-contained complexity.

Example config:

users:
- name: gke
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      command: gke-gcloud-auth-plugin
      installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
        https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
      provideClusterInfo: true

Support client certificate authentication

mTLS support for fetch() just merged into deno's development branch from denoland/deno#11721

Once that merge commit denoland/deno@dccf4cb is in a tagged release we can introduce client certificate support as seen in #5.

Unfortunately, there's still not a way of passing these configurations to a WebSocket client, which continues to keep exec/attach/portforward just a tad out of reach.

Support server-side apply with `KubectlRawRestClient`

Server-side apply is stable nowadays, and available with kubectl apply --server-side --field-manager=....
Given that our relevant codepath is for kubectl patch and comes from HTTP PATCH verbs, it might be interesting to see how these pieces want to fit together.

if (patchMode === 'apply') throw new Error(
`TODO: Server-Side Apply is not yet implemented (and also not enabled in vanilla Kubernetes yet)`);

Properly handle loading KubeConfig certs/keys

CA and key data can be either in-line or in a file, and there's currently no abstraction over this disparity. There's technically some complexity around file paths (mostly relative paths - they're supposed to be relative to the file that the path was originally found in).

The KubeConfigContext class should expose a way to reliably grab the cluster CA and the client key&cert, taking into account where the relevant file paths came from.

Convert Client Key Data to supported format on the fly

I have something like

export async function getPatchedLocalKube() {
    const config = await KubeConfig.getDefaultConfig();
    const ctx = config.fetchContext();
    const tlsAuth = await ctx.getClientTls();
    if (tlsAuth?.userKey.includes("BEGIN EC PRIVATE KEY")) {
        console.log(btoa(await convertEcKeyToPKCS8(tlsAuth?.userKey!)));
        ctx.user[ 'client-key-data' ] = btoa(await convertEcKeyToPKCS8(tlsAuth?.userKey!));
    }
    return KubeConfigRestClient.forKubeConfig(config);
}

async function convertEcKeyToPKCS8(key: string) {
    const derStream = new Deno.Command("openssl", {
        args: [ "ec", "-inform", "PEM", "-outform", "DER" ],
        stdin: "piped",
        stdout: "piped",
        stderr: "null"
    }).spawn();


    await new Response(key).body?.pipeTo(derStream.stdin!);

    const pkcs8Stream = new Deno.Command("openssl", {
        args: [ "pkcs8", "-topk8", "-nocrypt", "-outform", "PEM" ],
        stdin: "piped",
        stdout: "piped",
        stderr: "null"
    }).spawn();

    await derStream.stdout?.pipeTo(pkcs8Stream.stdin!);

    return await new Response(pkcs8Stream.stdout).text();
}

Would be could if it could be native + portable :D

After i wrote this code snippet i noticed that i can just modify my kubeconfig. it would be awesome anyway to have some logs or something to notice that it could work but just that the private key format is unsupported

Support for opening Tunnels (via WebSocket, etc)

Apparently the pod-exec API is WebSocket based, so websockets need to be available for use to make that API work. cloudydeno/deno-kubernetes_apis#2

The performRequest() interface allows for request and response streaming, so the primary change here might simply be adding an upgrade flag.

The larger work will be supporting kubectl API emulation because it will be API-specific. How the websocket and kubectl both behave will impact how easily the websocket can be emulated on a dev laptop. This will likely be a second pass but might get bundled into the same version if the pod-exec API goes smoothly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.