Skip to content
Closed
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
110 changes: 110 additions & 0 deletions docs/resources/kibana_security_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "elasticstack_kibana_security_list Resource - terraform-provider-elasticstack"
subcategory: "Kibana"
description: |-
Manages Kibana security lists (also known as value lists). Security lists are used by exception items to define sets of values for matching or excluding in security rules.
Example Usage

resource "elasticstack_kibana_security_list" "ip_list" {
space_id = "default"
name = "Trusted IP Addresses"
description = "List of trusted IP addresses for security rules"
type = "ip"
}

resource "elasticstack_kibana_security_list" "keyword_list" {
space_id = "security"
list_id = "custom-keywords"
name = "Custom Keywords"
description = "Custom keyword list for detection rules"
type = "keyword"
}

Notes
Security lists define the type of data they can contain via the type attributeOnce created, the type of a list cannot be changedLists can be referenced by exception items to create more sophisticated matching rulesThe list_id is auto-generated if not provided
---

# elasticstack_kibana_security_list (Resource)

Manages Kibana security lists (also known as value lists). Security lists are used by exception items to define sets of values for matching or excluding in security rules.

## Example Usage

```terraform
resource "elasticstack_kibana_security_list" "ip_list" {
space_id = "default"
name = "Trusted IP Addresses"
description = "List of trusted IP addresses for security rules"
type = "ip"
}

resource "elasticstack_kibana_security_list" "keyword_list" {
space_id = "security"
list_id = "custom-keywords"
name = "Custom Keywords"
description = "Custom keyword list for detection rules"
type = "keyword"
}
```

## Notes

- Security lists define the type of data they can contain via the `type` attribute
- Once created, the `type` of a list cannot be changed
- Lists can be referenced by exception items to create more sophisticated matching rules
- The `list_id` is auto-generated if not provided

## Example Usage

### IP address list

```terraform
resource "elasticstack_kibana_security_list" "ip_list" {
space_id = "default"
name = "Trusted IP Addresses"
description = "List of trusted IP addresses for security rules"
type = "ip"
}
```

### Keyword list with custom list_id

```terraform
resource "elasticstack_kibana_security_list" "keyword_list" {
space_id = "security"
list_id = "custom-keywords"
name = "Custom Keywords"
description = "Custom keyword list for detection rules"
type = "keyword"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `description` (String) Describes the security list.
- `name` (String) The name of the security list.
- `type` (String) Specifies the Elasticsearch data type of values the list contains. Valid values include: `binary`, `boolean`, `byte`, `date`, `date_nanos`, `date_range`, `double`, `double_range`, `float`, `float_range`, `geo_point`, `geo_shape`, `half_float`, `integer`, `integer_range`, `ip`, `ip_range`, `keyword`, `long`, `long_range`, `shape`, `short`, `text`.

### Optional

- `deserializer` (String) Determines how retrieved list item values are presented. By default, list items are presented using Handlebars expressions based on the type.
- `id` (String) The unique identifier of the security list (auto-generated by Kibana if not specified).
- `list_id` (String) The value list's human-readable identifier.
- `meta` (String) Placeholder for metadata about the value list as JSON string.
- `serializer` (String) Determines how uploaded list item values are parsed. By default, list items are parsed using named regex groups based on the type.
- `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used.
- `version` (Number) The document version number.

### Read-Only

- `created_at` (String) The timestamp of when the list was created.
- `created_by` (String) The user who created the list.
- `immutable` (Boolean) Whether the list is immutable.
- `tie_breaker_id` (String) Field used in search to ensure all containers are sorted and returned correctly.
- `updated_at` (String) The timestamp of when the list was last updated.
- `updated_by` (String) The user who last updated the list.
- `version_id` (String) The version id, normally returned by the API when the document is retrieved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# First create a security list
resource "elasticstack_kibana_security_list" "my_list" {
list_id = "allowed_domains"
name = "Allowed Domains"
description = "List of allowed domains"
type = "keyword"
}

# Add an item to the list
resource "elasticstack_kibana_security_list_item" "domain_example" {
list_id = elasticstack_kibana_security_list.my_list.list_id
value = "example.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# First create an IP address list
resource "elasticstack_kibana_security_list" "ip_list" {
list_id = "allowed_ips"
name = "Allowed IP Addresses"
description = "List of allowed IP addresses"
type = "ip"
}

# Add an IP address to the list
resource "elasticstack_kibana_security_list_item" "ip_example" {
list_id = elasticstack_kibana_security_list.ip_list.list_id
value = "192.168.1.1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# First create a security list
resource "elasticstack_kibana_security_list" "tagged_domains" {
list_id = "tagged_domains"
name = "Tagged Domains"
description = "Domains with associated metadata"
type = "keyword"
}

# Add an item with metadata
resource "elasticstack_kibana_security_list_item" "domain_with_meta" {
list_id = elasticstack_kibana_security_list.tagged_domains.list_id
value = "internal.example.com"
meta = jsonencode({
category = "internal"
owner = "infrastructure-team"
note = "Primary internal domain"
})
}
105 changes: 105 additions & 0 deletions internal/kibana/security_list/acc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package security_list_test

import (
"context"
"testing"

"github.com/elastic/terraform-provider-elasticstack/internal/acctest"
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-testing/config"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

func ensureListIndexExists(t *testing.T) {
client, err := clients.NewAcceptanceTestingClient()
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}

kibanaClient, err := client.GetKibanaOapiClient()
if err != nil {
t.Fatalf("Failed to get Kibana client: %v", err)
}

diags := kibana_oapi.CreateListIndex(context.Background(), kibanaClient, "default")
if diags.HasError() {
// It's OK if it already exists, we'll only fail on other errors
for _, d := range diags {
if d.Summary() != "Unexpected status code from server: got HTTP 409" {
t.Fatalf("Failed to create list index: %v", d.Detail())
}
}
}
}

func TestAccResourceSecurityList(t *testing.T) {
listID := "test-list-" + uuid.New().String()
resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
ensureListIndexExists(t)
},
ProtoV6ProviderFactories: acctest.Providers,
Steps: []resource.TestStep{
{ // Create
ConfigDirectory: acctest.NamedTestCaseDirectory("create"),
ConfigVariables: config.Variables{
"list_id": config.StringVariable(listID),
"name": config.StringVariable("Test Security List"),
"description": config.StringVariable("A test security list for IP addresses"),
"type": config.StringVariable("ip"),
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "id"),
resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "name", "Test Security List"),
resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "description", "A test security list for IP addresses"),
resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "type", "ip"),
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "created_at"),
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "created_by"),
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "updated_at"),
resource.TestCheckResourceAttrSet("elasticstack_kibana_security_list.test", "updated_by"),
),
},
{ // Update
ConfigDirectory: acctest.NamedTestCaseDirectory("update"),
ConfigVariables: config.Variables{
"list_id": config.StringVariable(listID),
"name": config.StringVariable("Updated Security List"),
"description": config.StringVariable("An updated test security list"),
"type": config.StringVariable("ip"),
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "name", "Updated Security List"),
resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "description", "An updated test security list"),
),
},
},
})
}

func TestAccResourceSecurityList_KeywordType(t *testing.T) {
listID := "keyword-list-" + uuid.New().String()
resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(t)
ensureListIndexExists(t)
},
ProtoV6ProviderFactories: acctest.Providers,
Steps: []resource.TestStep{
{
ConfigDirectory: acctest.NamedTestCaseDirectory("keyword_type"),
ConfigVariables: config.Variables{
"list_id": config.StringVariable(listID),
"name": config.StringVariable("Keyword Security List"),
"description": config.StringVariable("A test security list for keywords"),
"type": config.StringVariable("keyword"),
},
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("elasticstack_kibana_security_list.test", "type", "keyword"),
),
},
},
})
}
69 changes: 69 additions & 0 deletions internal/kibana/security_list/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package security_list

import (
"context"

"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
"github.com/hashicorp/terraform-plugin-framework/resource"
)

func (r *securityListResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan SecurityListModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

// Get Kibana client
client, err := r.client.GetKibanaOapiClient()
if err != nil {
resp.Diagnostics.AddError("Failed to get Kibana client", err.Error())
return
}

// Convert plan to API request
createReq, diags := plan.toCreateRequest()
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// Create the list
spaceID := plan.SpaceID.ValueString()
createResp, diags := kibana_oapi.CreateList(ctx, client, spaceID, *createReq)

Check failure on line 34 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: kibana_oapi.CreateList

Check failure on line 34 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Build

undefined: kibana_oapi.CreateList

Check failure on line 34 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Build

undefined: kibana_oapi.CreateList

Check failure on line 34 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: kibana_oapi.CreateList
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

if createResp == nil || createResp.JSON200 == nil {
resp.Diagnostics.AddError("Failed to create security list", "API returned empty response")
return
}

// Read the created list to populate state
readParams := &kbapi.ReadListParams{
Id: createResp.JSON200.Id,
}

readResp, diags := kibana_oapi.GetList(ctx, client, spaceID, readParams)

Check failure on line 50 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: kibana_oapi.GetList

Check failure on line 50 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Build

undefined: kibana_oapi.GetList

Check failure on line 50 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Build

undefined: kibana_oapi.GetList

Check failure on line 50 in internal/kibana/security_list/create.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: kibana_oapi.GetList
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

if readResp == nil || readResp.JSON200 == nil {
resp.State.RemoveResource(ctx)
return
}

// Update state with read response
diags = plan.fromAPI(ctx, readResp.JSON200)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
}
33 changes: 33 additions & 0 deletions internal/kibana/security_list/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package security_list

import (
"context"

"github.com/elastic/terraform-provider-elasticstack/generated/kbapi"
"github.com/elastic/terraform-provider-elasticstack/internal/clients/kibana_oapi"
"github.com/hashicorp/terraform-plugin-framework/resource"
)

func (r *securityListResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state SecurityListModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

client, err := r.client.GetKibanaOapiClient()
if err != nil {
resp.Diagnostics.AddError("Failed to get Kibana client", err.Error())
return
}

spaceID := state.SpaceID.ValueString()
listID := state.ListID.ValueString()

params := &kbapi.DeleteListParams{
Id: kbapi.SecurityListsAPIListId(listID),
}

diags := kibana_oapi.DeleteList(ctx, client, spaceID, params)

Check failure on line 31 in internal/kibana/security_list/delete.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: kibana_oapi.DeleteList

Check failure on line 31 in internal/kibana/security_list/delete.go

View workflow job for this annotation

GitHub Actions / Build

undefined: kibana_oapi.DeleteList

Check failure on line 31 in internal/kibana/security_list/delete.go

View workflow job for this annotation

GitHub Actions / Build

undefined: kibana_oapi.DeleteList

Check failure on line 31 in internal/kibana/security_list/delete.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: kibana_oapi.DeleteList
resp.Diagnostics.Append(diags...)
}
Loading
Loading