We run our production Rails app on GKE, and we require all production access to go through a Bastion host.
To access it, I SSH into the Bastion host:
gcloud compute ssh --project=myproject --zone=myzone bastion-vm
Once that connects, I get the name of the desired pod, exec into it, and start an interactive Rails console:
kubectl --context=prod exec -it $(kubectl get pods -n mynamespace --no-headers -o custom-columns=":metadata.name" --selector="app=my-app") -n mynamespace -- /bin/sh -c '/berglas/bin/berglas exec -- bundle exec rails c'
I'd like to turn this into a one-liner that I can run from my local, but I'm struggling. My first attempt:
gcloud compute ssh --project=myproject --zone=usmyzone bastion-vm --command 'kubectl --context=prod exec -it $(kubectl get pods -n mynamespace --no-headers -o custom-columns=":metadata.name" --selector="app=my-app") -n mynamespace -- /bin/sh -c "/berglas/bin/berglas exec -- bundle exec rails c"'
When I ran that, it gave me the usual output I get when connecting to Bastion:
External IP address was not found; defaulting to using IAP tunneling.
WARNING:
To increase the performance of the tunnel, consider installing NumPy. For instructions,
please see https://cloud.google.com/iap/docs/using-tcp-forwarding#increasing_the_tcp_upload_bandwidth
And then it just hung until I hit ControlC. I figured "oh, okay, I need an interactive SSH session." So I looked at the gcloud docs and didn't see any built-in option for that, but I did see that you can pass flags down to the underlying ssh, and so I tried --ssh-flag='-t'
:
gcloud compute ssh --project=myproject --zone=usmyzone bastion-vm --ssh-flag='-t' --command 'kubectl --context=prod exec -it $(kubectl get pods -n mynamespace --no-headers -o custom-columns=":metadata.name" --selector="app=my-app") -n mynamespace -- /bin/sh -c "/berglas/bin/berglas exec -- bundle exec rails c"'
This connected as before, then dropped me at a terminal prompt on the bastion host as if I hadn't specified a command. I added -v
to the ssh flags and ran it again; it indicates that it's running the command:
debug1: Sending command: kubectl --context=prod exec $(kubectl get pods -n mynamespace --no-headers -o custom-columns=":metadata.name" --selector="app=my-app") -n mynamespace -- /bin/sh -c "/berglas/bin/berglas exec -- bundle exec rails c"
That's the end of the output before the shell prompt on the Bastion host. I see no other output or evidence that indicates that the command actually ran. I've done some additional experimentation, specifying things like ls
, /bin/dash
, and even things that should error like /bin/foo
as the command. Nothing changes; I just always get the shell prompt without further output (or, if I omit the -t
, it always just hangs).
I have to imagine that there's a way to accomplish this. What am I missing?
If it matters, I'm on macOS Monterey and my local shell is ZSH.