Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store token in a more secure manner , support pairs of tokens #808

Open
hadmut opened this issue Jul 5, 2024 · 6 comments
Open

Store token in a more secure manner , support pairs of tokens #808

hadmut opened this issue Jul 5, 2024 · 6 comments

Comments

@hadmut
Copy link

hadmut commented Jul 5, 2024

TL;DR

hcloud stores the tokens in plaintext in ~/.config/hcloud/cli.toml , where any other process, including any which reads from or includes files from random paths, making it too easy to steal the tokens.

Since hcloud enforces the use of these contexts stored in that file, and does not allow to pass the token per command (like, e.g. terraform/opentofu does) to the process without storing it, this is highly insecure and puts the tokens into high risk of beeing stolen, rendering the 2FA for the login to the Hetzner web console effectively useless.

Expected behavior

More secure handling of tokens, e.g.

  • ask for token during cli run without storing it
  • instead of storing the token in a file, store a command which is run and expected to output the token in stdout, thus allowing the usual Linux methods to store secrets in Wallets like Gnome Keyring or Keepass.
  • allow handling of a token pair of a read only and read/write token, where, e.g. the read only token with lower risk can be stored in plaintext in ~/.config/hcloud/cli.toml for fast and convenient read-only commands like hcloud server list, where aggressive commands like server create or server delete automatically choose the read/write token, which might be retrieved from a wallet then.
@jooola
Copy link
Member

jooola commented Jul 5, 2024

Since hcloud enforces the use of these contexts stored in that file, and does not allow to pass the token per command (like, e.g. terraform/opentofu does) to the process without storing it.

You should be able to pass the token using the HCLOUD_TOKEN env var, without storing it in any configuration file, for example:

export HCLOUD_TOKEN="$(get-hcloud-token)"
hcloud server list

instead of storing the token in a file, store a command which is run and expected to output the token in stdout, thus allowing the usual Linux methods to store secrets in Wallets like Gnome Keyring or Keepass.

I think this is a good idea, not sure if a library already offers a way to do this on all the platforms that we support.

An alternative would be to provide a token_command configuration that will be triggered to retrieve the token from any vault/password manager you want.

allow handling of a token pair of a read only and read/write token, where, e.g. the read only token with lower risk can be stored in plaintext in ~/.config/hcloud/cli.toml for fast and convenient read-only commands like hcloud server list, where aggressive commands like server create or server delete automatically choose the read/write token, which might be retrieved from a wallet then.

The ideal solution would be to have fine-grained permissions on the tokens (per operations/per resources), but we are limited by what the API supports. You should already be able to store the read only token in a context, and use env var for the read/write tokens.

@hadmut
Copy link
Author

hadmut commented Jul 5, 2024

Not a good idea to store secrets in environment, since environments can be read from other processes.

@jooola jooola added the feature label Jul 5, 2024
@apricote
Copy link
Member

apricote commented Jul 5, 2024

Thanks for the suggestion. Do you have any tools where you like how this is implemented?

@hadmut
Copy link
Author

hadmut commented Jul 5, 2024

e.g. mutt as a mail client or aws-cli for the Amazon Cloud do allow to configure to use the output of a subcommand as a credential

https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-configure.html
https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-sourcing-external.html

Better solutions would require to modify the Hetzner API itself, e.g. use FIDO tokens or a TLS client certificate in a PKCS#11-Token or TPM for authentication.

There would be a lightweight solution which would not require to change the API, which is used by latest version of ssh client: Store the credential (here the API token) encrypted with gpg or a FIDO token in a file, and use gpg or the FIDO token to decrypt the credential inside the process, then use it as a regular token. This way you don't need to change the API, since all magic happens inside the client, but I am not really sure, how secure this is at the end of the day (and still depends on the client cli programm has not been tampered with).

https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html

https://fido.ftsafe.com/open-ssh-with-fido-keys/

https://swjm.blog/the-complete-guide-to-ssh-with-fido2-security-keys-841063a04252

Maybe also have a look at Clevis/Tang and how they do store their secrets.

So there's mainly two options:

  • The big one with extending the Hetzner API allowing to use client certificates (including PKCS#11) or FIDO tokens, instead of a token, using PK cryptography

  • The small one using client side improvements only, and to use cryptography (PKCS#11, FIDO,...) to just store the token in an encrypted way or to call an external program to deliver the token through stdout (and handle all the tricky stuff in an external program).

Just calling some external program to fetch and output the token on stdout and read it from there might be by far the most flexible and easiest to implement way, because it allows to use any wallet or token, leaving it as the external program's problem how to do it.

@phm07
Copy link
Contributor

phm07 commented Jul 11, 2024

Unfortunately, although I would love to see some changes on how authentication and project management is handled in the API, we have to work with what we have right now.
I think the easiest way to securely store tokens would be to use the host system's keyring. There are libraries that already handle this, for example https://github.com/zalando/go-keyring.
Maybe we could also add support for calling third-party binaries. Although there the question would be, what would stop an attacker from just reading out the binary path from the config and then calling it too?

Copy link
Contributor

github-actions bot commented Oct 9, 2024

This issue has been marked as stale because it has not had recent activity. The bot will close the issue if no further action occurs.

@github-actions github-actions bot added the stale label Oct 9, 2024
@jooola jooola added pinned and removed stale labels Oct 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants