Git Product home page Git Product logo

vault-rs's Introduction

Vault

Build Status

HashiCorp Vault API client for Rust.

You can start a local test server running using:

vault server -dev

vault version
Vault v1.12.0 (558abfa75702b5dab4c98e86b802fb9aef43b0eb), built 2022-10-10T18:14:33Z

Record the Root Token: printed at startup time, and use it to create a test token:

export VAULT_ADDR=http://localhost:8200
export VAULT_TOKEN=<root token from server startup>
vault token create -id="test12345" -ttl="720h"
vault secrets enable transit

High Availability

To use this with a highly available vault, you need to either let consul handle DNS for this crate or handle identifying the Vault leader separately.

TODO

  • Add support for managing Vault

vault-rs's People

Contributors

cholcombe973 avatar chrismacnaughton avatar compressed avatar emk avatar expobrain avatar fourbytes avatar grahamc avatar lucab avatar rokadias avatar soleinik-figment avatar stephaneyfx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

vault-rs's Issues

Read secrets with key unknown ahead of time

Hi @ChrisMacNaughton,
this is a follow-up to #42. I made some good progress with the latest iteration but now experiencing the following feature gap:

A user wants to access secrets without knowing the key ahead of time so providing a secret struct to get_custom_secret doesn't work as the key can't be omitted when parsing (at least that I know of). Would it be possible to expose parse_vault_response (see here) and let the user handle decoding?

Thanks!

set_secret not accepting JSON or JSON string

Hi,
Maybe i missed it, but it seems that is only possible to store a string as a secret even thought Vault can accept JSON file or values.
The only way i've found to store a json is to encode it as a base64 string?
If not present are you considering to implement this feature?

Thanks

Cannot publish to crates.io

When trying to publish:

error: api errors: invalid upload request: invalid value: string "vault_0.6.1", expected a valid crate name to start with a letter, contain only letters, numbers, hyphens, or underscores and have at most 64 characters at line 1 column 1337

Can't read secret with key other than 'value'

Hi @ChrisMacNaughton,

thanks for creating this library. This is my first time playing around with rust so excuse if this is a user error.

I'm trying to read an existing secret from vault, e.g

❯ vault kv get secret/hello/test
====== Metadata ======
Key              Value
---              -----
created_time     2021-02-08T04:13:52.094224Z
deletion_time    n/a
destroyed        false
version          1

== Data ==
Key    Value
---    -----
a      b

Creating a secret using your crate always writes them as:

❯ vault kv get secret/hello/bob
====== Metadata ======
Key              Value
---              -----
created_time     2021-02-08T04:14:23.762412Z
deletion_time    n/a
destroyed        false
version          1

==== Data ====
Key      Value
---      -----
value    world

As it stands I'm not able to retrieve a secret with a custom key as serde fails to deserialize:
Err(SerdeJson(Error("missing field value", line: 1, column: 128)))

I believe this is caused by the SecretData declaration https://github.com/ChrisMacNaughton/vault-rs/blob/master/src/client/mod.rs#L292 called here.

I couldn't find an API that allows me to set the key explicitly when calling get_secret.
Am I missing something or is this indeed not supported right now?

Thanks!

301 result redirection changes HTTP verb

Hi!
I've been using this for a small project, and I notice that when Vault returns a 301, my POST (or PUT) verb turns into a GET verb. So it seems when following 301's the verb is reset.

You can test this by doing an API call to /sys/tools/random, Vault will rewrite with a 301 to /v1//sys/tools/random and to /v1/sys/tools/random and in the process the POST verb is lost.

Usage from async contexts

I have been looking into laying the groundwork for moving some Vault-dependent microservices to Rust, likely using async. I was somewhat surprised to see that this client still exposes a totally blocking API, even though e.g. reqwest's primary API is now blocking, and (I imagine) many of the applications which would want to talk to Vault would be using async. As it stands, an async application would have to spawn_blocking the request, which would then internally use async anyway (in the reqwest implementation).

Until #51, I believe writing an async implementation and basing the (current) synchronous API on it could have been done in a non-breaking way, but it seems that ship has now sailed for 2.x. Such an approach would now require two separate implementations.

What are your thoughts on catering to the async use case?

Complex secrets and secret metadata (e.g., lease IDs and TTLs)

At some point in the future, I'd also love to port https://github.com/emk/credentials and https://github.com/faradayio/credentials_to_env to use your vault-rs library instead of the dodgy, hand-rolled internal library that I use now.

To do this, I would need to add some new APIs to vault-rs:

  1. APIs for reading and writing compound secrets easily. These would correspond to vault secrets created like this:

    $ vault write secret/test user="foo" pass="bar"
    Success! Data written to: secret/test
    $ vault read secret/test
    Key                 Value
    ---                 -----
    refresh_interval    720h0m0s
    pass                bar
    user                foo

    Code using this API might hypothetically look something like:

    #[derive(RustcEncodable, RustcDecodable)]
    struct Secret {
        user: String,
        pass: String,
    }
    let secret: VaultResponse<Secret> = try!(client.get_secret_data("secret/test"));
  2. APIs for accessing the lease ID, TTL, etc. These could be accessed via the VaultResponse object, I believe, in the example above.

Do these features already exist anywhere in the current release (I didn't see them)? If not, would you be interested in receiving a PR adding APIs along these general lines? Please feel free to suggest better names, API improvements, etc.

Once again, thank you for maintaining this crate!

Release a new version

I wanted to use this client to access KV-v2, but the API for "call_endpoint" isn't in the latest released version (on crates.io). Could you release a newer version that contains this API?

Thanks!

Vault client silently generates too-powerful tokens if vault host URL ends in a slash

We're making heavy use of vault-rs for production deploys, and it's working great!

But we discovered a tricky issue. There's a lot of code in vault-rs that concatenates URL fragments using {}{}. For example:

    fn get(&self, endpoint: &str, wrap_ttl: Option<&str>) -> Result<Response> {
        let mut req = self.client
            .get(&format!("{}{}", self.host, endpoint)[..])

These low-level HTTP routines are called by higher level routines that include leading slashes:

let mut res = try!(self.post("/v1/auth/token/create", Some(&body)));

If the passed-in host value is of the form https://vault.example.com/, then this will generate a URL of the form https://vault.example.com//v1/auth/token/create with a double slash //.

The plot thickens

When I use this URL to create a new token, the following series of events happen deep inside hyper:

  1. Hyper issues a POST //v1/auth/token/create (two slashes) containing JSON data in the body. This JSON data contains a policies field saying what vault policies the apply to the newly created token.
  2. Vault redirects this to /v1/auth/token/create.
  3. Hyper retries with POST /v1/auth/token/create (one slash) but without any JSON data in the body. No policies field is present.
  4. Vault issues a token that inherits all the policies of its parent token.

The fix here is to build URLs using the url crate and not format!, or at least to strip any trailing slash from the supplied host.

I'm going to be very busy this coming week, but if you want, I can try to find time to prepare a PR converting the code to use url internally.

More APIs? (auth_token.create, auth_token.renew, sys.policies)

Hello, thank you for providing a great Vault library for Rust!

I'm the maintainer of https://github.com/faradayio/add-vault-tokens, a simple Ruby library for adding vault tokens to a docker-compose file. This uses the vault API to do three things:

  1. Enumerate all policies available from vault.
  2. Create new tokens.
  3. Renew existing tokens.

I'm porting the Ruby code to Rust, and I need to re-implement these three Vault APIs in Rust. Would you be interested in me implementing these APIs as a pull request and submitting them to your library?

(I may also want to want to switch https://github.com/emk/credentials to use your Vault client instead of my hand-rolled one at some point, but that's a topic for another day.)

Can't get a kv secret outside 'secret' named engine

Hi

I was struggling on finding a way to use a kv engine. Digging into the code, I found "secret" URL path is hardcoded.

https://github.com/ChrisMacNaughton/vault-rs/blob/master/src/client/mod.rs#L1117

    pub fn get_custom_secret<S: AsRef<str>, S2: DeserializeOwned + std::fmt::Debug>(
        &self,
        secret_name: S,
    ) -> Result<S2> {
        let res = self.get::<_, String>(
            &format!("/v1/secret/data/{}", secret_name.as_ref())[..],
            None,
        )?;
        let decoded: VaultResponse<SecretDataWrapper<S2>> = parse_vault_response(res)?;
        match decoded.data {
            Some(data) => Ok(data.data),
            _ => Err(Error::Vault(format!(
                "No secret found in response: `{:#?}`",
                decoded
            ))),
        }
    }

Instead, I suggest adding a new argument for the engine name. If you agree with the idea, I can do it if you want and send a PR. Let me know what's your POV.

Thanks

OpenSSL Error?

When running cargo build it fails on openssl, which is odd since I do have openssl installed on my MacOS.

--- stdout
  cargo:rustc-cfg=const_fn
  cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR
  X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR unset
  cargo:rerun-if-env-changed=OPENSSL_LIB_DIR
  OPENSSL_LIB_DIR unset
  cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR
  X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR unset
  cargo:rerun-if-env-changed=OPENSSL_INCLUDE_DIR
  OPENSSL_INCLUDE_DIR unset
  cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR
  X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR unset
  cargo:rerun-if-env-changed=OPENSSL_DIR
  OPENSSL_DIR unset
  cargo:rerun-if-env-changed=OPENSSL_NO_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG
  cargo:rerun-if-env-changed=OPENSSL_STATIC
  cargo:rerun-if-env-changed=OPENSSL_DYNAMIC
  cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
  cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_PATH
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_LIBDIR
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
  run pkg_config fail: "`\"pkg-config\" \"--libs\" \"--cflags\" \"openssl\"` did not exit successfully: exit status: 1\n--- stderr\nPackage openssl was not found in the pkg-config search path.\nPerhaps you should add the directory containing `openssl.pc'\nto the PKG_CONFIG_PATH environment variable\nNo package 'openssl' found\n"

  --- stderr
  thread 'main' panicked at '

  Could not find directory of OpenSSL installation, and this `-sys` crate cannot
  proceed without this knowledge. If OpenSSL is installed and this crate had
  trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
  compilation process.

  Make sure you also have the development packages of openssl installed.
  For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.

  If you're in a situation where you think the directory *should* be found
  automatically, please open a bug at https://github.com/sfackler/rust-openssl
  and include information about your system as well as this message.

  $HOST = x86_64-unknown-linux-gnu
  $TARGET = x86_64-unknown-linux-musl
  openssl-sys = 0.9.65

Cant seem to figure out a solution. I have reinstalled openssl via homebrew and configured all the env variables and still no luck

Replace `println!` with `log` crate, and be very careful about not leaking secrets to logs (at least at `debug` and above?)

OK, one more suggestion for your consideration. :-)

Right now, the crate contains debugging messages such as:

        println!("Vault request failed: {:?}, error message: `{}`",
                 res,
                 error_msg);

...and:

    println!("Response: {:?}", &body);

This has two drawbacks:

  1. It causes programs using this library to very noisy.
  2. Secrets may be leaked to standard output, and wind up in logs somewhere, which is often against policy for people using vault.

To fix (1), we could simple use the log crate. To fix (2), we'd either need to give up certain useful logging output, or perhaps relegate it to the trace! level, so it won't show up when normally when debug logging is activated. Even then, it's worth thinking about the security issues carefully.

TryFrom Url

I think the url library pulled into this crate isn't new enough. I'm seeing the following error with vault_host being type String:

33  |         let vault_client = VaultClient::new(&vault_host, &token)?;
    |                            ^^^^^^^^^^^^^^^^ the trait `hashicorp_vault::TryFrom<&std::string::String>` is not implemented for `url::Url`
    | 
   ::: /Users/cholcombe/.cargo/registry/src/github.com-1ecc6299db9ec823/hashicorp_vault-1.0.0/src/client/mod.rs:654:12
    |
654 |         U: TryInto<Url, Err = Error>,
    |            ------------------------- required by this bound in `hashicorp_vault::client::VaultClient::<hashicorp_vault::client::TokenData>::new`
    |
    = help: the following implementations were found:
              <url::Url as hashicorp_vault::TryFrom<&'a str>>
              <url::Url as hashicorp_vault::TryFrom<&'a url::Url>>
              <url::Url as hashicorp_vault::TryFrom<url::Url>>
    = note: required because of the requirements on the impl of `hashicorp_vault::TryInto<url::Url>` for `&std::string::String`

TryFrom is implemented in version 2.0 of url but it doesn't seem to be in 1.5.x which this crate uses. It works fine if i manually pull in the url 1.5.x crate and do a Url::parse(&str)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.