Skip to content

Commit e334da0

Browse files
committed
Add store/get/erase option.
1 parent 6062e2a commit e334da0

File tree

1 file changed

+105
-51
lines changed

1 file changed

+105
-51
lines changed

text/0000-cargo-token-from-process.md

Lines changed: 105 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,51 +29,115 @@ keyring.
2929

3030
Suppose a user has their authentication token stored in a password manager, and
3131
the password manager provides a command, `/usr/bin/cargo-creds`, 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:
32+
print that token in a secure way. Instead of storing the token in plaintext,
33+
the user can add this snippet to their own Cargo config to authenticate with
34+
crates.io:
3535

3636
```toml
3737
[registry]
38-
token-from-process = "/usr/bin/cargo-creds"
38+
credential-process = "/usr/bin/cargo-creds"
3939
```
4040

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. If the
43-
command requires arguments, for example `password-manager creds crates-io`, you
44-
can add them in a list:
41+
When authentication is required, Cargo will execute the command to acquire the
42+
token, which will never be stored by Cargo on disk.
43+
44+
It will be possible to use `credential-process` on both crates.io and alternative
45+
registries.
46+
47+
# Reference-level explanation
48+
[reference-level-explanation]: #reference-level-explanation
49+
50+
A new key, `credential-process`, will be added to the `[registry]` and
51+
`[registries.NAME]` sections of the configuration file. When a `token` key is
52+
also present, the latter will take precedence over `credential-process` to
53+
maintain backward compatibility, and a warning will be issued to let the user
54+
know about that.
55+
56+
The `registry.credential-process` value will be used for all registries. If a
57+
specific registry specifies the value in the `registries` table, then that
58+
will take precedence.
59+
60+
The `credential-process` key accepts either a string containing the executable
61+
and arguments or an array containing the executable name and the arguments.
62+
This follows Cargo's convention for executables defined in config.
63+
64+
There are special strings in the `credential-process` that Cargo will replace
65+
with a given value:
66+
67+
* `{name}` — Name of the registry.
68+
* `{api_url}` — The API URL.
69+
* `{action}` — The authentication action (described below).
4570

4671
```toml
4772
[registry]
48-
token-from-process = ["password-manager", "creds", "crates-io"]
73+
credential-process = 'cargo osxkeychain {action}'
74+
75+
[registries.my-registry]
76+
credential-process = ['/path/to/myscript', '{name}']
4977
```
5078

51-
It will be possible to use `token-from-process` on both crates.io and
52-
alternative registries.
79+
There are two different kinds of token processes that Cargo supports. The
80+
simple "basic" kind will only be called by Cargo when it needs a token. This
81+
is intended for simple and easy integration with password managers, that can
82+
often use pre-existing tooling. The more advanced "Cargo" kind supports
83+
different actions passed as a command-line argument. This is intended for more
84+
pleasant integration experience, at the expense of requiring a Cargo-specific
85+
process to glue to the password manager. Cargo will determine which kind is
86+
supported by the `credential-process` definition. If it contains the
87+
`{action}` argument, then it uses the advanced style, otherwise it assumes it
88+
only supports the "basic" kind.
5389

54-
# Reference-level explanation
55-
[reference-level-explanation]: #reference-level-explanation
90+
## Basic authenticator
91+
92+
A basic authenticator is a process that returns a token on stdout. Newlines
93+
will be trimmed. The process inherits the user's stdin and stderr. It should
94+
exit 0 on success, and nonzero on error.
95+
96+
With this form, `cargo login` and `cargo logout` are not supported and return
97+
an error if used.
98+
99+
## Cargo authenticator
56100

57-
A new key, `token-from-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-from-process` to maintain backward compatibility, and a warning will be
61-
issued to let the user know about that.
101+
The protocol between the Cargo and the process is very basic, intended to
102+
ensure the credential process is kept as simple as possible. Cargo will
103+
execute the process with the `{action}` argument indicating which action to
104+
perform:
62105

63-
The `token-from-process` key accepts either a string containing the binary to
64-
call or a list containing the binary name and the arguments to provide to it.
106+
* `store` — Store the given token in secure storage.
107+
* `get` — Get a token from storage.
108+
* `erase` — Remove a token from storage.
65109

66-
When a `cargo` subcommand needs the authentication token, Cargo will execute
67-
the binary contained in the configuration key with the defined arguments (if
68-
provided by the user). The process will inherit Cargo's standard input and
69-
error, and the standard output will be captured by Cargo to read the token
70-
(with trimmed newlines). If the command returns an exit code other than `0`
71-
Cargo will treat that as a failure.
110+
The `cargo login` command will use `store` to save a token. Commands that
111+
require authentication, like `cargo publish`, will use `get` to retrieve a
112+
token. A new command, `cargo logout` will be added which will use the `erase`
113+
command to remove a token.
114+
115+
The process inherits the user's stderr, so the process can display messages.
116+
Some values are passed in via environment variables (see below). The expected
117+
interactions are:
118+
119+
* `store` — The token is sent to the process's stdin, terminated by a newline.
120+
The process should store the token keyed off the registry name. If the
121+
process fails, it should exit with a nonzero exit status.
122+
123+
* `get` — The process should send the token to its stdout (trailing newline
124+
will be trimmed). The process inherits the user's stdin, should it need to
125+
receive input.
126+
127+
If the process is unable to fulfill the request, it should exit with a
128+
nonzero exit code.
129+
130+
* `erase` — The process should remove the token associated with the registry
131+
name. If the token is not found, the process should exit with a 0 exit
132+
status.
133+
134+
## Environment
72135

73136
The following environment variables will be provided to the executed command:
74137

75-
* `CARGO` - Path to the `cargo` binary executing the command.
76-
* `CARGO_REGISTRY_NAME` - Name of the registry the authentication token is for.
138+
* `CARGO` — Path to the `cargo` binary executing the command.
139+
* `CARGO_REGISTRY_NAME` — Name of the registry the authentication token is for.
140+
* `CARGO_REGISTRY_API_URL` — The URL of the registry API.
77141

78142
# Drawbacks
79143
[drawbacks]: #drawbacks
@@ -87,37 +151,28 @@ The solution proposed by this RFC isn't tied to any secret storage services and
87151
can be adapted to work with virtually any secret storage the user might rely
88152
on, while being relatively easy to understand and use.
89153

90-
An alternative with better user experience but more limited customization would
91-
be for Cargo to provide cross platform, native integration with the most
92-
popular secret storages, for example the system keyring:
93-
94-
```toml
95-
[registry]
96-
token-from-system-keyring = true
97-
```
98-
99-
The issue with the native integration proposal is it helps only a subset of
100-
users, and it requires Cargo to implement and test integrations with each
101-
secret storage we expect a lot of users to use.
102-
103154
# Prior art
104155
[prior-art]: #prior-art
105156

106157
Multiple command line tools implement this system or a similar one to retrieve
107158
authentication tokens or other secrets:
108159

109-
* [awscli][awscli] includes the `credentials_process` setting with nearly the
110-
same behavior as the one proposed in this RFC.
160+
* [awscli][awscli] includes the `credentials_process` setting which calls
161+
a process with arguments provided by the user. The process is expected to
162+
emit JSON that contains the access key.
111163
* [Docker CLI][docker] offers "credential stores", programs the Docker CLI
112164
calls with specific arguments expecting JSON output. Implementations are
113165
provided for common storage systems, and the protocol is documented for users
114166
who want to integrate with their custom system.
115167
* [Ansible Vault][ansible] allows to specify an executable file as the
116168
decryption password, executing it when needed.
169+
* [Git] has a credential mechanism using store/get/erase arguments, and
170+
`key=value` parameters send and received with the process.
117171

118172
[awscli]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html
119173
[docker]: https://docs.docker.com/engine/reference/commandline/login/#credentials-store
120174
[ansible]: https://docs.ansible.com/ansible/latest/user_guide/vault.html#providing-vault-passwords
175+
[git]: https://git-scm.com/docs/gitcredentials#_custom_helpers
121176

122177
# Unresolved questions
123178
[unresolved-questions]: #unresolved-questions
@@ -127,15 +182,14 @@ authentication tokens or other secrets:
127182
# Future possibilities
128183
[future-possibilities]: #future-possibilities
129184

130-
To allow for a better user experience for users of popular secret storages the
131-
community could create Cargo plugins that easily integrate with such systems.
132-
For example, an hypothetical Cargo plugin to integrate with the system keyring
133-
could allow users to add this configuration snippet:
185+
To allow for a better user experience for users of popular secret storages,
186+
Cargo can provide built-in support for common systems. It is proposed that a
187+
`credential-process` with a `cargo:` prefix will use some internal support. For
188+
example, `credential-process = 'cargo:system-keychain'`.
134189

135-
```toml
136-
[registry]
137-
token-from-process = "cargo credentials-system-keyring"
138-
```
190+
Additionally, the community could create Cargo plugins that implement
191+
different storage systems. For example, a hypothetical Cargo plugin could be
192+
specified as `credential-process = 'cargo credential-1password {action}'`.
139193

140194
Encrypting the stored tokens or alternate authentication methods are out of the
141195
scope of this RFC, but could be proposed in the future to provide additional

0 commit comments

Comments
 (0)