cherry-picks for release 1.1.x (#394)
* 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>
This commit is contained in:
9 files changed
+223
-10
No files matched your search
+13
-1
@@ -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
|
||||
@@ -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!
|
||||
@@ -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 -->
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -28,5 +28,3 @@ The managed group resource allows you to configure a Boundary group.
|
||||
### Read-Only
|
||||
|
||||
- `id` (String) The ID of the group.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(),
|
||||
@@ -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))
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -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 (
|
||||
@@ -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" {
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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.",
|
||||
|
||||
Reference in new issue
Block a user