diff --git a/.changelog/28518.txt b/.changelog/28518.txt new file mode 100644 index 00000000000..62768271008 --- /dev/null +++ b/.changelog/28518.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_opensearchserverless_access_policy +``` diff --git a/internal/service/opensearchserverless/access_policy.go b/internal/service/opensearchserverless/access_policy.go new file mode 100644 index 00000000000..bab7267f380 --- /dev/null +++ b/internal/service/opensearchserverless/access_policy.go @@ -0,0 +1,264 @@ +package opensearchserverless + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/opensearchserverless" + awstypes "github.com/aws/aws-sdk-go-v2/service/opensearchserverless/types" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource +func newResourceAccessPolicy(_ context.Context) (resource.ResourceWithConfigure, error) { + return &resourceAccessPolicy{}, nil +} + +type resourceAccessPolicyData struct { + Description types.String `tfsdk:"description"` + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Policy types.String `tfsdk:"policy"` + PolicyVersion types.String `tfsdk:"policy_version"` + Type types.String `tfsdk:"type"` +} + +const ( + ResNameAccessPolicy = "Access Policy" +) + +type resourceAccessPolicy struct { + framework.ResourceWithConfigure +} + +func (r *resourceAccessPolicy) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_opensearchserverless_access_policy" +} + +func (r *resourceAccessPolicy) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "description": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 1000), + }, + }, + "id": framework.IDAttribute(), + "name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(3, 32), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "policy": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 20480), + }, + }, + "policy_version": schema.StringAttribute{ + Computed: true, + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + enum.FrameworkValidate[awstypes.AccessPolicyType](), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + } +} + +func (r *resourceAccessPolicy) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan resourceAccessPolicyData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + + if resp.Diagnostics.HasError() { + return + } + + conn := r.Meta().OpenSearchServerlessClient(ctx) + + in := &opensearchserverless.CreateAccessPolicyInput{ + ClientToken: aws.String(id.UniqueId()), + Name: aws.String(plan.Name.ValueString()), + Policy: aws.String(plan.Policy.ValueString()), + Type: awstypes.AccessPolicyType(plan.Type.ValueString()), + } + + if !plan.Description.IsNull() { + in.Description = aws.String(plan.Description.ValueString()) + } + + out, err := conn.CreateAccessPolicy(ctx, in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionCreating, ResNameAccessPolicy, plan.Name.String(), nil), + err.Error(), + ) + return + } + + state := plan + resp.Diagnostics.Append(state.refreshFromOutput(ctx, out.AccessPolicyDetail)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceAccessPolicy) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().OpenSearchServerlessClient(ctx) + + var state resourceAccessPolicyData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + out, err := FindAccessPolicyByNameAndType(ctx, conn, state.ID.ValueString(), state.Type.ValueString()) + if tfresource.NotFound(err) { + resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + resp.State.RemoveResource(ctx) + return + } + + resp.Diagnostics.Append(state.refreshFromOutput(ctx, out)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceAccessPolicy) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + conn := r.Meta().OpenSearchServerlessClient(ctx) + + var plan, state resourceAccessPolicyData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + if !plan.Description.Equal(state.Description) || + !plan.Policy.Equal(state.Policy) { + input := &opensearchserverless.UpdateAccessPolicyInput{ + ClientToken: aws.String(id.UniqueId()), + Name: flex.StringFromFramework(ctx, plan.Name), + PolicyVersion: flex.StringFromFramework(ctx, state.PolicyVersion), + Type: awstypes.AccessPolicyType(plan.Type.ValueString()), + } + + if !plan.Description.Equal(state.Description) { + input.Description = aws.String(plan.Description.ValueString()) + } + + if !plan.Policy.Equal(state.Policy) { + input.Policy = aws.String(plan.Policy.ValueString()) + } + + out, err := conn.UpdateAccessPolicy(ctx, input) + + if err != nil { + resp.Diagnostics.AddError(fmt.Sprintf("updating Security Policy (%s)", plan.Name.ValueString()), err.Error()) + return + } + resp.Diagnostics.Append(state.refreshFromOutput(ctx, out.AccessPolicyDetail)...) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceAccessPolicy) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().OpenSearchServerlessClient(ctx) + + var state resourceAccessPolicyData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := conn.DeleteAccessPolicy(ctx, &opensearchserverless.DeleteAccessPolicyInput{ + ClientToken: aws.String(id.UniqueId()), + Name: aws.String(state.Name.ValueString()), + Type: awstypes.AccessPolicyType(state.Type.ValueString()), + }) + if err != nil { + var nfe *awstypes.ResourceNotFoundException + if errors.As(err, &nfe) { + return + } + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionDeleting, ResNameAccessPolicy, state.Name.String(), nil), + err.Error(), + ) + } +} + +func (r *resourceAccessPolicy) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + parts := strings.Split(req.ID, idSeparator) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + err := fmt.Errorf("unexpected format for ID (%[1]s), expected security-policy-name%[2]ssecurity-policy-type", req.ID, idSeparator) + resp.Diagnostics.AddError(fmt.Sprintf("importing Security Policy (%s)", req.ID), err.Error()) + return + } + + state := resourceAccessPolicyData{ + ID: types.StringValue(parts[0]), + Name: types.StringValue(parts[0]), + Type: types.StringValue(parts[1]), + } + + diags := resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// refreshFromOutput writes state data from an AWS response object +func (rd *resourceAccessPolicyData) refreshFromOutput(ctx context.Context, out *awstypes.AccessPolicyDetail) diag.Diagnostics { + var diags diag.Diagnostics + + if out == nil { + return diags + } + + rd.ID = flex.StringToFramework(ctx, out.Name) + rd.Description = flex.StringToFramework(ctx, out.Description) + rd.Name = flex.StringToFramework(ctx, out.Name) + rd.Type = flex.StringValueToFramework(ctx, out.Type) + rd.PolicyVersion = flex.StringToFramework(ctx, out.PolicyVersion) + + policyBytes, err := out.Policy.MarshalSmithyDocument() + if err != nil { + diags.AddError(fmt.Sprintf("refreshing state for Security Policy (%s)", rd.Name), err.Error()) + return diags + } + + p := string(policyBytes) + + rd.Policy = flex.StringToFramework(ctx, &p) + + return diags +} diff --git a/internal/service/opensearchserverless/access_policy_test.go b/internal/service/opensearchserverless/access_policy_test.go new file mode 100644 index 00000000000..8ebab3ee413 --- /dev/null +++ b/internal/service/opensearchserverless/access_policy_test.go @@ -0,0 +1,265 @@ +package opensearchserverless_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/opensearchserverless" + "github.com/aws/aws-sdk-go-v2/service/opensearchserverless/types" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tfopensearchserverless "github.com/hashicorp/terraform-provider-aws/internal/service/opensearchserverless" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccOpenSearchServerlessAccessPolicy_basic(t *testing.T) { + ctx := acctest.Context(t) + var accesspolicy types.AccessPolicyDetail + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_opensearchserverless_access_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.OpenSearchServerlessEndpointID) + testAccPreCheckAccessPolicy(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServerlessEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAccessPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAccessPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPolicyExists(ctx, resourceName, &accesspolicy), + resource.TestCheckResourceAttr(resourceName, "type", "data"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAccessPolicyImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccOpenSearchServerlessAccessPolicy_update(t *testing.T) { + ctx := acctest.Context(t) + var accesspolicy types.AccessPolicyDetail + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_opensearchserverless_access_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.OpenSearchServerlessEndpointID) + testAccPreCheckAccessPolicy(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServerlessEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAccessPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAccessPolicyConfig_update(rName, "description"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPolicyExists(ctx, resourceName, &accesspolicy), + resource.TestCheckResourceAttr(resourceName, "type", "data"), + resource.TestCheckResourceAttr(resourceName, "description", "description"), + ), + }, + { + Config: testAccAccessPolicyConfig_update(rName, "description updated"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPolicyExists(ctx, resourceName, &accesspolicy), + resource.TestCheckResourceAttr(resourceName, "type", "data"), + resource.TestCheckResourceAttr(resourceName, "description", "description updated"), + ), + }, + }, + }) +} + +func TestAccOpenSearchServerlessAccessPolicy_disappears(t *testing.T) { + ctx := acctest.Context(t) + + var accesspolicy types.AccessPolicyDetail + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_opensearchserverless_access_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.OpenSearchServerlessEndpointID) + testAccPreCheckAccessPolicy(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServerlessEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAccessPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAccessPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPolicyExists(ctx, resourceName, &accesspolicy), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfopensearchserverless.ResourceAccessPolicy, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAccessPolicyDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchServerlessClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_opensearchserverless_access_policy" { + continue + } + + _, err := tfopensearchserverless.FindAccessPolicyByNameAndType(ctx, conn, rs.Primary.ID, rs.Primary.Attributes["type"]) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return create.Error(names.OpenSearchServerless, create.ErrActionCheckingDestroyed, tfopensearchserverless.ResNameAccessPolicy, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckAccessPolicyExists(ctx context.Context, name string, accesspolicy *types.AccessPolicyDetail) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.OpenSearchServerless, create.ErrActionCheckingExistence, tfopensearchserverless.ResNameAccessPolicy, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.OpenSearchServerless, create.ErrActionCheckingExistence, tfopensearchserverless.ResNameAccessPolicy, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchServerlessClient(ctx) + resp, err := tfopensearchserverless.FindAccessPolicyByNameAndType(ctx, conn, rs.Primary.ID, rs.Primary.Attributes["type"]) + + if err != nil { + return create.Error(names.OpenSearchServerless, create.ErrActionCheckingExistence, tfopensearchserverless.ResNameAccessPolicy, rs.Primary.ID, err) + } + + *accesspolicy = *resp + + return nil + } +} + +func testAccAccessPolicyImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("not found: %s", resourceName) + } + + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["name"], rs.Primary.Attributes["type"]), nil + } +} + +func testAccPreCheckAccessPolicy(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchServerlessClient(ctx) + + input := &opensearchserverless.ListAccessPoliciesInput{ + Type: types.AccessPolicyTypeData, + } + _, err := conn.ListAccessPolicies(ctx, input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func testAccAccessPolicyConfig_basic(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_opensearchserverless_access_policy" "test" { + name = %[1]q + type = "data" + policy = jsonencode([ + { + "Rules" : [ + { + "ResourceType" : "index", + "Resource" : [ + "index/books/*" + ], + "Permission" : [ + "aoss:CreateIndex", + "aoss:ReadDocument", + "aoss:UpdateIndex", + "aoss:DeleteIndex", + "aoss:WriteDocument" + ] + } + ], + "Principal" : [ + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:user/admin" + ] + } + ]) +} +`, rName) +} + +func testAccAccessPolicyConfig_update(rName, description string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_opensearchserverless_access_policy" "test" { + name = %[1]q + type = "data" + description = %[2]q + policy = jsonencode([ + { + "Rules" : [ + { + "ResourceType" : "index", + "Resource" : [ + "index/books/*" + ], + "Permission" : [ + "aoss:CreateIndex", + "aoss:ReadDocument", + "aoss:UpdateIndex", + "aoss:DeleteIndex", + "aoss:WriteDocument" + ] + } + ], + "Principal" : [ + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:user/admin" + ] + } + ]) +} +`, rName, description) +} diff --git a/internal/service/opensearchserverless/const.go b/internal/service/opensearchserverless/const.go new file mode 100644 index 00000000000..39e0a350e46 --- /dev/null +++ b/internal/service/opensearchserverless/const.go @@ -0,0 +1,3 @@ +package opensearchserverless + +const idSeparator = "/" diff --git a/internal/service/opensearchserverless/exports_test.go b/internal/service/opensearchserverless/exports_test.go index ba907149d6b..6bb7d2a0a47 100644 --- a/internal/service/opensearchserverless/exports_test.go +++ b/internal/service/opensearchserverless/exports_test.go @@ -2,5 +2,6 @@ package opensearchserverless // Exports for use in tests only. var ( + ResourceAccessPolicy = newResourceAccessPolicy ResourceSecurityPolicy = newResourceSecurityPolicy ) diff --git a/internal/service/opensearchserverless/find.go b/internal/service/opensearchserverless/find.go index 738d4f4cc6d..e7090ea8db7 100644 --- a/internal/service/opensearchserverless/find.go +++ b/internal/service/opensearchserverless/find.go @@ -11,6 +11,31 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) +func FindAccessPolicyByNameAndType(ctx context.Context, conn *opensearchserverless.Client, id, policyType string) (*types.AccessPolicyDetail, error) { + in := &opensearchserverless.GetAccessPolicyInput{ + Name: aws.String(id), + Type: types.AccessPolicyType(policyType), + } + out, err := conn.GetAccessPolicy(ctx, in) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil || out.AccessPolicyDetail == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out.AccessPolicyDetail, nil +} + func FindSecurityPolicyByNameAndType(ctx context.Context, conn *opensearchserverless.Client, name, policyType string) (*types.SecurityPolicyDetail, error) { in := &opensearchserverless.GetSecurityPolicyInput{ Name: aws.String(name), diff --git a/internal/service/opensearchserverless/security_policy.go b/internal/service/opensearchserverless/security_policy.go index 8ad924a2eeb..37813f3283d 100644 --- a/internal/service/opensearchserverless/security_policy.go +++ b/internal/service/opensearchserverless/security_policy.go @@ -43,7 +43,6 @@ type resourceSecurityPolicyData struct { const ( ResNameSecurityPolicy = "Security Policy" - idSeparator = "/" ) type resourceSecurityPolicy struct { diff --git a/internal/service/opensearchserverless/service_package_gen.go b/internal/service/opensearchserverless/service_package_gen.go index 1d4890e3d79..8ce92e2ffa1 100644 --- a/internal/service/opensearchserverless/service_package_gen.go +++ b/internal/service/opensearchserverless/service_package_gen.go @@ -17,6 +17,9 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { return []*types.ServicePackageFrameworkResource{ + { + Factory: newResourceAccessPolicy, + }, { Factory: newResourceSecurityPolicy, }, diff --git a/website/docs/r/opensearchserverless_access_policy.html.markdown b/website/docs/r/opensearchserverless_access_policy.html.markdown new file mode 100644 index 00000000000..10e52d5e5e0 --- /dev/null +++ b/website/docs/r/opensearchserverless_access_policy.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: "OpenSearch Serverless" +layout: "aws" +page_title: "AWS: aws_opensearchserverless_access_policy" +description: |- + Terraform resource for managing an AWS OpenSearch Serverless Access Policy. +--- + +# Resource: aws_opensearchserverless_access_policy + +Terraform resource for managing an AWS OpenSearch Serverless Access Policy. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_opensearchserverless_access_policy" "test" { + name = "example" + type = "data" + policy = jsonencode([ + { + "Rules" : [ + { + "ResourceType" : "index", + "Resource" : [ + "index/books/*" + ], + "Permission" : [ + "aoss:CreateIndex", + "aoss:ReadDocument", + "aoss:UpdateIndex", + "aoss:DeleteIndex", + "aoss:WriteDocument" + ] + } + ], + "Principal" : [ + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:user/admin" + ] + } + ]) +} +``` + +## Argument Reference + +The following arguments are required: + +* `name` - (Required) Name of the policy. +* `policy` - (Required) JSON policy document to use as the content for the new policy +* `type` - (Required) Type of access policy. Must be `data`. + +The following arguments are optional: + +* `description` - (Optional) Description of the policy. Typically used to store information about the permissions defined in the policy. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `policy_version` - Version of the policy. + +## Import + +OpenSearchServerless Access Policy can be imported using the `name` and `type` arguments separated by a slash (`/`), e.g., + +``` +$ terraform import aws_opensearchserverless_access_policy.example example/data +```