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-restricted access, and wildcard patterns for multi-collection policies.

Security policies apply to OpenSearch Serverless collections and may reference KMS keys or VPC endpoints that must exist separately. The examples are intentionally small. Combine them with your own collection definitions and network 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 type property specifies “encryption” to create an encryption policy. The policy JSON defines Rules that target specific collections by name. Setting AWSOwnedKey to true uses AWS-managed encryption keys, which AWS rotates automatically.

Encrypt collections with customer-managed KMS keys

Organizations with compliance requirements often need control over encryption keys for rotation and access policies.

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 keys. You control key rotation, access policies, and audit logging through KMS. The KMS key must exist before creating the policy.

Apply encryption to multiple collections with wildcards

When managing many collections with similar security requirements, wildcard patterns reduce policy duplication.

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 array accepts wildcard patterns like “collection/example*” to match multiple collections. This extends the single-collection pattern by applying the same encryption settings to all collections whose names begin with “example”.

Allow public access to collections and dashboards

Network policies control whether collections and dashboards are accessible from the public internet or restricted to 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: "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

Setting type to “network” creates a network policy. The policy JSON defines Rules that specify ResourceType (collection or dashboard) and which collections to target. Setting AllowFromPublic to true enables internet access to both the collection API and the OpenSearch Dashboards interface.

Restrict access to VPC endpoints

Production deployments often require private network access to prevent exposure to the public internet.

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 specific VPC endpoints. Only traffic originating from the listed VPC endpoints can reach the collection and dashboard. The VPC endpoint must exist before creating the policy.

Configure different access rules per collection

Organizations often need different network policies for different teams, such as private access for internal analytics and public access for customer-facing 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: "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

A single network policy can contain multiple rule sets, each with different AllowFromPublic and SourceVPCEs settings. This example applies VPC-restricted access to collections matching “marketing*” and public access to the “finance” collection. Wildcard patterns and multiple rules combine to create flexible access controls.

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-restricted access, and wildcard patterns for multi-collection policies. They’re intentionally minimal rather than full OpenSearch deployments.

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 surrounding infrastructure.

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

  • Data access policies (separate resource type)
  • Policy versioning and updates
  • Cross-account KMS key access
  • Multiple VPC endpoint sources

These omissions are intentional: the goal is to illustrate how each security policy feature is wired, not provide drop-in OpenSearch 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 & Structure
What's the difference between encryption and network security policies?
Encryption policies control encryption settings for collections (AWS-owned or customer-managed keys), while network policies control access to collection and dashboard endpoints (public or VPC-based access).
Why does my policy JSON format look different for encryption vs network policies?
Encryption policies use a JSON object structure, while network policies use a JSON array structure. Check the examples for the correct format based on your policy type.
Encryption Configuration
What encryption key options are available?
You can use AWS-owned keys (set AWSOwnedKey: true) or customer-managed KMS keys (set AWSOwnedKey: false and provide KmsARN).
Network Access Control
How do I allow public access to my OpenSearch Serverless collection?
In your network policy, set AllowFromPublic: true in the policy rules.
How do I restrict access to specific VPC endpoints?
Set AllowFromPublic: false and specify VPC endpoint IDs in the SourceVPCEs array.
What's the difference between collection and dashboard resource types?
Collection resources control access to the OpenSearch collection endpoint, while dashboard resources control access to the Dashboards UI endpoint. You typically need rules for both to provide full access.
Resource Targeting
Can I apply a security policy to multiple collections at once?
Yes, use wildcard patterns in the Resource array, such as collection/example* to match all collections starting with “example”.
Can I configure different access rules for different collections in one policy?
Yes, network policies support multiple rules with different access patterns (public vs VPC) in a single policy document.
How do I import an existing security policy?
Use the format name/type, for example: pulumi import aws:opensearch/serverlessSecurityPolicy:ServerlessSecurityPolicy example example/encryption

Using a different cloud?

Explore security guides for other cloud providers: