1

While using Kubernetes API, I came across this issue where I am not able to pod exec into another pod using the API.

I made sure I am running a pod with a serviceAccount that has correct RBAC permissions (and both pods are in the same namespace). I tried with curl (7.74.0) but I stumbled upon this SO answer that curl may not be the right utility to do this. I have already tried other possible options (this and this) mentioned in the comments in the same post, but no luck.

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)    

curl -k -H "Upgrade: SPDY/3.1" -H "Authorization: Bearer $TOKEN" -H "Connection: Upgrade" -H "Sec-WebSocket-Version: 13" -H "Accept: application/json" "https://kuberne
    tes.default.svc/api/v1/namespaces/$NAMESPACE/pods/nginx-deployment-5c547569b4-jgm85/exec?command=ls"
    {
      "kind": "Status",
      "apiVersion": "v1",
      "metadata": {},
      "status": "Failure",
      "message": "Upgrade request required",
      "reason": "BadRequest",
      "code": 400
    }

Have already tried adding/removing few of those headers.

The next thing I tried was wscat (5.2.0). Tried a couple of variations, but needless to say, "no luck" again.

wscat -n -H "Authorization: Bearer $TOKEN" -c wss://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods/nginx-deployment-5c547569b4-jgm85/exec?command=ls

error: Unexpected server response: 403

This command outputs nothing (at all):

wscat -c wss://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods/nginx-deployment-5c547569b4-jgm85/exec?command=ls&stdin=true&stdout=true&tty=true&token=$TOKEN&namespace=$NAMESPACE 

I looked at this SO post, but it doesn't work for me.

wscat  -n -H "Authorization: Bearer $TOKEN" -c 'https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods/nginx-deployment-5c547569b4-jgm85/exec?command=ls&stdin=true&stdout=true&tty=true'

...
SyntaxError: The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"
...

Not sure how the fella even managed to use http(s) in the first place.

Can someone kindly advise if there's something wrong with what I doing or an alternative (can't use kubectl) to do the same? TIA

rock'n rolla
  • 1,883
  • 1
  • 13
  • 19
  • What is your end goal here? Can you create a Job to do the relevant work instead? (I would not expect you to need `kubectl exec` or equivalents in routine operations, any more than you'd "go inside" the `wscat` command and run more shell commands.) – David Maze Apr 27 '23 at 11:19
  • It's more like to understand the `Kubernetes API` aspects and why this particular operation, which is supported, doesn't work (or doesn't work right for me). – rock'n rolla Apr 27 '23 at 11:28
  • Did you try with the upgrade header and using SPDY? -H "Connection: upgrade" -H "Upgrade: SPDY/3.1" {master url:port/pod/exec}` --> https://stackoverflow.com/questions/37349440/upgrade-request-required-when-running-exec-in-kubernetes/37396806#37396806 – Rick Rackow Apr 27 '23 at 11:37
  • Yes, already mentioned in the original post and I did install `nghttp2` before trying. Thanks for looking up though. – rock'n rolla Apr 27 '23 at 11:40

1 Answers1

1

Curl Magic and trial and error. Make sure that the user has the right permissions so you don't get the 403.

curl -k \
  --http1.1 \
  -H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
  -H "Sec-WebSocket-Version: 13" \
  -i \
  -N \
  -L \
  -k \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Authorization: Bearer $TOKEN" \
  "https://127.0.0.1:53329/api/v1/namespaces/default/pods/single-wrong-arch/exec?command=ls&command=-l&stdin=true&stdout=true&stderr=true"

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: qGEgH3En71di5rrssAZTmtRTyFk=
Sec-WebSocket-Protocol:


total 56
~drwxr-xr-x    2 root     root          4096 Mar 29 14:45 bin
drwxr-xr-x    5 root     root           360 Apr 27 11:03 dev
drwxr-xr-x    1 root     root          4096 Apr 27 11:03 etc
drwxr-xr-x    2 root     root          4096 Mar 29 14:45 home
drwxr-xr-x    7 root     root          4096 Mar 29 14:45 lib
drwxr-xr-x    5 root     root          4096 Mar 29 14:45 media
drwxr-xr-x    2 root     root          4096 Mar 29 14:45 mnt
drwxr-xr-x    2 root     root          4096 Mar 29 14:45 opt
dr-xr-xr-x  248 root     root             0 Apr 27 11:03 proc
drwx------    2 root     root          4096 Mar 29 14:45 root
drwxr-xr-x    1 root     root          4096 Apr 27 11:03 run
drwxr-xr-x    2 root     root          4096 Mar 29 14:45 sbin
drwxr-xr-x    2 root     root          4096 Mar 29 14:45 srv
dr-xr-xr-x   13 root     root             0 Apr 27 11:03 sys
drwxrwxrwt    2 root     root          4096 Mar 29 14:45 tmp
drwxr-xr-x    7 root     root          4096 Mar 29 14:45 usr
drwxr-xr-x   12 root     root          4096 Mar 29 14:45 var

That's against a minikube cluster, which should explain the port choice and here's the rest of the environemt:

$ curl --version
curl 7.87.0 (x86_64-apple-darwin22.0) libcurl/7.87.0 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.51.0
Release-Date: 2022-12-21
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL threadsafe UnixSockets

$ minikube version
minikube version: v1.30.1
commit: 08896fd1dc362c097c925146c4a0d0dac715ace0

$ kubectl version
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"27", GitVersion:"v1.27.0", GitCommit:"1b4df30b3cdfeaba6024e81e559a6cd09a089d65", GitTreeState:"clean", BuildDate:"2023-04-11T17:04:23Z", GoVersion:"go1.20.3", Compiler:"gc", Platform:"darwin/arm64"}
Kustomize Version: v5.0.1
Server Version: version.Info{Major:"1", Minor:"26", GitVersion:"v1.26.3", GitCommit:"9e644106593f3f4aa98f8a84b23db5fa378900bd", GitTreeState:"clean", BuildDate:"2023-03-15T13:33:12Z", GoVersion:"go1.19.7", Compiler:"gc", Platform:"linux/arm64"}

$ uname -a
Darwin 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:41 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T8103 arm64


Rick Rackow
  • 1,490
  • 8
  • 19
  • I guess you brought the complete arsenal of `curl` headers and flags out :D On a serious note though, the command didn't work as it is for me but you did motivate me to further trial & fail with `curl`. So, it did work when I exclude the flags `-i, -N, -L`. With these, I got the error `HTTP/1.1 405 Method Not Allowed`. Not sure why. But happy to accept yours as the answer. Thanks for looking up. – rock'n rolla Apr 27 '23 at 17:09
  • interesting that those break it for you. `-L` should just follow redirects, `-N` should stop the buffering and `-i` makes you see the response headers. What kind of cluster are you running? – Rick Rackow Apr 27 '23 at 17:24
  • It's an `EKS Cluster`, but I get the same result on `minikube` too. Version info from EKS: `kubectl version --short: Client Version: v1.26.1 Kustomize Version: v4.5.7 Server Version: v1.24.10-eks-48e63af` – rock'n rolla Apr 27 '23 at 17:33
  • Is this possibly an issue with your cURL version? with this PR https://github.com/curl/curl/pull/8995 and respectively this https://github.com/curl/curl/commit/664249d095275ec532f55dd1752d80c8c1093a77 the support for websockets was added to curl and that's in version 7.86.0 https://curl.se/changes.html – Rick Rackow Apr 27 '23 at 17:44
  • 1
    Yes, it was due to the `curl` version. Upgraded it and works fine with those flags. Cheers – rock'n rolla Apr 28 '23 at 10:22