Skip to content

Commit

Permalink
cherry-picks for release 1.1.x (#394)
Browse files Browse the repository at this point in the history
* feature: Use default auth method if no auth method ID is provided for provider (#385)

* Use default auth method if no auth method ID is provided for provider

* docs: Fix typo in Managed Group resource page (#370)

* fix(credlib): Force new resource on credential_type change (#389)

* update changelog

---------

Co-authored-by: Dan Heath <76443935+Dan-Heath@users.noreply.github.com>
Co-authored-by: Hugo <hugoamvieira@users.noreply.github.com>
  • Loading branch information
3 people authored May 5, 2023
1 parent 1a83d0e commit ede5377
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 10 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

Canonical reference for changes, improvements, and bugfixes for the Boundary Terraform provider.

## 1.1.6 (May 5, 2023)

### New and Improved
* Add support for using default auth method if no auth method ID is provided for provider
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/385))
* Fix typo in Managed Group resource page
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/370))

### Bug Fix
* Force new resource on credential_type change
([PR](https://github.com/hashicorp/terraform-provider-boundary/pull/389))

## 1.1.5 (April 21, 2023)

### New and Improved
Expand Down Expand Up @@ -222,4 +234,4 @@ Update provider to handle new domain errors ([PR](https://github.com/hashicorp/t

## 0.1.0 (October 14, 2020)

Initial release!
Initial release!
14 changes: 14 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ provider "boundary" {
password_auth_method_login_name = "myuser" # changeme
password_auth_method_password = "passpass" # changeme
}
provider "boundary" {
addr = "http://127.0.0.1:9200"
password_auth_method_login_name = "myuser"
password_auth_method_password = "passpass"
}
provider "boundary" {
addr = "http://127.0.0.1:9200"
password_auth_method_login_name = "myuser"
password_auth_method_password = "passpass"
scope_id = "s_1234567890"
}
```

<!-- schema generated by tfplugindocs -->
Expand All @@ -36,5 +49,6 @@ provider "boundary" {
- `password_auth_method_password` (String) The auth method password for password-style auth methods
- `plugin_execution_dir` (String) Specifies a directory that the Boundary provider can use to write and execute its built-in plugins.
- `recovery_kms_hcl` (String) Can be a heredoc string or a path on disk. If set, the string/file will be parsed as HCL and used with the recovery KMS mechanism. While this is set, it will override any other authentication information; the KMS mechanism will always be used. See Boundary's KMS docs for examples: https://boundaryproject.io/docs/configuration/kms
- `scope_id` (String) The scope ID for the default auth method.
- `tls_insecure` (Boolean) When set to true, does not validate the Boundary API endpoint certificate
- `token` (String) The Boundary token to use, as a string or path on disk containing just the string. If set, the token read here will be used in place of authenticating with the auth method specified in "auth_method_id", although the recovery KMS mechanism will still override this. Can also be set with the BOUNDARY_TOKEN environment variable.
1 change: 1 addition & 0 deletions docs/resources/credential_store_vault.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ resource "boundary_credential_store_vault" "example" {
- `namespace` (String) The namespace within Vault to use.
- `tls_server_name` (String) Name to use as the SNI host when connecting to Vault via TLS.
- `tls_skip_verify` (Boolean) Whether or not to skip TLS verification.
- `worker_filter` (String) HCP Only. A filter used to control which PKI workers can handle Vault requests. This allows the use of private Vault instances with Boundary.

### Read-Only

Expand Down
4 changes: 1 addition & 3 deletions docs/resources/managed_group.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The managed group resource allows you to configure a Boundary group.
### Required

- `auth_method_id` (String) The resource ID for the auth method.
- `filter` (String) Boolean expression to filter the workers for this managed group.
- `filter` (String) Boolean expression to filter the users for this managed group.

### Optional

Expand All @@ -28,5 +28,3 @@ The managed group resource allows you to configure a Boundary group.
### Read-Only

- `id` (String) The ID of the group.


1 change: 1 addition & 0 deletions docs/resources/target.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ resource "boundary_target" "address_foo" {

- `address` (String) Optionally, a valid network address to connect to for this target. Cannot be used alongside host_source_ids.
- `brokered_credential_source_ids` (Set of String) A list of brokered credential source ID's.
- `default_client_port` (Number) The default client port for this target.
- `default_port` (Number) The default port for this target.
- `description` (String) The target description.
- `egress_worker_filter` (String) Boolean expression to filter the workers used to access this target
Expand Down
13 changes: 13 additions & 0 deletions examples/provider/provider.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,16 @@ provider "boundary" {
password_auth_method_login_name = "myuser" # changeme
password_auth_method_password = "passpass" # changeme
}

provider "boundary" {
addr = "http://127.0.0.1:9200"
password_auth_method_login_name = "myuser"
password_auth_method_password = "passpass"
}

provider "boundary" {
addr = "http://127.0.0.1:9200"
password_auth_method_login_name = "myuser"
password_auth_method_password = "passpass"
scope_id = "s_1234567890"
}
77 changes: 72 additions & 5 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import (
kms_plugin_assets "github.com/hashicorp/terraform-provider-boundary/plugins/kms"
)

const (
PASSWORD_AUTH_METHOD_PREFIX = "ampw"
DEFAULT_PROVIDER_SCOPE = "global"
)

func init() {
// descriptions are written in markdown for docs
schema.DescriptionKind = schema.StringMarkdown
Expand Down Expand Up @@ -69,6 +74,11 @@ func New() *schema.Provider {
Optional: true,
Description: `Specifies a directory that the Boundary provider can use to write and execute its built-in plugins.`,
},
"scope_id": {
Type: schema.TypeString,
Optional: true,
Description: `The scope ID for the default auth method.`,
},
},
ResourcesMap: map[string]*schema.Resource{
"boundary_account": resourceAccount(),
Expand Down Expand Up @@ -114,13 +124,33 @@ type metaData struct {

func providerAuthenticate(ctx context.Context, d *schema.ResourceData, md *metaData) error {
var credentials map[string]interface{}
amClient := authmethods.NewClient(md.client)

var providerScope string
scopeId, scopeIdOk := d.GetOk("scope_id")
switch {
case scopeIdOk:
providerScope = scopeId.(string)
default:
providerScope = DEFAULT_PROVIDER_SCOPE
}

authMethodId, authMethodIdOk := d.GetOk("auth_method_id")
recoveryKmsHcl, recoveryKmsHclOk := d.GetOk("recovery_kms_hcl")
if token, ok := d.GetOk("token"); ok {
md.client.SetToken(token.(string))
}

// If auth_method_id is not set, get the default auth method ID for the given scope ID
authMethodId, authMethodIdOk := d.GetOk("auth_method_id")
if !authMethodIdOk {
defaultAuthMethodId, err := getDefaultAuthMethodId(ctx, amClient, providerScope, PASSWORD_AUTH_METHOD_PREFIX)
if err != nil {
return err
}
authMethodIdOk = true
authMethodId = defaultAuthMethodId
}

switch {
case recoveryKmsHclOk:
recoveryHclStr, _, err := ReadPathOrContents(recoveryKmsHcl.(string))
Expand Down Expand Up @@ -173,14 +203,14 @@ func providerAuthenticate(ctx context.Context, d *schema.ResourceData, md *metaD
"login_name": authMethodLoginName,
"password": authMethodPassword,
}

case strings.HasPrefix(authMethodId.(string), "amoidc"):
// OIDC-style
return errors.New("OIDC auth method is currently not supported by Boundary Terraform Provider. only password auth method is supported at this time")
default:
return errors.New("no suitable typed auth method information found")
}

am := authmethods.NewClient(md.client)

at, err := am.Authenticate(ctx, authMethodId.(string), "login", credentials)
at, err := amClient.Authenticate(ctx, authMethodId.(string), "login", credentials)
if err != nil {
if apiErr := api.AsServerError(err); apiErr != nil {
statusCode := apiErr.Response().StatusCode()
Expand Down Expand Up @@ -237,3 +267,40 @@ func providerConfigure(p *schema.Provider) schema.ConfigureContextFunc {
return md, nil
}
}

// getDefaultAuthMethodId iterates over boundary client.List() to find the default auth method ID for the given scopeId.
// If there is only one auth method, it'll return it even if it's not the primary auth method
// If scope ID is empty or no primary auth method is found, it returns an error.
func getDefaultAuthMethodId(ctx context.Context, client *authmethods.Client, scopeId, amType string) (string, error) {
if scopeId == "" {
return "", fmt.Errorf("must pass a non empty scope ID string to get default auth method ID")
}
authMethodListResult, err := client.List(ctx, scopeId)
if err != nil {
return "", err
}

authMethodItems := authMethodListResult.GetItems()

// If there is only one auth method that matches the auth method prefix, return it even if it's not the primary auth method
if len(authMethodItems) == 1 {
authMethod := authMethodItems[0]
if !strings.HasPrefix(authMethod.Id, amType) {
return "", fmt.Errorf("error looking up default auth method for scope ID: '%s'. got '%s' but the provider requires an auth method prefix of '%s'", scopeId, authMethod.Id, amType)
}

return authMethod.Id, nil
}

// find the primary auth method that matches auth method prefix
for _, m := range authMethodItems {
if m.IsPrimary {
if !strings.HasPrefix(m.Id, amType) {
return "", fmt.Errorf("error looking up primary auth method for scope ID: '%s'. got '%s' but the provider requires an auth method prefix of '%s'", scopeId, m.Id, amType)
}

return m.Id, nil
}
}
return "", fmt.Errorf("default auth method not found for scope ID: '%s'. Please set a primary auth method on this scope or pass one explicitly using the `auth_method_id` field", scopeId)
}
106 changes: 106 additions & 0 deletions internal/provider/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"regexp"
"strings"
"testing"

Expand All @@ -16,6 +17,7 @@ import (
"github.com/hashicorp/go-kms-wrapping/v2/aead"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

var (
Expand Down Expand Up @@ -98,6 +100,42 @@ provider "boundary" {
return strings.Join(c, "\n")
}

func testConfigWithDefaultAuthMethod(url string, res ...string) string {
provider := fmt.Sprintf(`
provider "boundary" {
addr = "%s"
password_auth_method_login_name = "%s"
password_auth_method_password = "%s"
}`, url, tcLoginName, tcPassword)

c := []string{provider}
c = append(c, res...)
return strings.Join(c, "\n")
}

func testConfigWithOIDCAuthMethod(url string, res ...string) string {
provider := fmt.Sprintf(`
provider "boundary" {
addr = "%s"
auth_method_id = "amoidc_0000000000"
}`, url)

c := []string{provider}
c = append(c, res...)
return strings.Join(c, "\n")
}

func testConfigWithoutAMPWCredentials(url string, res ...string) string {
provider := fmt.Sprintf(`
provider "boundary" {
addr = "%s"
}`, url)

c := []string{provider}
c = append(c, res...)
return strings.Join(c, "\n")
}

func testConfigWithRecovery(url string, res ...string) string {
provider := fmt.Sprintf(`
provider "boundary" {
Expand Down Expand Up @@ -139,3 +177,71 @@ func TestProvider(t *testing.T) {
t.Fatalf("err: %s", err)
}
}

func TestConfigWithDefaultAuthMethod(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]

var provider *schema.Provider
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProviderFactories: providerFactories(&provider),
CheckDestroy: testAccCheckScopeResourceDestroy(t, provider),
Steps: []resource.TestStep{
{
Config: testConfigWithDefaultAuthMethod(url, fooOrg, firstProjectFoo, secondProject),
Check: resource.ComposeTestCheckFunc(
testAccCheckScopeResourceExists(provider, "boundary_scope.org1"),
testProviderTokenExists(provider),
),
},
},
})
}

func TestConfigWithoutAMPWCredentials(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]

var provider *schema.Provider
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProviderFactories: providerFactories(&provider),
Steps: []resource.TestStep{
{
Config: testConfigWithoutAMPWCredentials(url, fooOrg, firstProjectFoo, secondProject),
ExpectError: regexp.MustCompile("password-style auth method login name not set, please set password_auth_method_login_name on the provider"),
},
},
})
}

func TestConfigWithOIDCAuthMethod(t *testing.T) {
tc := controller.NewTestController(t, tcConfig...)
defer tc.Shutdown()
url := tc.ApiAddrs()[0]

var provider *schema.Provider
resource.Test(t, resource.TestCase{
IsUnitTest: true,
ProviderFactories: providerFactories(&provider),
Steps: []resource.TestStep{
{
Config: testConfigWithOIDCAuthMethod(url, fooOrg, firstProjectFoo, secondProject),
ExpectError: regexp.MustCompile("OIDC auth method is currently not supported by Boundary Terraform Provider. only password auth method is supported at this time"),
},
},
})
}

func testProviderTokenExists(testProvider *schema.Provider) resource.TestCheckFunc {
return func(s *terraform.State) error {
md := testProvider.Meta().(*metaData)
if md.client.Token() == "" {
return fmt.Errorf("token not set")
}
return nil
}
}
3 changes: 2 additions & 1 deletion internal/provider/resource_credential_library_vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ func resourceCredentialLibraryVault() *schema.Resource {
Required: true,
},
credentialLibraryCredentialTypeKey: {
Description: "The type of credential the library generates.",
Description: "The type of credential the library generates. Cannot be updated on an existing resource.",
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
credentialLibraryCredentialMappingOverridesKey: {
Description: "The credential mapping override.",
Expand Down

0 comments on commit ede5377

Please sign in to comment.