Configure AWS OpenSearch Serverless Security Policies

The aws:opensearch/serverlessSecurityPolicy:ServerlessSecurityPolicy resource, part of the Pulumi AWS provider, defines security policies that control encryption and network access for OpenSearch Serverless collections. This guide focuses on three capabilities: encryption policies with AWS-managed and customer-managed keys, network policies for public and VPC-based access, and wildcard patterns for multi-collection policies.

Security policies operate independently of collections themselves. Encryption policies may reference KMS keys; network policies reference VPC endpoints for private access. The examples are intentionally small. Combine them with your own collection definitions and access infrastructure.

Encrypt a single collection with AWS-managed keys

Most deployments start by defining encryption policies that protect data at rest using AWS-managed keys.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.opensearch.ServerlessSecurityPolicy("example", {
    name: "example",
    type: "encryption",
    description: "encryption security policy for example-collection",
    policy: JSON.stringify({
        Rules: [{
            Resource: ["collection/example-collection"],
            ResourceType: "collection",
        }],
        AWSOwnedKey: true,
    }),
});
import pulumi
import json
import pulumi_aws as aws

example = aws.opensearch.ServerlessSecurityPolicy("example",
    name="example",
    type="encryption",
    description="encryption security policy for example-collection",
    policy=json.dumps({
        "Rules": [{
            "Resource": ["collection/example-collection"],
            "ResourceType": "collection",
        }],
        "AWSOwnedKey": True,
    }))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"Rules": []map[string]interface{}{
				map[string]interface{}{
					"Resource": []string{
						"collection/example-collection",
					},
					"ResourceType": "collection",
				},
			},
			"AWSOwnedKey": true,
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = opensearch.NewServerlessSecurityPolicy(ctx, "example", &opensearch.ServerlessSecurityPolicyArgs{
			Name:        pulumi.String("example"),
			Type:        pulumi.String("encryption"),
			Description: pulumi.String("encryption security policy for example-collection"),
			Policy:      pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.OpenSearch.ServerlessSecurityPolicy("example", new()
    {
        Name = "example",
        Type = "encryption",
        Description = "encryption security policy for example-collection",
        Policy = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["Rules"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Resource"] = new[]
                    {
                        "collection/example-collection",
                    },
                    ["ResourceType"] = "collection",
                },
            },
            ["AWSOwnedKey"] = true,
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicy;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ServerlessSecurityPolicy("example", ServerlessSecurityPolicyArgs.builder()
            .name("example")
            .type("encryption")
            .description("encryption security policy for example-collection")
            .policy(serializeJson(
                jsonObject(
                    jsonProperty("Rules", jsonArray(jsonObject(
                        jsonProperty("Resource", jsonArray("collection/example-collection")),
                        jsonProperty("ResourceType", "collection")
                    ))),
                    jsonProperty("AWSOwnedKey", true)
                )))
            .build());

    }
}
resources:
  example:
    type: aws:opensearch:ServerlessSecurityPolicy
    properties:
      name: example
      type: encryption
      description: encryption security policy for example-collection
      policy:
        fn::toJSON:
          Rules:
            - Resource:
                - collection/example-collection
              ResourceType: collection
          AWSOwnedKey: true

The policy property contains a JSON document with Rules that specify which collections to encrypt. The Resource array lists collection names or patterns; ResourceType must be “collection”. Setting AWSOwnedKey to true uses AWS-managed encryption without additional key management.

Encrypt collections with customer-managed KMS keys

Organizations with compliance requirements often use customer-managed KMS keys to control encryption key lifecycle.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.opensearch.ServerlessSecurityPolicy("example", {
    name: "example",
    type: "encryption",
    description: "encryption security policy using customer KMS key",
    policy: JSON.stringify({
        Rules: [{
            Resource: ["collection/customer-managed-key-collection"],
            ResourceType: "collection",
        }],
        AWSOwnedKey: false,
        KmsARN: "arn:aws:kms:us-east-1:123456789012:key/93fd6da4-a317-4c17-bfe9-382b5d988b36",
    }),
});
import pulumi
import json
import pulumi_aws as aws

example = aws.opensearch.ServerlessSecurityPolicy("example",
    name="example",
    type="encryption",
    description="encryption security policy using customer KMS key",
    policy=json.dumps({
        "Rules": [{
            "Resource": ["collection/customer-managed-key-collection"],
            "ResourceType": "collection",
        }],
        "AWSOwnedKey": False,
        "KmsARN": "arn:aws:kms:us-east-1:123456789012:key/93fd6da4-a317-4c17-bfe9-382b5d988b36",
    }))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"Rules": []map[string]interface{}{
				map[string]interface{}{
					"Resource": []string{
						"collection/customer-managed-key-collection",
					},
					"ResourceType": "collection",
				},
			},
			"AWSOwnedKey": false,
			"KmsARN":      "arn:aws:kms:us-east-1:123456789012:key/93fd6da4-a317-4c17-bfe9-382b5d988b36",
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = opensearch.NewServerlessSecurityPolicy(ctx, "example", &opensearch.ServerlessSecurityPolicyArgs{
			Name:        pulumi.String("example"),
			Type:        pulumi.String("encryption"),
			Description: pulumi.String("encryption security policy using customer KMS key"),
			Policy:      pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.OpenSearch.ServerlessSecurityPolicy("example", new()
    {
        Name = "example",
        Type = "encryption",
        Description = "encryption security policy using customer KMS key",
        Policy = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["Rules"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Resource"] = new[]
                    {
                        "collection/customer-managed-key-collection",
                    },
                    ["ResourceType"] = "collection",
                },
            },
            ["AWSOwnedKey"] = false,
            ["KmsARN"] = "arn:aws:kms:us-east-1:123456789012:key/93fd6da4-a317-4c17-bfe9-382b5d988b36",
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicy;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ServerlessSecurityPolicy("example", ServerlessSecurityPolicyArgs.builder()
            .name("example")
            .type("encryption")
            .description("encryption security policy using customer KMS key")
            .policy(serializeJson(
                jsonObject(
                    jsonProperty("Rules", jsonArray(jsonObject(
                        jsonProperty("Resource", jsonArray("collection/customer-managed-key-collection")),
                        jsonProperty("ResourceType", "collection")
                    ))),
                    jsonProperty("AWSOwnedKey", false),
                    jsonProperty("KmsARN", "arn:aws:kms:us-east-1:123456789012:key/93fd6da4-a317-4c17-bfe9-382b5d988b36")
                )))
            .build());

    }
}
resources:
  example:
    type: aws:opensearch:ServerlessSecurityPolicy
    properties:
      name: example
      type: encryption
      description: encryption security policy using customer KMS key
      policy:
        fn::toJSON:
          Rules:
            - Resource:
                - collection/customer-managed-key-collection
              ResourceType: collection
          AWSOwnedKey: false
          KmsARN: arn:aws:kms:us-east-1:123456789012:key/93fd6da4-a317-4c17-bfe9-382b5d988b36

Setting AWSOwnedKey to false and providing a KmsARN switches to customer-managed encryption. You control key rotation, access policies, and audit logging through KMS.

Apply encryption to multiple collections with wildcards

Teams managing related collections can use wildcard patterns to enforce consistent encryption across collections sharing naming conventions.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.opensearch.ServerlessSecurityPolicy("example", {
    name: "example",
    type: "encryption",
    description: "encryption security policy for collections that begin with \"example\"",
    policy: JSON.stringify({
        Rules: [{
            Resource: ["collection/example*"],
            ResourceType: "collection",
        }],
        AWSOwnedKey: true,
    }),
});
import pulumi
import json
import pulumi_aws as aws

example = aws.opensearch.ServerlessSecurityPolicy("example",
    name="example",
    type="encryption",
    description="encryption security policy for collections that begin with \"example\"",
    policy=json.dumps({
        "Rules": [{
            "Resource": ["collection/example*"],
            "ResourceType": "collection",
        }],
        "AWSOwnedKey": True,
    }))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"Rules": []map[string]interface{}{
				map[string]interface{}{
					"Resource": []string{
						"collection/example*",
					},
					"ResourceType": "collection",
				},
			},
			"AWSOwnedKey": true,
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = opensearch.NewServerlessSecurityPolicy(ctx, "example", &opensearch.ServerlessSecurityPolicyArgs{
			Name:        pulumi.String("example"),
			Type:        pulumi.String("encryption"),
			Description: pulumi.String("encryption security policy for collections that begin with \"example\""),
			Policy:      pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.OpenSearch.ServerlessSecurityPolicy("example", new()
    {
        Name = "example",
        Type = "encryption",
        Description = "encryption security policy for collections that begin with \"example\"",
        Policy = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["Rules"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["Resource"] = new[]
                    {
                        "collection/example*",
                    },
                    ["ResourceType"] = "collection",
                },
            },
            ["AWSOwnedKey"] = true,
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicy;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ServerlessSecurityPolicy("example", ServerlessSecurityPolicyArgs.builder()
            .name("example")
            .type("encryption")
            .description("encryption security policy for collections that begin with \"example\"")
            .policy(serializeJson(
                jsonObject(
                    jsonProperty("Rules", jsonArray(jsonObject(
                        jsonProperty("Resource", jsonArray("collection/example*")),
                        jsonProperty("ResourceType", "collection")
                    ))),
                    jsonProperty("AWSOwnedKey", true)
                )))
            .build());

    }
}
resources:
  example:
    type: aws:opensearch:ServerlessSecurityPolicy
    properties:
      name: example
      type: encryption
      description: encryption security policy for collections that begin with "example"
      policy:
        fn::toJSON:
          Rules:
            - Resource:
                - collection/example*
              ResourceType: collection
          AWSOwnedKey: true

The Resource pattern “collection/example*” matches any collection name starting with “example”. This applies the same encryption policy to all matching collections without listing each individually.

Allow public access to collections and dashboards

Public-facing search applications need network policies that permit internet access to both collection endpoints and OpenSearch Dashboards.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.opensearch.ServerlessSecurityPolicy("example", {
    name: "example",
    type: "network",
    description: "Public access",
    policy: JSON.stringify([{
        Description: "Public access to collection and Dashboards endpoint for example collection",
        Rules: [
            {
                ResourceType: "collection",
                Resource: ["collection/example-collection"],
            },
            {
                ResourceType: "dashboard",
                Resource: ["collection/example-collection"],
            },
        ],
        AllowFromPublic: true,
    }]),
});
import pulumi
import json
import pulumi_aws as aws

example = aws.opensearch.ServerlessSecurityPolicy("example",
    name="example",
    type="network",
    description="Public access",
    policy=json.dumps([{
        "Description": "Public access to collection and Dashboards endpoint for example collection",
        "Rules": [
            {
                "ResourceType": "collection",
                "Resource": ["collection/example-collection"],
            },
            {
                "ResourceType": "dashboard",
                "Resource": ["collection/example-collection"],
            },
        ],
        "AllowFromPublic": True,
    }]))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal([]map[string]interface{}{
			map[string]interface{}{
				"Description": "Public access to collection and Dashboards endpoint for example collection",
				"Rules": []map[string]interface{}{
					map[string]interface{}{
						"ResourceType": "collection",
						"Resource": []string{
							"collection/example-collection",
						},
					},
					map[string]interface{}{
						"ResourceType": "dashboard",
						"Resource": []string{
							"collection/example-collection",
						},
					},
				},
				"AllowFromPublic": true,
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = opensearch.NewServerlessSecurityPolicy(ctx, "example", &opensearch.ServerlessSecurityPolicyArgs{
			Name:        pulumi.String("example"),
			Type:        pulumi.String("network"),
			Description: pulumi.String("Public access"),
			Policy:      pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.OpenSearch.ServerlessSecurityPolicy("example", new()
    {
        Name = "example",
        Type = "network",
        Description = "Public access",
        Policy = JsonSerializer.Serialize(new[]
        {
            new Dictionary<string, object?>
            {
                ["Description"] = "Public access to collection and Dashboards endpoint for example collection",
                ["Rules"] = new[]
                {
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "collection",
                        ["Resource"] = new[]
                        {
                            "collection/example-collection",
                        },
                    },
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "dashboard",
                        ["Resource"] = new[]
                        {
                            "collection/example-collection",
                        },
                    },
                },
                ["AllowFromPublic"] = true,
            },
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicy;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ServerlessSecurityPolicy("example", ServerlessSecurityPolicyArgs.builder()
            .name("example")
            .type("network")
            .description("Public access")
            .policy(serializeJson(
                jsonArray(jsonObject(
                    jsonProperty("Description", "Public access to collection and Dashboards endpoint for example collection"),
                    jsonProperty("Rules", jsonArray(
                        jsonObject(
                            jsonProperty("ResourceType", "collection"),
                            jsonProperty("Resource", jsonArray("collection/example-collection"))
                        ), 
                        jsonObject(
                            jsonProperty("ResourceType", "dashboard"),
                            jsonProperty("Resource", jsonArray("collection/example-collection"))
                        )
                    )),
                    jsonProperty("AllowFromPublic", true)
                ))))
            .build());

    }
}
resources:
  example:
    type: aws:opensearch:ServerlessSecurityPolicy
    properties:
      name: example
      type: network
      description: Public access
      policy:
        fn::toJSON:
          - Description: Public access to collection and Dashboards endpoint for example collection
            Rules:
              - ResourceType: collection
                Resource:
                  - collection/example-collection
              - ResourceType: dashboard
                Resource:
                  - collection/example-collection
            AllowFromPublic: true

Network policies use type “network” and contain an array of rules. Each rule specifies ResourceType (“collection” or “dashboard”) and matching Resource patterns. Setting AllowFromPublic to true permits internet access.

Restrict access to VPC endpoints

Internal applications running in VPCs access OpenSearch Serverless privately through VPC endpoints.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.opensearch.ServerlessSecurityPolicy("example", {
    name: "example",
    type: "network",
    description: "VPC access",
    policy: JSON.stringify([{
        Description: "VPC access to collection and Dashboards endpoint for example collection",
        Rules: [
            {
                ResourceType: "collection",
                Resource: ["collection/example-collection"],
            },
            {
                ResourceType: "dashboard",
                Resource: ["collection/example-collection"],
            },
        ],
        AllowFromPublic: false,
        SourceVPCEs: ["vpce-050f79086ee71ac05"],
    }]),
});
import pulumi
import json
import pulumi_aws as aws

example = aws.opensearch.ServerlessSecurityPolicy("example",
    name="example",
    type="network",
    description="VPC access",
    policy=json.dumps([{
        "Description": "VPC access to collection and Dashboards endpoint for example collection",
        "Rules": [
            {
                "ResourceType": "collection",
                "Resource": ["collection/example-collection"],
            },
            {
                "ResourceType": "dashboard",
                "Resource": ["collection/example-collection"],
            },
        ],
        "AllowFromPublic": False,
        "SourceVPCEs": ["vpce-050f79086ee71ac05"],
    }]))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal([]map[string]interface{}{
			map[string]interface{}{
				"Description": "VPC access to collection and Dashboards endpoint for example collection",
				"Rules": []map[string]interface{}{
					map[string]interface{}{
						"ResourceType": "collection",
						"Resource": []string{
							"collection/example-collection",
						},
					},
					map[string]interface{}{
						"ResourceType": "dashboard",
						"Resource": []string{
							"collection/example-collection",
						},
					},
				},
				"AllowFromPublic": false,
				"SourceVPCEs": []string{
					"vpce-050f79086ee71ac05",
				},
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = opensearch.NewServerlessSecurityPolicy(ctx, "example", &opensearch.ServerlessSecurityPolicyArgs{
			Name:        pulumi.String("example"),
			Type:        pulumi.String("network"),
			Description: pulumi.String("VPC access"),
			Policy:      pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.OpenSearch.ServerlessSecurityPolicy("example", new()
    {
        Name = "example",
        Type = "network",
        Description = "VPC access",
        Policy = JsonSerializer.Serialize(new[]
        {
            new Dictionary<string, object?>
            {
                ["Description"] = "VPC access to collection and Dashboards endpoint for example collection",
                ["Rules"] = new[]
                {
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "collection",
                        ["Resource"] = new[]
                        {
                            "collection/example-collection",
                        },
                    },
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "dashboard",
                        ["Resource"] = new[]
                        {
                            "collection/example-collection",
                        },
                    },
                },
                ["AllowFromPublic"] = false,
                ["SourceVPCEs"] = new[]
                {
                    "vpce-050f79086ee71ac05",
                },
            },
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicy;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ServerlessSecurityPolicy("example", ServerlessSecurityPolicyArgs.builder()
            .name("example")
            .type("network")
            .description("VPC access")
            .policy(serializeJson(
                jsonArray(jsonObject(
                    jsonProperty("Description", "VPC access to collection and Dashboards endpoint for example collection"),
                    jsonProperty("Rules", jsonArray(
                        jsonObject(
                            jsonProperty("ResourceType", "collection"),
                            jsonProperty("Resource", jsonArray("collection/example-collection"))
                        ), 
                        jsonObject(
                            jsonProperty("ResourceType", "dashboard"),
                            jsonProperty("Resource", jsonArray("collection/example-collection"))
                        )
                    )),
                    jsonProperty("AllowFromPublic", false),
                    jsonProperty("SourceVPCEs", jsonArray("vpce-050f79086ee71ac05"))
                ))))
            .build());

    }
}
resources:
  example:
    type: aws:opensearch:ServerlessSecurityPolicy
    properties:
      name: example
      type: network
      description: VPC access
      policy:
        fn::toJSON:
          - Description: VPC access to collection and Dashboards endpoint for example collection
            Rules:
              - ResourceType: collection
                Resource:
                  - collection/example-collection
              - ResourceType: dashboard
                Resource:
                  - collection/example-collection
            AllowFromPublic: false
            SourceVPCEs:
              - vpce-050f79086ee71ac05

Setting AllowFromPublic to false and providing SourceVPCEs restricts access to specified VPC endpoints. Traffic flows privately without traversing the public internet.

Configure different access patterns per collection

Organizations often need different network policies for different teams, such as private access for analytics and public access for customer search.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.opensearch.ServerlessSecurityPolicy("example", {
    name: "example",
    type: "network",
    description: "Mixed access for marketing and sales",
    policy: JSON.stringify([
        {
            Description: "Marketing access",
            Rules: [
                {
                    ResourceType: "collection",
                    Resource: ["collection/marketing*"],
                },
                {
                    ResourceType: "dashboard",
                    Resource: ["collection/marketing*"],
                },
            ],
            AllowFromPublic: false,
            SourceVPCEs: ["vpce-050f79086ee71ac05"],
        },
        {
            Description: "Sales access",
            Rules: [{
                ResourceType: "collection",
                Resource: ["collection/finance"],
            }],
            AllowFromPublic: true,
        },
    ]),
});
import pulumi
import json
import pulumi_aws as aws

example = aws.opensearch.ServerlessSecurityPolicy("example",
    name="example",
    type="network",
    description="Mixed access for marketing and sales",
    policy=json.dumps([
        {
            "Description": "Marketing access",
            "Rules": [
                {
                    "ResourceType": "collection",
                    "Resource": ["collection/marketing*"],
                },
                {
                    "ResourceType": "dashboard",
                    "Resource": ["collection/marketing*"],
                },
            ],
            "AllowFromPublic": False,
            "SourceVPCEs": ["vpce-050f79086ee71ac05"],
        },
        {
            "Description": "Sales access",
            "Rules": [{
                "ResourceType": "collection",
                "Resource": ["collection/finance"],
            }],
            "AllowFromPublic": True,
        },
    ]))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal([]interface{}{
			map[string]interface{}{
				"Description": "Marketing access",
				"Rules": []map[string]interface{}{
					map[string]interface{}{
						"ResourceType": "collection",
						"Resource": []string{
							"collection/marketing*",
						},
					},
					map[string]interface{}{
						"ResourceType": "dashboard",
						"Resource": []string{
							"collection/marketing*",
						},
					},
				},
				"AllowFromPublic": false,
				"SourceVPCEs": []string{
					"vpce-050f79086ee71ac05",
				},
			},
			map[string]interface{}{
				"Description": "Sales access",
				"Rules": []map[string]interface{}{
					map[string]interface{}{
						"ResourceType": "collection",
						"Resource": []string{
							"collection/finance",
						},
					},
				},
				"AllowFromPublic": true,
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = opensearch.NewServerlessSecurityPolicy(ctx, "example", &opensearch.ServerlessSecurityPolicyArgs{
			Name:        pulumi.String("example"),
			Type:        pulumi.String("network"),
			Description: pulumi.String("Mixed access for marketing and sales"),
			Policy:      pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.OpenSearch.ServerlessSecurityPolicy("example", new()
    {
        Name = "example",
        Type = "network",
        Description = "Mixed access for marketing and sales",
        Policy = JsonSerializer.Serialize(new[]
        {
            new Dictionary<string, object?>
            {
                ["Description"] = "Marketing access",
                ["Rules"] = new[]
                {
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "collection",
                        ["Resource"] = new[]
                        {
                            "collection/marketing*",
                        },
                    },
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "dashboard",
                        ["Resource"] = new[]
                        {
                            "collection/marketing*",
                        },
                    },
                },
                ["AllowFromPublic"] = false,
                ["SourceVPCEs"] = new[]
                {
                    "vpce-050f79086ee71ac05",
                },
            },
            new Dictionary<string, object?>
            {
                ["Description"] = "Sales access",
                ["Rules"] = new[]
                {
                    new Dictionary<string, object?>
                    {
                        ["ResourceType"] = "collection",
                        ["Resource"] = new[]
                        {
                            "collection/finance",
                        },
                    },
                },
                ["AllowFromPublic"] = true,
            },
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicy;
import com.pulumi.aws.opensearch.ServerlessSecurityPolicyArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new ServerlessSecurityPolicy("example", ServerlessSecurityPolicyArgs.builder()
            .name("example")
            .type("network")
            .description("Mixed access for marketing and sales")
            .policy(serializeJson(
                jsonArray(
                    jsonObject(
                        jsonProperty("Description", "Marketing access"),
                        jsonProperty("Rules", jsonArray(
                            jsonObject(
                                jsonProperty("ResourceType", "collection"),
                                jsonProperty("Resource", jsonArray("collection/marketing*"))
                            ), 
                            jsonObject(
                                jsonProperty("ResourceType", "dashboard"),
                                jsonProperty("Resource", jsonArray("collection/marketing*"))
                            )
                        )),
                        jsonProperty("AllowFromPublic", false),
                        jsonProperty("SourceVPCEs", jsonArray("vpce-050f79086ee71ac05"))
                    ), 
                    jsonObject(
                        jsonProperty("Description", "Sales access"),
                        jsonProperty("Rules", jsonArray(jsonObject(
                            jsonProperty("ResourceType", "collection"),
                            jsonProperty("Resource", jsonArray("collection/finance"))
                        ))),
                        jsonProperty("AllowFromPublic", true)
                    )
                )))
            .build());

    }
}
resources:
  example:
    type: aws:opensearch:ServerlessSecurityPolicy
    properties:
      name: example
      type: network
      description: Mixed access for marketing and sales
      policy:
        fn::toJSON:
          - Description: Marketing access
            Rules:
              - ResourceType: collection
                Resource:
                  - collection/marketing*
              - ResourceType: dashboard
                Resource:
                  - collection/marketing*
            AllowFromPublic: false
            SourceVPCEs:
              - vpce-050f79086ee71ac05
          - Description: Sales access
            Rules:
              - ResourceType: collection
                Resource:
                  - collection/finance
            AllowFromPublic: true

The policy array can contain multiple rule sets, each with its own Description, Rules, and access configuration. This example applies VPC-only access to marketing collections and public access to finance collections.

Beyond these examples

These snippets focus on specific security policy features: encryption policies with AWS-managed and customer-managed keys, network policies for public and VPC-based access, and wildcard patterns for multi-collection policies. They’re intentionally minimal rather than complete access control solutions.

The examples may reference pre-existing infrastructure such as KMS keys for customer-managed encryption and VPC endpoints for private network access. They focus on configuring security policies rather than provisioning the underlying infrastructure.

To keep things focused, common policy patterns are omitted, including:

  • Data access policies (separate resource type)
  • Policy versioning and updates
  • Cross-account access patterns
  • IAM integration for authentication

These omissions are intentional: the goal is to illustrate how each security policy feature is wired, not provide drop-in access control modules. See the OpenSearch Serverless Security Policy resource reference for all available configuration options.

Let's configure AWS OpenSearch Serverless Security Policies

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Policy Types & Scope
What types of security policies can I create?
You can create two types: encryption policies (for managing encryption keys) and network policies (for controlling access to collections and dashboards).
Can I apply a security policy to multiple collections at once?
Yes, use wildcards in the Resource field. For example, collection/example* applies the policy to all collections starting with “example”.
What's the difference between collection and dashboard resource types?
Network policies can target collection (the OpenSearch collection endpoint) and dashboard (the Dashboards UI endpoint) separately, allowing different access rules for each.
Encryption Configuration
How do I use my own KMS key instead of an AWS-owned key?
Set AWSOwnedKey to false and provide your KmsARN in the encryption policy document.
Network Access Control
How do I allow public access to my OpenSearch collection?
Set AllowFromPublic to true in your network policy rules for both collection and dashboard resource types.
How do I restrict access to VPC endpoints only?
Set AllowFromPublic to false and specify your VPC endpoint IDs in the SourceVPCEs array.
Can I configure different access rules for different collections in one policy?
Yes, define multiple rules in the policy array with different Resource patterns, AllowFromPublic settings, and SourceVPCEs values.

Using a different cloud?

Explore security guides for other cloud providers: