From 5b35ae4ba2f4f6f78ff03afe5443de71091cae39 Mon Sep 17 00:00:00 2001 From: Yoko Hyakuna Date: Thu, 23 Mar 2023 16:04:50 -0700 Subject: [PATCH] Add OpenAPI Go and C# (#18896) * Add OpenAPI Go and C# * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Add code sample links for OpenAPI-based Go and .NET * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> * Remove command flags that are no longer needed * Fix 'OpenAPI C#' > 'OpenAPI .NET' * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel * Update website/content/docs/get-started/developer-qs.mdx Co-authored-by: AnPucel --------- Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com> Co-authored-by: AnPucel --- .../content/docs/get-started/developer-qs.mdx | 234 ++++++++++++++++-- 1 file changed, 217 insertions(+), 17 deletions(-) diff --git a/website/content/docs/get-started/developer-qs.mdx b/website/content/docs/get-started/developer-qs.mdx index 4cc34f86cfba..c969ca89aa00 100644 --- a/website/content/docs/get-started/developer-qs.mdx +++ b/website/content/docs/get-started/developer-qs.mdx @@ -15,6 +15,8 @@ The complete code samples for the steps below are available here: - [C#](https://github.com/hashicorp/vault-examples/blob/main/examples/_quick-start/dotnet/Example.cs) - [Python](https://github.com/hashicorp/vault-examples/blob/main/examples/_quick-start/python/example.py) - [Java (Spring)](https://github.com/hashicorp/vault-examples/blob/main/examples/_quick-start/java/Example.java) +- [OpenAPI-based Go](https://github.com/hashicorp/vault-client-go/#getting-started) +- [OpenAPI-based .NET](https://github.com/hashicorp/vault-client-dotnet/#getting-started) For an out-of-the-box runnable demo application showcasing these concepts and more, see the hello-vault repositories ([Go](https://github.com/hashicorp/hello-vault-go), [C#](https://github.com/hashicorp/hello-vault-dotnet) and [Java/Spring Boot](https://github.com/hashicorp/hello-vault-spring)). @@ -57,7 +59,7 @@ Let's install the Vault client library for your language of choice. -> **Note**: Some of these libraries are currently community-maintained. - + [Go](https://pkg.go.dev/github.com/hashicorp/vault/api) (official) client library: @@ -76,7 +78,7 @@ import vault "github.com/hashicorp/vault/api" - + [Ruby](https://github.com/hashicorp/vault-ruby) (official) client library: @@ -96,7 +98,7 @@ require "vault" - + [C#](https://github.com/rajanadar/VaultSharp) client library: @@ -119,7 +121,7 @@ using VaultSharp.V1.Commons; - + [Python](https://github.com/hvac/hvac) client library: @@ -139,7 +141,7 @@ import hvac - + [Java (Spring)](https://spring.io/projects/spring-vault) client library: @@ -167,6 +169,59 @@ import org.springframework.vault.core.VaultTemplate; + + + + +[OpenAPI Go](https://github.com/hashicorp/vault-client-go) (Beta) client library: + +```shell-session +$ go get github.com/hashicorp/vault-client-go +``` + +Now, let's add the import statements for the client library to the top of the file. + + + +```go +import ( + "github.com/hashicorp/vault-client-go" + "github.com/hashicorp/vault-client-go/schema" +) +``` + + + + + + + + +[OpenAPI .NET](https://github.com/hashicorp/vault-client-dotnet) (Beta) client library: + +Vault is a package available at [Hashicorp Nuget](https://www.nuget.org/profiles/hashicorp). + + +```shell-session +$ nuget install HashiCorp.Vault -Version "0.1.0-beta" +``` + +**Or:** + +```shell-session +$ dotnet add package Hashicorp.Vault -version "0.1.0-beta" +``` + +Now, let's add the import statements for the client library to the top of the file. + + + +```cs +using Vault; +using Vault.Client; +``` + + @@ -179,7 +234,8 @@ A variety of [authentication methods](/vault/docs/auth) can be used to prove you To keep things simple for our example, we'll just use the root token created in **Step 1**. Paste the following code to initialize a new Vault client that will use token-based authentication for all its requests: - + + ```go config := vault.DefaultConfig() @@ -194,6 +250,9 @@ if err != nil { client.SetToken("dev-only-token") ``` + + + ```ruby Vault.configure do |config| config.address = "http://127.0.0.1:8200" @@ -201,6 +260,9 @@ Vault.configure do |config| end ``` + + + ```cs IAuthMethodInfo authMethod = new TokenAuthMethodInfo(vaultToken: "dev-only-token"); @@ -209,6 +271,9 @@ VaultClientSettings("http://127.0.0.1:8200", authMethod); IVaultClient vaultClient = new VaultClient(vaultClientSettings); ``` + + + ```Python client = hvac.Client( url='http://127.0.0.1:8200', @@ -216,6 +281,9 @@ client = hvac.Client( ) ``` + + + ```Java VaultEndpoint vaultEndpoint = new VaultEndpoint(); @@ -229,11 +297,43 @@ VaultTemplate vaultTemplate = new VaultTemplate( ); ``` + + + ```shell-session -export VAULT_TOKEN="dev-only-token" +$ export VAULT_TOKEN="dev-only-token" ``` - + + + +```go +client, err := vault.New( + vault.WithAddress("http://127.0.0.1:8200"), + vault.WithRequestTimeout(30*time.Second), +) +if err != nil { + log.Fatal(err) +} + +if err := client.SetToken("dev-only-token"); err != nil { + log.Fatal(err) +} +``` + + + + +```cs +string address = "http://127.0.0.1:8200"; +VaultConfiguration config = new VaultConfiguration(address); + +VaultClient vaultClient = new VaultClient(config); +vaultClient.SetToken("dev-only-token"); +``` + + + ## Step 4: Store a secret @@ -241,7 +341,8 @@ Secrets are sensitive data like API keys and passwords that we shouldn’t be st We'll use the Vault client we just initialized to write a secret to Vault, like so: - + + ```go secretData := map[string]interface{}{ @@ -257,6 +358,9 @@ if err != nil { fmt.Println("Secret written successfully.") ``` + + + ```ruby secret_data = {data: {password: "Hashi123"}} Vault.logical.write("secret/data/my-secret-password", secret_data) @@ -264,6 +368,9 @@ Vault.logical.write("secret/data/my-secret-password", secret_data) puts "Secret written successfully." ``` + + + ```cs var secretData = new Dictionary { { "password", "Hashi123" } }; vaultClient.V1.Secrets.KeyValue.V2.WriteSecretAsync( @@ -275,6 +382,9 @@ vaultClient.V1.Secrets.KeyValue.V2.WriteSecretAsync( Console.WriteLine("Secret written successfully."); ``` + + + ```Python create_response = client.secrets.kv.v2.create_or_update_secret( path='my-secret-password', @@ -284,6 +394,9 @@ create_response = client.secrets.kv.v2.create_or_update_secret( print('Secret written successfully.') ``` + + + ```Java Map data = new HashMap<>(); data.put("password", "Hashi123"); @@ -295,8 +408,11 @@ Versioned.Metadata createResponse = vaultTemplate System.out.println("Secret written successfully."); ``` + + + ```shell-session -curl \ +$ curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ --header "Content-Type: application/json" \ --request POST \ @@ -304,7 +420,36 @@ curl \ http://127.0.0.1:8200/v1/secret/data/my-secret-password ``` - + + + +```go +_, err = client.Secrets.KVv2Write(context.Background(), "my-secret-password", schema.KVv2WriteRequest{ + Data: map[string]any{ + "password": "Hashi123", + }, +}) +if err != nil { + log.Fatal(err) +} + +log.Println("Secret written successfully.") +``` + + + + +```cs +var secretData = new Dictionary { { "password", "Hashi123" } }; + +// Write a secret +var kvRequestData = new KVv2WriteRequest(secretData); + +vaultClient.Secrets.KVv2Write("my-secret-password", kvRequestData); +``` + + + A common way of storing secrets is as key-value pairs using the [KV secrets engine (v2)](/vault/docs/secrets/kv/kv-v2). In the code we've just added, `password` is the key in the key-value pair, and `Hashi123` is the value. @@ -318,7 +463,8 @@ Now that we know how to write a secret, let's practice reading one. Underneath the line where you wrote a secret to Vault, let's add a few more lines, where we will be retrieving the secret and unpacking the value: - + + ```go secret, err := client.KVv2("secret").Get(context.Background(), "my-secret-password") @@ -332,11 +478,17 @@ log.Fatalf("value type assertion failed: %T %#v", secret.Data["password"], secre } ``` + + + ```ruby secret = Vault.logical.read("secret/data/my-secret-password") password = secret.data[:data][:password] ``` + + + ```cs Secret secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync( path: "/my-secret-password", @@ -346,12 +498,18 @@ Secret secret = vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync( var password = secret.Data.Data["password"]; ``` + + + ```Python read_response = client.secrets.kv.read_secret_version(path='my-secret-password') password = read_response['data']['data']['password'] ``` + + + ```Java Versioned> readResponse = vaultTemplate .opsForVersionedKeyValue("secret") @@ -363,17 +521,42 @@ if (readResponse != null && readResponse.hasData()) { } ``` + + + ```shell-session -curl \ +$ curl \ --header "X-Vault-Token: $VAULT_TOKEN" \ http://127.0.0.1:8200/v1/secret/data/my-secret-password > secrets.json ``` - + + + +```go +s, err := client.Secrets.KVv2Read(context.Background(), "my-secret-password") +if err != nil { + log.Fatal(err) +} + +log.Println("Secret retrieved:", s.Data) +``` + + + + +```cs +VaultResponse resp = vaultClient.Secrets.KVv2Read("my-secret-password"); +Console.WriteLine(resp.Data); +``` + + + Last, confirm that the value we unpacked from the read response is correct: - + + ```go if value != "Hashi123" { @@ -383,12 +566,18 @@ if value != "Hashi123" { fmt.Println("Access granted!") ``` + + + ```ruby abort "Unexpected password" if password != "Hashi123" puts "Access granted!" ``` + + + ```cs if (password.ToString() != "Hashi123") { @@ -398,6 +587,9 @@ if (password.ToString() != "Hashi123") Console.WriteLine("Access granted!"); ``` + + + ```Python if password != 'Hashi123': sys.exit('unexpected password') @@ -405,6 +597,9 @@ if password != 'Hashi123': print('Access granted!') ``` + + + ```Java if (!password.equals("Hashi123")) { throw new Exception("Unexpected password"); @@ -413,10 +608,15 @@ if (!password.equals("Hashi123")) { System.out.println("Access granted!"); ``` + + + ```shell-session - cat secrets.json | jq '.data.data' +$ cat secrets.json | jq '.data.data' ``` - + + + If the secret was fetched successfully, you should see the `Access granted!` message after you run the code. If not, check to see if you provided the correct path to your secret.