Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for consul secret engine #73

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod auth;
pub mod consul;
pub mod database;
pub mod kv1;
pub mod kv2;
Expand Down
2 changes: 2 additions & 0 deletions src/api/consul.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod requests;
pub mod responses;
139 changes: 139 additions & 0 deletions src/api/consul/requests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use super::responses::{GenerateConsulCredsResponse, ListRolesResponse, ReadRoleResponse};
use rustify_derive::Endpoint;

/// ## Create/Update access Config
/// This endpoint creates or updates a consul secret engines access configuration.
///
/// * Path: {self.mount}/config/access
/// * Method: POST
/// * Response: N/A
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#configure-access
#[derive(Builder, Debug, Default, Endpoint)]
#[endpoint(path = "{self.mount}/config/access", method = "POST", builder = "true")]
#[builder(setter(into, strip_option), default)]
pub struct SetAccessConfigRequest {
#[endpoint(skip)]
pub mount: String,
pub address: String,
pub schema: Option<String>,
pub token: Option<String>,
pub ca_cert: Option<String>,
pub client_cert: Option<String>,
pub client_key: Option<String>,
}

/// ## Create Role
/// This endpoint creates or updates a named role.
///
/// * Path: {self.mount}/roles/{self.name}
/// * Method: POST
/// * Response: N/A
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#configure-access
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#configure-access
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#create-update-role

#[derive(Builder, Debug, Default, Endpoint)]
#[endpoint(
path = "{self.mount}/roles/{self.name}",
method = "POST",
builder = "true"
)]
#[builder(setter(into, strip_option), default)]
pub struct SetRoleRequest {
#[endpoint(skip)]
pub mount: String,
pub name: String,
pub token_type: Option<String>, // DEPRECATED since consul version 1.4 and removed in 1.11
pub partition: Option<String>,
pub node_identities: Option<Vec<String>>,
pub consul_namespace: Option<String>,
pub service_identities: Option<Vec<String>>,
pub consul_roles: Option<Vec<String>>,
pub consul_policies: Option<Vec<String>>,
pub policy: Option<String>, // DEPRECATED since consul version 1.4 and removed in 1.11
pub policies: Option<Vec<String>>, // DEPRECATED since consul version 1.4 and removed in 1.11
pub local: Option<bool>,
pub max_ttl: Option<String>,
pub ttl: Option<String>,
}

/// ## Read Role
/// This endpoint queries a named role.
///
/// * Path: {self.mount}/roles/{self.name}
/// * Method: GET
/// * Response: [ReadRoleResponse]
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#read-role
#[derive(Builder, Debug, Default, Endpoint)]
#[endpoint(
path = "{self.mount}/roles/{self.name}",
response = "ReadRoleResponse",
builder = "true"
)]
#[builder(setter(into, strip_option), default)]
pub struct ReadRoleRequest {
#[endpoint(skip)]
pub mount: String,
#[endpoint(skip)]
pub name: String,
}

/// ## List Roles
/// This endpoint returns a list of available roles.
///
/// * Path: {self.mount}/roles
/// * Method: LIST
/// * Response: [ListRolesResponse]
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#list-roles
#[derive(Builder, Debug, Default, Endpoint)]
#[endpoint(
path = "{self.mount}/roles",
method = "LIST",
response = "ListRolesResponse",
builder = "true"
)]
#[builder(setter(into, strip_option), default)]
pub struct ListRolesRequest {
#[endpoint(skip)]
pub mount: String,
}

/// ## Delete Role
/// This endpoint deletes a named role.
///
/// * Path: {self.mount}/roles/{self.name}
/// * Method: DELETE
/// * Response: N/A
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#delete-role
#[derive(Builder, Debug, Default, Endpoint)]
#[endpoint(
path = "{self.mount}/roles/{self.name}",
method = "DELETE",
builder = "true"
)]
#[builder(setter(into, strip_option), default)]
pub struct DeleteRoleRequest {
#[endpoint(skip)]
pub mount: String,
#[endpoint(skip)]
pub name: String,
}

/// ## Generate Consul Credentials
/// This endpoint creates credentials with the parameters defined in the given role.
///
/// * Path: {self.mount}/creds/{self.name}
/// * Method: POST
/// * Response: [GenerateConsulCredsResponse]
/// * Reference: https://www.vaultproject.io/api-docs/secret/consul#generate-credential
#[derive(Builder, Debug, Default, Endpoint)]
#[endpoint(
path = "{self.mount}/creds/{self.name}",
method = "POST",
response = "GenerateConsulCredsResponse",
builder = "true"
)]
#[builder(setter(into, strip_option), default)]
pub struct GenerateConsulCredsRequest {
#[endpoint(skip)]
pub mount: String,
#[endpoint(skip)]
pub name: String,
}
33 changes: 33 additions & 0 deletions src/api/consul/responses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use serde::{Deserialize, Serialize};

/// Response from executing
/// [ReadRoleRequest][crate::api::consul::requests::ReadRoleRequest]
#[derive(Deserialize, Debug, Serialize)]
pub struct ReadRoleResponse {
pub token_type: Option<String>, // DEPRECATED since consul version 1.4 and removed in 1.11
pub partition: Option<String>,
pub node_identities: Option<Vec<String>>,
pub consul_namespace: Option<String>,
pub service_identities: Option<Vec<String>>,
pub consul_roles: Option<Vec<String>>,
pub policy: Option<String>, // DEPRECATED since consul version 1.4 and removed in 1.11
pub policies: Option<Vec<String>>, // DEPRECATED since consul version 1.4 and removed in 1.11
pub consul_policies: Option<Vec<String>>,
pub local: bool,
pub max_ttl: u64,
pub ttl: u64,
}

/// Response from executing
/// [ListRolesRequest][crate::api::consul::requests::ListRolesRequest]
#[derive(Deserialize, Debug, Serialize)]
pub struct ListRolesResponse {
pub keys: Vec<String>,
}

/// Response from executing
/// [GenerateConsulCredsRequest][crate::api::consul::requests::GenerateConsulCredsRequest]
#[derive(Deserialize, Debug, Serialize)]
pub struct GenerateConsulCredsResponse {
pub token: String,
}
115 changes: 115 additions & 0 deletions src/consul.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::api;
use crate::api::consul::requests::GenerateConsulCredsRequest;
use crate::api::consul::responses::GenerateConsulCredsResponse;
use crate::client::Client;
use crate::error::ClientError;

/// Generates Consul credentials for the given role
///
/// See [GenerateConsulCredsRequest]
#[instrument(skip(client), err)]
pub async fn generate(
client: &impl Client,
mount: &str,
name: &str,
) -> Result<GenerateConsulCredsResponse, ClientError> {
let endpoint = GenerateConsulCredsRequest::builder()
.mount(mount)
.name(name)
.build()
.unwrap();
api::exec_with_result(client, endpoint).await
}

pub mod config {
use crate::api;
use crate::api::consul::requests::{SetAccessConfigRequest, SetAccessConfigRequestBuilder};
use crate::client::Client;
use crate::error::ClientError;

/// Creates or updates Consul access config
///
/// See [SetAccessConfigRequest]
#[instrument(skip(client, opts), err)]
pub async fn set(
client: &impl Client,
mount: &str,
opts: Option<&mut SetAccessConfigRequestBuilder>,
) -> Result<(), ClientError> {
let mut t = SetAccessConfigRequest::builder();
let endpoint = opts.unwrap_or(&mut t).mount(mount).build().unwrap();
api::exec_with_empty(client, endpoint).await
}
}

pub mod role {
use crate::api;
use crate::api::consul::{
requests::{
DeleteRoleRequest, ListRolesRequest, ReadRoleRequest, SetRoleRequest,
SetRoleRequestBuilder,
},
responses::{ListRolesResponse, ReadRoleResponse},
};
use crate::client::Client;
use crate::error::ClientError;

/// Deletes a role
///
/// See [DeleteRoleRequest]
#[instrument(skip(client), err)]
pub async fn delete(client: &impl Client, mount: &str, name: &str) -> Result<(), ClientError> {
let endpoint = DeleteRoleRequest::builder()
.mount(mount)
.name(name)
.build()
.unwrap();
api::exec_with_empty(client, endpoint).await
}

/// Lists all roles
///
/// See [ListRolesRequest]
#[instrument(skip(client), err)]
pub async fn list(client: &impl Client, mount: &str) -> Result<ListRolesResponse, ClientError> {
let endpoint = ListRolesRequest::builder().mount(mount).build().unwrap();
api::exec_with_result(client, endpoint).await
}

/// Reads a role
///
/// See [ReadRoleRequest]
#[instrument(skip(client), err)]
pub async fn read(
client: &impl Client,
mount: &str,
name: &str,
) -> Result<ReadRoleResponse, ClientError> {
let endpoint = ReadRoleRequest::builder()
.mount(mount)
.name(name)
.build()
.unwrap();
api::exec_with_result(client, endpoint).await
}

/// Creates or updates a role
///
/// See [SetRoleRequest]
#[instrument(skip(client, opts), err)]
pub async fn set(
client: &impl Client,
mount: &str,
name: &str,
opts: Option<&mut SetRoleRequestBuilder>,
) -> Result<(), ClientError> {
let mut t = SetRoleRequest::builder();
let endpoint = opts
.unwrap_or(&mut t)
.mount(mount)
.name(name)
.build()
.unwrap();
api::exec_with_empty(client, endpoint).await
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! * [Token](https://www.vaultproject.io/docs/auth/token)
//! * [Userpass](https://www.vaultproject.io/docs/auth/userpass)
//! * Secrets
//! * [Consul](https://www.vaultproject.io/api-docs/secret/consul)
//! * [Databases](https://www.vaultproject.io/api-docs/secret/databases)
//! * [KV v2](https://www.vaultproject.io/docs/secrets/kv/kv-v2)
//! * [PKI](https://www.vaultproject.io/docs/secrets/pki)
Expand Down Expand Up @@ -199,6 +200,7 @@ extern crate tracing;
pub mod api;
pub mod auth;
pub mod client;
pub mod consul;
pub mod database;
pub mod error;
pub mod kv1;
Expand Down
18 changes: 17 additions & 1 deletion tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use async_trait::async_trait;
pub use dockertest_server::servers::cloud::localstack::{LocalStackServer, LocalStackServerConfig};

Check warning on line 2 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `LocalStackServer`

Check warning on line 2 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `LocalStackServer`
pub use dockertest_server::servers::database::postgres::{PostgresServer, PostgresServerConfig};

Check warning on line 3 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `PostgresServer`

Check warning on line 3 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `PostgresServer`

Check warning on line 3 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `PostgresServer`

Check warning on line 3 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `PostgresServer`
pub use dockertest_server::servers::hashi::{VaultServer, VaultServerConfig};
pub use dockertest_server::servers::hashi::{
ConsulServer, ConsulServerConfig, VaultServer, VaultServerConfig,

Check warning on line 5 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `ConsulServer`

Check warning on line 5 in tests/common.rs

View workflow job for this annotation

GitHub Actions / Run cargo test for vaultrs

unused import: `ConsulServer`
};
use dockertest_server::servers::webserver::nginx::{
ManagedContent, NginxServerConfig, WebserverContent,
};
Expand Down Expand Up @@ -151,6 +153,20 @@
test
}

// Sets up a new consul test.
#[allow(dead_code)]
pub fn new_consul_test() -> Test {
let mut test = new_test();
let consul_config = ConsulServerConfig::builder()
.port(8500)
.version("1.15".to_string())
.token("test".to_string())
.build()
.unwrap();
test.register(consul_config);
test
}

// Sets up a new database test.
#[allow(dead_code)]
pub fn new_db_test() -> Test {
Expand Down
Loading
Loading