Git Product home page Git Product logo

vaultrs's Introduction

vaultrs

An asynchronous Rust client library for the Hashicorp Vault API

The following features are currently supported:

See something missing? Open an issue.

Installation

First, choose one of the two TLS implementations for vaultrs' connection to Vault:

  • rustls (default) to use Rustls
  • native-tls to use rust-native-tls, which builds on your platform-specific TLS implementation.

Then, add vaultrs as a dependency to your cargo.toml:

  1. To use Rustls, import as follows:
[dependencies]
vaultrs = "0.7.1"
  1. To use rust-native-tls, which builds on your platform-specific TLS implementation, specify:
[dependencies]
vaultrs = { version = "0.7.1", default-features = false, features = [ "native-tls" ] }

Usage

Basic

The client is used to configure the connection to Vault and is required to be passed to all API calls for execution. Behind the scenes it uses an asynchronous client from Reqwest for communicating to Vault.

use vaultrs::client::{VaultClient, VaultClientSettingsBuilder};

// Create a client
let client = VaultClient::new(
    VaultClientSettingsBuilder::default()
        .address("https://127.0.0.1:8200")
        .token("TOKEN")
        .build()
        .unwrap()
).unwrap();

Secrets

AWS

The library currently supports all operations available for the AWS Secret Engine.

See tests/aws.rs for more examples.

use vaultrs::sys::mount;
use vaultrs::aws;
use vaultrs::api::aws::requests::{SetConfigurationRequest, CreateUpdateRoleRequest, GenerateCredentialsRequest};

// Mount AWS SE
mount::enable(&client, "aws_test", "aws", None).await?;

// Configure AWS SE
aws::config::set(&client, "aws_test", "access_key", "secret_key", Some(SetConfigurationRequest::builder()        
    .max_retries(3)
    .region("eu-central-1")
)).await?;

// Create HVault role
aws::roles::create_update(&client, "aws_test", "my_role", "assumed_role", Some(CreateUpdateRoleRequest::builder()
        .role_arns( vec!["arn:aws:iam::123456789012:role/test_role".to_string()] )
)).await?;

// Generate credentials
let res = aws::roles::credentials(&client, "aws_test", "my_role", Some(GenerateCredentialsRequest::builder()
    .ttl("3h")
)).await?;

let creds = res;
// creds.access_key
// creds.secret_key
// creds.security_token

Key Value v2

The library currently supports all operations available for version 2 of the key/value store.

use serde::{Deserialize, Serialize};
use vaultrs::kv2;

// Create and read secrets
#[derive(Debug, Deserialize, Serialize)]
struct MySecret {
    key: String,
    password: String,
}

let secret = MySecret {
    key: "super".to_string(),
    password: "secret".to_string(),
};
kv2::set(
    &client,
    "secret",
    "mysecret",
    &secret,
).await;

let secret: MySecret = kv2::read(&client, "secret", "mysecret").await.unwrap();
println!("{}", secret.password); // "secret"

Key Value v1

The library currently supports all operations available for version 1 of the key/value store.

use vaultrs::kv1;
use std::collections::HashMap;

let my_secrets = HashMap::from([
    ("key1".to_string(), "value1".to_string()),
    ("key2".to_string(), "value2".to_string())
]);

kv1::set(&client, "secret", "my/secrets", &my_secrets).await.unwrap();

let read_secrets: HashMap<String, String> = kv1::get(&client, "secret", "my/secrets").await.unwrap();

println!("{:}", read_secrets.get("key1").unwrap()); // value1

let list_secret = kv1::list(&client, "secret", "my").await.unwrap();

println!("{:?}", list_secret.data.keys); // [ "secrets" ]

kv1::delete(&client, "secret", "my/secrets").await.unwrap();

PKI

The library currently supports all operations available for the PKI secrets engine.

use vaultrs::api::pki::requests::GenerateCertificateRequest;
use vaultrs::pki::cert;

// Generate a certificate using the PKI backend
let cert = cert::generate(
    &client,
    "pki",
    "my_role",
    Some(GenerateCertificateRequest::builder().common_name("test.com")),
).await.unwrap();
println!("{}", cert.certificate) // "{PEM encoded certificate}"

Transit

The library supports most operations for the Transit secrets engine, other than importing keys or batch_input parameters.

use vaultrs::api::transit::requests::CreateKeyRequest;
use vaultrs::api::transit::KeyType;
use vaultrs::transit::key;

// Create an encryption key using the /transit backend
key::create(
    &client,
    "transit",
    "my-transit-key",
    Some(CreateKeyRequest::builder()
       .derive(true)
       .key_type(KeyType::Aes256Gcm96)
       .auto_rotate_period("30d")),
).await.unwrap();

Wrapping

All requests implement the ability to be wrapped. These can be passed in your application internally before being unwrapped.

use vaultrs::api::ResponseWrapper;
use vaultrs::api::sys::requests::ListMountsRequest;

let endpoint = ListMountsRequest::builder().build().unwrap();
let wrap_resp = endpoint.wrap(&client).await; // Wrapped response
assert!(wrap_resp.is_ok());

let wrap_resp = wrap_resp.unwrap(); // Unwrap Result<>
let info = wrap_resp.lookup(&client).await; // Check status of this wrapped response
assert!(info.is_ok());

let unwrap_resp = wrap_resp.unwrap(&client).await; // Unwrap the response
assert!(unwrap_resp.is_ok());

let info = wrap_resp.lookup(&client).await; // Error: response already unwrapped
assert!(info.is_err());

Error Handling and Tracing

All errors generated by this crate are wrapped in the ClientError enum provided by the crate. API warnings are automatically captured via tracing and API errors are captured and returned as their own variant. Connection related errors from rustify are wrapped and returned as a single variant.

All top level API operations are instrumented with tracing's #[instrument] attribute.

Testing

See the the tests directory for tests. Run tests with cargo test.

Note: All tests rely on bringing up a local Vault development server using Docker. In order to run tests Docker must be running locally (Docker Desktop works).

Contributing

Check out the issues for items needing attention or submit your own and then:

  1. Fork the repo (https://github.com/jmgilman/vaultrs/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

See CONTRIBUTING for extensive documentation on the architecture of this library and how to add additional functionality to it.

vaultrs's People

Contributors

adriennecohea avatar anexen avatar cobbinma avatar darkecho731 avatar fourbytes avatar grahambinns avatar haennetz avatar jmgilman avatar johanot avatar kornelski avatar lablans avatar matteosister avatar mrioqueiroz avatar nicoulaj avatar nl5887 avatar outscale-fba avatar pierrebeucher avatar r-arias avatar sbcdn avatar sjm42 avatar stormshield-gt avatar taheris avatar thorhs avatar valentincolin 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  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  avatar

vaultrs's Issues

Support for cas option in `SetSecretRequest`?

I need to use the compare-and-swap feature of vault and see that it is not currently supported.

I think it would be fairly simple to add here via something like:

#[derive(Builder, Debug, Endpoint)]
#[endpoint(
    path = "{self.mount}/data/{self.path}",
    response = "SecretVersionMetadata",
    method = "POST",
    builder = "true"
)]
#[builder(setter(into))]
pub struct SetSecretRequest {
    #[endpoint(skip)]
    pub mount: String,
    #[endpoint(skip)]
    pub path: String,
    pub data: Value,
    pub options: Option<SetSecretRequestOptions>,
}

#[derive(Builder, Clone, Debug, serde::Serialize)]
#[builder(setter(into))]
pub struct SetSecretRequestOptions {
    pub cas: u32,
}

is this a feature that would be accepted if I open a PR?

Add support for Vault issuers

Suggested changes

POST /pki//issuer/{issuer_ref}/json implemented by issuer::read
POST /pki/issuers/{issuer_ref}/sign-intermediate implemented by issuer::sign_intermediate
POST /pki/issuers/import/bundle implemented by issuer::import
POST /pki/config/issuers implemented by issuer::set_default
DELETE /pki/issuer/{issuer_ref} implemented by issuer::delete

POST /pki/intermediate/cross-sign implemented by cert::ca::int::cross_sign
DELETE /pki/key/{key_ref} implemented by key::delete

Pull request

#68

Prerequisites

Merge PR in dockertest-server repo that adds support for testing with newest Vault versions (>1.13.3)

URL-Encoding in Path is applied twice

Hi,

I guess I've found a bug when trying to use a path (or the mount) with whitespaces. They seem to be encoded twice.

Example:

kv2::list(&client, "some secret engine", "some path to a secret").await.unwrap();

will yield the following path: https://some-vault-url.com/v1/some%2520secret%2520engine/metadata/some%2520path%2520to%2520a%2520secret

The whitespace seems to be encoded twice. First to %20 and then the % is encoded to %25 which yields %2520. In the end this obviously leads to a 404 on the Vault.

The same behavior can be observed on kv2::read etc.

Here are the relevant logs:

[2023-04-04T20:37:37Z DEBUG rustify::endpoint] Executing endpoint
[2023-04-04T20:37:37Z DEBUG rustify::http] Building endpoint request
[2023-04-04T20:37:37Z DEBUG vaultrs::api] Middleware: prepending v1 version to URL
[2023-04-04T20:37:37Z DEBUG vaultrs::api] Middleware: final URL is https://some-vault-url.com/v1/some%2520secret%2520engine/metadata/some%2520path%2520to%2520a%2520secret
[2023-04-04T20:37:37Z DEBUG vaultrs::api] Middleware: adding token to header

thanks for your work on this library.

RUSTSEC-2020-0159: Potential segfault in `localtime_r` invocations

Potential segfault in localtime_r invocations

Details
Package chrono
Version 0.4.19
URL chronotope/chrono#499
Date 2020-11-10

Impact

Unix-like operating systems may segfault due to dereferencing a dangling pointer in specific circumstances. This requires an environment variable to be set in a different thread than the affected functions. This may occur without the user's knowledge, notably in a third-party library.

Workarounds

No workarounds are known.

References

See advisory page for additional details.

Any plans to add Okta auth method?

Hi! Thanks for the nice implementation of the vault client.

I am planning to use this client for my project, but I failed to find Okta auth method, which is very needed for me.

Are you planning to add it?

Use JWT auth

Hi all,

First of all, thank you for this very useful crate!

I'm trying to migrate some terraform code that interacts with Vault to this crate and I'm facing some difficulties understanding how I should configure the Client for auth.

Here is my terrafrom provider configuration:

provider "vault" {
  address = var.vault_host
  auth_login_jwt {
    mount = var.vault_auth_mount
    jwt   = var.vault_token
    role  = var.auth_role
  }
}

So what I'm currently doing is:

let vault_client = VaultClient::new(
    VaultClientSettingsBuilder::default()
        .address(vault_endpoint)
        .build()
        .map_err(|e| error!("Unable to configure Vault client: {e:?}"))?,
    )
    .map_err(|e| error!("Unable to create Vault Client: {e:?}"))?;

let mut jwt_config = auth::oidc::requests::JWTLoginRequestBuilder::default();
jwt_config
    .mount(auth_mount)
    .role(auth_role)
    .jwt(vault_token);

// This offcourse does not compile!
vaultrs::auth::oidc::config::set(&vault_client, auth_mount, Some(&mut jwt_config))
    .await
    .map_err(|e| error!("Unable to connect to Vault: {e:?}"))?;

Any suggestion?

New crate version with last modifications

Bonjour,

Is it possible to publish a new version of vaultrs on crates.io with the lasts modifications merged on the master branch ?
(notably for namespaces support)

Thanks a lot !

TLS verification is being skipped if VAULT_SKIP_VERIFY has any value

Hi,

I noticed that the VaultClientSettings.verify field is being set to false for any value specified in VAULT_SKIP_VERIFY, whether it is set to true or false.

Vault uses strconv.ParseBool to validate this value:

if v := os.Getenv(EnvVaultSkipVerify); v != "" {
  var err error
  envInsecure, err = strconv.ParseBool(v)
  if err != nil {
    return fmt.Errorf("could not parse VAULT_SKIP_VERIFY")
  }
}

So "1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False" are parsed.

I'm going to submit a PR trying to solve this issue.

RUSTSEC-2023-0052: webpki: CPU denial of service in certificate path building

webpki: CPU denial of service in certificate path building

Details
Package webpki
Version 0.21.4
Date 2023-08-22
Patched versions >=0.22.1

When this crate is given a pathological certificate chain to validate, it will
spend CPU time exponential with the number of candidate certificates at each
step of path building.

Both TLS clients and TLS servers that accept client certificate are affected.

This was previously reported in
<briansmith/webpki#69> and re-reported recently
by Luke Malinowski.

See advisory page for additional details.

Considering migrating to testcontainers

I have the following problems with the dockertest-server used in the test suite:

  • it's no longer maintained
  • it force users to disconnect from VPN to launch the test suite, which is quite annoying (otherwise we get this error)
  • it's not possible to run all the tests locally (Bind for 127.0.0.1:8300 failed: port is already allocated), I'm obligated to run only a subset

I've successfully used testcontainers with Vault at work and it's really easy to setup. I see a lot of advantages

  • maintained
  • supports setting up multiple containers, so we can continue to spawn additional docker (ex AWS)
  • works if a VPN is activated
  • tests are parallelized using different ports so it should also give a significant speedup to the test suite

Add support for asymmetric keys to the transit client

Currently the read and export functions for the transit client do not support asymmetric keypairs.

The read response fails to deserialize, as the response differs for symmetric vs asymmetric keys.

Asymmetric read response:

// vault@926ee8c21172:/$ curl -XGET --insecure --silent -H "X-Vault-Token: $VAULT_TOKEN" $VAULT_ADDR/v1/transit/keys/my-new-key
{
    "request_id": "b59d5612-b16f-8742-641c-32e29943433f",
    "lease_id": "",
    "renewable": false,
    "lease_duration": 0,
    "data": {
        "allow_plaintext_backup": false,
        "auto_rotate_period": 0,
        "deletion_allowed": false,
        "derived": false,
        "exportable": false,
        "imported_key": false,
        "keys": {
            "1": {
                "creation_time": "2024-05-10T13:36:49.809157592Z",
                "name": "rsa-2048",
                "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA01QgwZl/tD7cWZl1NPQ2\nG8+cvI6KkF+wB94xfatdKJ07Ga0bsqYaeE98ZUZU7amRH9Kmdz/4Cu9xXdwlosSS\ntedXfRT8zcWpqEUpV4c4/lT/ox6W67KW2l44liiVt2f9PmviRoYclNWUJa6X+ZCU\n68p/Rd9RSb/xBsywTb8uJN1Q1cZM2JbKhWnaLa7jPsXG9hvnxJ2QFuN3+iZ2OCff\nCjhl0Anumc7lL6wEU/Yd1WuX+5afcHaGttHkWAasrhq3KFHhXlwf4+jrJ5C+aOfb\nevJgGUYjXgf4buV3sPFVmnhvyiyyEV/CysNbXx3KrI/OGgf7HQ+f3+hnpomo8lhd\nwwIDAQAB\n-----END PUBLIC KEY-----\n"
            },
            "2": {
                "creation_time": "2024-05-10T13:36:49.878041842Z",
                "name": "rsa-2048",
                "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7Ttq3kD0Tev7uWnupVGS\neGl4IURKqiUpoPKdevpnYTfuKt/MVP9Ej1Qz7XOP3q6mC3Vb0mSK+6FNjWNakd7D\nQecJwVFuZXp4lF8uzTF5xXFiPiiw5WMS7v7oNmzTE15Msse1yLHcxQGveeRmrl1L\nTYzcLHb705AzgeXoHqLNNWfTC72fqlPhMvOIcWyWOatz/Dp9ukfcR7HAmxhlpluY\n8e+lift8xah4uQFFDuIwXBQ7f5G8+j9RKMyWjA8pv/pY12jDl/vOi6V2b5YJvJie\nVV9gNa1+9JjamG1bsmHYhRIK0rBTewdvD3Tyg+T8Yl5HQNqkIvdwaBZ/RIc+PVeI\ndwIDAQAB\n-----END PUBLIC KEY-----\n"
            },
            "3": {
                "creation_time": "2024-05-10T13:36:49.958724342Z",
                "name": "rsa-2048",
                "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5FQYHEs8U1QsnkTMDrB\n6MfpGK1eVdS84FepYyvpA//suDbJGS9l6XP333wuebwoTL42B5qiZ1tudbIeOWaK\nBDQ5dfjbjRB87k/h4nuQ2DNEUwhgVPjxS3XEocefVWxCfmwQqTjSvhVX2l3DmWiE\n1b/vgikBcYxkqTDTUytuN+IbvZmkFzcM+20UaemRQ5VeNP2MEjZsX4cBATFMkC6k\nYoXb3r+SeKd5JDp/qCSUeabkaxBoV1MprXCy8sEgxSEn/1SGOlVQvB9COQQ/Y/bq\nHQUNGKgrQWGXh4W+Uz4C/GIsKosVuTcGV/o/eONg5uft958NTa1vf93XaKpLOlbw\nOQIDAQAB\n-----END PUBLIC KEY-----\n"
            }
        },
        "latest_version": 3,
        "min_available_version": 0,
        "min_decryption_version": 1,
        "min_encryption_version": 0,
        "name": "my-new-key",
        "supports_decryption": true,
        "supports_derivation": false,
        "supports_encryption": true,
        "supports_signing": true,
        "type": "rsa-2048"
    },
    "wrap_info": null,
    "warnings": null,
    "auth": null
}

This does not follow the "{key_id}": {unix_timestamp} format that symmetric keys use, and hence does not deserialize.

A similar issue for the export route exists, where the only supported key types are:

pub enum ExportKeyType {
    EncryptionKey,
    SigningKey,
    HmacKey,
}

Where PublicKey is omitted.

It would be nice to support asymmetric keys; I will probably start working on some basic support in a fork, and see how I get along.

RUSTSEC-2021-0139: ansi_term is Unmaintained

ansi_term is Unmaintained

Details
Status unmaintained
Package ansi_term
Version 0.12.1
URL ogham/rust-ansi-term#72
Date 2021-08-18

The maintainer has adviced that this crate is deprecated and will not receive any maintenance.

The crate does not seem to have much dependencies and may or may not be ok to use as-is.

Last release seems to have been three years ago.

Possible Alternative(s)

The below list has not been vetted in any way and may or may not contain alternatives;

Dependency Specific Migration(s)

See advisory page for additional details.

SSL cert issue with rustify >0.5.3

Our Vault uses certs signed by our CA and the client has the CA certs in the host trust store. I was able to pin rustify to 0.5.3 and things work just fine, but removing the pin causes this error.

[2024-06-14T19:05:55Z ERROR rustify::clients::reqwest] error=Error sending HTTP request
[2024-06-14T19:05:55Z ERROR rustify::client] error=Error sending HTTP request
[2024-06-14T19:05:55Z ERROR rustify::endpoint] error=Error sending HTTP request
[2024-06-14T19:05:55Z ERROR vaultrs::auth::approle] error=An error occurred with the request
thread 'main' panicked at /home/user/projects/my_project/systemvault/src/lib.rs:355:18:
called Result::unwrap() on an Err value: RestClientError { source: RequestError { source: error sending request for url (https://myvault.example.com:8200/v1/auth/approle/login): error trying to connect: invalid peer certificate: UnknownIssuer

Caused by:
0: error trying to connect: invalid peer certificate: UnknownIssuer
1: invalid peer certificate: UnknownIssuer, url: "https://myvault.example.com:8200/v1/auth/approle/login", method: "POST" } }
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace

Panic when building `VaultClientSettings` without an address

Hi!

I found an issue with the builder for VaultClientSettings.

The following code panics:

fn main() {
    // VAULT_TOKEN and VAULT_ADDR are both set in the environment

    println!("Building without specifying a token...");
    let settings = VaultClientSettingsBuilder::default()
        .address("https://127.0.0.1:8200")
        .build()
        .unwrap(); // works

    println!("{settings:?}");

    println!("Building without specifying an addr...");
    let settings = VaultClientSettingsBuilder::default()
        .token("TOKEN")
        .build() // panics!
        .unwrap();

    println!("{settings:?}");
}

The panic comes from VaultClientSettingsBuilder::validate which unwrap()s self.address.as_ref().

The problem is that according to derive_builder's documentation

Default values are applied after validation, and will therefore not be validated!

So, validate() is called before default_addr() sets anything, making the unwrap panic.

I have created an issue with derive_builder, because I think validation should happen after applying defaults. However, I think the panic here is still avoidable.

See this PR: #30

ResponseParseError in vaultrs::auth::oidc::role::set

Hi, I've a simple function which tries to enable OIDC authentication.

/// Enables Google OIDC
    pub async fn enable_google_oidc(
        &self,
        client_id: &str,
        client_secret: &str,
        redirect_url: &str,
    ) -> Result<(), Box<dyn Error>> {
        let mut oidc_config =
            vaultrs::api::auth::oidc::requests::SetConfigurationRequestBuilder::default();

        oidc_config
            .oidc_discovery_url("https://accounts.google.com")
            .oidc_client_id(client_id)
            .oidc_client_secret(client_secret)
            .default_role("authrole");

        vaultrs::auth::oidc::config::set(&self.client, "google_oidc", Some(&mut oidc_config))
            .await?;

        let token_policies = ["reader".to_string()];
        let scopes = [
            "profile".to_string(),
            "email".to_string(),
            "openid".to_string(),
        ];
        let bound_audiences = [client_id.to_string()];
        let allowed_redir_urls = [redirect_url.to_string()];
        let claim_mappings = HashMap::from([
            ("given_name".to_string(), "given_name".to_string()),
            ("family_name".to_string(), "family_name".to_string()),
            ("email".to_string(), "email".to_string()),
            ("sub".to_string(), "sub".to_string()),
            ("name".to_string(), "name".to_string()),
        ]);

        let mut oidc_auth_role =
            vaultrs::api::auth::oidc::requests::SetRoleRequestBuilder::default();
        oidc_auth_role
            .token_policies(token_policies)
            .oidc_scopes(scopes)
            .bound_audiences(bound_audiences)
            .role_type("oidc")
            .claim_mappings(claim_mappings);

        vaultrs::auth::oidc::role::set(
            &self.client,
            "google_oidc",
            "authrole",
            "email",
            allowed_redir_urls.to_vec(),
            Some(&mut oidc_auth_role),
        )
        .await?;

        Ok(())
    }

However the vaultrs::auth::oidc::role::set function returns the following error after executing it despite the call seems to execute correctly:

RestClientError {
    source: ResponseParseError {
        source: Error("EOF while parsing a value", line: 1, column: 0),
        content: Some(
            "",
        ),
    },
}

Here there's the request/response payload captured using Wireshark:

POST /v1/auth/google_oidc/role/authrole HTTP/1.1
x-vault-token: hvs.E1g3PCrdjvPVslGEMTRoIqwz
accept: */*
host: localhost:8200
content-length: 321

{"allowed_redirect_uris":["http://localhost:8200"],"user_claim":"email","bound_audiences":["google_oidc_client_id"],"claim_mappings":{"given_name":"given_name","name":"name","email":"email","family_name":"family_name","sub":"sub"},"oidc_scopes":["profile","email","openid"],"role_type":"oidc","token_policies":["reader"]}

HTTP/1.1 204 No Content
Cache-Control: no-store
Content-Type: application/json
Strict-Transport-Security: max-age=31536000; includeSubDomains
Date: Thu, 27 Apr 2023 08:59:57 GMT

Vault version used: Vault v1.13.1 (4472e4a3fbcc984b7e3dc48f5a8283f3efe6f282), built 2023-03-23T12:51:35Z

Am I doing something wrong?

Kind Regards.

Allow client certificates for mTLS connections

Hi, our infrastructure configures the vault server to require mTLS connections, which requires configuring client certificates for the http connection.

Also, our client certificates are encrypted with a passphrase, so they need to be decrypted before configuring them in the reqwest builder.

We started a contribution to this project (now closed), but soon we realised that it was not enough and the implementation was a bit trickier than expected, so we decided to use a custom Client in our side until this feature is fully supported here.

We are still aiming at helping with that, but it definitively requires some guidance from the maintainers:

  • How can we decrypt the certificates when the rustls feature is enabled?
  • In case that we leave the decryption out of this lib, is it ok to change String to be a Vec<u8> for the settings involving the client cert, key and passphrase? That would allow the client decrypt them and pass the raw bytes to the lib.
  • What about changing the ca_cert into a Vec<u8> in case we leave the reading of the CA stack to the user too?

Thanks!

There is room for improvement for the logs

The logs right now contains some repetitive information. For instance, here is the log for a simple health check that failed.

2024-03-26T10:20:48.070995Z  INFO status:health: vaultrs::api: Executing /sys/health and expecting an unwrapped response
2024-03-26T10:20:48.072528Z ERROR status:health:exec:execute:send: rustify::clients::reqwest: error=Error sending HTTP request
2024-03-26T10:20:48.072579Z ERROR status:health:exec:execute: rustify::client: error=Error sending HTTP request
2024-03-26T10:20:48.072605Z ERROR status:health:exec: rustify::endpoint: error=Error sending HTTP request
2024-03-26T10:20:48.072630Z ERROR status:health: vaultrs::sys: error=An error occurred with the request
2024-03-26T10:20:48.072651Z ERROR status: vaultrs::sys: error=An error occurred with the request

We get 5 logs, all containing the same information.

We can control some of them, but ones are inside the rustify crate. As the crate seems no longer maintained, they would be difficult to fix. In my opinion, the trace shouldn't have been added to rustify at the first place, as is made to be a building block for client library and shouldn't add log by itself (or at trace or debug level). Hopefully, we can filter them using RUST_LOG="info,rustify=off".

This divide by 2 the number of logs, but it still got redundant information:

2024-03-26T10:40:21.078675Z  INFO status:health: vaultrs::api: Executing /sys/health and expecting an unwrapped response
2024-03-26T10:40:21.080194Z ERROR status:health: vaultrs::sys: error=An error occurred with the request
2024-03-26T10:40:21.080245Z ERROR status: vaultrs::sys: error=An error occurred with the request

Even in the happy path they are still redundant information:

2024-03-26T10:40:21.309718Z  INFO read_by_name{name="mygroup"}: vaultrs::api: Executing identity/group/name/mygroup and expecting a response
2024-03-26T10:40:21.312644Z  INFO read_by_name{name="mygroup"}: vaultrs::api: Stripping response wrapper from API response

Here, "Stripping response wrapper from API response" is an implementation details and shouldn't be logged as info.
Besides, we can notice that a crucial information is missing, the http verbs, which does not makes which method of the endpoint we are actually using.
I think having a span that looks like this request{method=GET path="/foo"}: would be a goal to reach.

In a perfect world, I think logging should be provided as middleware so users can provide their own if they want and we could reuse works from the ecosystem.
Ideally when reqwest will have a better support for middleware (which is on roadmap for 2024) we could just use something like tower_http::trace to do the logging.
If we want to use the midlleware approach right now, we could use already this project, but hopefully by the end of the year this won't be even needed.

If my concerns are also shared, I will submit a PR that will try to improve the current state of logging in vaultrs, by cleaning some of the already existing traces.

[META] Looking for maintainer help

Hi all,

I apologize for being slow to respond to issues/PRs in this repository. I picked up a new day job at the beginning of the year that has been very demanding on my time, and unfortunately, it's caused some projects to slip. I am looking for one or two individuals who are actively using this project and would be interested in helping maintain it. If you're interested in helping out, please reply directly to this issue.

Thanks!

RUSTSEC-2020-0071: Potential segfault in the time crate

Potential segfault in the time crate

Details
Package time
Version 0.1.43
URL time-rs/time#293
Date 2020-11-18
Patched versions >=0.2.23
Unaffected versions =0.2.0,=0.2.1,=0.2.2,=0.2.3,=0.2.4,=0.2.5,=0.2.6

Impact

Unix-like operating systems may segfault due to dereferencing a dangling pointer in specific circumstances. This requires an environment variable to be set in a different thread than the affected functions. This may occur without the user's knowledge, notably in a third-party library.

The affected functions from time 0.2.7 through 0.2.22 are:

  • time::UtcOffset::local_offset_at
  • time::UtcOffset::try_local_offset_at
  • time::UtcOffset::current_local_offset
  • time::UtcOffset::try_current_local_offset
  • time::OffsetDateTime::now_local
  • time::OffsetDateTime::try_now_local

The affected functions in time 0.1 (all versions) are:

  • at
  • at_utc
  • now

Non-Unix targets (including Windows and wasm) are unaffected.

Patches

Pending a proper fix, the internal method that determines the local offset has been modified to always return None on the affected operating systems. This has the effect of returning an Err on the try_* methods and UTC on the non-try_* methods.

Users and library authors with time in their dependency tree should perform cargo update, which will pull in the updated, unaffected code.

Users of time 0.1 do not have a patch and should upgrade to an unaffected version: time 0.2.23 or greater or the 0.3 series.

Workarounds

No workarounds are known.

References

time-rs/time#293

See advisory page for additional details.

Incompatible types on v0.6+ for Ubuntu 20.04 and 22.04

I was trying to build some code that depends on vaultrs and it was failing on these errors. I checked out the vaultrs repo to isolate the issue and found that v0.5.4 is able to compile just fine, but nothing newer. This is Ubuntu 20.04 with latest rustup install, also tried Ubuntu 22.04 with the same error.

~/code/vaultrs$ cargo build
   Compiling vaultrs v0.7.2 (/home/me/code/vaultrs)
error[E0053]: method `request` has an incompatible type for trait
   --> src/api.rs:147:14
    |
147 |         req: &mut http::Request<Vec<u8>>,
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              expected `http::request::Request<Vec<u8>>`, found `http::Request<Vec<u8>>`
    |              help: change the parameter type to match the trait: `&mut http::request::Request<Vec<u8>>`
    |
    = note: expected signature `fn(&EndpointMiddleware, &_, &mut http::request::Request<Vec<u8>>) -> Result<_, _>`
               found signature `fn(&EndpointMiddleware, &_, &mut http::Request<Vec<u8>>) -> Result<_, _>`

error[E0053]: method `response` has an incompatible type for trait
   --> src/api.rs:201:12
    |
201 |         _: &mut http::Response<Vec<u8>>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |            |
    |            expected `http::response::Response<Vec<u8>>`, found `http::Response<Vec<u8>>`
    |            help: change the parameter type to match the trait: `&mut http::response::Response<Vec<u8>>`
    |
    = note: expected signature `fn(&EndpointMiddleware, &_, &mut http::response::Response<Vec<u8>>) -> Result<_, _>`
               found signature `fn(&EndpointMiddleware, &_, &mut http::Response<Vec<u8>>) -> Result<_, _>`

error[E0308]: mismatched types
   --> src/client.rs:134:63
    |
134 |         let http = HTTPClient::new(settings.address.as_str(), http_client);
    |                    ---------------                            ^^^^^^^^^^^ expected `reqwest::async_impl::client::Client`, found `reqwest::Client`
    |                    |
    |                    arguments to this function are incorrect
    |
    = note: `reqwest::Client` and `reqwest::async_impl::client::Client` have similar names, but are actually distinct types
note: `reqwest::Client` is defined in crate `reqwest`
   --> /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/reqwest-0.11.27/src/async_impl/client.rs:69:1
    |
69  | pub struct Client {
    | ^^^^^^^^^^^^^^^^^
note: `reqwest::async_impl::client::Client` is defined in crate `reqwest`
   --> /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/reqwest-0.12.4/src/async_impl/client.rs:71:1
    |
71  | pub struct Client {
    | ^^^^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `reqwest` are being used?
note: associated function defined here
   --> /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rustify-0.5.4/src/clients/reqwest.rs:43:12
    |
43  |     pub fn new(base: &str, http: reqwest::Client) -> Self {
    |            ^^^

Some errors have detailed explanations: E0053, E0308.
For more information about an error, try `rustc --explain E0053`.
error: could not compile `vaultrs` (lib) due to 3 previous errors

Introduce tracing to improve debugging

The library currently doesn't utilize any form of logging. The tokio project has a crate that introduces tracing which seems like a reasonable solution considering most consumers are likely already using the tokio runtime. It's also well-integrated with other logging crates for choose-your-adventure type support.

v0.7.1 build fails for native-tls

When building v0.7.1 with native-tls feature and default-features disabled
vaultrs = { version = "0.7.1", features = ["native-tls"], default-features = false }

getting this error:

$ cargo check
    Checking vaultrs v0.7.1
error[E0599]: no method named `identity` found for struct `ClientBuilder` in the current scope
   --> /home/redacted/.cargo/registry/src/index.crates.io-6f17d22bba15001f/vaultrs-0.7.1/src/client.rs:118:39
    |
118 |             http_client = http_client.identity(identity.clone());
    |                                       ^^^^^^^^ method not found in `ClientBuilder`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `vaultrs` (lib) due to previous error

This doesn't happen in v0.7.0 .

I suppose the added lines client certificates have some issue with feature gate, because the build completes without default-features = false

UqlQueryParseError while reading secret using kv2::read()

When trying to read the latest version of a secret, the following error is returned:

RestClientError { source: UrlQueryParseError { source: unsupported value } }

This is probably related to the version number not being optional.

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.