Skip to content

Commit

Permalink
AppRole can have multiple mounts. Closes #115
Browse files Browse the repository at this point in the history
  • Loading branch information
abedra committed Apr 17, 2023
1 parent dcfec8a commit b8f4359
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 115 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12)
project(
vault
VERSION 0.53.0
VERSION 0.54.0
DESCRIPTION "Vault library for C++")

set(CMAKE_CXX_STANDARD 17)
Expand Down
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# libvault
![CMake](https://github.com/abedra/libvault/workflows/CMake/badge.svg)
<a href="https://lgtm.com/projects/g/abedra/libvault/">
<img src="https://img.shields.io/lgtm/alerts/g/abedra/libvault" alt="Total alerts"/>
</a>
![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/abedra/libvault)
[![Version](https://img.shields.io/badge/version-0.53.0-4a8fff)](https://img.shields.io/badge/version-0.53.0-4a8fff)
[![Version](https://img.shields.io/badge/version-0.54.0-4a8fff)](https://img.shields.io/badge/version-0.54.0-4a8fff)

A C++ library for [Hashicorp Vault](https://www.vaultproject.io/)

Expand Down
10 changes: 7 additions & 3 deletions example/authentication/approle/Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
default: example

example.o: example.cpp
g++ -std=c++17 -c ../../../lib/json.hpp example.cpp
g++ -Wall -std=c++17 -I../../../include -c ../../../lib/json.hpp example.cpp

example: example.o
g++ example.o -o example -lvault -lcurl
g++ -L../../../cmake-build-debug example.o -o example -lvault -lcurl

.PHONY: macos
macos:
install_name_tool -change @rpath/libvault.0.dylib ../../../cmake-build-debug/libvault.0.dylib example

.PHONY: clean
clean:
rm -f example.o example

vault:
docker run -p 8200:8200 vault
docker run -p 8200:8200 vault
25 changes: 13 additions & 12 deletions example/authentication/approle/example.cpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
#include <iostream>
#include "VaultClient.h"
#include "../../shared/shared.h"
#include <iostream>

Vault::Client setup(const Vault::Client &rootClient) {
Vault::Client setup(const Vault::Client &rootClient, const Vault::Path &mount) {
Vault::Sys::Auth authAdmin{rootClient};
Vault::AppRole appRoleAdmin{rootClient};
Vault::AppRole appRoleAdmin{rootClient, mount};

enableAppRole(authAdmin);
enableAppRole(authAdmin, mount);
createRole(appRoleAdmin);

Vault::RoleId roleId = getRoleId(appRoleAdmin);
Vault::SecretId secretId = getSecretId(appRoleAdmin);

return getAppRoleClient(roleId, secretId);
return getAppRoleClient(roleId, secretId, mount);
}

void cleanup(const Vault::Client &rootClient) {
void cleanup(const Vault::Client &rootClient, const Vault::Path &mount) {
Vault::Sys::Auth authAdmin = Vault::Sys::Auth{rootClient};
Vault::AppRole appRoleAdmin = Vault::AppRole{rootClient};
Vault::AppRole appRoleAdmin = Vault::AppRole{rootClient, mount};

deleteRole(appRoleAdmin);
disableAppRole(authAdmin);
disableAppRole(authAdmin, mount);
}

int main(void) {
char *rootTokenEnv = std::getenv("VAULT_ROOT_TOKEN");
if (!rootTokenEnv) {
std::cout << "The VAULT_ROOT_TOKEN environment variable must be set" << std::endl;
std::cout << "The VAULT_ROOT_TOKEN environment variable must be set"
<< std::endl;
exit(-1);
}
Vault::Token rootToken{rootTokenEnv};
Vault::Client rootClient = getRootClient(rootToken);
Vault::Client appRoleClient = setup(rootClient);
Vault::Path mount{"approle"};
Vault::Client appRoleClient = setup(rootClient, mount);

if (appRoleClient.is_authenticated()) {
std::cout << "Authenticated: " << appRoleClient.getToken() << std::endl;
} else {
std::cout << "Unable to authenticate" << std::endl;
}

cleanup(rootClient);
cleanup(rootClient, mount);
}
112 changes: 68 additions & 44 deletions example/shared/shared.h
Original file line number Diff line number Diff line change
@@ -1,120 +1,144 @@
#pragma once
#include <iostream>
#include "../../lib/json.hpp"
#include "libvault/VaultClient.h"
#include "VaultClient.h"
#include <iostream>

Vault::Client getRootClient(const Vault::Token &rootToken) {
inline Vault::Client getRootClient(const Vault::Token &rootToken) {
Vault::TokenStrategy tokenStrategy{rootToken};
Vault::Config config = Vault::ConfigBuilder().withDebug(false).withTlsEnabled(false).build();
Vault::Config config =
Vault::ConfigBuilder().withDebug(false).withTlsEnabled(false).build();
Vault::HttpErrorCallback httpErrorCallback = [&](std::string err) {
std::cout << err << std::endl;
};
Vault::ResponseErrorCallback responseCallback = [&](Vault::HttpResponse err) {
std::cout << err.statusCode << " : " << err.url.value() << " : " << err.body.value() << std::endl;
std::cout << err.statusCode << " : " << err.url.value() << " : "
<< err.body.value() << std::endl;
};
return Vault::Client{config, tokenStrategy, httpErrorCallback, responseCallback};
return Vault::Client{config, tokenStrategy, httpErrorCallback,
responseCallback};
}

Vault::Client getAppRoleClient(const Vault::RoleId &roleId, const Vault::SecretId &secretId) {
Vault::AppRoleStrategy authStrategy{roleId, secretId};
inline Vault::Client getAppRoleClient(const Vault::RoleId &roleId,
const Vault::SecretId &secretId,
const Vault::Path &mount) {
Vault::AppRoleStrategy authStrategy{roleId, secretId, mount};
Vault::Config config = Vault::ConfigBuilder().withTlsEnabled(false).build();

return Vault::Client{config, authStrategy};
}

Vault::Client getJwtClient(const Vault::RoleId &role, const Vault::Jwt &jwt) {
inline Vault::Client getJwtClient(const Vault::RoleId &role,
const Vault::Jwt &jwt) {
Vault::JwtStrategy authStrategy{role, jwt};
Vault::Config config = Vault::ConfigBuilder().withDebug(false).withTlsEnabled(false).build();
Vault::Config config =
Vault::ConfigBuilder().withDebug(false).withTlsEnabled(false).build();
Vault::HttpErrorCallback httpErrorCallback = [&](std::string err) {
std::cout << err << std::endl;
};
Vault::ResponseErrorCallback responseCallback = [&](Vault::HttpResponse err) {
std::cout << err.statusCode << " : " << err.url.value() << " : " << err.body.value() << std::endl;
std::cout << err.statusCode << " : " << err.url.value() << " : "
<< err.body.value() << std::endl;
};

return Vault::Client{config, authStrategy, httpErrorCallback, responseCallback};
return Vault::Client{config, authStrategy, httpErrorCallback,
responseCallback};
}

std::optional<std::string> createPolicy(const Vault::Sys::Policy &policyAdmin) {
Vault::Parameters parameters{{
"policy", "path \"secret/*\" {capabilities = [\"read\", \"update\", \"list\", \"delete\", \"create\"]}"
}};
inline std::optional<std::string>
createPolicy(const Vault::Sys::Policy &policyAdmin) {
Vault::Parameters parameters{
{"policy", "path \"secret/*\" {capabilities = [\"read\", \"update\", "
"\"list\", \"delete\", \"create\"]}"}};
return policyAdmin.create(Vault::Path{"example"}, parameters);
}

std::optional<std::string> deletePolicy(const Vault::Sys::Policy &policyAdmin) {
inline std::optional<std::string>
deletePolicy(const Vault::Sys::Policy &policyAdmin) {
return policyAdmin.del(Vault::Path{"example"});
}

std::optional<std::string> enableAppRole(const Vault::Sys::Auth &authAdmin) {
return authAdmin.enable(Vault::Path{"approle"}, Vault::Parameters{{"type", "approle"}});
inline std::optional<std::string>
enableAppRole(const Vault::Sys::Auth &authAdmin, const Vault::Path &mount) {
return authAdmin.enable(mount, Vault::Parameters{{"type", "approle"}});
}

std::optional<std::string> disableAppRole(const Vault::Sys::Auth &authAdmin) {
return authAdmin.disable(Vault::Path{"approle"});
inline std::optional<std::string>
disableAppRole(const Vault::Sys::Auth &authAdmin, const Vault::Path &mount) {
return authAdmin.disable(mount);
}

std::optional<std::string> createRole(const Vault::AppRole &appRoleAdmin) {
inline std::optional<std::string>
createRole(const Vault::AppRole &appRoleAdmin) {
Vault::Parameters parameters{{"token_policies", "example"}};
return appRoleAdmin.create(Vault::Path{"example"}, parameters);
}

std::optional<std::string> createRole(const Vault::JwtOidc &jwtAdmin) {
Vault::Parameters parameters{
{"role_type", "jwt"},
{"user_claim", "example"},
{"bound_audiences", "example"},
{"policies", "example"}
};
inline std::optional<std::string> createRole(const Vault::JwtOidc &jwtAdmin) {
Vault::Parameters parameters{{"role_type", "jwt"},
{"user_claim", "example"},
{"bound_audiences", "example"},
{"policies", "example"}};

return jwtAdmin.createRole(Vault::Path{"example"}, parameters);
}

std::optional<std::string> deleteRole(const Vault::AppRole &appRoleAdmin) {
inline std::optional<std::string>
deleteRole(const Vault::AppRole &appRoleAdmin) {
return appRoleAdmin.del(Vault::Path{"example"});
}

std::optional<std::string> deleteRole(const Vault::JwtOidc &jwtAdmin) {
inline std::optional<std::string> deleteRole(const Vault::JwtOidc &jwtAdmin) {
return jwtAdmin.deleteRole(Vault::Path{"example"});
}

Vault::RoleId getRoleId(const Vault::AppRole &appRoleAdmin) {
inline Vault::RoleId getRoleId(const Vault::AppRole &appRoleAdmin) {
auto response = appRoleAdmin.getRoleId(Vault::Path{"example"});
if (response) {
return Vault::RoleId{nlohmann::json::parse(response.value())["data"]["role_id"]};
return Vault::RoleId{
nlohmann::json::parse(response.value())["data"]["role_id"]};
} else {
std::cout << "Could not get role id" << std::endl;
exit(-1);
}
}

Vault::SecretId getSecretId(const Vault::AppRole &appRoleAdmin) {
auto response = appRoleAdmin.generateSecretId(Vault::Path{"example"}, Vault::Parameters{});
inline Vault::SecretId getSecretId(const Vault::AppRole &appRoleAdmin) {
auto response = appRoleAdmin.generateSecretId(Vault::Path{"example"},
Vault::Parameters{});
if (response) {
return Vault::SecretId{nlohmann::json::parse(response.value())["data"]["secret_id"]};
return Vault::SecretId{
nlohmann::json::parse(response.value())["data"]["secret_id"]};
} else {
std::cout << "Could not get role id" << std::endl;
exit(-1);
}
}

std::optional<std::string> enableKeyValue(const Vault::Sys::Mounts &mountAdmin) {
return mountAdmin.enable(Vault::Path{}, Vault::Parameters{}, Vault::Parameters{}, Vault::Parameters{});
inline std::optional<std::string>
enableKeyValue(const Vault::Sys::Mounts &mountAdmin) {
return mountAdmin.enable(Vault::Path{}, Vault::Parameters{},
Vault::Parameters{}, Vault::Parameters{});
}

std::optional<std::string> disableKeyValue(const Vault::Sys::Mounts &mountAdmin) {
inline std::optional<std::string>
disableKeyValue(const Vault::Sys::Mounts &mountAdmin) {
return mountAdmin.disable(Vault::Path{});
}

std::optional<std::string> enableJwtAuthentication(const Vault::Sys::Auth &authAdmin) {
return authAdmin.enable(Vault::Path{"jwt"}, Vault::Parameters{{"type", "jwt"}});
inline std::optional<std::string>
enableJwtAuthentication(const Vault::Sys::Auth &authAdmin) {
return authAdmin.enable(Vault::Path{"jwt"},
Vault::Parameters{{"type", "jwt"}});
}

std::optional<std::string> disableJwtAuthentication(const Vault::Sys::Auth &authAdmin) {
inline std::optional<std::string>
disableJwtAuthentication(const Vault::Sys::Auth &authAdmin) {
return authAdmin.disable(Vault::Path{"jwt"});
}

std::optional<std::string> configureJwtAuthentication(const Vault::JwtOidc &jwtAdmin, std::string publicKeyString) {
inline std::optional<std::string>
configureJwtAuthentication(const Vault::JwtOidc &jwtAdmin,
std::string publicKeyString) {
Vault::Parameters parameters{{"jwt_validation_pubkeys", publicKeyString}};
return jwtAdmin.configure(parameters);
}
}
16 changes: 13 additions & 3 deletions include/VaultClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,16 +413,22 @@ class TokenStrategy : public AuthenticationStrategy {

class AppRoleStrategy : public AuthenticationStrategy {
public:
AppRoleStrategy(RoleId roleId, SecretId secretId);
explicit AppRoleStrategy(RoleId roleId, SecretId secretId)
: roleId_(std::move(roleId)), secretId_(std::move(secretId)),
mount_(Path{"approle"}) {}
explicit AppRoleStrategy(RoleId roleId, SecretId secretId, Path mount)
: roleId_(std::move(roleId)), secretId_(std::move(secretId)),
mount_(std::move(mount)) {}

std::optional<AuthenticationResponse>
authenticate(const Client &client) override;

private:
static Url getUrl(const Client &vaultClient, const Path &path);
Url getUrl(const Client &vaultClient, const Path &path);

RoleId roleId_;
SecretId secretId_;
Path mount_;
};

class WrappedSecretAppRoleStrategy : public AuthenticationStrategy {
Expand Down Expand Up @@ -600,7 +606,10 @@ class Transit {

class AppRole {
public:
explicit AppRole(const Client &client) : client_(client) {}
explicit AppRole(const Client &client)
: client_(client), mount_(Path{"approle"}) {}
explicit AppRole(const Client &client, Path mount)
: client_(client), mount_(std::move(mount)) {}

[[nodiscard]] std::optional<std::string> list() const;
[[nodiscard]] std::optional<std::string>
Expand Down Expand Up @@ -642,6 +651,7 @@ class AppRole {
[[nodiscard]] Url getUrl(const Path &path) const;

const Client &client_;
Path mount_;
};

class Sys {
Expand Down
Loading

0 comments on commit b8f4359

Please sign in to comment.