abedra / libvault

A C++ library for Hashicorp Vault
MIT License
34 stars 25 forks source link

Choose which version of a key-value to read #105

Closed markus456 closed 2 years ago

markus456 commented 2 years ago

The current code appears to have an implicit method of retrieving versioned keys using the v2 key-value store: by adding ?version=<int> to the end of the Vault::Path, an older version of the secret can be retrieved.

Here's a piece of code that I used to test it:

#include <string>
#include <vector>
#include <iostream>

#include <libvault/VaultClient.h>

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        return 1;
    }

    std::string token = "hvs.F2K0LSocjRYqriKuwLCrjQx6";

    auto error_cb = [&](std::string msg){
        std::cout << "Vault error: " << msg << std::endl;
    };

    auto http_error_cb = [&](Vault::HttpResponse resp) {
        std::cout << "Vault HTTP error: " << resp.statusCode << " " << resp.body << std::endl;
    };

    Vault::TokenStrategy auth{Vault::Token{token}};

    auto builder = Vault::ConfigBuilder()
        .withTlsEnabled(false)
        .withPort(Vault::Port {"8200"})
        .withHost(Vault::Host {"127.0.0.1"});

    Vault::Config config = builder.build();
    Vault::Client client{config, auth, error_cb, http_error_cb};
    Vault::SecretMount mount{"secret"};
    Vault::KeyValue kv{client, mount};
    Vault::Path key{argv[1]};

    if (auto response = kv.read(key))
    {
        std::cout << "Read: " << response.value() << std::endl;
    }

    return 0;
}

And here's the output it produces with a local Vault server (v1.10.3) and a single secret with two versions (the key is 1):

[markusjm@monolith build-develop]$ ./test_vault '1'|jq .
{
  "request_id": "910a93c5-777f-ecb2-b5e6-7b2fc4aa1402",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "data": {
      "data": "d120fbda01f2d6256ea05e1d2ca63178b526428a29225c7e61cf56b05bd59b1c"
    },
    "metadata": {
      "created_time": "2022-06-20T10:13:41.915947528Z",
      "custom_metadata": null,
      "deletion_time": "",
      "destroyed": false,
      "version": 2
    }
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}
[markusjm@monolith build-develop]$ ./test_vault '1?version=1'|jq .
{
  "request_id": "2613dae7-a091-30a8-966b-ebdc05515da6",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "data": {
      "data": "c2575996f82849bd8be10259188421e157eed4bbd9cf985a2382f35c0c8738ac"
    },
    "metadata": {
      "created_time": "2022-06-20T10:13:30.366271133Z",
      "custom_metadata": null,
      "deletion_time": "",
      "destroyed": false,
      "version": 1
    }
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

Is there an explicit method of requesting a certain version of a secret? This doesn't seem like the intended method of using the versioning and none of the examples seem to read versioned values: they appear to only be deleted in tests.

abedra commented 2 years ago

It appears there's a missing overload of read that should take either a specific version or a generic Parameters. The documentation specifies the URL option you have mentioned, but that definitely isn't the intended path forward https://www.vaultproject.io/api-docs/secret/kv/kv-v2#read-secret-version. I'll get this added.

markus456 commented 2 years ago

OK, thanks for confirming!

abedra commented 2 years ago

This is available as of https://github.com/abedra/libvault/commit/225f929242545a625efb029cede4cd464bb71940 and in release https://github.com/abedra/libvault/releases/tag/0.51.0