Skip to content

Commit

Permalink
Add new data source for HCP Vault (#524)
Browse files Browse the repository at this point in the history
* Add new data source

* add changelog
  • Loading branch information
austinvalle committed Jun 13, 2023
1 parent 2ae1559 commit 08a0a25
Show file tree
Hide file tree
Showing 11 changed files with 429 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .changelog/524.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
hcp_vault_secrets_app: New data source that allows bulk retrieval of all secret values in a secrets app
```
34 changes: 34 additions & 0 deletions docs/data-sources/vault_secrets_app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
page_title: "Data Source hcp_vault_secrets_app - terraform-provider-hcp"
subcategory: ""
description: |-
The Vault Secrets app data source retrieves secrets and their latest version values for a given application.
---

# hcp_vault_secrets_app (Data Source)

-> **Note:** This data source is currently in public beta.

The Vault Secrets app data source retrieves secrets and their latest version values for a given application.

## Example Usage

```terraform
data "hcp_vault_secrets_app" "example" {
app_name = "example-vault-secrets-app"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `app_name` (String) The name of the Vault Secrets application.

### Read-Only

- `id` (String) The ID of this resource.
- `organization_id` (String) The ID of the HCP organization where the Vault Secrets app is located.
- `project_id` (String) The ID of the HCP project where the Vault Secrets app is located.
- `secrets` (Map of String, Sensitive) A map of all secrets in the Vault Secrets app. Key is the secret name, value is the latest secret version value.
3 changes: 3 additions & 0 deletions examples/data-sources/hcp_vault_secrets_app/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "hcp_vault_secrets_app" "example" {
app_name = "example-vault-secrets-app"
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/google/uuid v1.3.0
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcp-sdk-go v0.46.0
github.com/hashicorp/hcp-sdk-go v0.49.0
github.com/hashicorp/terraform-plugin-docs v0.13.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0
github.com/stretchr/testify v1.8.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ github.com/hashicorp/hc-install v0.5.0 h1:D9bl4KayIYKEeJ4vUDe9L5huqxZXczKaykSRcm
github.com/hashicorp/hc-install v0.5.0/go.mod h1:JyzMfbzfSBSjoDCRPna1vi/24BEDxFaCPfdHtM5SCdo=
github.com/hashicorp/hcl/v2 v2.16.1 h1:BwuxEMD/tsYgbhIW7UuI3crjovf3MzuFWiVgiv57iHg=
github.com/hashicorp/hcl/v2 v2.16.1/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng=
github.com/hashicorp/hcp-sdk-go v0.46.0 h1:LXKVJDb7QNoqMJt5/sLZwv1Wd4o1dVP3E9K30Sk0nks=
github.com/hashicorp/hcp-sdk-go v0.46.0/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc=
github.com/hashicorp/hcp-sdk-go v0.49.0 h1:eKjJfDdngfIB17G8EmzMWJmye3daK+UbxWO9qjPVS1Q=
github.com/hashicorp/hcp-sdk-go v0.49.0/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-exec v0.17.3 h1:MX14Kvnka/oWGmIkyuyvL6POx25ZmKrjlaclkx3eErU=
Expand Down
5 changes: 5 additions & 0 deletions internal/clients/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
cloud_vault "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-service/stable/2020-11-25/client"
"github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-service/stable/2020-11-25/client/vault_service"

cloud_vault_secrets "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/preview/2023-06-13/client"
"github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/preview/2023-06-13/client/secret_service"

cloud_packer "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/client"
"github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/client/packer_service"

Expand All @@ -43,6 +46,7 @@ type Client struct {
Organization organization_service.ClientService
Consul consul_service.ClientService
Vault vault_service.ClientService
VaultSecrets secret_service.ClientService
Packer packer_service.ClientService
Boundary boundary_service.ClientService
}
Expand Down Expand Up @@ -89,6 +93,7 @@ func NewClient(config ClientConfig) (*Client, error) {
Organization: cloud_resource_manager.New(httpClient, nil).OrganizationService,
Consul: cloud_consul.New(httpClient, nil).ConsulService,
Vault: cloud_vault.New(httpClient, nil).VaultService,
VaultSecrets: cloud_vault_secrets.New(httpClient, nil).SecretService,
Packer: cloud_packer.New(httpClient, nil).PackerService,
Boundary: cloud_boundary.New(httpClient, nil).BoundaryService,
}
Expand Down
119 changes: 119 additions & 0 deletions internal/clients/vault_secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package clients

import (
"context"

sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models"

"github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/preview/2023-06-13/client/secret_service"
secretmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/preview/2023-06-13/models"
)

// CreateVaultSecretsApp will create a Vault Secrets application.
func CreateVaultSecretsApp(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName string) (*secretmodels.Secrets20230613App, error) {

createParams := secret_service.NewCreateAppParams()
createParams.Context = ctx
createParams.Body.Name = appName
createParams.LocationOrganizationID = loc.OrganizationID
createParams.LocationProjectID = loc.ProjectID

createResp, err := client.VaultSecrets.CreateApp(createParams, nil)
if err != nil {
return nil, err
}

return createResp.Payload.App, nil
}

// ListVaultSecretsAppSecrets will retrieve all app secrets metadata for a Vault Secrets application.
func ListVaultSecretsAppSecrets(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName string) ([]*secretmodels.Secrets20230613Secret, error) {

listParams := secret_service.NewListAppSecretsParams()
listParams.Context = ctx
listParams.AppName = appName
listParams.LocationOrganizationID = loc.OrganizationID
listParams.LocationProjectID = loc.ProjectID

listResp, err := client.VaultSecrets.ListAppSecrets(listParams, nil)
if err != nil {
return nil, err
}

return listResp.Payload.Secrets, nil
}

// DeleteVaultSecretsApp will delete a Vault Secrets application.
func DeleteVaultSecretsApp(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName string) error {

deleteParams := secret_service.NewDeleteAppParams()
deleteParams.Context = ctx
deleteParams.Name = appName
deleteParams.LocationOrganizationID = loc.OrganizationID
deleteParams.LocationProjectID = loc.ProjectID

_, err := client.VaultSecrets.DeleteApp(deleteParams, nil)
if err != nil {
return err
}

return nil
}

// CreateVaultSecretsAppSecret will create a Vault Secrets application secret.
func CreateVaultSecretsAppSecret(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName, secretName, secretValue string) (*secretmodels.Secrets20230613Secret, error) {

createParams := secret_service.NewCreateAppKVSecretParams()
createParams.Context = ctx
createParams.AppName = appName
createParams.Body.Name = secretName
createParams.Body.Value = secretValue
createParams.LocationOrganizationID = loc.OrganizationID
createParams.LocationProjectID = loc.ProjectID

createResp, err := client.VaultSecrets.CreateAppKVSecret(createParams, nil)
if err != nil {
return nil, err
}

return createResp.Payload.Secret, nil
}

// OpenVaultSecretsAppSecret will retrieve the latest secret for a Vault Secrets app, including it's value.
func OpenVaultSecretsAppSecret(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName, secretName string) (*secretmodels.Secrets20230613OpenSecret, error) {

getParams := secret_service.NewOpenAppSecretParams()
getParams.Context = ctx
getParams.AppName = appName
getParams.SecretName = secretName
getParams.LocationOrganizationID = loc.OrganizationID
getParams.LocationProjectID = loc.ProjectID

getResp, err := client.VaultSecrets.OpenAppSecret(getParams, nil)
if err != nil {
return nil, err
}

return getResp.Payload.Secret, nil
}

// DeleteVaultSecretsAppSecret will delete a Vault Secrets application secret.
func DeleteVaultSecretsAppSecret(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName, secretName string) error {

deleteParams := secret_service.NewDeleteAppSecretParams()
deleteParams.Context = ctx
deleteParams.AppName = appName
deleteParams.SecretName = secretName
deleteParams.LocationOrganizationID = loc.OrganizationID
deleteParams.LocationProjectID = loc.ProjectID

_, err := client.VaultSecrets.DeleteAppSecret(deleteParams, nil)
if err != nil {
return err
}

return nil
}
111 changes: 111 additions & 0 deletions internal/provider/data_source_vault_secrets_app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package provider

import (
"context"
"log"

sharedmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-shared/v1/models"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/hashicorp/terraform-provider-hcp/internal/clients"
)

func dataSourceVaultSecretsApp() *schema.Resource {
return &schema.Resource{
Description: "The Vault Secrets app data source retrieves secrets and their latest version values for a given application.",
ReadContext: dataSourceVaultSecretsAppRead,
Schema: map[string]*schema.Schema{
"app_name": {
Description: "The name of the Vault Secrets application.",
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validateSlugID,
},
"organization_id": {
Description: "The ID of the HCP organization where the Vault Secrets app is located.",
Type: schema.TypeString,
Computed: true,
},
"project_id": {
Description: "The ID of the HCP project where the Vault Secrets app is located.",
Type: schema.TypeString,
Computed: true,
},
"secrets": {
Description: "A map of all secrets in the Vault Secrets app. Key is the secret name, value is the latest secret version value.",
Type: schema.TypeMap,
Computed: true,
Sensitive: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func dataSourceVaultSecretsAppRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
appName, ok := d.Get("app_name").(string)
if !ok {
return diag.Errorf("Failed to read app_name during data source Read.")
}
client := meta.(*clients.Client)
loc := &sharedmodels.HashicorpCloudLocationLocation{
OrganizationID: client.Config.OrganizationID,
ProjectID: client.Config.ProjectID,
}

log.Printf("[INFO] Listing Vault Secrets App secrets (%s) [project_id=%s, organization_id=%s]", appName, loc.ProjectID, loc.OrganizationID)

appSecrets, err := clients.ListVaultSecretsAppSecrets(ctx, client, loc, appName)
if err != nil {
if clients.IsResponseCodeNotFound(err) {
return diag.Errorf("VCS app (%s) does not exist", appName)
}
return diag.FromErr(err)
}

openAppSecrets := map[string]string{}
for _, appSecret := range appSecrets {
secretName := appSecret.Name

log.Printf("[INFO] Opening latest Vault Secrets App Secret (%s - %s) [project_id=%s, organization_id=%s]", appName, secretName, loc.ProjectID, loc.OrganizationID)

openSecret, err := clients.OpenVaultSecretsAppSecret(ctx, client, loc, appName, secretName)
if err != nil {
if clients.IsResponseCodeNotFound(err) {
return diag.Errorf("Vault Secrets App Secret (%s - %s) does not exist", appName, secretName)
}
return diag.FromErr(err)
}

openAppSecrets[secretName] = openSecret.Version.Value
}

err = setVaultSecretsAppDataSourceAttributes(d, appName, loc, openAppSecrets)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func setVaultSecretsAppDataSourceAttributes(d *schema.ResourceData, appName string, loc *sharedmodels.HashicorpCloudLocationLocation, openSecrets map[string]string) error {
d.SetId(appName)

if err := d.Set("organization_id", loc.OrganizationID); err != nil {
return err
}
if err := d.Set("project_id", loc.ProjectID); err != nil {
return err
}
if err := d.Set("secrets", openSecrets); err != nil {
return err
}

return nil
}
Loading

0 comments on commit 08a0a25

Please sign in to comment.