kubernetes / kubectl

Issue tracker and mirror of kubectl code
Apache License 2.0
2.75k stars 894 forks source link

`kubectl exec -i` echoes passwords #1579

Closed tnozicka closed 3 months ago

tnozicka commented 3 months ago

What happened?

kubectl exec -i sets up a terminal that prevents disabling echoing. So when an application ask for a password, it is visible in the terminal.

$ kubectl exec -i pod/test -- passwd
New password: mypassword
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
Retype new password: mypassword
Changing password for user root.
passwd: all authentication tokens updated successfully.

It may seem that adding the -t is the way to help out here, but -t merges stdout and stderr together on purpose, unfortunately. So when you try to redirect the output of such command into a variable (or stdout to a file), you will never see the "Password: " promt because it gets written into stdout because of how kubectl exec -it sets up the terminal using raw option.

$ STDOUT_RESULT="$( kubectl exec -i pod/test -- passwd )"
New password: mypassword
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
Retype new password: mypassword
$ echo "${STDOUT_RESULT}"
Changing password for user root.
passwd: all authentication tokens updated successfully.
$ STDOUT_RESULT="$( kubectl exec -it pod/test -- passwd )"
# (Without any prompt, I have blindly typed two times `mypassword` into the terminal.)
$ echo "${STDOUT_RESULT}"
Changing password for user root.
New password: 
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
Retype new password: 
passwd: all authentication tokens updated successfully.

/sig cli

What did you expect to happen?

kubectl exec -i should set up terminal in a way that allows disabling echo. Alternatively, -t should distinguish between stdout and stderr.

How can we reproduce it (as minimally and precisely as possible)?

  1. kubectl run test --image=registry.access.redhat.com/ubi9/ubi:9.3-1610@sha256:66233eebd72bb5baa25190d4f55e1dc3fff3a9b77186c1f91a0abdb274452072 -- sleep infinity
  2. kubectl exec -i pod/test -- passwd
  3. see the password echoed
  4. STDOUT_RESULT="$( kubectl exec -it pod/test -- passwd )"
  5. observe the missing password prompt

Anything else we need to know?

I have used passwd as an example of a tool that ask for password on stderr and is available to everyone to reproduce this. It doesn't return much useful value on stdout, so here is a real word example of a cqlsh query that needs to ask for a password first:

(password echoed)

TOKEN="$( kubectl exec -i "service/scylla-client" -c scylla -- cqlsh --user cassandra -e "SELECT salted_hash from system_auth.roles WHERE role = 'cassandra'" )"
/opt/scylladb/python3/lib64/python3.11/getpass.py:91: GetPassWarning: Can not control echo on the terminal.
Warning: Password input may be echoed.
Password: cassandra

(no output but silently expects the password)

TOKEN="$( kubectl exec -it "service/scylla-client" -c scylla -- cqlsh --user cassandra -e "SELECT salted_hash from system_auth.roles WHERE role = 'cassandra'" )"

Kubernetes version

```console $ kubectl version # paste output here ```

Cloud provider

kubeadm version kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.2", GitCommit:"89a4ea3e1e4ddd7f7572286090359983e0387b2f", GitTreeState:"clean", BuildDate:"2023-09-13T09:34:32Z", GoVersion:"go1.20.8", Compiler:"gc", Platform:"linux/amd64"}

OS version

```console # On Linux: $ cat /etc/os-release PRETTY_NAME="Ubuntu 22.04.4 LTS" NAME="Ubuntu" VERSION_ID="22.04" VERSION="22.04.4 LTS (Jammy Jellyfish)" VERSION_CODENAME=jammy ID=ubuntu ID_LIKE=debian HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" UBUNTU_CODENAME=jammy $ uname -a Linux ubuntu-2204 5.15.0-100-generic kubernetes/kubernetes#110-Ubuntu SMP Wed Feb 7 13:27:48 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux ```

Install tools

Container runtime (CRI) and version (if applicable)

$ crictl version Version: 0.1.0 RuntimeName: cri-o RuntimeVersion: 1.24.6 RuntimeApiVersion: v1

Related plugins (CNI, CSI, ...) and versions (if applicable)

$ kubectl version Client Version: v1.30.0-beta.0.7+c9384550cbf771 Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3 Server Version: v1.28.3
k8s-ci-robot commented 3 months ago

This issue is currently awaiting triage.

If a SIG or subproject determines this is a relevant issue, they will accept it by applying the triage/accepted label and provide further guidance.

The triage/accepted label can be added by org members by writing /triage accepted in a comment.

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
apaar-gh commented 3 months ago

Issue kubernetes/kubectl#1579

You might have assumed the -i flag in kubectl exec -i would disable echo, allowing you to type passwords without them being displayed on the screen.Echoing is disabled by default with -i, but typed characters are visible in terminal history.

The -t flag allocates a pseudo-tty (terminal) for the container. This does not distinguish between standard output and standard error. Both streams are combined and displayed on the terminal.

Try these approach

tnozicka commented 3 months ago

Environment Variables: Store passwords securely as environment variables within the container image. Access them using the designated environment variable name inside the container.

Utilize kubectl create secret to store passwords securely.

I can't see how that helps for the case of kubectl exec. What you are pointing to is how a Pod should be setup for the database (daemon) itself. The issue here is using the database CLI by a particular user, his password shouldn't be exposed to everyone through environment variable or a secret. (Plus the password hashes are stored within the database.)

ardaguclu commented 3 months ago

In our bi-weekly bug scrub meeting, we discussed this issue. Although we agreed upon that this would be a reasonable ask, this should require significant changes to make it happen. /transfer kubectl /triage accepted /priority backlog

In case someone want to have a look at it.

eddiezane commented 3 months ago

What did you expect to happen? kubectl exec -i should set up terminal in a way that allows disabling echo.

I think you can do this on your own with stty -echo.

image

Alternatively, -t should distinguish between stdout and stderr

As far as I understand, this is what allocating a psuedo-tty is inteded for. It creates an "actual" tty device inside the container. It attaches local stdout to the combined remote streams so we can distinguish remote output from local output (kubectl).

eddiezane commented 3 months ago

I don't think there's anything for us to actually implement here. Feel free to reopen if that's not the case.

/close

k8s-ci-robot commented 3 months ago

@eddiezane: Closing this issue.

In response to [this](https://github.com/kubernetes/kubectl/issues/1579#issuecomment-2033268826): >I don't think there's anything for us to actually implement here. Feel free to reopen if that's not the case. > >/close Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.