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

Devel bot defense saas #1037

Open
wants to merge 8 commits into
base: devel
Choose a base branch
from
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ jobs:
name: Import GPG key
id: import_gpg
# see https://github.com/hashicorp/terraform-provider-scaffolding/issues/22
uses: crazy-max/ghaction-import-gpg@v6.1.0
uses: crazy-max/ghaction-import-gpg@v6.2.0
with:
# These secrets will need to be configured for the repository:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6.0.0
uses: goreleaser/goreleaser-action@v6.1.0
with:
version: v1.25.1
args: release --rm-dist
Expand Down
1 change: 1 addition & 0 deletions bigip/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ func Provider() *schema.Provider {
"bigip_ltm_profile_bot_defense": resourceBigipLtmProfileBotDefense(),
"bigip_ltm_profile_rewrite": resourceBigipLtmRewriteProfile(),
"bigip_ltm_profile_rewrite_uri_rules": resourceBigipLtmRewriteProfileUriRules(),
"bigip_saas_bot_defense_profile": resourceBigipSaasBotDefenseProfile(),
},
}
p.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
Expand Down
247 changes: 247 additions & 0 deletions bigip/resource_bigip_saas_bot_defense.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/*
Copyright 2024 F5 Networks Inc.
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package bigip

import (
"context"
"log"

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

func resourceBigipSaasBotDefenseProfile() *schema.Resource {
return &schema.Resource{
CreateContext: resourceBigipSaasBotDefenseProfileCreate,
ReadContext: resourceBigipSaasBotDefenseProfileRead,
UpdateContext: resourceBigipSaasBotDefenseProfileUpdate,
DeleteContext: resourceBigipSaasBotDefenseProfileDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Unique name for the Distributed Cloud Services Bot Defense profile",
ValidateFunc: validateF5NameWithDirectory,
},
"defaults_from": {
Type: schema.TypeString,
Optional: true,
Default: "/Common/bd",
Description: "Distributed Cloud Services Bot Defense parent profile from which this profile will inherit settings.",
ValidateFunc: validateF5Name,
},
"description": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Specifies descriptive text that identifies the BD profile.",
},
"application_id": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
Description: "Specifies the Bot Defense API application ID, enter the value provided by F5 Support",
},
"tenant_id": {
Type: schema.TypeString,
Required: true,
Description: "Specifies the tenant ID, enter the value provided by F5 Support",
},
"api_key": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
Description: "Specifies the API key, enter the value provided by F5 Support.",
},
"shape_protection_pool": {
Type: schema.TypeString,
Required: true,
Description: "Specifies the web hostname to which API requests are made",
},
"ssl_profile": {
Type: schema.TypeString,
Required: true,
Description: "Specifies a server-side SSL profile that is different from what the application pool uses",
},
"protected_endpoints": {
Type: schema.TypeList,
Required: true,
Description: "Use these settings to configure which pages on the website will be protected by BD",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Unique name for the protected endpoint",
},
"host": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "hostname or IP address of the web page to be protected by the Bot Defense",
},
"endpoint": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Specifies the path to the web page to be protected by BD. For example, `/login`.",
},
"mitigation_action": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Specifies whether the BIG-IP or F5 XC Bot Defense handles mitigation of malicious HTTP requests. This field is enabled only if the Service Level field is set to Advanced/Premium",
},
"post": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "POST field to protect the path when it has a POST method, `enabled` or `disabled`",
},
"put": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "PUT field to protect the path when it has a PUT method,`enabled` or `disabled`",
},
},
},
},
},
}
}

func resourceBigipSaasBotDefenseProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*bigip.BigIP)
name := d.Get("name").(string)
log.Printf("[INFO] Creating Bot Defense Profile:%+v ", name)
pss := &bigip.SaasBotDefenseProfile{

Check failure on line 126 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

undefined: bigip.SaasBotDefenseProfile
Name: name,
}
config := getSaasBotDefenseProfileConfig(d, pss)
log.Printf("[DEBUG] Bot Defense Profile config :%+v ", config)
err := client.AddSaasBotDefenseProfile(config)

Check failure on line 131 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

client.AddSaasBotDefenseProfile undefined (type *"github.com/f5devcentral/go-bigip".BigIP has no field or method AddSaasBotDefenseProfile)
if err != nil {
return diag.FromErr(err)
}
d.SetId(name)
return resourceBigipSaasBotDefenseProfileRead(ctx, d, meta)
}

func resourceBigipSaasBotDefenseProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*bigip.BigIP)
log.Printf("[INFO] Reading Bot Defense Profile:%+v ", client)
name := d.Id()
log.Printf("[INFO] Reading Bot Defense Profile:%+v ", name)
botProfile, err := client.GetSaasBotDefenseProfile(name)

Check failure on line 144 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

client.GetSaasBotDefenseProfile undefined (type *"github.com/f5devcentral/go-bigip".BigIP has no field or method GetSaasBotDefenseProfile)
if err != nil {
return diag.FromErr(err)
}
log.Printf("[DEBUG] Defense Profile Resp :%+v ", botProfile)
d.Set("name", botProfile.FullPath)
d.Set("defaults_from", botProfile.DefaultsFrom)
d.Set("description", botProfile.Description)
d.Set("tenant_id", botProfile.TenantId)
d.Set("api_key", botProfile.ApiKey)
d.Set("shape_protection_pool", botProfile.ShapeProtectionPool)
d.Set("ssl_profile", botProfile.SslProfile)
d.Set("protected_endpoints", flattenProtectedEndpointsReference(botProfile.ProtectedEndpointsReference.Items))
return nil
}

func resourceBigipSaasBotDefenseProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*bigip.BigIP)
name := d.Id()
log.Printf("[INFO] Updating Bot Defense Profile:%+v ", name)
pss := &bigip.SaasBotDefenseProfile{

Check failure on line 164 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

undefined: bigip.SaasBotDefenseProfile
Name: name,
}
config := getSaasBotDefenseProfileConfig(d, pss)

err := client.ModifySaasBotDefenseProfile(name, config)

Check failure on line 169 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

client.ModifySaasBotDefenseProfile undefined (type *"github.com/f5devcentral/go-bigip".BigIP has no field or method ModifySaasBotDefenseProfile)
if err != nil {
return diag.FromErr(err)
}
return resourceBigipSaasBotDefenseProfileRead(ctx, d, meta)
}

func resourceBigipSaasBotDefenseProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*bigip.BigIP)

name := d.Id()
log.Println("[INFO] Deleting Bot Defense Profile " + name)
err := client.DeleteSaasBotDefenseProfile(name)

Check failure on line 181 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

client.DeleteSaasBotDefenseProfile undefined (type *"github.com/f5devcentral/go-bigip".BigIP has no field or method DeleteSaasBotDefenseProfile)
if err != nil {
return diag.FromErr(err)
}
d.SetId("")
return nil
}

func getSaasBotDefenseProfileConfig(d *schema.ResourceData, config *bigip.SaasBotDefenseProfile) *bigip.SaasBotDefenseProfile {

Check failure on line 189 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

undefined: bigip.SaasBotDefenseProfile
config.Name = d.Get("name").(string)
config.DefaultsFrom = d.Get("defaults_from").(string)
config.Description = d.Get("description").(string)
config.ApplicationId = d.Get("application_id").(string)
config.TenantId = d.Get("tenant_id").(string)
config.ApiKey = d.Get("api_key").(string)
config.ShapeProtectionPool = d.Get("shape_protection_pool").(string)
config.SslProfile = d.Get("ssl_profile").(string)
var protectEndpoint []bigip.ProtectedEndpoint

Check failure on line 198 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

undefined: bigip.ProtectedEndpoint
for _, endpoint := range d.Get("protected_endpoints").([]interface{}) {
ep := endpoint.(map[string]interface{})
protectEndpoint = append(protectEndpoint, bigip.ProtectedEndpoint{

Check failure on line 201 in bigip/resource_bigip_saas_bot_defense.go

View workflow job for this annotation

GitHub Actions / golint

undefined: bigip.ProtectedEndpoint
Name: ep["name"].(string),
Host: ep["host"].(string),
Endpoint: ep["endpoint"].(string),
Post: ep["post"].(string),
Put: ep["put"].(string),
MitigationAction: ep["mitigation_action"].(string),
})
}
config.ProtectedEndpointsReference.Items = protectEndpoint
log.Printf("[INFO][getSaasBotDefenseProfileConfig] config:%+v ", config)
return config
}

func flattenProtectedEndpointsReference(data interface{}) []interface{} {
var prtctEndpt []interface{}
for _, ep := range data.([]bigip.ProtectedEndpoint) {
prtctEndpt = append(prtctEndpt, map[string]interface{}{
"name": ep.Name,
"host": ep.Host,
"endpoint": ep.Endpoint,
"post": ep.Post,
"put": ep.Put,
"mitigation_action": ep.MitigationAction,
})
}
return prtctEndpt
}

// {
// "name": "/Common/bd-test",
// "applicationId": "89fb0bfcb4bf4c578fad9adb37ce3b19",
// "tenantId": "a-aavN9vaYOV",
// "apiKey": "49840d1dd6fa4c4d86c88762eb398eee",
// "shapeProtectionPool": "/Common/cs1.pool",
// "sslProfile": "/Common/cloud-service-default-ssl",
// "protectedEndpointsReference": {
// "items": [
// {
// "name": "pe1",
// "host": "abc.com",
// "endpoint": "/login",
// "post": "enabled"
// }
// ]
// }
// }
89 changes: 89 additions & 0 deletions bigip/resource_bigip_saas_bot_defense_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package bigip

import (
"fmt"
"testing"

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

var resSaasBotDefenseName = "bigip_saas_bot_defense_profile"

func TestAccBigipSaasBotDefenseProfileTC1(t *testing.T) {
t.Parallel()
var instName = "test-saas-bot-defense-tc1"
var TestBotDefenseName = fmt.Sprintf("/%s/%s", TestPartition, instName)
resFullName := fmt.Sprintf("%s.%s", resSaasBotDefenseName, instName)
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAcctPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testCheckSaasBotDefensesDestroyed,
Steps: []resource.TestStep{
{
Config: testaccbigipSaasBotDefenseDefaultConfig(TestPartition, TestBotDefenseName, instName),
Check: resource.ComposeTestCheckFunc(
testCheckSaasBotDefenseExists(TestBotDefenseName),
resource.TestCheckResourceAttr(resFullName, "name", TestBotDefenseName),
resource.TestCheckResourceAttr(resFullName, "defaults_from", "/Common/bd"),
),
Destroy: false,
},
},
})
}

func testCheckSaasBotDefenseExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
client := testAccProvider.Meta().(*bigip.BigIP)
p, err := client.GetSaasBotDefenseProfile(name)
if err != nil {
return err
}
if p == nil {
return fmt.Errorf("BotDefense %s was not created ", name)
}

return nil
}
}

func testCheckSaasBotDefensesDestroyed(s *terraform.State) error {
client := testAccProvider.Meta().(*bigip.BigIP)

for _, rs := range s.RootModule().Resources {
if rs.Type != "bigip_saas_bot_defense_profile" {
continue
}

name := rs.Primary.ID
BotDefense, err := client.GetSaasBotDefenseProfile(name)
if err != nil {
return nil
}
if BotDefense != nil {
return fmt.Errorf("BotDefense %s not destroyed. ", name)
}
}
return nil
}

func testaccbigipSaasBotDefenseDefaultConfig(partition, profileName, resourceName string) string {
return fmt.Sprintf(`resource "bigip_saas_bot_defense_profile" "%[3]s" {
name = "%[2]s"
application_id = "89fb0bfcb4bf4c578fad9adb37ce3b19"
tenant_id = "a-aavN9vaYOV"
api_key = "49840d1dd6fa4c4d86c88762eb398eee"
shape_protection_pool = "/%[1]s/cs1.pool"
ssl_profile = "/%[1]s/cloud-service-default-ssl"
protected_endpoints {
name = "pe1"
host = "abc.com"
endpoint = "/login"
post = "enabled"
}
}`, partition, profileName, resourceName)
}
Loading
Loading