Merge "Add OpenSearch as index backend option"
diff --git a/Documentation/examples/1-gerritcluster.yaml b/Documentation/examples/1-gerritcluster.yaml
index 4cf206f..a2faba6 100644
--- a/Documentation/examples/1-gerritcluster.yaml
+++ b/Documentation/examples/1-gerritcluster.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/examples/2-gerritcluster-with-replica.yaml b/Documentation/examples/2-gerritcluster-with-replica.yaml
index 83093c4..4115756 100644
--- a/Documentation/examples/2-gerritcluster-with-replica.yaml
+++ b/Documentation/examples/2-gerritcluster-with-replica.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/examples/3-gerritcluster-istio.yaml b/Documentation/examples/3-gerritcluster-istio.yaml
index a7b820f..cb06266 100644
--- a/Documentation/examples/3-gerritcluster-istio.yaml
+++ b/Documentation/examples/3-gerritcluster-istio.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/examples/4-gerritcluster-ha-replica.yaml b/Documentation/examples/4-gerritcluster-ha-replica.yaml
index cb6b1c0..5d87662 100644
--- a/Documentation/examples/4-gerritcluster-ha-replica.yaml
+++ b/Documentation/examples/4-gerritcluster-ha-replica.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/examples/5-gerritcluster-refdb.yaml b/Documentation/examples/5-gerritcluster-refdb.yaml
index 0281aed..0f2da8d 100644
--- a/Documentation/examples/5-gerritcluster-refdb.yaml
+++ b/Documentation/examples/5-gerritcluster-refdb.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/examples/6-gerritcluster-ha-primary.yaml b/Documentation/examples/6-gerritcluster-ha-primary.yaml
index dd1926d..6f46a8f 100644
--- a/Documentation/examples/6-gerritcluster-ha-primary.yaml
+++ b/Documentation/examples/6-gerritcluster-ha-primary.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/examples/gerritcluster-3-nodes-pr-kafka-multisite.yaml b/Documentation/examples/gerritcluster-3-nodes-pr-kafka-multisite.yaml
index a5ba33c..bbc87dd 100644
--- a/Documentation/examples/gerritcluster-3-nodes-pr-kafka-multisite.yaml
+++ b/Documentation/examples/gerritcluster-3-nodes-pr-kafka-multisite.yaml
@@ -16,7 +16,7 @@
 type: Opaque
 
 ---
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/Documentation/operator-api-reference.md b/Documentation/operator-api-reference.md
index 53a10a3..fea6e78 100644
--- a/Documentation/operator-api-reference.md
+++ b/Documentation/operator-api-reference.md
@@ -33,7 +33,6 @@
   - [DynamoDbRefDbConfig](#dynamodbrefdbconfig)
   - [IndexConfig](#indexconfig)
   - [IndexType](#indextype)
-  - [ElasticSearchConfig](#elasticsearchconfig)
   - [EventsBrokerConfig](#eventsbrokerconfig)
   - [BrokerType](#brokertype)
   - [KafkaConfig](#kafkaconfig)
@@ -64,6 +63,7 @@
   - [NetworkMember](#networkmember)
   - [NetworkMemberWithSsh](#networkmemberwithssh)
   - [ScheduledTasks](#scheduledtasks)
+  - [RemoteIndexConfig](#remoteindexconfig)
   - [IncomingReplicationTaskTemplate](#incomingreplicationtasktemplate)
   - [IncomingReplicationTaskTemplateSpec](#incomingreplicationtasktemplatespec)
   - [IncomingReplicationConfig](#incomingreplicationconfig)
@@ -87,7 +87,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: GerritCluster
 
 ---
@@ -104,7 +104,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
@@ -427,7 +427,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: Gerrit
 
 ---
@@ -444,7 +444,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Gerrit
 metadata:
   name: gerrit
@@ -658,7 +658,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: Receiver
 
 ---
@@ -675,7 +675,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Receiver
 metadata:
   name: receiver
@@ -786,7 +786,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: GitGarbageCollection
 
 ---
@@ -803,7 +803,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GitGarbageCollection
 metadata:
   name: gitgc
@@ -847,7 +847,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: GerritNetwork
 
 ---
@@ -863,7 +863,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit-network
@@ -897,7 +897,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: IncomingReplicationTask
 
 ---
@@ -913,7 +913,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: IncomingReplicationTask
 metadata:
   name: incoming-repl-task
@@ -972,7 +972,7 @@
 ---
 
 **Group**: gerritoperator.google.com \
-**Version**: v1beta17 \
+**Version**: v1beta18 \
 **Kind**: GerritIndexer
 
 ---
@@ -988,7 +988,7 @@
 Example:
 
 ```yaml
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritIndexer
 metadata:
   name: gerrit-indexer
@@ -1227,8 +1227,8 @@
 
 | Field | Type | Description |
 |---|---|---|
-| `type` | [`IndexType`](#indextype) | Which index type to use. Choices: `LUCENE`, `ELASTICSEARCH`. (default: `LUCENE`) |
-| `elasticsearch` | [`ElasticSearchConfig`](#elasticsearchconfig) | Configuration of elasticsearch. Only used if elasticsearch was configured to be used for the search index. |
+| `type` | [`IndexType`](#indextype) | Which index type to use. Choices: `LUCENE`, `ELASTICSEARCH`, `OPENSEARCH`. (default: `LUCENE`) |
+| `remoteIndexConfig` | [`RemoteIndexConfig`](#RemoteIndexConfig) | Configuration of the search engine. Only used if elasticsearch or opensearch was configured to be used for the search index. |
 
 ## IndexType
 
@@ -1236,13 +1236,14 @@
 |---|---|
 | `LUCENE` | Lucene will be used for the search index |
 | `ELASTICSEARCH` | Elasticsearch will be used for the search index (Requires Elasticsearch instance to be available.) |
+| `OPENSEARCH` | Opensearch will be used for the search index (Requires Opensearch instance to be available.) |
 
-## ElasticSearchConfig
+## RemoteIndexConfig
 
 | Field | Type | Description |
 |---|---|---|
-| `server` | `String` | URL to use for connecting to Elasticsearch |
-| `config` | `String` | Config snippet used for the `elasticsearch` section in `gerrit.config` |
+| `server` | `String` | URL to use for connecting to the search engine |
+| `config` | `String` | Config snippet used for the search section in `gerrit.config`, either `opensearch` or `elasticsearch` |
 
 ## EventsBrokerConfig
 
diff --git a/container-images/gerrit-indexer/tools/start b/container-images/gerrit-indexer/tools/start
index 62e2572..543a9e7 100755
--- a/container-images/gerrit-indexer/tools/start
+++ b/container-images/gerrit-indexer/tools/start
@@ -41,6 +41,8 @@
 INDEX_MODULE="$(git config --file /var/gerrit/etc/gerrit.config gerrit.installIndexModule | tr '[:upper:]' '[:lower:]')"
 if [ "$INDEX_MODULE" = "elasticsearch" ]; then
   INDEX_TYPE="ELASTICSEARCH"
+elif [ "$INDEX_MODULE" = "opensearch" ]; then
+  INDEX_TYPE="OPENSEARCH"
 fi
 
 JAVA_OPTIONS=$(git config --file /var/gerrit/etc/gerrit.config --get-all container.javaOptions)
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py
index 2963498..f76b5fa 100755
--- a/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/download_plugins.py
@@ -101,6 +101,8 @@
             required.append(f"{self.config.refdb}-refdb")
         if get_index_type(self.gerrit_config) == IndexType.ELASTICSEARCH:
             required.append("index-elasticsearch")
+        elif get_index_type(self.gerrit_config) == IndexType.OPENSEARCH:
+            required.append("index-opensearch")
         LOG.info(
             "Requiring plugins (ClusterMode: %s): %s",
             self.config.cluster_mode.name,
@@ -118,6 +120,8 @@
             required.append("global-refdb")
         if get_index_type(self.gerrit_config) == IndexType.ELASTICSEARCH:
             required.append("index-elasticsearch")
+        elif get_index_type(self.gerrit_config) == IndexType.OPENSEARCH:
+            required.append("index-opensearch")
         LOG.info(
             "Requiring libs (ClusterMode: %s): %s",
             self.config.cluster_mode.name,
diff --git a/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py
index 4eff0c8..9e981b1 100755
--- a/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py
+++ b/container-images/gerrit-init/tools/gerrit-initializer/initializer/tasks/reindex.py
@@ -35,6 +35,7 @@
 class IndexType(enum.Enum):
     LUCENE = enum.auto()
     ELASTICSEARCH = enum.auto()
+    OPENSEARCH = enum.auto()
 
 
 class GerritAbstractReindexer(abc.ABC):
@@ -164,23 +165,24 @@
         return lucene_indices
 
 
-class GerritElasticSearchReindexer(GerritAbstractReindexer):
-    def _get_elasticsearch_config(self):
-        es_config = {}
+class GerritRemoteIndexer(GerritAbstractReindexer):
+    def _get_config(self):
+        engine_config = {}
         gerrit_config = git.GitConfigParser(
             os.path.join(SITE_PATH, "etc", "gerrit.config")
         )
-        es_config["prefix"] = gerrit_config.get(
-            "elasticsearch.prefix", default=""
+        index_type = get_index_type(gerrit_config).name.lower()
+        engine_config["prefix"] = gerrit_config.get(
+            f"{index_type}.prefix", default=""
         ).lower()
-        es_config["server"] = gerrit_config.get(
-            "elasticsearch.server", default=""
+        engine_config["server"] = gerrit_config.get(
+            f"{index_type}.server", default=""
         ).lower()
-        return es_config
+        return engine_config
 
     def _get_indices(self):
-        es_config = self._get_elasticsearch_config()
-        url = f"{es_config['server']}/{es_config['prefix']}*"
+        engine_config = self._get_config()
+        url = f"{engine_config['server']}/{engine_config['prefix']}*"
         try:
             response = requests.get(url)
         except requests.exceptions.SSLError:
@@ -189,7 +191,7 @@
         es_indices = {}
         for index, _ in response.json().items():
             try:
-                index = index.replace(es_config["prefix"], "", 1)
+                index = index.replace(engine_config["prefix"], "", 1)
                 (name, version) = index.split("_")
                 es_indices[name] = version
             except ValueError:
@@ -213,8 +215,11 @@
 
 
 def get_reindexer(gerrit_config, initializer_config):
-    if get_index_type(gerrit_config) == IndexType.ELASTICSEARCH:
-        return GerritElasticSearchReindexer(gerrit_config, initializer_config)
+    if (
+        get_index_type(gerrit_config) == IndexType.ELASTICSEARCH
+        or get_index_type(gerrit_config) == IndexType.OPENSEARCH
+    ):
+        return GerritRemoteIndexer(gerrit_config, initializer_config)
 
     return GerritLuceneReindexer(gerrit_config, initializer_config)
 
@@ -223,5 +228,7 @@
     indexModule = gerrit_config.get("gerrit.installIndexModule")
     if indexModule and indexModule.startswith("com.google.gerrit.elasticsearch"):
         return IndexType.ELASTICSEARCH
+    if indexModule and indexModule.startswith("com.google.gerrit.opensearch"):
+        return IndexType.OPENSEARCH
 
     return IndexType.LUCENE
diff --git a/crd/current/gerritclusters.gerritoperator.google.com-v1.yml b/crd/current/gerritclusters.gerritoperator.google.com-v1.yml
index 54914f2..84edf2d 100644
--- a/crd/current/gerritclusters.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritclusters.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritcluster
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
@@ -876,7 +876,7 @@
                 type: array
               index:
                 properties:
-                  elasticsearch:
+                  remoteIndexConfig:
                     properties:
                       config:
                         type: string
@@ -887,6 +887,7 @@
                     enum:
                     - ELASTICSEARCH
                     - LUCENE
+                    - OPENSEARCH
                     type: string
                 type: object
               ingress:
diff --git a/crd/current/gerritindexers.gerritoperator.google.com-v1.yml b/crd/current/gerritindexers.gerritoperator.google.com-v1.yml
index 1603b3c..2cccb93 100644
--- a/crd/current/gerritindexers.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritindexers.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritindexer
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
@@ -355,7 +355,7 @@
                 type: object
               index:
                 properties:
-                  elasticsearch:
+                  remoteIndexConfig:
                     properties:
                       config:
                         type: string
@@ -366,6 +366,7 @@
                     enum:
                     - ELASTICSEARCH
                     - LUCENE
+                    - OPENSEARCH
                     type: string
                 type: object
               resources:
diff --git a/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml b/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml
index f5c6c18..7f7bfcf 100644
--- a/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritmaintenances.gerritoperator.google.com-v1.yml
@@ -11,7 +11,7 @@
     singular: gerritmaintenance
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
diff --git a/crd/current/gerritnetworks.gerritoperator.google.com-v1.yml b/crd/current/gerritnetworks.gerritoperator.google.com-v1.yml
index ac47f95..88773db 100644
--- a/crd/current/gerritnetworks.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerritnetworks.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritnetwork
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
diff --git a/crd/current/gerrits.gerritoperator.google.com-v1.yml b/crd/current/gerrits.gerritoperator.google.com-v1.yml
index 3d8a00b..0eac805 100644
--- a/crd/current/gerrits.gerritoperator.google.com-v1.yml
+++ b/crd/current/gerrits.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerrit
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
@@ -461,7 +461,7 @@
                 type: integer
               index:
                 properties:
-                  elasticsearch:
+                  remoteIndexConfig:
                     properties:
                       config:
                         type: string
@@ -472,6 +472,7 @@
                     enum:
                     - ELASTICSEARCH
                     - LUCENE
+                    - OPENSEARCH
                     type: string
                 type: object
               ingress:
diff --git a/crd/current/gitgcs.gerritoperator.google.com-v1.yml b/crd/current/gitgcs.gerritoperator.google.com-v1.yml
index 6d70443..9ce6167 100644
--- a/crd/current/gitgcs.gerritoperator.google.com-v1.yml
+++ b/crd/current/gitgcs.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gitgarbagecollection
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
diff --git a/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml b/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml
index 7c00b02..d338ee0 100644
--- a/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml
+++ b/crd/current/incomingreplicationtasks.gerritoperator.google.com-v1.yml
@@ -11,7 +11,7 @@
     singular: incomingreplicationtask
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
diff --git a/crd/current/receivers.gerritoperator.google.com-v1.yml b/crd/current/receivers.gerritoperator.google.com-v1.yml
index f3f1fe1..5cb719d 100644
--- a/crd/current/receivers.gerritoperator.google.com-v1.yml
+++ b/crd/current/receivers.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: receiver
   scope: Namespaced
   versions:
-  - name: v1beta17
+  - name: v1beta18
     schema:
       openAPIV3Schema:
         properties:
diff --git a/crd/deprecated/gerritclusters.gerritoperator.google.com-v1.yml b/crd/deprecated/gerritclusters.gerritoperator.google.com-v1.yml
index 524d335..64d20a0 100644
--- a/crd/deprecated/gerritclusters.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/gerritclusters.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritcluster
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -876,7 +876,7 @@
                   type: array
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -887,6 +887,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 ingress:
@@ -914,6 +915,8 @@
                           additionalProperties:
                             type: string
                           type: object
+                        mTLS:
+                          type: boolean
                       type: object
                     pathPrefix:
                       type: string
diff --git a/crd/deprecated/gerritindexers.gerritoperator.google.com-v1.yml b/crd/deprecated/gerritindexers.gerritoperator.google.com-v1.yml
index 803a6b3..f1327b8 100644
--- a/crd/deprecated/gerritindexers.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/gerritindexers.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritindexer
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -355,7 +355,7 @@
                   type: object
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -366,6 +366,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 resources:
diff --git a/crd/deprecated/gerritmaintenances.gerritoperator.google.com-v1.yml b/crd/deprecated/gerritmaintenances.gerritoperator.google.com-v1.yml
index 91bbfb7..fcc963b 100644
--- a/crd/deprecated/gerritmaintenances.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/gerritmaintenances.gerritoperator.google.com-v1.yml
@@ -11,7 +11,7 @@
     singular: gerritmaintenance
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/crd/deprecated/gerritnetworks.gerritoperator.google.com-v1.yml b/crd/deprecated/gerritnetworks.gerritoperator.google.com-v1.yml
index 6916ebf..cef26ac 100644
--- a/crd/deprecated/gerritnetworks.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/gerritnetworks.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritnetwork
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -53,6 +53,8 @@
                           additionalProperties:
                             type: string
                           type: object
+                        mTLS:
+                          type: boolean
                       type: object
                     pathPrefix:
                       type: string
diff --git a/crd/deprecated/gerrits.gerritoperator.google.com-v1.yml b/crd/deprecated/gerrits.gerritoperator.google.com-v1.yml
index c549565..4bc3eda 100644
--- a/crd/deprecated/gerrits.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/gerrits.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerrit
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -461,7 +461,7 @@
                   type: integer
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -472,6 +472,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 ingress:
diff --git a/crd/deprecated/gitgcs.gerritoperator.google.com-v1.yml b/crd/deprecated/gitgcs.gerritoperator.google.com-v1.yml
index fc2f252..4ad5728 100644
--- a/crd/deprecated/gitgcs.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/gitgcs.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gitgarbagecollection
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/crd/deprecated/incomingreplicationtasks.gerritoperator.google.com-v1.yml b/crd/deprecated/incomingreplicationtasks.gerritoperator.google.com-v1.yml
index 6aa75fe..c995151 100644
--- a/crd/deprecated/incomingreplicationtasks.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/incomingreplicationtasks.gerritoperator.google.com-v1.yml
@@ -11,7 +11,7 @@
     singular: incomingreplicationtask
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/crd/deprecated/receivers.gerritoperator.google.com-v1.yml b/crd/deprecated/receivers.gerritoperator.google.com-v1.yml
index 6aa02a4..0ffe5fc 100644
--- a/crd/deprecated/receivers.gerritoperator.google.com-v1.yml
+++ b/crd/deprecated/receivers.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: receiver
   scope: Namespaced
   versions:
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml
index 94c43d3..7999764 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritclusters.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritcluster
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -876,7 +876,7 @@
                   type: array
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -887,6 +887,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 ingress:
@@ -2563,7 +2564,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -3426,7 +3427,7 @@
                   type: array
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -3437,6 +3438,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 ingress:
@@ -3464,6 +3466,8 @@
                           additionalProperties:
                             type: string
                           type: object
+                        mTLS:
+                          type: boolean
                       type: object
                     pathPrefix:
                       type: string
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml
index 4e5f95a..21f576d 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritindexers.gerritoperator.google.com-v1.yml
@@ -13,6 +13,481 @@
     singular: gerritindexer
   scope: Namespaced
   versions:
+    - name: v1beta18
+      schema:
+        openAPIV3Schema:
+          properties:
+            spec:
+              properties:
+                affinity:
+                  properties:
+                    nodeAffinity:
+                      properties:
+                        preferredDuringSchedulingIgnoredDuringExecution:
+                          items:
+                            properties:
+                              preference:
+                                properties:
+                                  matchExpressions:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                  matchFields:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                type: object
+                              weight:
+                                type: integer
+                            type: object
+                          type: array
+                        requiredDuringSchedulingIgnoredDuringExecution:
+                          properties:
+                            nodeSelectorTerms:
+                              items:
+                                properties:
+                                  matchExpressions:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                  matchFields:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                type: object
+                              type: array
+                          type: object
+                      type: object
+                    podAffinity:
+                      properties:
+                        preferredDuringSchedulingIgnoredDuringExecution:
+                          items:
+                            properties:
+                              podAffinityTerm:
+                                properties:
+                                  labelSelector:
+                                    properties:
+                                      matchExpressions:
+                                        items:
+                                          properties:
+                                            key:
+                                              type: string
+                                            operator:
+                                              type: string
+                                            values:
+                                              items:
+                                                type: string
+                                              type: array
+                                          type: object
+                                        type: array
+                                      matchLabels:
+                                        additionalProperties:
+                                          type: string
+                                        type: object
+                                    type: object
+                                  matchLabelKeys:
+                                    items:
+                                      type: string
+                                    type: array
+                                  mismatchLabelKeys:
+                                    items:
+                                      type: string
+                                    type: array
+                                  namespaceSelector:
+                                    properties:
+                                      matchExpressions:
+                                        items:
+                                          properties:
+                                            key:
+                                              type: string
+                                            operator:
+                                              type: string
+                                            values:
+                                              items:
+                                                type: string
+                                              type: array
+                                          type: object
+                                        type: array
+                                      matchLabels:
+                                        additionalProperties:
+                                          type: string
+                                        type: object
+                                    type: object
+                                  namespaces:
+                                    items:
+                                      type: string
+                                    type: array
+                                  topologyKey:
+                                    type: string
+                                type: object
+                              weight:
+                                type: integer
+                            type: object
+                          type: array
+                        requiredDuringSchedulingIgnoredDuringExecution:
+                          items:
+                            properties:
+                              labelSelector:
+                                properties:
+                                  matchExpressions:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                  matchLabels:
+                                    additionalProperties:
+                                      type: string
+                                    type: object
+                                type: object
+                              matchLabelKeys:
+                                items:
+                                  type: string
+                                type: array
+                              mismatchLabelKeys:
+                                items:
+                                  type: string
+                                type: array
+                              namespaceSelector:
+                                properties:
+                                  matchExpressions:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                  matchLabels:
+                                    additionalProperties:
+                                      type: string
+                                    type: object
+                                type: object
+                              namespaces:
+                                items:
+                                  type: string
+                                type: array
+                              topologyKey:
+                                type: string
+                            type: object
+                          type: array
+                      type: object
+                    podAntiAffinity:
+                      properties:
+                        preferredDuringSchedulingIgnoredDuringExecution:
+                          items:
+                            properties:
+                              podAffinityTerm:
+                                properties:
+                                  labelSelector:
+                                    properties:
+                                      matchExpressions:
+                                        items:
+                                          properties:
+                                            key:
+                                              type: string
+                                            operator:
+                                              type: string
+                                            values:
+                                              items:
+                                                type: string
+                                              type: array
+                                          type: object
+                                        type: array
+                                      matchLabels:
+                                        additionalProperties:
+                                          type: string
+                                        type: object
+                                    type: object
+                                  matchLabelKeys:
+                                    items:
+                                      type: string
+                                    type: array
+                                  mismatchLabelKeys:
+                                    items:
+                                      type: string
+                                    type: array
+                                  namespaceSelector:
+                                    properties:
+                                      matchExpressions:
+                                        items:
+                                          properties:
+                                            key:
+                                              type: string
+                                            operator:
+                                              type: string
+                                            values:
+                                              items:
+                                                type: string
+                                              type: array
+                                          type: object
+                                        type: array
+                                      matchLabels:
+                                        additionalProperties:
+                                          type: string
+                                        type: object
+                                    type: object
+                                  namespaces:
+                                    items:
+                                      type: string
+                                    type: array
+                                  topologyKey:
+                                    type: string
+                                type: object
+                              weight:
+                                type: integer
+                            type: object
+                          type: array
+                        requiredDuringSchedulingIgnoredDuringExecution:
+                          items:
+                            properties:
+                              labelSelector:
+                                properties:
+                                  matchExpressions:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                  matchLabels:
+                                    additionalProperties:
+                                      type: string
+                                    type: object
+                                type: object
+                              matchLabelKeys:
+                                items:
+                                  type: string
+                                type: array
+                              mismatchLabelKeys:
+                                items:
+                                  type: string
+                                type: array
+                              namespaceSelector:
+                                properties:
+                                  matchExpressions:
+                                    items:
+                                      properties:
+                                        key:
+                                          type: string
+                                        operator:
+                                          type: string
+                                        values:
+                                          items:
+                                            type: string
+                                          type: array
+                                      type: object
+                                    type: array
+                                  matchLabels:
+                                    additionalProperties:
+                                      type: string
+                                    type: object
+                                type: object
+                              namespaces:
+                                items:
+                                  type: string
+                                type: array
+                              topologyKey:
+                                type: string
+                            type: object
+                          type: array
+                      type: object
+                  type: object
+                cluster:
+                  type: string
+                configFiles:
+                  additionalProperties:
+                    type: string
+                  type: object
+                index:
+                  properties:
+                    remoteIndexConfig:
+                      properties:
+                        config:
+                          type: string
+                        server:
+                          type: string
+                      type: object
+                    type:
+                      enum:
+                        - ELASTICSEARCH
+                        - LUCENE
+                        - OPENSEARCH
+                      type: string
+                  type: object
+                resources:
+                  properties:
+                    claims:
+                      items:
+                        properties:
+                          name:
+                            type: string
+                        type: object
+                      type: array
+                    limits:
+                      additionalProperties:
+                        anyOf:
+                          - type: integer
+                          - type: string
+                        x-kubernetes-int-or-string: true
+                      type: object
+                    requests:
+                      additionalProperties:
+                        anyOf:
+                          - type: integer
+                          - type: string
+                        x-kubernetes-int-or-string: true
+                      type: object
+                  type: object
+                storage:
+                  properties:
+                    output:
+                      properties:
+                        persistentVolumeClaim:
+                          type: string
+                        subPath:
+                          type: string
+                      type: object
+                    repositories:
+                      properties:
+                        persistentVolumeClaim:
+                          type: string
+                        subPath:
+                          type: string
+                      type: object
+                    site:
+                      properties:
+                        persistentVolumeClaim:
+                          type: string
+                        subPath:
+                          type: string
+                      type: object
+                  type: object
+                tolerations:
+                  items:
+                    properties:
+                      effect:
+                        type: string
+                      key:
+                        type: string
+                      operator:
+                        type: string
+                      tolerationSeconds:
+                        type: integer
+                      value:
+                        type: string
+                    type: object
+                  type: array
+              type: object
+            status:
+              properties:
+                apiVersion:
+                  type: string
+                code:
+                  type: integer
+                details:
+                  properties:
+                    causes:
+                      items:
+                        properties:
+                          field:
+                            type: string
+                          message:
+                            type: string
+                          reason:
+                            type: string
+                        type: object
+                      type: array
+                    group:
+                      type: string
+                    kind:
+                      type: string
+                    name:
+                      type: string
+                    retryAfterSeconds:
+                      type: integer
+                    uid:
+                      type: string
+                  type: object
+                kind:
+                  type: string
+                message:
+                  type: string
+                metadata:
+                  properties:
+                    continue:
+                      type: string
+                    remainingItemCount:
+                      type: integer
+                    resourceVersion:
+                      type: string
+                    selfLink:
+                      type: string
+                  type: object
+                reason:
+                  type: string
+                status:
+                  type: string
+              type: object
+          type: object
+      served: true
+      storage: true
+      subresources:
+        status: {}
     - name: v1beta17
       schema:
         openAPIV3Schema:
@@ -355,7 +830,7 @@
                   type: object
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -366,480 +841,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
-                      type: string
-                  type: object
-                resources:
-                  properties:
-                    claims:
-                      items:
-                        properties:
-                          name:
-                            type: string
-                        type: object
-                      type: array
-                    limits:
-                      additionalProperties:
-                        anyOf:
-                          - type: integer
-                          - type: string
-                        x-kubernetes-int-or-string: true
-                      type: object
-                    requests:
-                      additionalProperties:
-                        anyOf:
-                          - type: integer
-                          - type: string
-                        x-kubernetes-int-or-string: true
-                      type: object
-                  type: object
-                storage:
-                  properties:
-                    output:
-                      properties:
-                        persistentVolumeClaim:
-                          type: string
-                        subPath:
-                          type: string
-                      type: object
-                    repositories:
-                      properties:
-                        persistentVolumeClaim:
-                          type: string
-                        subPath:
-                          type: string
-                      type: object
-                    site:
-                      properties:
-                        persistentVolumeClaim:
-                          type: string
-                        subPath:
-                          type: string
-                      type: object
-                  type: object
-                tolerations:
-                  items:
-                    properties:
-                      effect:
-                        type: string
-                      key:
-                        type: string
-                      operator:
-                        type: string
-                      tolerationSeconds:
-                        type: integer
-                      value:
-                        type: string
-                    type: object
-                  type: array
-              type: object
-            status:
-              properties:
-                apiVersion:
-                  type: string
-                code:
-                  type: integer
-                details:
-                  properties:
-                    causes:
-                      items:
-                        properties:
-                          field:
-                            type: string
-                          message:
-                            type: string
-                          reason:
-                            type: string
-                        type: object
-                      type: array
-                    group:
-                      type: string
-                    kind:
-                      type: string
-                    name:
-                      type: string
-                    retryAfterSeconds:
-                      type: integer
-                    uid:
-                      type: string
-                  type: object
-                kind:
-                  type: string
-                message:
-                  type: string
-                metadata:
-                  properties:
-                    continue:
-                      type: string
-                    remainingItemCount:
-                      type: integer
-                    resourceVersion:
-                      type: string
-                    selfLink:
-                      type: string
-                  type: object
-                reason:
-                  type: string
-                status:
-                  type: string
-              type: object
-          type: object
-      served: true
-      storage: true
-      subresources:
-        status: {}
-    - name: v1beta16
-      schema:
-        openAPIV3Schema:
-          properties:
-            spec:
-              properties:
-                affinity:
-                  properties:
-                    nodeAffinity:
-                      properties:
-                        preferredDuringSchedulingIgnoredDuringExecution:
-                          items:
-                            properties:
-                              preference:
-                                properties:
-                                  matchExpressions:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                  matchFields:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                type: object
-                              weight:
-                                type: integer
-                            type: object
-                          type: array
-                        requiredDuringSchedulingIgnoredDuringExecution:
-                          properties:
-                            nodeSelectorTerms:
-                              items:
-                                properties:
-                                  matchExpressions:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                  matchFields:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                type: object
-                              type: array
-                          type: object
-                      type: object
-                    podAffinity:
-                      properties:
-                        preferredDuringSchedulingIgnoredDuringExecution:
-                          items:
-                            properties:
-                              podAffinityTerm:
-                                properties:
-                                  labelSelector:
-                                    properties:
-                                      matchExpressions:
-                                        items:
-                                          properties:
-                                            key:
-                                              type: string
-                                            operator:
-                                              type: string
-                                            values:
-                                              items:
-                                                type: string
-                                              type: array
-                                          type: object
-                                        type: array
-                                      matchLabels:
-                                        additionalProperties:
-                                          type: string
-                                        type: object
-                                    type: object
-                                  matchLabelKeys:
-                                    items:
-                                      type: string
-                                    type: array
-                                  mismatchLabelKeys:
-                                    items:
-                                      type: string
-                                    type: array
-                                  namespaceSelector:
-                                    properties:
-                                      matchExpressions:
-                                        items:
-                                          properties:
-                                            key:
-                                              type: string
-                                            operator:
-                                              type: string
-                                            values:
-                                              items:
-                                                type: string
-                                              type: array
-                                          type: object
-                                        type: array
-                                      matchLabels:
-                                        additionalProperties:
-                                          type: string
-                                        type: object
-                                    type: object
-                                  namespaces:
-                                    items:
-                                      type: string
-                                    type: array
-                                  topologyKey:
-                                    type: string
-                                type: object
-                              weight:
-                                type: integer
-                            type: object
-                          type: array
-                        requiredDuringSchedulingIgnoredDuringExecution:
-                          items:
-                            properties:
-                              labelSelector:
-                                properties:
-                                  matchExpressions:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                  matchLabels:
-                                    additionalProperties:
-                                      type: string
-                                    type: object
-                                type: object
-                              matchLabelKeys:
-                                items:
-                                  type: string
-                                type: array
-                              mismatchLabelKeys:
-                                items:
-                                  type: string
-                                type: array
-                              namespaceSelector:
-                                properties:
-                                  matchExpressions:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                  matchLabels:
-                                    additionalProperties:
-                                      type: string
-                                    type: object
-                                type: object
-                              namespaces:
-                                items:
-                                  type: string
-                                type: array
-                              topologyKey:
-                                type: string
-                            type: object
-                          type: array
-                      type: object
-                    podAntiAffinity:
-                      properties:
-                        preferredDuringSchedulingIgnoredDuringExecution:
-                          items:
-                            properties:
-                              podAffinityTerm:
-                                properties:
-                                  labelSelector:
-                                    properties:
-                                      matchExpressions:
-                                        items:
-                                          properties:
-                                            key:
-                                              type: string
-                                            operator:
-                                              type: string
-                                            values:
-                                              items:
-                                                type: string
-                                              type: array
-                                          type: object
-                                        type: array
-                                      matchLabels:
-                                        additionalProperties:
-                                          type: string
-                                        type: object
-                                    type: object
-                                  matchLabelKeys:
-                                    items:
-                                      type: string
-                                    type: array
-                                  mismatchLabelKeys:
-                                    items:
-                                      type: string
-                                    type: array
-                                  namespaceSelector:
-                                    properties:
-                                      matchExpressions:
-                                        items:
-                                          properties:
-                                            key:
-                                              type: string
-                                            operator:
-                                              type: string
-                                            values:
-                                              items:
-                                                type: string
-                                              type: array
-                                          type: object
-                                        type: array
-                                      matchLabels:
-                                        additionalProperties:
-                                          type: string
-                                        type: object
-                                    type: object
-                                  namespaces:
-                                    items:
-                                      type: string
-                                    type: array
-                                  topologyKey:
-                                    type: string
-                                type: object
-                              weight:
-                                type: integer
-                            type: object
-                          type: array
-                        requiredDuringSchedulingIgnoredDuringExecution:
-                          items:
-                            properties:
-                              labelSelector:
-                                properties:
-                                  matchExpressions:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                  matchLabels:
-                                    additionalProperties:
-                                      type: string
-                                    type: object
-                                type: object
-                              matchLabelKeys:
-                                items:
-                                  type: string
-                                type: array
-                              mismatchLabelKeys:
-                                items:
-                                  type: string
-                                type: array
-                              namespaceSelector:
-                                properties:
-                                  matchExpressions:
-                                    items:
-                                      properties:
-                                        key:
-                                          type: string
-                                        operator:
-                                          type: string
-                                        values:
-                                          items:
-                                            type: string
-                                          type: array
-                                      type: object
-                                    type: array
-                                  matchLabels:
-                                    additionalProperties:
-                                      type: string
-                                    type: object
-                                type: object
-                              namespaces:
-                                items:
-                                  type: string
-                                type: array
-                              topologyKey:
-                                type: string
-                            type: object
-                          type: array
-                      type: object
-                  type: object
-                cluster:
-                  type: string
-                configFiles:
-                  additionalProperties:
-                    type: string
-                  type: object
-                index:
-                  properties:
-                    elasticsearch:
-                      properties:
-                        config:
-                          type: string
-                        server:
-                          type: string
-                      type: object
-                    type:
-                      enum:
-                        - ELASTICSEARCH
-                        - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 resources:
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml
index ef2204a..b8c63bc 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritmaintenances.gerritoperator.google.com-v1.yml
@@ -11,7 +11,7 @@
     singular: gerritmaintenance
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -555,7 +555,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/helm-charts/gerrit-operator-crds/templates/gerritnetworks.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerritnetworks.gerritoperator.google.com-v1.yml
index 5bb8b53..267a3d3 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerritnetworks.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerritnetworks.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerritnetwork
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -143,7 +143,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -183,6 +183,8 @@
                           additionalProperties:
                             type: string
                           type: object
+                        mTLS:
+                          type: boolean
                       type: object
                     pathPrefix:
                       type: string
diff --git a/helm-charts/gerrit-operator-crds/templates/gerrits.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gerrits.gerritoperator.google.com-v1.yml
index 5ff69a2..eb32fd9 100644
--- a/helm-charts/gerrit-operator-crds/templates/gerrits.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gerrits.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gerrit
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -461,7 +461,7 @@
                   type: integer
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -472,6 +472,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 ingress:
@@ -947,7 +948,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
@@ -1395,7 +1396,7 @@
                   type: integer
                 index:
                   properties:
-                    elasticsearch:
+                    remoteIndexConfig:
                       properties:
                         config:
                           type: string
@@ -1406,6 +1407,7 @@
                       enum:
                         - ELASTICSEARCH
                         - LUCENE
+                        - OPENSEARCH
                       type: string
                   type: object
                 ingress:
diff --git a/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml
index 780c9a7..10eaf8a 100644
--- a/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/gitgcs.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: gitgarbagecollection
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -422,7 +422,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml
index 1c78390..f00f004 100644
--- a/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/incomingreplicationtasks.gerritoperator.google.com-v1.yml
@@ -11,7 +11,7 @@
     singular: incomingreplicationtask
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -568,7 +568,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml b/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml
index 8bfbf2e..243fc7d 100644
--- a/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml
+++ b/helm-charts/gerrit-operator-crds/templates/receivers.gerritoperator.google.com-v1.yml
@@ -13,7 +13,7 @@
     singular: receiver
   scope: Namespaced
   versions:
-    - name: v1beta17
+    - name: v1beta18
       schema:
         openAPIV3Schema:
           properties:
@@ -687,7 +687,7 @@
       storage: true
       subresources:
         status: {}
-    - name: v1beta16
+    - name: v1beta17
       schema:
         openAPIV3Schema:
           properties:
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/Constants.java b/operator/src/main/java/com/google/gerrit/k8s/operator/Constants.java
index 3333d5f..64de43f 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/Constants.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/Constants.java
@@ -17,7 +17,7 @@
 import com.google.inject.AbstractModule;
 
 public class Constants extends AbstractModule {
-  public static final String VERSION = "v1beta17";
+  public static final String VERSION = "v1beta18";
 
   // The resource kind always has to be plural for use in webhooks
   public static final String GERRIT_CLUSTER_KIND = "gerritclusters";
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexConfig.java b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexConfig.java
index f61a66a..dc8f3c0 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexConfig.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexConfig.java
@@ -18,7 +18,7 @@
 
 public class IndexConfig {
   private IndexType type = IndexType.LUCENE;
-  private ElasticSearchConfig elasticsearch = new ElasticSearchConfig();
+  private RemoteIndexConfig remoteIndexConfig = new RemoteIndexConfig();
 
   public IndexType getType() {
     return type;
@@ -28,17 +28,17 @@
     this.type = type;
   }
 
-  public ElasticSearchConfig getElasticsearch() {
-    return elasticsearch;
+  public RemoteIndexConfig getRemoteIndexConfig() {
+    return remoteIndexConfig;
   }
 
-  public void setElasticsearch(ElasticSearchConfig elasticsearch) {
-    this.elasticsearch = elasticsearch;
+  public void setRemoteIndexConfig(RemoteIndexConfig remoteIndexConfig) {
+    this.remoteIndexConfig = remoteIndexConfig;
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(elasticsearch, type);
+    return Objects.hash(remoteIndexConfig, type);
   }
 
   @Override
@@ -47,11 +47,11 @@
     if (obj == null) return false;
     if (getClass() != obj.getClass()) return false;
     IndexConfig other = (IndexConfig) obj;
-    return Objects.equals(elasticsearch, other.elasticsearch) && type == other.type;
+    return Objects.equals(remoteIndexConfig, other.remoteIndexConfig) && type == other.type;
   }
 
   @Override
   public String toString() {
-    return "IndexConfig [type=" + type + ", elasticsearch=" + elasticsearch + "]";
+    return "IndexConfig [type=" + type + ", remoteIndexConfig=" + remoteIndexConfig + "]";
   }
 }
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexType.java b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexType.java
index f3e3dad..ee14b85 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexType.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/IndexType.java
@@ -15,6 +15,17 @@
 package com.google.gerrit.k8s.operator.api.model.shared;
 
 public enum IndexType {
-  LUCENE,
-  ELASTICSEARCH,
+  LUCENE(false),
+  ELASTICSEARCH(true),
+  OPENSEARCH(true);
+
+  private final boolean remote;
+
+  IndexType(boolean remote) {
+    this.remote = remote;
+  }
+
+  public boolean isRemote() {
+    return remote;
+  }
 }
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/ElasticSearchConfig.java b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/RemoteIndexConfig.java
similarity index 88%
rename from operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/ElasticSearchConfig.java
rename to operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/RemoteIndexConfig.java
index 004ff9d..b1bc8d2 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/ElasticSearchConfig.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/api/model/shared/RemoteIndexConfig.java
@@ -16,7 +16,7 @@
 
 import java.util.Objects;
 
-public class ElasticSearchConfig {
+public class RemoteIndexConfig {
   private String server;
   private String config;
 
@@ -46,12 +46,12 @@
     if (this == obj) return true;
     if (obj == null) return false;
     if (getClass() != obj.getClass()) return false;
-    ElasticSearchConfig other = (ElasticSearchConfig) obj;
+    RemoteIndexConfig other = (RemoteIndexConfig) obj;
     return Objects.equals(config, other.config) && Objects.equals(server, other.server);
   }
 
   @Override
   public String toString() {
-    return "ElasticSearchConfig [server=" + server + ", config=" + config + "]";
+    return "RemoteIndexConfig [server=" + server + ", config=" + config + "]";
   }
 }
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java
index 63a8ad8..d7b477c 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java
@@ -23,11 +23,11 @@
 import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
 import com.google.gerrit.k8s.operator.api.model.gerrit.GerritTemplateSpec.GerritMode;
 import com.google.gerrit.k8s.operator.api.model.indexer.GerritIndexer;
-import com.google.gerrit.k8s.operator.api.model.shared.ElasticSearchConfig;
 import com.google.gerrit.k8s.operator.api.model.shared.EventsBrokerConfig;
 import com.google.gerrit.k8s.operator.api.model.shared.GlobalRefDbConfig.RefDatabase;
 import com.google.gerrit.k8s.operator.api.model.shared.IndexType;
 import com.google.gerrit.k8s.operator.api.model.shared.IngressConfig;
+import com.google.gerrit.k8s.operator.api.model.shared.RemoteIndexConfig;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -36,7 +36,6 @@
 import org.eclipse.jgit.lib.Config;
 
 public class GerritConfigBuilder extends ConfigBuilder {
-  private static final String ES_SECTION_NAME = "elasticsearch";
 
   public GerritConfigBuilder(Gerrit gerrit) {
     super(
@@ -54,8 +53,8 @@
     List<RequiredOption<?>> requiredOptions = new ArrayList<>();
     requiredOptions.addAll(cacheSection(gerrit));
     requiredOptions.addAll(containerSection(gerrit));
-    if (gerrit.getSpec().getIndex().getType() == IndexType.ELASTICSEARCH) {
-      requiredOptions.addAll(elasticsearchSection(gerrit));
+    if (gerrit.getSpec().getIndex().getType().isRemote()) {
+      requiredOptions.addAll(searchIndexSection(gerrit));
     }
     requiredOptions.addAll(gerritSection(gerrit));
     requiredOptions.addAll(httpdSection(gerrit));
@@ -85,31 +84,41 @@
     return requiredOptions;
   }
 
-  private static List<RequiredOption<?>> elasticsearchSection(Gerrit gerrit) {
+  private static List<RequiredOption<?>> searchIndexSection(Gerrit gerrit) {
+    String sectionName =
+        switch (gerrit.getSpec().getIndex().getType()) {
+          case ELASTICSEARCH, OPENSEARCH ->
+              gerrit.getSpec().getIndex().getType().name().toLowerCase();
+          default ->
+              throw new IllegalStateException(
+                  "Unsupported index type: " + gerrit.getSpec().getIndex().getType());
+        };
     List<RequiredOption<?>> requiredOptions = new ArrayList<>();
-    ElasticSearchConfig esConfig = gerrit.getSpec().getIndex().getElasticsearch();
+    RemoteIndexConfig searchConfig = gerrit.getSpec().getIndex().getRemoteIndexConfig();
     requiredOptions.add(
-        new RequiredOption<String>(ES_SECTION_NAME, "server", esConfig.getServer()));
-    if (esConfig.getConfig() != null) {
+        new RequiredOption<String>(sectionName, "server", searchConfig.getServer()));
+    if (searchConfig.getConfig() != null) {
       try {
-        Config parsedEsConfig = new Config();
-        parsedEsConfig.fromText(esConfig.getConfig());
-        Set<String> sections = parsedEsConfig.getSections();
-        if (sections.size() > 1 || !sections.toArray()[0].equals(ES_SECTION_NAME)) {
+        Config parsedSearchConfig = new Config();
+        parsedSearchConfig.fromText(searchConfig.getConfig());
+        Set<String> sections = parsedSearchConfig.getSections();
+        if (sections.size() > 1 || !sections.toArray()[0].equals(sectionName)) {
           throw new IllegalStateException(
-              "No section other than `[elasticsearch]` is allowed in the elasticsearch configuration.");
+              String.format(
+                  "No section other than `[%s]` is allowed in the %s configuration.",
+                  sectionName, sectionName));
         }
-        Set<String> keys = parsedEsConfig.getNames(ES_SECTION_NAME);
+        Set<String> keys = parsedSearchConfig.getNames(sectionName);
         for (String key : keys) {
           if (key.toLowerCase().equals("server")) {
             continue;
           }
           requiredOptions.add(
               new RequiredOption<String>(
-                  ES_SECTION_NAME, key, parsedEsConfig.getString(ES_SECTION_NAME, null, key)));
+                  sectionName, key, parsedSearchConfig.getString(sectionName, null, key)));
         }
       } catch (ConfigInvalidException e) {
-        throw new IllegalStateException("Invalid ElasticSearch config.", e);
+        throw new IllegalStateException(String.format("Invalid %s config.", sectionName), e);
       }
     }
     return requiredOptions;
@@ -159,6 +168,15 @@
                   gerrit.getSpec().getMode() == GerritMode.REPLICA
                       ? "com.google.gerrit.elasticsearch.ReplicaElasticIndexModule"
                       : "com.google.gerrit.elasticsearch.ElasticIndexModule")));
+    } else if (gerrit.getSpec().getIndex().getType() == IndexType.OPENSEARCH) {
+      requiredOptions.add(
+          new RequiredOption<Set<String>>(
+              "gerrit",
+              "installIndexModule",
+              Set.of(
+                  gerrit.getSpec().getMode() == GerritMode.REPLICA
+                      ? "com.google.gerrit.opensearch.ReplicaOpenSearchIndexModule"
+                      : "com.google.gerrit.opensearch.OpenSearchIndexModule")));
     }
 
     IngressConfig ingressConfig = gerrit.getSpec().getIngress();
@@ -191,7 +209,8 @@
     List<RequiredOption<?>> requiredOptions = new ArrayList<>();
     IndexType indexType = gerrit.getSpec().getIndex().getType();
     GerritMode gerritMode = gerrit.getSpec().getMode();
-    if (indexType == IndexType.ELASTICSEARCH && gerritMode == GerritMode.REPLICA) {
+    if ((indexType == IndexType.ELASTICSEARCH || indexType == IndexType.OPENSEARCH)
+        && gerritMode == GerritMode.REPLICA) {
       requiredOptions.add(
           new RequiredOption<Boolean>("index", "scheduledIndexer", "enabled", false));
       requiredOptions.add(
@@ -209,6 +228,8 @@
     }
     if (gerrit.getSpec().getIndex().getType() == IndexType.ELASTICSEARCH) {
       mandatoryPlugins.add("index-elasticsearch");
+    } else if (gerrit.getSpec().getIndex().getType() == IndexType.OPENSEARCH) {
+      mandatoryPlugins.add("index-opensearch");
     }
     RefDatabase refDb = gerrit.getSpec().getRefdb().getDatabase();
     switch (refDb) {
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/HighAvailabilityPluginConfigBuilder.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/HighAvailabilityPluginConfigBuilder.java
index 6c10e7a..358845e 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/HighAvailabilityPluginConfigBuilder.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/HighAvailabilityPluginConfigBuilder.java
@@ -53,6 +53,7 @@
           break;
         }
       case ELASTICSEARCH:
+      case OPENSEARCH:
         {
           requiredOptions.add(new RequiredOption<Boolean>("index", "synchronize", false));
           break;
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritStatefulSet.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritStatefulSet.java
index 4e5fe9b..0e28945 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritStatefulSet.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritStatefulSet.java
@@ -22,7 +22,6 @@
 import com.google.gerrit.k8s.operator.api.model.gerrit.GerritModule;
 import com.google.gerrit.k8s.operator.api.model.gerrit.GerritModuleData;
 import com.google.gerrit.k8s.operator.api.model.shared.ContainerImageConfig;
-import com.google.gerrit.k8s.operator.api.model.shared.IndexType;
 import com.google.gerrit.k8s.operator.api.model.shared.NfsWorkaroundConfig;
 import com.google.gerrit.k8s.operator.cluster.GerritClusterLabelFactory;
 import com.google.gerrit.k8s.operator.components.GerritSecurityContext;
@@ -323,7 +322,7 @@
     if (gerrit.getSpec().isHighlyAvailablePrimary()) {
       volumeMounts.add(GerritCluster.getHAShareVolumeMount());
     }
-    if (gerrit.getSpec().getIndex().getType() == IndexType.ELASTICSEARCH) {
+    if (gerrit.getSpec().getIndex().getType().isRemote()) {
       volumeMounts.add(GerritCluster.getIndexConfigVolumeMount());
     }
     if (OperatorContext.getClusterMode() == ClusterMode.HIGH_AVAILABILITY) {
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilderTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilderTest.java
index ee3e9e0..4c50707 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilderTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilderTest.java
@@ -20,10 +20,10 @@
 
 import com.google.gerrit.k8s.operator.api.model.gerrit.Gerrit;
 import com.google.gerrit.k8s.operator.api.model.gerrit.GerritSpec;
-import com.google.gerrit.k8s.operator.api.model.shared.ElasticSearchConfig;
 import com.google.gerrit.k8s.operator.api.model.shared.IndexConfig;
 import com.google.gerrit.k8s.operator.api.model.shared.IndexType;
 import com.google.gerrit.k8s.operator.api.model.shared.IngressConfig;
+import com.google.gerrit.k8s.operator.api.model.shared.RemoteIndexConfig;
 import java.util.Map;
 import java.util.Set;
 import org.assertj.core.util.Arrays;
@@ -114,6 +114,54 @@
     assertTrue(cfg.getString("elasticsearch", null, "codec").equals("default"));
   }
 
+  @Test
+  public void validOpenSearchConfigIsParsed() {
+    assertOsConfig("[opensearch]\n  codec = default");
+    assertOsConfig("[opensearch]\n # test comment\n codec = default");
+    assertOsConfig("[opensearch]\n codec = default # test comment");
+    assertOsConfig("[opensearch]\n\n codec = default");
+
+    Gerrit gerrit = createGerritWithOpenSearch("[opensearch]\n username = \"hash#tag\"");
+    Config cfg = new GerritConfigBuilder(gerrit).build();
+    assertTrue(cfg.getString("opensearch", null, "username").equals("hash#tag"));
+  }
+
+  @Test
+  public void invalidOpenSearchConfigCausesError() {
+    assertThrows(
+        IllegalStateException.class,
+        () ->
+            new GerritConfigBuilder(createGerritWithOpenSearch("[invalid]\n  codec = default"))
+                .build());
+    assertThrows(
+        IllegalStateException.class,
+        () ->
+            new GerritConfigBuilder(createGerritWithOpenSearch("[invalid]\n  invalidText"))
+                .build());
+  }
+
+  private void assertOsConfig(String osConfig) {
+    Gerrit gerrit = createGerritWithOpenSearch(osConfig);
+    Config cfg = new GerritConfigBuilder(gerrit).build();
+    assertTrue(cfg.getString("opensearch", null, "server").equals("http://os.example.com"));
+    assertTrue(cfg.getString("opensearch", null, "codec").equals("default"));
+  }
+
+  private Gerrit createGerritWithOpenSearch(String osConfigText) {
+    IndexConfig indexConfig = new IndexConfig();
+    indexConfig.setType(IndexType.OPENSEARCH);
+    RemoteIndexConfig osConfig = new RemoteIndexConfig();
+    osConfig.setServer("http://os.example.com");
+    osConfig.setConfig(osConfigText);
+    indexConfig.setRemoteIndexConfig(osConfig);
+
+    GerritSpec gerritSpec = new GerritSpec();
+    gerritSpec.setIndex(indexConfig);
+    Gerrit gerrit = new Gerrit();
+    gerrit.setSpec(gerritSpec);
+    return gerrit;
+  }
+
   private Gerrit createGerrit(String configText) {
     GerritSpec gerritSpec = new GerritSpec();
     gerritSpec.setConfigFiles(Map.of("gerrit.config", configText));
@@ -125,10 +173,10 @@
   private Gerrit createGerritWithElasticSearch(String esConfigText) {
     IndexConfig indexConfig = new IndexConfig();
     indexConfig.setType(IndexType.ELASTICSEARCH);
-    ElasticSearchConfig esConfig = new ElasticSearchConfig();
+    RemoteIndexConfig esConfig = new RemoteIndexConfig();
     esConfig.setServer("http://es.example.com");
     esConfig.setConfig(esConfigText);
-    indexConfig.setElasticsearch(esConfig);
+    indexConfig.setRemoteIndexConfig(esConfig);
 
     GerritSpec gerritSpec = new GerritSpec();
     gerritSpec.setIndex(indexConfig);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java
index 86179a7..909e49f 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/dependent/GerritTest.java
@@ -134,6 +134,13 @@
             "gerrit-init_configmap_ha_primary.yaml",
             "statefulset_es_primary.yaml",
             "service_ha_primary.yaml",
+            "headless_service_ha_primary.yaml"),
+        Arguments.of(
+            "../gerrit_os_primary.yaml",
+            "gerrit_configmap_os_primary.yaml",
+            "gerrit-init_configmap_ha_primary.yaml",
+            "statefulset_os_primary.yaml",
+            "service_ha_primary.yaml",
             "headless_service_ha_primary.yaml"));
   }
 }
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_maintenance.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_maintenance.yaml
index 0453ee5..6f78336 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_maintenance.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_maintenance.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritMaintenance
 metadata:
   name: gerrit-gerrit-maintenance
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_primary.yaml
index 1993a68..de1acd6 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_primary.yaml
@@ -1,9 +1,9 @@
-apiVersion: gerritoperator.google.com/v1beta17
+apiVersion: gerritoperator.google.com/v1beta18
 kind: Gerrit
 metadata:
   name: gerrit
   annotations:
-    gerritoperator.google.com/apiVersion: gerritoperator.google.com/v1beta17
+    gerritoperator.google.com/apiVersion: gerritoperator.google.com/v1beta18
 spec:
   configFiles: {}
   containerImages:
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_replica.yaml
index 7c867fb..d43d02e 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/dependent/gerrit_replica.yaml
@@ -1,9 +1,9 @@
-apiVersion: gerritoperator.google.com/v1beta17
+apiVersion: gerritoperator.google.com/v1beta18
 kind: Gerrit
 metadata:
   name: gerrit-replica
   annotations:
-    gerritoperator.google.com/apiVersion: gerritoperator.google.com/v1beta17
+    gerritoperator.google.com/apiVersion: gerritoperator.google.com/v1beta18
 spec:
   configFiles: {}
   containerImages:
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/gerritcluster_primary_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/gerritcluster_primary_replica.yaml
index 24966c1..07fbdf2 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/gerritcluster_primary_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/cluster/gerritcluster_primary_replica.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/gerrit_configmap_os_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/gerrit_configmap_os_primary.yaml
new file mode 100644
index 0000000..825da97
--- /dev/null
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/gerrit_configmap_os_primary.yaml
@@ -0,0 +1,77 @@
+apiVersion: v1
+data:
+  healthcheck.config: |-
+    [healthcheck "auth"]
+        enabled = false
+    [healthcheck "querychanges"]
+        enabled = false
+  gerrit.config: |-
+    [cache]
+        directory = cache
+    [container]
+        user = gerrit
+        replica = false
+        javaHome = /usr/lib/jvm/java-11-openjdk
+        javaOptions = -Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore
+        javaOptions=-Djava.net.preferIPv4Stack=true
+        javaOptions = -Djava.io.tmpdir=/var/gerrit/tmp/java
+    [opensearch]
+        server = http://opensearch.example.com:9200
+        codec = default
+    [gerrit]
+        basepath = git
+        serverId = server-1
+        installModule = com.gerritforge.gerrit.globalrefdb.validation.LibModule
+        installDbModule = com.ericsson.gerrit.plugins.highavailability.ValidationModule
+        installIndexModule = com.google.gerrit.opensearch.OpenSearchIndexModule
+        canonicalWebUrl = https://example.com/
+    [httpd]
+        listenUrl = proxy-https://*:8080/
+    [plugins]
+        mandatory = healthcheck
+        mandatory = high-availability
+        mandatory = zookeeper-refdb
+        mandatory = index-opensearch
+    [sshd]
+        listenAddress = *:29418
+        advertisedAddress = example.com:29418
+  high-availability.config: |-
+    [main]
+        sharedDirectory = shared
+    [peerInfo]
+        strategy = jgroups
+    [jgroups]
+        clusterName = gerrit
+        kubernetes = true
+    [jgroups"kubernetes"]
+        namespace = gerrit
+        label = app.kubernetes.io/instance=gerrit
+        label = app.kubernetes.io/name=gerrit
+        label = app.kubernetes.io/component=gerrit-statefulset-gerrit
+        label = app.kubernetes.io/part-of=gerrit
+        label = app.kubernetes.io/managed-by=gerrit-operator
+    [cache]
+        synchronize = true
+    [event]
+        synchronize = true
+    [index]
+        synchronize = false
+    [healthcheck]
+        enable = true
+    [ref-database]
+        enabled = true
+  zookeeper-refdb.config: |-
+    [ref-database "zookeeper"]
+      connectString = zookeeper.example.com
+kind: ConfigMap
+metadata:
+  labels:
+    app.kubernetes.io/component: gerrit-configmap
+    app.kubernetes.io/created-by: GerritConfigMap
+    app.kubernetes.io/instance: gerrit
+    app.kubernetes.io/managed-by: gerrit-operator
+    app.kubernetes.io/name: gerrit
+    app.kubernetes.io/part-of: gerrit
+    app.kubernetes.io/version: unknown
+  name: gerrit-configmap
+  namespace: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_os_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_os_primary.yaml
new file mode 100644
index 0000000..b1b5da8
--- /dev/null
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/dependent/statefulset_os_primary.yaml
@@ -0,0 +1,196 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  labels:
+    app.kubernetes.io/managed-by: gerrit-operator
+    app.kubernetes.io/name: gerrit
+    app.kubernetes.io/part-of: gerrit
+    app.kubernetes.io/created-by: GerritReconciler
+    app.kubernetes.io/instance: gerrit
+    app.kubernetes.io/version: unknown
+    app.kubernetes.io/component: gerrit-statefulset-gerrit
+  name: gerrit
+  namespace: gerrit
+spec:
+  replicas: 2
+  selector:
+    matchLabels:
+      app.kubernetes.io/managed-by: gerrit-operator
+      app.kubernetes.io/name: gerrit
+      app.kubernetes.io/part-of: gerrit
+      app.kubernetes.io/instance: gerrit
+      app.kubernetes.io/component: gerrit-statefulset-gerrit
+  serviceName: gerrit
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/managed-by: gerrit-operator
+        app.kubernetes.io/name: gerrit
+        app.kubernetes.io/part-of: gerrit
+        app.kubernetes.io/created-by: GerritReconciler
+        app.kubernetes.io/instance: gerrit
+        app.kubernetes.io/version: unknown
+        app.kubernetes.io/component: gerrit-statefulset-gerrit
+    spec:
+      containers:
+      - env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        - name: GERRIT_URL
+          value: http://$(POD_NAME).gerrit.gerrit.svc.cluster.local:8080
+        image: docker.io/k8sgerrit/gerrit:latest
+        imagePullPolicy: Always
+        lifecycle:
+          preStop:
+            exec:
+              command:
+              - /bin/ash
+              - -c
+              - kill -s SIGTERM $(pidof java); jstack $(pidof java) > /var/gerrit/logs/td_$(date +%Y-%m-%dT%H:%M); tail --pid=$(pidof java) -f /dev/null
+        livenessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: 8080
+        name: gerrit
+        securityContext:
+          runAsGroup: 100
+          runAsUser: 1000
+          runAsNonRoot: true
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+          seccompProfile:
+            type: RuntimeDefault
+          capabilities:
+            drop:
+            - ALL
+        ports:
+        - containerPort: 8080
+          name: http
+        - containerPort: 29418
+          name: ssh
+        - containerPort: 7800
+          name: jgroups
+        readinessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: 8080
+        startupProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: 8080
+        volumeMounts:
+        - mountPath: /var/mnt/etc/secret
+          name: gerrit-secure-config
+        - mountPath: /var/gerrit
+          name: gerrit-site
+        - mountPath: /var/mnt/shared
+          name: shared
+          subPath: shared
+        - mountPath: /home/gerrit
+          subPath: home
+          name: tmp
+        - mountPath: /var/mnt/etc/config
+          name: gerrit-config
+        - mountPath: /var/mnt/git
+          name: shared
+          subPath: git
+        - mountPath: /tmp
+          subPath: tmp
+          name: tmp
+        - mountPath: /var/mnt/index
+          name: shared
+          subPath: index
+      initContainers:
+      - env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        - name: GERRIT_URL
+          value: http://$(POD_NAME).gerrit.gerrit.svc.cluster.local:8080
+        image: docker.io/k8sgerrit/gerrit-init:latest
+        imagePullPolicy: Always
+        name: gerrit-init
+        securityContext:
+          runAsGroup: 100
+          runAsUser: 1000
+          runAsNonRoot: true
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+          seccompProfile:
+            type: RuntimeDefault
+          capabilities:
+            drop:
+            - ALL
+        volumeMounts:
+        - mountPath: /var/mnt/etc/secret
+          name: gerrit-secure-config
+        - mountPath: /var/config
+          name: gerrit-init-config
+        - mountPath: /var/gerrit
+          name: gerrit-site
+        - mountPath: /var/mnt/shared
+          name: shared
+          subPath: shared
+        - mountPath: /home/gerrit
+          subPath: home
+          name: tmp
+        - mountPath: /var/mnt/etc/config
+          name: gerrit-config
+        - mountPath: /var/mnt/git
+          name: shared
+          subPath: git
+        - mountPath: /tmp
+          subPath: tmp
+          name: tmp
+        - mountPath: /var/mnt/index
+          name: shared
+          subPath: index
+      securityContext:
+        fsGroup: 100
+        runAsGroup: 100
+        runAsUser: 1000
+        runAsNonRoot: true
+        seccompProfile:
+          type: RuntimeDefault
+      serviceAccount: gerrit
+      terminationGracePeriodSeconds: 30
+      volumes:
+      - name: shared
+        persistentVolumeClaim:
+          claimName: shared-pvc
+      - name: tmp
+        emptyDir:
+          sizeLimit: 500Mi
+      - name: gerrit-secure-config
+        secret:
+          secretName: gerrit-secure-config
+      - configMap:
+          name: gerrit-configmap
+        name: gerrit-config
+      - configMap:
+          name: gerrit-init-configmap
+        name: gerrit-init-config
+  updateStrategy:
+    rollingUpdate:
+      partition: 0
+  volumeClaimTemplates:
+  - apiVersion: v1
+    kind: PersistentVolumeClaim
+    metadata:
+      labels:
+        app.kubernetes.io/managed-by: gerrit-operator
+        app.kubernetes.io/name: gerrit
+        app.kubernetes.io/part-of: gerrit
+        app.kubernetes.io/instance: gerrit
+        app.kubernetes.io/component: gerrit-statefulset-gerrit
+      name: gerrit-site
+    spec:
+      accessModes:
+      - ReadWriteOnce
+      resources:
+        requests:
+          storage: 1Gi
+      storageClassName: default
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_es_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_es_primary.yaml
index 314ea3d..4189eda 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_es_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_es_primary.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Gerrit
 metadata:
   name: gerrit
@@ -44,7 +44,7 @@
 
   index:
     type: ELASTICSEARCH
-    elasticsearch:
+    remoteIndexConfig:
       server: http://elasticsearch.example.com:9200
       config: |-
         [elasticsearch]
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_ha_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_ha_primary.yaml
index 0b8ee24..3a9f0db 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_ha_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_ha_primary.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Gerrit
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_os_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_os_primary.yaml
new file mode 100644
index 0000000..0240683
--- /dev/null
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_os_primary.yaml
@@ -0,0 +1,63 @@
+apiVersion: "gerritoperator.google.com/v1beta18"
+kind: Gerrit
+metadata:
+  name: gerrit
+  namespace: gerrit
+spec:
+  containerImages:
+    imagePullSecrets: []
+    imagePullPolicy: Always
+    gerritImages:
+      registry: docker.io
+      org: k8sgerrit
+      tag: latest
+    busyBox:
+      registry: docker.io
+      tag: latest
+
+  storage:
+    storageClasses:
+      readWriteOnce: default
+      readWriteMany: shared-storage
+    sharedStorage:
+      size: 1Gi
+      volumeName: "vol"
+      selector:
+        matchLabels:
+          volume-type: ssd
+          aws-availability-zone: us-east-1
+
+  serverId: "server-1"
+
+  fluentBitSidecar:
+    enabled: false
+
+  ingress:
+    enabled: true
+    host: example.com
+    tlsEnabled: true
+
+  refdb:
+    database: ZOOKEEPER
+    zookeeper:
+      connectString: zookeeper.example.com
+
+  index:
+    type: OPENSEARCH
+    remoteIndexConfig:
+      server: http://opensearch.example.com:9200
+      config: |-
+        [opensearch]
+          codec = default
+
+  serviceAccount: gerrit
+  replicas: 2
+  service:
+    type: NodePort
+    httpPort: 80
+    sshPort: 29418
+  site:
+    size: 1Gi
+  plugins:
+  - name: download-commands
+  secretRef: gerrit-secure-config
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_single_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_single_primary.yaml
index 895ddd3..475804a 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_single_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gerrit/gerrit_single_primary.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Gerrit
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_default.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_default.yaml
index c418a40..e0d9ab0 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_default.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_default.yaml
@@ -14,7 +14,7 @@
   annotations:
     app.kubernetes.io/managed-by: gerrit-operator
   ownerReferences:
-  - apiVersion: gerritoperator.google.com/v1beta17
+  - apiVersion: gerritoperator.google.com/v1beta18
     kind: GitGarbageCollection
     name: gitgc
     uid: abcd1234
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_nfs_workaround.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_nfs_workaround.yaml
index 20c8d1e..e46db51 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_nfs_workaround.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_nfs_workaround.yaml
@@ -14,7 +14,7 @@
   annotations:
     app.kubernetes.io/managed-by: gerrit-operator
   ownerReferences:
-  - apiVersion: gerritoperator.google.com/v1beta17
+  - apiVersion: gerritoperator.google.com/v1beta18
     kind: GitGarbageCollection
     name: gitgc
     uid: abcd1234
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_options_enabled.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_options_enabled.yaml
index 19d2835..5b270f9 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_options_enabled.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_all_options_enabled.yaml
@@ -14,7 +14,7 @@
   annotations:
     app.kubernetes.io/managed-by: gerrit-operator
   ownerReferences:
-  - apiVersion: gerritoperator.google.com/v1beta17
+  - apiVersion: gerritoperator.google.com/v1beta18
     kind: GitGarbageCollection
     name: gitgc
     uid: abcd1234
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_default.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_default.yaml
index c03cf4e..035afc8 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_default.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_default.yaml
@@ -14,7 +14,7 @@
   annotations:
     app.kubernetes.io/managed-by: gerrit-operator
   ownerReferences:
-  - apiVersion: gerritoperator.google.com/v1beta17
+  - apiVersion: gerritoperator.google.com/v1beta18
     kind: GitGarbageCollection
     name: gitgc
     uid: abcd1234
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_options_enabled.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_options_enabled.yaml
index 8e3f3ca..b6486a0 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_options_enabled.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/dependent/cronjob_selected_options_enabled.yaml
@@ -14,7 +14,7 @@
   annotations:
     app.kubernetes.io/managed-by: gerrit-operator
   ownerReferences:
-  - apiVersion: gerritoperator.google.com/v1beta17
+  - apiVersion: gerritoperator.google.com/v1beta18
     kind: GitGarbageCollection
     name: gitgc
     uid: abcd1234
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_minimal.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_minimal.yaml
index c07ec0b..ee176d6 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_minimal.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_minimal.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_nfs_workaround.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_nfs_workaround.yaml
index d41cf7c..e46dcd7 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_nfs_workaround.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gerritcluster_nfs_workaround.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_default.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_default.yaml
index cd86d4d..8f0512a 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_default.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_default.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GitGarbageCollection
 metadata:
   name: gitgc
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_options_enabled.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_options_enabled.yaml
index 02f8d1b..4d9fbbe 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_options_enabled.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_all_options_enabled.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GitGarbageCollection
 metadata:
   name: gitgc
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_default.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_default.yaml
index 7db79d4..5c1b7d5 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_default.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_default.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GitGarbageCollection
 metadata:
   name: gitgc
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_options_enabled.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_options_enabled.yaml
index 785e8b7..3188cf1 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_options_enabled.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/gitgc/gitgc_selected_options_enabled.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GitGarbageCollection
 metadata:
   name: gitgc
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_es.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_es.yaml
index 6befbcc..e2c7898 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_es.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_es.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
@@ -41,7 +41,7 @@
 
   index:
     type: ELASTICSEARCH
-    elasticsearch:
+    remoteIndexConfig:
       server: http://elasticsearch.example.com:9200
       config: |-
         [elasticsearch]
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_minimal.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_minimal.yaml
index e9fd6ac..32c253e 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_minimal.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/gerritcluster_minimal.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer.yaml
index 318c4e2..9db2d8a 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritIndexer
 metadata:
   name: gerrit-indexer
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer_es.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer_es.yaml
index e7d6863..fe63d13 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer_es.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/indexer/indexer_es.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritIndexer
 metadata:
   name: gerrit-indexer
@@ -7,7 +7,7 @@
   cluster: gerrit
   index:
     type: ELASTICSEARCH
-    elasticsearch:
+    remoteIndexConfig:
       server: http://elasticsearch.example.com:9200
       config: |-
         [elasticsearch]
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/maintenance/gerrit-maintenance.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/maintenance/gerrit-maintenance.yaml
index 0453ee5..6f78336 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/maintenance/gerrit-maintenance.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/maintenance/gerrit-maintenance.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritMaintenance
 metadata:
   name: gerrit-gerrit-maintenance
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary.yaml
index 3e91bab..64e59b3 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica.yaml
index e66c8ff..719d590 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_ssh.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_ssh.yaml
index bfe4d7b..f8885db 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_ssh.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_ssh.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_tls.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_tls.yaml
index b08c798..35e1651 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_tls.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_replica_tls.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_ssh.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_ssh.yaml
index cd987ea..b83b688 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_ssh.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_primary_ssh.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica.yaml
index 84e3e93..747dc16 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_ssh.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_ssh.yaml
index 5b44bc5..1c010ca 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_ssh.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_ssh.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_tls.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_tls.yaml
index 2b049b5..9efa650 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_tls.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_receiver_replica_tls.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica.yaml
index bebdbe8..bbb6fd5 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica_ssh.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica_ssh.yaml
index d6a89c4..ae45f88 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica_ssh.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/gerritnetwork_replica_ssh.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritNetwork
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver.yaml
index 30e7c46..429f17c 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Receiver
 metadata:
   name: receiver
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver_minimal.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver_minimal.yaml
index 022a933..d6cb111 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver_minimal.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/receiver/receiver_minimal.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: Receiver
 metadata:
   name: receiver
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/gerritcluster_incomingrepl.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/gerritcluster_incomingrepl.yaml
index 1c1fa16..aff47e2 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/gerritcluster_incomingrepl.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/gerritcluster_incomingrepl.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: GerritCluster
 metadata:
   name: gerrit
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/incomingrepltask.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/incomingrepltask.yaml
index 8a7dd07..7278ad9 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/incomingrepltask.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/tasks/incomingrepl/incomingrepltask.yaml
@@ -1,4 +1,4 @@
-apiVersion: "gerritoperator.google.com/v1beta17"
+apiVersion: "gerritoperator.google.com/v1beta18"
 kind: IncomingReplicationTask
 metadata:
   name: incoming-replication-test