Skip to content

Commit

Permalink
Merge pull request #139 from andrew-bulford-form3/add-kong-consumer-k…
Browse files Browse the repository at this point in the history
…ey-auth-resource

Add `kong_consumer_key_auth` resource
  • Loading branch information
kevholditch-f3 authored Oct 8, 2021
2 parents f3e7282 + 2b14ef2 commit 82d072e
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 14 deletions.
28 changes: 28 additions & 0 deletions docs/resources/consumer_key_auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# kong_consumer_key_auth

Resource that allows you to configure the [Key Authentication](https://docs.konghq.com/hub/kong-inc/key-auth/) plugin for a consumer.

## Example Usage

```hcl
resource "kong_consumer" "my_consumer" {
username = "User1"
custom_id = "123"
}
resource "kong_plugin" "key_auth_plugin" {
name = "key-auth"
}
resource "kong_consumer_key_auth" "consumer_key_auth" {
consumer_id = kong_consumer.my_consumer.id
key = "secret"
tags = ["myTag", "anotherTag"]
}
```

## Argument Reference

* `consumer_id` - (Required) the id of the consumer to associate the credentials to
* `key` - (Optional) Unique key to authenticate the client; if omitted the plugin will generate one
* `tags` - (Optional) A list of strings associated with the consumer key auth for grouping and filtering
1 change: 1 addition & 0 deletions kong/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func Provider() *schema.Provider {
"kong_consumer": resourceKongConsumer(),
"kong_consumer_acl": resourceKongConsumerACL(),
"kong_consumer_basic_auth": resourceKongConsumerBasicAuth(),
"kong_consumer_key_auth": resourceKongConsumerKeyAuth(),
"kong_plugin": resourceKongPlugin(),
"kong_upstream": resourceKongUpstream(),
"kong_target": resourceKongTarget(),
Expand Down
4 changes: 2 additions & 2 deletions kong/resource_kong_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ func resourceKongConsumer() *schema.Resource {
func resourceKongConsumerCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {

consumerRequest := &kong.Consumer{
Username: NilString(d.Get("username").(string)),
CustomID: NilString(d.Get("custom_id").(string)),
Username: readStringPtrFromResource(d, "username"),
CustomID: readStringPtrFromResource(d, "custom_id"),
Tags: readStringArrayPtrFromResource(d, "tags"),
}

Expand Down
2 changes: 1 addition & 1 deletion kong/resource_kong_consumer_basic_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func resourceKongConsumerBasicAuthRead(ctx context.Context, d *schema.ResourceDa
if kong.IsNotFoundErr(err) {
d.SetId("")
} else if err != nil {
return diag.FromErr(fmt.Errorf("could not find kong ACLGroup with id: %s error: %v", id, err))
return diag.FromErr(fmt.Errorf("could not find kong basic auth with id: %s error: %v", id, err))
}

if basicAuth == nil {
Expand Down
2 changes: 1 addition & 1 deletion kong/resource_kong_consumer_basic_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func testAccCheckConsumerBasicAuthDestroy(state *terraform.State) error {
}

if ConsumerBasicAuth != nil {
return fmt.Errorf("jwt auth %s still exists, %+v", id.ID, ConsumerBasicAuth)
return fmt.Errorf("basic auth %s still exists, %+v", id.ID, ConsumerBasicAuth)
}

return nil
Expand Down
132 changes: 132 additions & 0 deletions kong/resource_kong_consumer_key_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package kong

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/kong/go-kong/kong"
)

func resourceKongConsumerKeyAuth() *schema.Resource {
return &schema.Resource{
CreateContext: resourceKongConsumerKeyAuthCreate,
ReadContext: resourceKongConsumerKeyAuthRead,
DeleteContext: resourceKongConsumerKeyAuthDelete,
UpdateContext: resourceKongConsumerKeyAuthUpdate,
Schema: map[string]*schema.Schema{
"consumer_id": {
Type: schema.TypeString,
Required: true,
ForceNew: false,
},
"key": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: false,
Sensitive: true,
},
"tags": {
Type: schema.TypeList,
Optional: true,
ForceNew: false,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}

func resourceKongConsumerKeyAuthCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
KeyAuthRequest := &kong.KeyAuth{
Key: readStringPtrFromResource(d, "key"),
Tags: readStringArrayPtrFromResource(d, "tags"),
}

consumerId := kong.String(d.Get("consumer_id").(string))

client := meta.(*config).adminClient.KeyAuths
keyAuth, err := client.Create(ctx, consumerId, KeyAuthRequest)

if err != nil {
return diag.FromErr(fmt.Errorf("failed to create kong key auth: %v error: %v", KeyAuthRequest, err))
}

d.SetId(buildConsumerPairID(*keyAuth.ID, *consumerId))

return resourceKongConsumerKeyAuthRead(ctx, d, meta)
}

func resourceKongConsumerKeyAuthUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
id, err := splitConsumerID(d.Id())

KeyAuthRequest := &kong.KeyAuth{
ID: kong.String(id.ID),
Key: readStringPtrFromResource(d, "key"),
Tags: readStringArrayPtrFromResource(d, "tags"),
}

consumerId := kong.String(d.Get("consumer_id").(string))

client := meta.(*config).adminClient.KeyAuths
_, err = client.Update(ctx, consumerId, KeyAuthRequest)

if err != nil {
return diag.FromErr(fmt.Errorf("error updating kong key auth: %s", err))
}

return resourceKongConsumerKeyAuthRead(ctx, d, meta)
}

func resourceKongConsumerKeyAuthRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
id, err := splitConsumerID(d.Id())
if err != nil {
return diag.FromErr(err)
}

client := meta.(*config).adminClient.KeyAuths
keyAuth, err := client.Get(ctx, kong.String(id.ConsumerID), kong.String(id.ID))

if kong.IsNotFoundErr(err) {
d.SetId("")
} else if err != nil {
return diag.FromErr(fmt.Errorf("could not find kong key auth with id: %s error: %v", id, err))
}

if keyAuth == nil {
d.SetId("")
} else {
err = d.Set("consumer_id", keyAuth.Consumer.ID)
if err != nil {
return diag.FromErr(err)
}
err = d.Set("key", keyAuth.Key)
if err != nil {
return diag.FromErr(err)
}
err = d.Set("tags", keyAuth.Tags)
if err != nil {
return diag.FromErr(err)
}
}

return diags
}

func resourceKongConsumerKeyAuthDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
id, err := splitConsumerID(d.Id())
if err != nil {
return diag.FromErr(err)
}
client := meta.(*config).adminClient.KeyAuths
err = client.Delete(ctx, kong.String(id.ConsumerID), kong.String(id.ID))

if err != nil {
return diag.FromErr(fmt.Errorf("could not delete kong key auth: %v", err))
}

return diags
}
171 changes: 171 additions & 0 deletions kong/resource_kong_consumer_key_auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package kong

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/kong/go-kong/kong"
)

func TestAccConsumerKeyAuth(t *testing.T) {

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
CheckDestroy: testAccCheckConsumerKeyAuthDestroy,
Steps: []resource.TestStep{
{
Config: testCreateConsumerKeyAuthConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckConsumerKeyAuthExists("kong_consumer_key_auth.consumer_key_auth"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "key", "foo"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.#", "1"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.0", "myTag"),
),
},
{
Config: testUpdateConsumerKeyAuthConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckConsumerKeyAuthExists("kong_consumer_key_auth.consumer_key_auth"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "key", "foo_updated"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.#", "2"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.0", "myTag"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.1", "anotherTag"),
),
},
},
})
}

func TestAccConsumerKeyAuthComputed(t *testing.T) {

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
CheckDestroy: testAccCheckConsumerKeyAuthDestroy,
Steps: []resource.TestStep{
{
Config: testCreateConsumerKeyAuthConfigKeyComputed,
Check: resource.ComposeTestCheckFunc(
testAccCheckConsumerKeyAuthExists("kong_consumer_key_auth.consumer_key_auth"),
resource.TestCheckResourceAttrSet("kong_consumer_key_auth.consumer_key_auth", "key"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.#", "1"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.0", "myTag"),
),
},
{
Config: testUpdateConsumerKeyAuthConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckConsumerKeyAuthExists("kong_consumer_key_auth.consumer_key_auth"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "key", "foo_updated"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.#", "2"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.0", "myTag"),
resource.TestCheckResourceAttr("kong_consumer_key_auth.consumer_key_auth", "tags.1", "anotherTag"),
),
},
},
})
}

func testAccCheckConsumerKeyAuthDestroy(state *terraform.State) error {

client := testAccProvider.Meta().(*config).adminClient.KeyAuths

resources := getResourcesByType("kong_consumer_key_auth", state)

if len(resources) != 1 {
return fmt.Errorf("expecting only 1 consumer key auth resource found %v", len(resources))
}

id, err := splitConsumerID(resources[0].Primary.ID)
ConsumerKeyAuth, err := client.Get(context.Background(), kong.String(id.ConsumerID), kong.String(id.ID))

if !kong.IsNotFoundErr(err) && err != nil {
return fmt.Errorf("error calling get consumer auth by id: %v", err)
}

if ConsumerKeyAuth != nil {
return fmt.Errorf("key auth %s still exists, %+v", id.ID, ConsumerKeyAuth)
}

return nil
}

func testAccCheckConsumerKeyAuthExists(resourceKey string) resource.TestCheckFunc {

return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceKey]

if !ok {
return fmt.Errorf("not found: %s", resourceKey)
}

if rs.Primary.ID == "" {
return fmt.Errorf("no ID is set")
}

client := testAccProvider.Meta().(*config).adminClient.KeyAuths
id, err := splitConsumerID(rs.Primary.ID)

ConsumerKeyAuth, err := client.Get(context.Background(), kong.String(id.ConsumerID), kong.String(id.ID))

if err != nil {
return err
}

if ConsumerKeyAuth == nil {
return fmt.Errorf("ConsumerKeyAuth with id %v not found", id.ID)
}

return nil
}
}

const testCreateConsumerKeyAuthConfig = `
resource "kong_consumer" "my_consumer" {
username = "User1"
custom_id = "123"
}
resource "kong_plugin" "key_auth_plugin" {
name = "key-auth"
}
resource "kong_consumer_key_auth" "consumer_key_auth" {
consumer_id = "${kong_consumer.my_consumer.id}"
key = "foo"
tags = ["myTag"]
}
`
const testUpdateConsumerKeyAuthConfig = `
resource "kong_consumer" "my_consumer" {
username = "User1"
custom_id = "123"
}
resource "kong_plugin" "key_auth_plugin" {
name = "key-auth"
}
resource "kong_consumer_key_auth" "consumer_key_auth" {
consumer_id = "${kong_consumer.my_consumer.id}"
key = "foo_updated"
tags = ["myTag", "anotherTag"]
}
`
const testCreateConsumerKeyAuthConfigKeyComputed = `
resource "kong_consumer" "my_consumer" {
username = "User1"
custom_id = "123"
}
resource "kong_plugin" "key_auth_plugin" {
name = "key-auth"
}
resource "kong_consumer_key_auth" "consumer_key_auth" {
consumer_id = "${kong_consumer.my_consumer.id}"
tags = ["myTag"]
}
`
10 changes: 0 additions & 10 deletions kong/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,3 @@ func IDToString(v *string) string {
}
return *v
}

// NilString converts a string to a string pointer,
// or if empty returns nil.
func NilString(str string) *string {
if str == "" {
return nil
} else {
return kong.String(str)
}
}

0 comments on commit 82d072e

Please sign in to comment.