|
| 1 | +- Feature Name: `cargo_token_process` |
| 2 | +- Start Date: 2019-07-22 |
| 3 | +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) |
| 4 | +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +Add a cargo setting to fetch registry authentication tokens by calling an |
| 10 | +external process. |
| 11 | + |
| 12 | +# Motivation |
| 13 | +[motivation]: #motivation |
| 14 | + |
| 15 | +Some interactions with a registry require an authentication token, and Cargo |
| 16 | +currently stores such token in plaintext in the [`.cargo/credentials`][creds] |
| 17 | +file. While Cargo properly sets permissions on that file to only allow the |
| 18 | +current user to read it, that's not enough to prevent other processes ran by |
| 19 | +the same user from reading the token. |
| 20 | + |
| 21 | +This RFC aims to provide a way to configure Cargo to instead fetch the token |
| 22 | +from any secrets storage system, for example a password manager or the system |
| 23 | +keyring. |
| 24 | + |
| 25 | +[creds]: https://doc.rust-lang.org/stable/cargo/reference/config.html#credentials |
| 26 | + |
| 27 | +# Guide-level explanation |
| 28 | +[guide-level-explanation]: #guide-level-explanation |
| 29 | + |
| 30 | +Suppose an user has their authentication token stored in a password manager, |
| 31 | +and the password manager provides a command, `creds cargo`, to decrypt and |
| 32 | +print that token in a secure way. Instead of also storing the token in |
| 33 | +plaintext, the user can add this snippet to their own `.cargo/credentials` to |
| 34 | +authenticate with crates.io: |
| 35 | + |
| 36 | +```toml |
| 37 | +[registry] |
| 38 | +token-process = "creds cargo" |
| 39 | +``` |
| 40 | + |
| 41 | +When authentication is required Cargo will execute the command and use its |
| 42 | +output as the token, which will never be stored by Cargo on disk. The command |
| 43 | +will be executed inside the system's shell environment, to allow the usage of |
| 44 | +CLI utilities: |
| 45 | + |
| 46 | +```toml |
| 47 | +[registry] |
| 48 | +token-process = "creds cargo | awk '{print($2)}'" |
| 49 | +``` |
| 50 | + |
| 51 | +It will be possible to use `token-process` on both crates.io and alternative |
| 52 | +registries. |
| 53 | + |
| 54 | +# Reference-level explanation |
| 55 | +[reference-level-explanation]: #reference-level-explanation |
| 56 | + |
| 57 | +A new key, `token-process`, will be added to the `[registry]` and |
| 58 | +`[registries.NAME]` sections of the `.cargo/credentials` configuration file. |
| 59 | +When a `token` key is also present, the latter will take precedence over |
| 60 | +`token-process` to maintain backward compatibility, and a warning will be |
| 61 | +issued to let the user know about that. |
| 62 | + |
| 63 | +When a `cargo` subcommand needs the authentication token, Cargo will execute |
| 64 | +the string contained in the configuration key with the system shell (`cmd.exe` |
| 65 | +on Windows and `sh` on other platforms). If the command returns the `0` exit |
| 66 | +code, the stardard output (with trimmed newlines) will be treated as the |
| 67 | +authentication token. Otherwise an error message will be shown to the user, |
| 68 | +along with the standard output. |
| 69 | + |
| 70 | +The following environment variables will be provided to the executed command: |
| 71 | + |
| 72 | +* `CARGO` - Path to the `cargo` binary executing the command. |
| 73 | +* `CARGO_REGISTRY_NAME` - Name of the registry the authentication token is for. |
| 74 | + |
| 75 | +# Drawbacks |
| 76 | +[drawbacks]: #drawbacks |
| 77 | + |
| 78 | +This RFC requires cargo to execute a command with the system shell, which could |
| 79 | +make it more difficult to port Cargo to a new operative system without a shell. |
| 80 | + |
| 81 | +# Rationale and alternatives |
| 82 | +[rationale-and-alternatives]: #rationale-and-alternatives |
| 83 | + |
| 84 | +The solution proposed by this RFC isn't tied to any secret storage services and |
| 85 | +can be adapted to work with virtually any secret storage the user might rely |
| 86 | +on, while being relatively easy to understand and use. |
| 87 | + |
| 88 | +An alternative with better user experience but more limited customization would |
| 89 | +be for Cargo to provide cross platform, native integration with the most popular |
| 90 | +secret storages, for example the system keyring: |
| 91 | + |
| 92 | +```toml |
| 93 | +[registry] |
| 94 | +system-keyring = true |
| 95 | +``` |
| 96 | + |
| 97 | +The issue with the native integration proposal is it helps only a subset of |
| 98 | +users, and it requires Cargo to implement and test integrations with each |
| 99 | +secret storage we expect a lot of users to use. |
| 100 | + |
| 101 | +# Prior art |
| 102 | +[prior-art]: #prior-art |
| 103 | + |
| 104 | +Multiple command line tools implement this system or a similar one to retrieve |
| 105 | +authentication tokens or other secrets: |
| 106 | + |
| 107 | +* [awscli][awscli] includes the `credentials_process` setting with the same |
| 108 | + behavior as the one proposed in this RFC. |
| 109 | +* [Docker CLI][docker] offers "credential stores", programs the Docker CLI |
| 110 | + calls with specific arguments expecting JSON output. Implementations are |
| 111 | + provided for common storage systems, and the protocol is documented for users |
| 112 | + who want to integrate with their custom system. |
| 113 | +* [Ansible Vault][ansible] allows to specify an executable file as the |
| 114 | + decryption password, executing it when needed. |
| 115 | + |
| 116 | +[awscli]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html |
| 117 | +[docker]: https://docs.docker.com/engine/reference/commandline/login/#credentials-store |
| 118 | +[ansible]: https://docs.ansible.com/ansible/latest/user_guide/vault.html#providing-vault-passwords |
| 119 | + |
| 120 | +# Unresolved questions |
| 121 | +[unresolved-questions]: #unresolved-questions |
| 122 | + |
| 123 | +*Nothing here yet.* |
| 124 | + |
| 125 | +# Future possibilities |
| 126 | +[future-possibilities]: #future-possibilities |
| 127 | + |
| 128 | +To allow for a better user experience for users of popular secret storages the |
| 129 | +community could create Cargo plugins that easily integrate with such systems. |
| 130 | +For example, an hypothetical Cargo plugin to integrate with the system keyring |
| 131 | +could allow users to add this configuration snippet: |
| 132 | + |
| 133 | +```toml |
| 134 | +[registry] |
| 135 | +token-process = "cargo credentials-system-keyring" |
| 136 | +``` |
| 137 | + |
| 138 | +Encrypting the stored tokens or alternate authentication methods are out of the |
| 139 | +scope of this RFC, but could be proposed in the future to provide additional |
| 140 | +security for our users. |
0 commit comments