Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support importing okta_auth_backend resource #1123

Merged
merged 14 commits into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/hashicorp/go-hclog v0.16.1
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1
github.com/hashicorp/terraform-plugin-sdk v1.9.0
github.com/hashicorp/vault v1.2.0
github.com/hashicorp/vault/api v1.1.2-0.20210719211531-6b31c12b0af2
Expand Down
116 changes: 105 additions & 11 deletions vault/resource_okta_auth_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"errors"
"fmt"
"log"
"strconv"
"strings"

"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/terraform-plugin-sdk/helper/hashcode"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-provider-vault/util"
Expand All @@ -20,9 +22,11 @@ func oktaAuthBackendResource() *schema.Resource {
Delete: oktaAuthBackendDelete,
Read: oktaAuthBackendRead,
Update: oktaAuthBackendUpdate,

Exists: oktaAuthBackendExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{

"path": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -76,17 +80,23 @@ func oktaAuthBackendResource() *schema.Resource {
},

"ttl": {
Type: schema.TypeString,
Required: false,
Optional: true,
Description: "Duration after which authentication will be expired",
Type: schema.TypeString,
Required: false,
Optional: true,
Default: "0",
tvoran marked this conversation as resolved.
Show resolved Hide resolved
Description: "Duration after which authentication will be expired",
ValidateFunc: validateOktaTTL,
StateFunc: normalizeOktaTTL,
},

"max_ttl": {
Type: schema.TypeString,
Required: false,
Optional: true,
Description: "Maximum duration after which authentication will be expired",
Type: schema.TypeString,
Required: false,
Optional: true,
Description: "Maximum duration after which authentication will be expired",
Default: "0",
ValidateFunc: validateOktaTTL,
StateFunc: normalizeOktaTTL,
},

"group": {
Expand Down Expand Up @@ -204,6 +214,35 @@ func oktaAuthBackendResource() *schema.Resource {
}
}

func normalizeOktaTTL(i interface{}) string {
s, err := parseDurationSeconds(i)
if err != nil {
// validateOktaTTL should prevent ever getting here
return i.(string)
benashz marked this conversation as resolved.
Show resolved Hide resolved
}
return s
}

func validateOktaTTL(i interface{}, k string) ([]string, []error) {
var values []string
var errors []error
s, err := parseDurationSeconds(i)
if err != nil {
errors = append(errors, fmt.Errorf("invalid value for %q, could not parse %q", k, i))
values = append(values, s)
}
return values, errors
}

func parseDurationSeconds(i interface{}) (string, error) {
d, err := parseutil.ParseDurationSecond(i)
if err != nil {
log.Printf("[ERROR] Could not parse %v to seconds, error: %s", i, err)
return "", err
}
return strconv.Itoa(int(d.Seconds())), nil
}

func oktaAuthBackendWrite(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

Expand Down Expand Up @@ -245,6 +284,10 @@ func oktaAuthBackendDelete(d *schema.ResourceData, meta interface{}) error {
return nil
}

func oktaAuthBackendExists(d *schema.ResourceData, meta interface{}) (bool, error) {
return isOktaAuthBackendPresent(meta.(*api.Client), d.Id())
}

func oktaAuthBackendRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

Expand All @@ -263,12 +306,21 @@ func oktaAuthBackendRead(d *schema.ResourceData, meta interface{}) error {
return nil
}

if err := d.Set("path", path); err != nil {
return err
}

mount, err := authMountInfoGet(client, path)
if err != nil {
return fmt.Errorf("error reading okta oth mount from '%q': %s", path, err)
}

d.Set("accessor", mount.Accessor)
if err := d.Set("accessor", mount.Accessor); err != nil {
return err
}
if err := d.Set("description", mount.Description); err != nil {
return err
}

log.Printf("[DEBUG] Reading groups for mount %s from Vault", path)
groups, err := oktaReadAllGroups(client, path)
Expand All @@ -288,8 +340,50 @@ func oktaAuthBackendRead(d *schema.ResourceData, meta interface{}) error {
return err
}

if err := oktaReadAuthConfig(client, path, d); err != nil {
return err
}

return nil
}

func oktaReadAuthConfig(client *api.Client, path string, d *schema.ResourceData) error {
log.Printf("[DEBUG] Reading auth config for mount %s from Vault", path)
config, err := client.Logical().Read(oktaConfigEndpoint(path))
if err != nil {
return err
}

// map schema config TTL strings to okta auth TTL params.
// the provider input type of string does not match Vault's API of int64
ttlFieldMap := map[string]string{
"ttl": "token_ttl",
"max_ttl": "token_max_ttl",
}
for k, v := range ttlFieldMap {
if v, ok := config.Data[v]; ok {
s, err := parseutil.ParseString(v)
if err != nil {
return err
}
if err := d.Set(k, s); err != nil {
return err
}
}
}

params := []string{
"base_url",
"bypass_okta_mfa",
"organization",
}
for _, param := range params {
if err := d.Set(param, config.Data[param]); err != nil {
return err
}
}

return nil
}

func oktaAuthBackendUpdate(d *schema.ResourceData, meta interface{}) error {
Expand Down
113 changes: 108 additions & 5 deletions vault/resource_okta_auth_backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@ package vault
import (
"encoding/json"
"fmt"
"strconv"
"regexp"
"testing"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/hashicorp/terraform-provider-vault/util"
"github.com/hashicorp/vault/api"
)

func TestAccOktaAuthBackend(t *testing.T) {
path := "okta-" + strconv.Itoa(acctest.RandInt())
func TestAccOktaAuthBackend_basic(t *testing.T) {
organization := "example"
path := resource.PrefixedUniqueId("okta-basic-")

resource.Test(t, resource.TestCase{
PreCheck: func() { util.TestAccPreCheck(t) },
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccOktaAuthBackend_Destroyed(path),
Steps: []resource.TestStep{
{
Expand All @@ -42,6 +41,84 @@ func TestAccOktaAuthBackend(t *testing.T) {
})
}

func TestAccOktaAuthBackend_import(t *testing.T) {
organization := "example"
path := resource.PrefixedUniqueId("okta-import-")

resource.Test(t, resource.TestCase{
PreCheck: func() { util.TestAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAccOktaAuthBackend_Destroyed(path),
Steps: []resource.TestStep{
{
Config: testAccOktaAuthConfig_basic(path, organization),
Check: resource.ComposeTestCheckFunc(
testAccOktaAuthBackend_InitialCheck,
testAccOktaAuthBackend_GroupsCheck(path, "dummy", []string{"one", "two", "default"}),
testAccOktaAuthBackend_UsersCheck(path, "foo", []string{"dummy"}, []string{}),
),
},
{
ResourceName: "vault_okta_auth_backend.test",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"token",
},
},
{
Config: testAccOktaAuthConfig_updated(path, organization),
Check: resource.ComposeTestCheckFunc(
testAccOktaAuthBackend_GroupsCheck(path, "example", []string{"three", "four", "default"}),
testAccOktaAuthBackend_UsersCheck(path, "bar", []string{"example"}, []string{}),
),
},
{
ResourceName: "vault_okta_auth_backend.test",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"token",
},
},
},
})
}

func TestAccOktaAuthBackend_invalid_ttl(t *testing.T) {
organization := "example"
path := resource.PrefixedUniqueId("okta-invalid-ttl-")

resource.Test(t, resource.TestCase{
PreCheck: func() { util.TestAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAccOktaAuthBackend_Destroyed(path),
Steps: []resource.TestStep{
{
Config: testAccOktaAuthConfig_invalid_ttl(path, organization),
ExpectError: regexp.MustCompile(`invalid value for "ttl", could not parse "invalid_ttl"$`),
},
},
})
}

func TestAccOktaAuthBackend_invalid_max_ttl(t *testing.T) {
organization := "example"
path := resource.PrefixedUniqueId("okta-invalid_max_ttl-")

resource.Test(t, resource.TestCase{
PreCheck: func() { util.TestAccPreCheck(t) },
Providers: testProviders,
CheckDestroy: testAccOktaAuthBackend_Destroyed(path),
Steps: []resource.TestStep{
{
Config: testAccOktaAuthConfig_invalid_max_ttl(path, organization),
ExpectError: regexp.MustCompile(`invalid value for "max_ttl", could not parse "invalid_max_ttl"$`),
},
},
})
}

func testAccOktaAuthConfig_basic(path string, organization string) string {
return fmt.Sprintf(`
resource "vault_okta_auth_backend" "test" {
Expand Down Expand Up @@ -81,6 +158,32 @@ resource "vault_okta_auth_backend" "test" {
`, path, organization)
}

func testAccOktaAuthConfig_invalid_ttl(path string, organization string) string {
return fmt.Sprintf(`
resource "vault_okta_auth_backend" "test" {
description = "Testing the Terraform okta auth backend"
path = "%s"
organization = "%s"
token = "this must be kept secret"
ttl = "invalid_ttl"
max_ttl = "1h"
}
`, path, organization)
}

func testAccOktaAuthConfig_invalid_max_ttl(path string, organization string) string {
return fmt.Sprintf(`
resource "vault_okta_auth_backend" "test" {
description = "Testing the Terraform okta auth backend"
path = "%s"
organization = "%s"
token = "this must be kept secret"
ttl = "1h"
max_ttl = "invalid_max_ttl"
}
`, path, organization)
}

func testAccOktaAuthBackend_InitialCheck(s *terraform.State) error {
resourceState := s.Modules[0].Resources["vault_okta_auth_backend.test"]
if resourceState == nil {
Expand Down
8 changes: 8 additions & 0 deletions website/docs/r/okta_auth_backend.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,11 @@ If this is not supplied only locally configured groups will be enabled.
In addition to all arguments above, the following attributes are exported:

* `accessor` - The mount accessor related to the auth mount. It is useful for integration with [Identity Secrets Engine](https://www.vaultproject.io/docs/secrets/identity/index.html).

## Import

Okta authentication backends can be imported using its `path`, e.g.

```
$ terraform import vault_okta_auth_backend.example okta
```