Compare commits

...
1 Commits
Author SHA1 Message Date
Pradeep SekarandAndrew Gaffney babc45b758 Bump newversion (#779)
Lint GitHub Actions workflows / actionlint (push) Successful in 2s
build / Detect Go toolchain version (push) Successful in 3s
build / Parse version file (push) Successful in 4s
make-gen-delta / Check for uncommitted changes from make gen (push) Failing after 36s
test / test (push) Canceled after 31m0s
build / generate-metadata-file (push) Canceled after 0s
build / upload-terraform-registry-manifest-artifact (push) Canceled after 0s
build / Go darwin 386 build (push) Canceled after 0s
build / Go darwin amd64 build (push) Canceled after 0s
build / Go darwin arm64 build (push) Canceled after 0s
build / Go freebsd 386 build (push) Canceled after 0s
build / Go freebsd amd64 build (push) Canceled after 0s
build / Go freebsd arm build (push) Canceled after 0s
build / Go linux 386 build (push) Canceled after 0s
build / Go linux amd64 build (push) Canceled after 0s
build / Go linux arm64 build (push) Canceled after 0s
build / Go linux arm build (push) Canceled after 0s
build / Go windows 386 build (push) Canceled after 0s
build / Go windows amd64 build (push) Canceled after 0s
build / What's next? (push) Canceled after 0s
* feat(provider): Implement Vault Ldap Resource (#778)

* Bump version 1.5.1.

---------

Co-authored-by: Andrew Gaffney <109917432+anGaffney@users.noreply.github.com>
2026-02-02 17:42:37 -08:00
9 changed files with 420 additions and 1 deletions

No files matched your search

+7
View File
@@ -4,6 +4,13 @@ Canonical reference for changes, improvements, and bugfixes for the Boundary Ter
## Next
## 1.5.1 (Feb 2nd, 2026)
### New and Improved
* Adds support for Vault LDAP Credential Store.
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/778))
## 1.5.0 (December 19th, 2025)
### New and Improved
@@ -0,0 +1,79 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "boundary_credential_library_vault_ldap Resource - terraform-provider-boundary"
subcategory: ""
description: |-
The credential library for Vault LDAP resource allows you to configure a Boundary credential library for Vault LDAP.
---
# boundary_credential_library_vault_ldap (Resource)
The credential library for Vault LDAP resource allows you to configure a Boundary credential library for Vault LDAP.
## Example Usage
```terraform
resource "boundary_scope" "org" {
name = "organization_one"
description = "My first scope!"
scope_id = "global"
auto_create_admin_role = true
auto_create_default_role = true
}
resource "boundary_scope" "project" {
name = "project_one"
description = "My first scope!"
scope_id = boundary_scope.org.id
auto_create_admin_role = true
}
resource "boundary_credential_store_vault" "foo" {
name = "foo"
description = "My first Vault credential store!"
address = "http://127.0.0.1:8200" # change to Vault address
token = "s.0ufRo6XEGU2jOqnIr7OlFYP5" # change to valid Vault token
scope_id = boundary_scope.project.id
}
resource "boundary_credential_library_vault_ldap" "foo-static" {
name = "foo"
description = "My first static Vault LDAP credential library!"
credential_store_id = boundary_credential_store_vault.foo.id
path = "ldap/static-cred/foo" # change to Vault backend path
}
resource "boundary_credential_library_vault_ldap" "bar-dynamic" {
name = "bar"
description = "My first dynamic Vault LDAP credential library!"
credential_store_id = boundary_credential_store_vault.foo.id
path = "ldap/creds/bar" # change to Vault backend path
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `credential_store_id` (String) The ID of the credential store that this library belongs to.
- `path` (String) The path in Vault to request credentials from.
### Optional
- `description` (String) The Vault LDAP credential library description.
- `name` (String) The Vault LDAP credential library name. Defaults to the resource name.
### Read-Only
- `id` (String) The ID of the Vault LDAP credential library.
## Import
Import is supported using the following syntax:
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
```shell
terraform import boundary_credential_library_vault_ldap.foo <my-id>
```
@@ -0,0 +1 @@
terraform import boundary_credential_library_vault_ldap.foo <my-id>
@@ -0,0 +1,36 @@
resource "boundary_scope" "org" {
name = "organization_one"
description = "My first scope!"
scope_id = "global"
auto_create_admin_role = true
auto_create_default_role = true
}
resource "boundary_scope" "project" {
name = "project_one"
description = "My first scope!"
scope_id = boundary_scope.org.id
auto_create_admin_role = true
}
resource "boundary_credential_store_vault" "foo" {
name = "foo"
description = "My first Vault credential store!"
address = "http://127.0.0.1:8200" # change to Vault address
token = "s.0ufRo6XEGU2jOqnIr7OlFYP5" # change to valid Vault token
scope_id = boundary_scope.project.id
}
resource "boundary_credential_library_vault_ldap" "foo-static" {
name = "foo"
description = "My first static Vault LDAP credential library!"
credential_store_id = boundary_credential_store_vault.foo.id
path = "ldap/static-cred/foo" # change to Vault backend path
}
resource "boundary_credential_library_vault_ldap" "bar-dynamic" {
name = "bar"
description = "My first dynamic Vault LDAP credential library!"
credential_store_id = boundary_credential_store_vault.foo.id
path = "ldap/creds/bar" # change to Vault backend path
}
+1
View File
@@ -105,6 +105,7 @@ func New() *schema.Provider {
"boundary_auth_method_ldap": resourceAuthMethodLdap(),
"boundary_credential_library_vault": resourceCredentialLibraryVault(),
"boundary_credential_library_vault_ssh_certificate": resourceCredentialLibraryVaultSshCertificate(),
"boundary_credential_library_vault_ldap": resourceCredentialLibraryVaultLdap(),
"boundary_credential_store_vault": resourceCredentialStoreVault(),
"boundary_credential_store_static": resourceCredentialStoreStatic(),
"boundary_credential_username_password": resourceCredentialUsernamePassword(),
@@ -0,0 +1,204 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"context"
"net/http"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/credentiallibraries"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
credentialLibraryVaultLdapType = "vault-ldap"
credentialLibraryVaultLdapPathKey = "path"
)
var libraryVaultLdapAttrs = []string{
credentialLibraryVaultLdapPathKey,
}
func resourceCredentialLibraryVaultLdap() *schema.Resource {
return &schema.Resource{
Description: "The credential library for Vault LDAP resource allows you to configure a Boundary credential library for Vault LDAP.",
CreateContext: resourceCredentialLibraryCreateVaultLdap,
ReadContext: resourceCredentialLibraryReadVaultLdap,
UpdateContext: resourceCredentialLibraryUpdateVaultLdap,
DeleteContext: resourceCredentialLibraryDeleteVaultLdap,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
IDKey: {
Description: "The ID of the Vault LDAP credential library.",
Type: schema.TypeString,
Computed: true,
},
NameKey: {
Description: "The Vault LDAP credential library name. Defaults to the resource name.",
Type: schema.TypeString,
Optional: true,
},
DescriptionKey: {
Description: "The Vault LDAP credential library description.",
Type: schema.TypeString,
Optional: true,
},
credentialStoreIdKey: {
Description: "The ID of the credential store that this library belongs to.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
credentialLibraryVaultLdapPathKey: {
Description: "The path in Vault to request credentials from.",
Type: schema.TypeString,
Required: true,
},
},
}
}
func setFromVaultLdapCredentialLibraryResponseMap(d *schema.ResourceData, raw map[string]interface{}) error {
if err := d.Set(NameKey, raw[NameKey]); err != nil {
return err
}
if err := d.Set(DescriptionKey, raw[DescriptionKey]); err != nil {
return err
}
if err := d.Set(credentialStoreIdKey, raw[credentialStoreIdKey]); err != nil {
return err
}
if attrsVal, ok := raw["attributes"]; ok {
attrs := attrsVal.(map[string]interface{})
for _, v := range libraryVaultLdapAttrs {
if err := d.Set(v, attrs[v]); err != nil {
return err
}
}
}
d.SetId(raw["id"].(string))
return nil
}
func resourceCredentialLibraryCreateVaultLdap(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
var opts []credentiallibraries.Option
if v, ok := d.GetOk(NameKey); ok {
opts = append(opts, credentiallibraries.WithName(v.(string)))
}
if v, ok := d.GetOk(DescriptionKey); ok {
opts = append(opts, credentiallibraries.WithDescription(v.(string)))
}
if v, ok := d.GetOk(credentialLibraryVaultLdapPathKey); ok {
opts = append(opts, credentiallibraries.WithVaultLdapCredentialLibraryPath(v.(string)))
}
var credentialStoreId string
cid, ok := d.GetOk(credentialStoreIdKey)
if ok {
credentialStoreId = cid.(string)
} else {
return diag.Errorf("no credential store ID is set")
}
client := credentiallibraries.NewClient(md.client)
cr, err := client.Create(ctx, credentialLibraryVaultLdapType, credentialStoreId, opts...)
if err != nil {
return diag.Errorf("error creating credential library: %v", err)
}
if cr == nil {
return diag.Errorf("nil credential library after create")
}
if err := setFromVaultLdapCredentialLibraryResponseMap(d, cr.GetResponse().Map); err != nil {
return diag.FromErr(err)
}
return nil
}
func resourceCredentialLibraryReadVaultLdap(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
client := credentiallibraries.NewClient(md.client)
cr, err := client.Read(ctx, d.Id())
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
d.SetId("")
return nil
}
return diag.Errorf("error reading credential library: %v", err)
}
if cr == nil {
return diag.Errorf("credential library nil after read")
}
if err := setFromVaultLdapCredentialLibraryResponseMap(d, cr.GetResponse().Map); err != nil {
return diag.FromErr(err)
}
return nil
}
func resourceCredentialLibraryUpdateVaultLdap(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
client := credentiallibraries.NewClient(md.client)
var opts []credentiallibraries.Option
if d.HasChange(NameKey) {
opts = append(opts, credentiallibraries.DefaultName())
nameVal, ok := d.GetOk(NameKey)
if ok {
opts = append(opts, credentiallibraries.WithName(nameVal.(string)))
}
}
if d.HasChange(DescriptionKey) {
opts = append(opts, credentiallibraries.DefaultDescription())
descVal, ok := d.GetOk(DescriptionKey)
if ok {
opts = append(opts, credentiallibraries.WithDescription(descVal.(string)))
}
}
if d.HasChange(credentialLibraryVaultLdapPathKey) {
v, ok := d.GetOk(credentialLibraryVaultLdapPathKey)
if ok {
opts = append(opts, credentiallibraries.WithVaultLdapCredentialLibraryPath(v.(string)))
}
}
if len(opts) > 0 {
opts = append(opts, credentiallibraries.WithAutomaticVersioning(true))
aur, err := client.Update(ctx, d.Id(), 0, opts...)
if err != nil {
return diag.Errorf("error updating credential library: %v", err)
}
if err := setFromVaultLdapCredentialLibraryResponseMap(d, aur.GetResponse().Map); err != nil {
return diag.Errorf("error setting credential library from response: %v", err)
}
}
return nil
}
func resourceCredentialLibraryDeleteVaultLdap(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
md := meta.(*metaData)
client := credentiallibraries.NewClient(md.client)
_, err := client.Delete(ctx, d.Id())
if err != nil {
return diag.Errorf("error deleting credential library: %v", err)
}
return nil
}
@@ -0,0 +1,90 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"fmt"
"testing"
"github.com/hashicorp/boundary/testing/controller"
"github.com/hashicorp/boundary/testing/vault"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
const (
vaultLdapCredResc = "boundary_credential_library_vault_ldap.example"
vaultLdapCredLibName = "foo"
vaultLdapCredLibDesc = "the foo"
vaultLdapCredLibPath = "/ldap/static-cred/foo"
vaultLdapCredLibStringUpdate = "_random"
)
var vaultLdapCredLibResource = fmt.Sprintf(`
resource "boundary_credential_library_vault_ldap" "example" {
name = "%s"
description = "%s"
credential_store_id = boundary_credential_store_vault.example.id
path = "%s"
}`, vaultLdapCredLibName,
vaultLdapCredLibDesc,
vaultLdapCredLibPath)
var vaultLdapCredLibResourceUpdate = fmt.Sprintf(`
resource "boundary_credential_library_vault_ldap" "example" {
name = "%s"
description = "%s"
credential_store_id = boundary_credential_store_vault.example.id
path = "%s"
}`, vaultLdapCredLibName+vaultLdapCredLibStringUpdate,
vaultLdapCredLibDesc+vaultLdapCredLibStringUpdate,
vaultLdapCredLibPath+vaultLdapCredLibStringUpdate)
func TestAccCredentialLibraryVaultLdap(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]
vc := vault.NewTestVaultServer(t)
_, token := vc.CreateToken(t)
credStoreRes := vaultCredStoreResource(vc,
vaultCredStoreName,
vaultCredStoreDesc,
vaultCredStoreNamespace,
"www.original.com",
token,
true)
var provider *schema.Provider
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProviderFactories: providerFactories(&provider),
CheckDestroy: testAccCheckCredentialLibraryVaultResourceDestroy(t, provider, ldapVaultCredentialLibraryType),
Steps: []resource.TestStep{
{
// create
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultLdapCredLibResource),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(vaultLdapCredResc, NameKey, vaultLdapCredLibName),
resource.TestCheckResourceAttr(vaultLdapCredResc, DescriptionKey, vaultLdapCredLibDesc),
resource.TestCheckResourceAttr(vaultLdapCredResc, credentialLibraryVaultLdapPathKey, vaultLdapCredLibPath),
testAccCheckCredentialLibraryResourceExists(provider, vaultLdapCredResc),
),
},
importStep(vaultLdapCredResc),
{
// update
Config: testConfig(url, fooOrg, firstProjectFoo, credStoreRes, vaultLdapCredLibResourceUpdate),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(vaultLdapCredResc, NameKey, vaultLdapCredLibName+vaultLdapCredLibStringUpdate),
resource.TestCheckResourceAttr(vaultLdapCredResc, DescriptionKey, vaultLdapCredLibDesc+vaultLdapCredLibStringUpdate),
resource.TestCheckResourceAttr(vaultLdapCredResc, credentialLibraryVaultLdapPathKey, vaultLdapCredLibPath+vaultLdapCredLibStringUpdate),
testAccCheckCredentialLibraryResourceExists(provider, vaultLdapCredResc),
),
},
importStep(vaultLdapCredResc),
},
})
}
@@ -302,6 +302,7 @@ type vaultCredentialLibraryType string
const (
baseVaultCredentialLibraryType vaultCredentialLibraryType = "boundary_credential_library_vault"
sshCertVaultCredentialLibraryType vaultCredentialLibraryType = "boundary_credential_library_vault_ssh_certificate"
ldapVaultCredentialLibraryType vaultCredentialLibraryType = "boundary_credential_library_vault_ldap"
)
func testAccCheckCredentialLibraryVaultResourceDestroy(t *testing.T, testProvider *schema.Provider, typ vaultCredentialLibraryType) resource.TestCheckFunc {
+1 -1
View File
@@ -1 +1 @@
1.5.0
1.5.1