Skip to content

Resource: awsOpensearchDomain

Manages an Amazon OpenSearch Domain.

Elasticsearch vs. OpenSearch

Amazon OpenSearch Service is the successor to Amazon Elasticsearch Service and supports OpenSearch and legacy Elasticsearch OSS (up to 7.10, the final open source version of the software).

OpenSearch Domain configurations are similar in many ways to Elasticsearch Domain configurations. However, there are important differences including these:

  • OpenSearch has engineVersion while Elasticsearch has elasticsearchVersion
  • Versions are specified differently - e.g., elasticsearch710 with OpenSearch vs. 710 for Elasticsearch.
  • instanceType argument values end in search for OpenSearch vs. elasticsearch for Elasticsearch (e.g., t2MicroSearch vs. t2MicroElasticsearch).
  • The AWS-managed service-linked role for OpenSearch is called awsServiceRoleForAmazonOpenSearchService instead of awsServiceRoleForAmazonElasticsearchService for Elasticsearch.

There are also some potentially unexpected similarities in configurations:

  • ARNs for both are prefaced with arn:aws:es:.
  • Both OpenSearch and Elasticsearch use assume role policies that refer to the principal service as esAmazonawsCom.
  • IAM policy actions, such as those you will find in accessPolicies, are prefaced with es: for both.

Example Usage

Basic Usage

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.opensearchDomain.OpensearchDomain(this, "example", {
  clusterConfig: {
    instanceType: "r4.large.search",
  },
  domainName: "example",
  engineVersion: "Elasticsearch_7.10",
  tags: {
    Domain: "TestDomain",
  },
});

Access Policy

-> See also: awsOpensearchDomainPolicy resource

import * as cdktf from "cdktf";
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
/*Terraform Variables are not always the best fit for getting inputs in the context of Terraform CDK.
You can read more about this at https://cdk.tf/variables*/
const domain = new cdktf.TerraformVariable(this, "domain", {
  default: "tf-test",
});
const dataAwsCallerIdentityCurrent =
  new aws.dataAwsCallerIdentity.DataAwsCallerIdentity(this, "current", {});
const dataAwsRegionCurrent = new aws.dataAwsRegion.DataAwsRegion(
  this,
  "current_2",
  {}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
dataAwsRegionCurrent.overrideLogicalId("current");
const dataAwsIamPolicyDocumentExample =
  new aws.dataAwsIamPolicyDocument.DataAwsIamPolicyDocument(this, "example", {
    statement: [
      {
        actions: ["es:*"],
        condition: [
          {
            test: "IpAddress",
            values: ["66.193.100.22/32"],
            variable: "aws:SourceIp",
          },
        ],
        effect: "Allow",
        principals: [
          {
            identifiers: ["*"],
            type: "*",
          },
        ],
        resources: [
          `arn:aws:es:\${${dataAwsRegionCurrent.name}}:\${${dataAwsCallerIdentityCurrent.accountId}}:domain/\${${domain.value}}/*`,
        ],
      },
    ],
  });
const awsOpensearchDomainExample = new aws.opensearchDomain.OpensearchDomain(
  this,
  "example_4",
  {
    accessPolicies: dataAwsIamPolicyDocumentExample.json,
    domainName: domain.value,
  }
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsOpensearchDomainExample.overrideLogicalId("example");

Log publishing to CloudWatch Logs

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsCloudwatchLogGroupExample =
  new aws.cloudwatchLogGroup.CloudwatchLogGroup(this, "example", {
    name: "example",
  });
const awsOpensearchDomainExample = new aws.opensearchDomain.OpensearchDomain(
  this,
  "example_1",
  {
    logPublishingOptions: [
      {
        cloudwatchLogGroupArn: awsCloudwatchLogGroupExample.arn,
        logType: "INDEX_SLOW_LOGS",
      },
    ],
  }
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsOpensearchDomainExample.overrideLogicalId("example");
const dataAwsIamPolicyDocumentExample =
  new aws.dataAwsIamPolicyDocument.DataAwsIamPolicyDocument(this, "example_2", {
    statement: [
      {
        actions: [
          "logs:PutLogEvents",
          "logs:PutLogEventsBatch",
          "logs:CreateLogStream",
        ],
        effect: "Allow",
        principals: [
          {
            identifiers: ["es.amazonaws.com"],
            type: "Service",
          },
        ],
        resources: ["arn:aws:logs:*"],
      },
    ],
  });
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
dataAwsIamPolicyDocumentExample.overrideLogicalId("example");
const awsCloudwatchLogResourcePolicyExample =
  new aws.cloudwatchLogResourcePolicy.CloudwatchLogResourcePolicy(
    this,
    "example_3",
    {
      policyDocument: dataAwsIamPolicyDocumentExample.json,
      policyName: "example",
    }
  );
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsCloudwatchLogResourcePolicyExample.overrideLogicalId("example");

VPC based OpenSearch

import * as cdktf from "cdktf";
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
/*Terraform Variables are not always the best fit for getting inputs in the context of Terraform CDK.
You can read more about this at https://cdk.tf/variables*/
const domain = new cdktf.TerraformVariable(this, "domain", {
  default: "tf-test",
});
const vpc = new cdktf.TerraformVariable(this, "vpc", {});
const awsIamServiceLinkedRoleExample =
  new aws.iamServiceLinkedRole.IamServiceLinkedRole(this, "example", {
    awsServiceName: "opensearchservice.amazonaws.com",
  });
const dataAwsCallerIdentityCurrent =
  new aws.dataAwsCallerIdentity.DataAwsCallerIdentity(this, "current", {});
const dataAwsRegionCurrent = new aws.dataAwsRegion.DataAwsRegion(
  this,
  "current_4",
  {}
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
dataAwsRegionCurrent.overrideLogicalId("current");
const dataAwsVpcExample = new aws.dataAwsVpc.DataAwsVpc(this, "example_5", {
  tags: {
    Name: vpc.value,
  },
});
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
dataAwsVpcExample.overrideLogicalId("example");
const awsSecurityGroupExample = new aws.securityGroup.SecurityGroup(
  this,
  "example_6",
  {
    description: "Managed by Terraform",
    ingress: [
      {
        cidrBlocks: [dataAwsVpcExample.cidrBlock],
        fromPort: 443,
        protocol: "tcp",
        toPort: 443,
      },
    ],
    name: `\${${vpc.value}}-opensearch-\${${domain.value}}`,
    vpcId: dataAwsVpcExample.id,
  }
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsSecurityGroupExample.overrideLogicalId("example");
const dataAwsIamPolicyDocumentExample =
  new aws.dataAwsIamPolicyDocument.DataAwsIamPolicyDocument(this, "example_7", {
    statement: [
      {
        actions: ["es:*"],
        effect: "Allow",
        principals: [
          {
            identifiers: ["*"],
            type: "*",
          },
        ],
        resources: [
          `arn:aws:es:\${${dataAwsRegionCurrent.name}}:\${${dataAwsCallerIdentityCurrent.accountId}}:domain/\${${domain.value}}/*`,
        ],
      },
    ],
  });
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
dataAwsIamPolicyDocumentExample.overrideLogicalId("example");
const dataAwsSubnetIdsExample = new aws.dataAwsSubnetIds.DataAwsSubnetIds(
  this,
  "example_8",
  {
    tags: {
      Tier: "private",
    },
    vpcId: dataAwsVpcExample.id,
  }
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
dataAwsSubnetIdsExample.overrideLogicalId("example");
const awsOpensearchDomainExample = new aws.opensearchDomain.OpensearchDomain(
  this,
  "example_9",
  {
    accessPolicies: dataAwsIamPolicyDocumentExample.json,
    advancedOptions: {
      "rest.action.multi.allow_explicit_index": "true",
    },
    clusterConfig: {
      instanceType: "m4.large.search",
      zoneAwarenessEnabled: true,
    },
    depends_on: [`\${${awsIamServiceLinkedRoleExample.fqn}}`],
    domainName: domain.value,
    engineVersion: "OpenSearch_1.0",
    tags: {
      Domain: "TestDomain",
    },
    vpcOptions: {
      securityGroupIds: [awsSecurityGroupExample.id],
      subnetIds: [
        `\${${dataAwsSubnetIdsExample.ids.fqn}[0]}`,
        `\${${dataAwsSubnetIdsExample.ids.fqn}[1]}`,
      ],
    },
  }
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsOpensearchDomainExample.overrideLogicalId("example");

Enabling fine-grained access control on an existing domain

This example shows two configurations: one to create a domain without fine-grained access control and the second to modify the domain to enable fine-grained access control. For more information, see Enabling fine-grained access control.

First apply

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.opensearchDomain.OpensearchDomain(this, "example", {
  advancedSecurityOptions: {
    anonymousAuthEnabled: true,
    enabled: false,
    internalUserDatabaseEnabled: true,
    masterUserOptions: {
      masterUserName: "example",
      masterUserPassword: "Barbarbarbar1!",
    },
  },
  clusterConfig: {
    instanceType: "r5.large.search",
  },
  domainEndpointOptions: {
    enforceHttps: true,
    tlsSecurityPolicy: "Policy-Min-TLS-1-2-2019-07",
  },
  domainName: "ggkitty",
  ebsOptions: {
    ebsEnabled: true,
    volumeSize: 10,
  },
  encryptAtRest: {
    enabled: true,
  },
  engineVersion: "Elasticsearch_7.1",
  nodeToNodeEncryption: {
    enabled: true,
  },
});

Second apply

Notice that the only change is advancedSecurityOptions0Enabled is now set to true.

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.opensearchDomain.OpensearchDomain(this, "example", {
  advancedSecurityOptions: {
    anonymousAuthEnabled: true,
    enabled: true,
    internalUserDatabaseEnabled: true,
    masterUserOptions: {
      masterUserName: "example",
      masterUserPassword: "Barbarbarbar1!",
    },
  },
  clusterConfig: {
    instanceType: "r5.large.search",
  },
  domainEndpointOptions: {
    enforceHttps: true,
    tlsSecurityPolicy: "Policy-Min-TLS-1-2-2019-07",
  },
  domainName: "ggkitty",
  ebsOptions: {
    ebsEnabled: true,
    volumeSize: 10,
  },
  encryptAtRest: {
    enabled: true,
  },
  engineVersion: "Elasticsearch_7.1",
  nodeToNodeEncryption: {
    enabled: true,
  },
});

Argument Reference

The following arguments are required:

  • domainName - (Required) Name of the domain.

The following arguments are optional:

  • accessPolicies - (Optional) IAM policy document specifying the access policies for the domain.
  • advancedOptions - (Optional) Key-value string pairs to specify advanced configuration options. Note that the values for these configuration options must be strings (wrapped in quotes) or they may be wrong and cause a perpetual diff, causing Terraform to want to recreate your OpenSearch domain on every apply.
  • advancedSecurityOptions - (Optional) Configuration block for fine-grained access control. Detailed below.
  • autoTuneOptions - (Optional) Configuration block for the Auto-Tune options of the domain. Detailed below.
  • clusterConfig - (Optional) Configuration block for the cluster of the domain. Detailed below.
  • cognitoOptions - (Optional) Configuration block for authenticating dashboard with Cognito. Detailed below.
  • domainEndpointOptions - (Optional) Configuration block for domain endpoint HTTP(S) related options. Detailed below.
  • ebsOptions - (Optional) Configuration block for EBS related options, may be required based on chosen instance size. Detailed below.
  • engineVersion - (Optional) Either elasticsearchXY or openSearchXY to specify the engine version for the Amazon OpenSearch Service domain. For example, openSearch10 or elasticsearch79. See Creating and managing Amazon OpenSearch Service domains. Defaults to openSearch11.
  • encryptAtRest - (Optional) Configuration block for encrypt at rest options. Only available for certain instance types. Detailed below.
  • logPublishingOptions - (Optional) Configuration block for publishing slow and application logs to CloudWatch Logs. This block can be declared multiple times, for each log_type, within the same resource. Detailed below.
  • nodeToNodeEncryption - (Optional) Configuration block for node-to-node encryption options. Detailed below.
  • snapshotOptions - (Optional) Configuration block for snapshot related options. Detailed below. DEPRECATED. For domains running OpenSearch 5.3 and later, Amazon OpenSearch takes hourly automated snapshots, making this setting irrelevant. For domains running earlier versions, OpenSearch takes daily automated snapshots.
  • tags - (Optional) Map of tags to assign to the resource. If configured with a provider defaultTags configuration block present, tags with matching keys will overwrite those defined at the provider-level.
  • vpcOptions - (Optional) Configuration block for VPC related options. Adding or removing this configuration forces a new resource (documentation). Detailed below.

advancedSecurityOptions

  • anonymousAuthEnabled - (Optional) Whether Anonymous auth is enabled. Enables fine-grained access control on an existing domain. Ignored unless advancedSecurityOptions are enabled. Can only be enabled on an existing domain.
  • enabled - (Required, Forces new resource when changing from true to false) Whether advanced security is enabled.
  • internalUserDatabaseEnabled - (Optional) Whether the internal user database is enabled. Default is false.
  • masterUserOptions - (Optional) Configuration block for the main user. Detailed below.

masterUserOptions

  • masterUserArn - (Optional) ARN for the main user. Only specify if internalUserDatabaseEnabled is not set or set to false.
  • masterUserName - (Optional) Main user's username, which is stored in the Amazon OpenSearch Service domain's internal database. Only specify if internalUserDatabaseEnabled is set to true.
  • masterUserPassword - (Optional) Main user's password, which is stored in the Amazon OpenSearch Service domain's internal database. Only specify if internalUserDatabaseEnabled is set to true.

autoTuneOptions

  • desiredState - (Required) Auto-Tune desired state for the domain. Valid values: enabled or disabled.
  • maintenanceSchedule - (Required if rollbackOnDisable is set to DEFAULT_ROLLBACK) Configuration block for Auto-Tune maintenance windows. Can be specified multiple times for each maintenance window. Detailed below.
  • rollbackOnDisable - (Optional) Whether to roll back to default Auto-Tune settings when disabling Auto-Tune. Valid values: DEFAULT_ROLLBACK or NO_ROLLBACK.

maintenanceSchedule

  • startAt - (Required) Date and time at which to start the Auto-Tune maintenance schedule in RFC3339 format.
  • duration - (Required) Configuration block for the duration of the Auto-Tune maintenance window. Detailed below.
  • cronExpressionForRecurrence - (Required) A cron expression specifying the recurrence pattern for an Auto-Tune maintenance schedule.
duration
  • value - (Required) An integer specifying the value of the duration of an Auto-Tune maintenance window.
  • unit - (Required) Unit of time specifying the duration of an Auto-Tune maintenance window. Valid values: hours.

clusterConfig

  • coldStorageOptions - (Optional) Configuration block containing cold storage configuration. Detailed below.
  • dedicatedMasterCount - (Optional) Number of dedicated main nodes in the cluster.
  • dedicatedMasterEnabled - (Optional) Whether dedicated main nodes are enabled for the cluster.
  • dedicatedMasterType - (Optional) Instance type of the dedicated main nodes in the cluster.
  • instanceCount - (Optional) Number of instances in the cluster.
  • instanceType - (Optional) Instance type of data nodes in the cluster.
  • warmCount - (Optional) Number of warm nodes in the cluster. Valid values are between 2 and 150. warmCount can be only and must be set when warmEnabled is set to true.
  • warmEnabled - (Optional) Whether to enable warm storage.
  • warmType - (Optional) Instance type for the OpenSearch cluster's warm nodes. Valid values are ultrawarm1MediumSearch, ultrawarm1LargeSearch and ultrawarm1XlargeSearch. warmType can be only and must be set when warmEnabled is set to true.
  • zoneAwarenessConfig - (Optional) Configuration block containing zone awareness settings. Detailed below.
  • zoneAwarenessEnabled - (Optional) Whether zone awareness is enabled, set to true for multi-az deployment. To enable awareness with three Availability Zones, the availabilityZoneCount within the zoneAwarenessConfig must be set to 3.

coldStorageOptions

  • enabled - (Optional) Boolean to enable cold storage for an OpenSearch domain. Defaults to false. Master and ultrawarm nodes must be enabled for cold storage.

zoneAwarenessConfig

  • availabilityZoneCount - (Optional) Number of Availability Zones for the domain to use with zoneAwarenessEnabled. Defaults to 2. Valid values: 2 or 3.

cognitoOptions

AWS documentation: Amazon Cognito Authentication for Dashboard

  • enabled - (Optional) Whether Amazon Cognito authentication with Dashboard is enabled or not. Default is false.
  • identityPoolId - (Required) ID of the Cognito Identity Pool to use.
  • roleArn - (Required) ARN of the IAM role that has the AmazonOpenSearchServiceCognitoAccess policy attached.
  • userPoolId - (Required) ID of the Cognito User Pool to use.

domainEndpointOptions

  • customEndpointCertificateArn - (Optional) ACM certificate ARN for your custom endpoint.
  • customEndpointEnabled - (Optional) Whether to enable custom endpoint for the OpenSearch domain.
  • customEndpoint - (Optional) Fully qualified domain for your custom endpoint.
  • enforceHttps - (Optional) Whether or not to require HTTPS. Defaults to true.
  • tlsSecurityPolicy - (Optional) Name of the TLS security policy that needs to be applied to the HTTPS endpoint. Valid values: policyMinTls10201907 and policyMinTls12201907. Terraform will only perform drift detection if a configuration value is provided.

ebsOptions

  • ebsEnabled - (Required) Whether EBS volumes are attached to data nodes in the domain.
  • iops - (Optional) Baseline input/output (I/O) performance of EBS volumes attached to data nodes. Applicable only for the GP3 and Provisioned IOPS EBS volume types.
  • throughput - (Required if volumeType is set to gp3) Specifies the throughput (in MiB/s) of the EBS volumes attached to data nodes. Applicable only for the gp3 volume type.
  • volumeSize - (Required if ebsEnabled is set to true.) Size of EBS volumes attached to data nodes (in GiB).
  • volumeType - (Optional) Type of EBS volumes attached to data nodes.

encryptAtRest

\~> Note: You can enable encryptAtRest in place for an existing, unencrypted domain only if you are using OpenSearch or your Elasticsearch version is 6.7 or greater. For other versions, if you enable encryptAtRest, Terraform with recreate the domain, potentially causing data loss. For any version, if you disable encryptAtRest for an existing, encrypted domain, Terraform will recreate the domain, potentially causing data loss. If you change the kmsKeyId, Terraform will also recreate the domain, potentially causing data loss.

  • enabled - (Required) Whether to enable encryption at rest. If the encryptAtRest block is not provided then this defaults to false. Enabling encryption on new domains requires an engineVersion of openSearchXY or elasticsearch51 or greater.
  • kmsKeyId - (Optional) KMS key ARN to encrypt the Elasticsearch domain with. If not specified then it defaults to using the aws/es service KMS key. Note that KMS will accept a KMS key ID but will return the key ARN. To prevent Terraform detecting unwanted changes, use the key ARN instead.

logPublishingOptions

  • cloudwatchLogGroupArn - (Required) ARN of the Cloudwatch log group to which log needs to be published.
  • enabled - (Optional, Default: true) Whether given log publishing option is enabled or not.
  • logType - (Required) Type of OpenSearch log. Valid values: INDEX_SLOW_LOGS, SEARCH_SLOW_LOGS, ES_APPLICATION_LOGS, AUDIT_LOGS.

nodeToNodeEncryption

\~> Note: You can enable nodeToNodeEncryption in place for an existing, unencrypted domain only if you are using OpenSearch or your Elasticsearch version is 6.7 or greater. For other versions, if you enable nodeToNodeEncryption, Terraform will recreate the domain, potentially causing data loss. For any version, if you disable nodeToNodeEncryption for an existing, node-to-node encrypted domain, Terraform will recreate the domain, potentially causing data loss.

  • enabled - (Required) Whether to enable node-to-node encryption. If the nodeToNodeEncryption block is not provided then this defaults to false. Enabling node-to-node encryption of a new domain requires an engineVersion of openSearchXY or elasticsearch60 or greater.

snapshotOptions

  • automatedSnapshotStartHour - (Required) Hour during which the service takes an automated daily snapshot of the indices in the domain.

vpcOptions

AWS documentation: VPC Support for Amazon OpenSearch Service Domains

\~> Note: You must have created the service linked role for the OpenSearch service to use vpcOptions. If you need to create the service linked role at the same time as the OpenSearch domain then you must use dependsOn to make sure that the role is created before the OpenSearch domain. See the VPC based ES domain example above.

-> Security Groups and Subnets referenced in these attributes must all be within the same VPC. This determines what VPC the endpoints are created in.

  • securityGroupIds - (Optional) List of VPC Security Group IDs to be applied to the OpenSearch domain endpoints. If omitted, the default Security Group for the VPC will be used.
  • subnetIds - (Required) List of VPC Subnet IDs for the OpenSearch domain endpoints to be created in.

Attributes Reference

In addition to all arguments above, the following attributes are exported:

  • arn - ARN of the domain.
  • domainId - Unique identifier for the domain.
  • domainName - Name of the OpenSearch domain.
  • endpoint - Domain-specific endpoint used to submit index, search, and data upload requests.
  • dashboardEndpoint - Domain-specific endpoint for Dashboard without https scheme.
  • kibanaEndpoint - Domain-specific endpoint for kibana without https scheme. OpenSearch Dashboards do not use Kibana, so this attribute will be DEPRECATED in a future version.
  • tagsAll - Map of tags assigned to the resource, including those inherited from the provider defaultTags configuration block.
  • vpcOptions0AvailabilityZones - If the domain was created inside a VPC, the names of the availability zones the configured subnetIds were created inside.
  • vpcOptions0VpcId - If the domain was created inside a VPC, the ID of the VPC.

Timeouts

Configuration options:

  • create - (Default 60M)
  • update - (Default 180M)
  • delete - (Default 90M)

Import

OpenSearch domains can be imported using the domainName, e.g.,

$ terraform import aws_opensearch_domain.example domain_name