chore(search): support Elastic Cloud API keys (#15231)
# Pull Request Template ## Description Adds API-key authorization support for Searchkick/OpenSearch so Elastic Cloud deployments can configure advanced search with an Elastic API key instead of embedding basic auth in the URL. The initializer now accepts `OPENSEARCH_API_KEY` or `ELASTICSEARCH_API_KEY` and forwards it as an `Authorization: ApiKey ...` header. `.env.example` also documents the OpenSearch/Elasticsearch-compatible search variables. Refs https://linear.app/chatwoot/issue/CW-7511/populate-test-data-set-and-run-experiments ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [x] This change requires a documentation update ## How Has This Been Tested? - `bundle exec ruby -c config/initializers/searchkick.rb` - `bundle exec ruby -c spec/config/searchkick_spec.rb` - `bundle exec rspec spec/config/searchkick_spec.rb` - `bundle exec rubocop config/initializers/searchkick.rb spec/config/searchkick_spec.rb` - `git diff --check` ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules
This commit is contained in:
10
.env.example
10
.env.example
@@ -59,6 +59,16 @@ REDIS_SENTINEL_MASTER_NAME=
|
||||
# ref: https://github.com/chatwoot/chatwoot/issues/2420
|
||||
# REDIS_OPENSSL_VERIFY_MODE=none
|
||||
|
||||
# OpenSearch / Elasticsearch-compatible search config
|
||||
# Set OPENSEARCH_URL to enable advanced search. Elastic Cloud API keys can be configured with either key name below.
|
||||
# API key values must be provided without the ApiKey authorization scheme prefix.
|
||||
# OPENSEARCH_URL=
|
||||
# OPENSEARCH_API_KEY=
|
||||
# ELASTICSEARCH_API_KEY=
|
||||
# OPENSEARCH_AWS_ACCESS_KEY_ID=
|
||||
# OPENSEARCH_AWS_SECRET_ACCESS_KEY=
|
||||
# OPENSEARCH_AWS_REGION=us-east-1
|
||||
|
||||
# Postgres Database config variables
|
||||
# You can leave POSTGRES_DATABASE blank. The default name of
|
||||
# the database in the production environment is chatwoot_production
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
Searchkick.queue_name = :async_database_migration if ENV.fetch('OPENSEARCH_URL', '').present?
|
||||
|
||||
api_key = ENV.fetch('OPENSEARCH_API_KEY', '').presence || ENV.fetch('ELASTICSEARCH_API_KEY', '').presence
|
||||
access_key_id = ENV.fetch('OPENSEARCH_AWS_ACCESS_KEY_ID', '')
|
||||
secret_access_key = ENV.fetch('OPENSEARCH_AWS_SECRET_ACCESS_KEY', '')
|
||||
|
||||
if access_key_id.present? && secret_access_key.present?
|
||||
if api_key.present?
|
||||
Searchkick.client_options = Searchkick.client_options.deep_merge(
|
||||
transport_options: {
|
||||
headers: {
|
||||
'Authorization' => "ApiKey #{api_key}"
|
||||
}
|
||||
}
|
||||
)
|
||||
elsif access_key_id.present? && secret_access_key.present?
|
||||
region = ENV.fetch('OPENSEARCH_AWS_REGION', 'us-east-1')
|
||||
|
||||
Searchkick.aws_credentials = {
|
||||
|
||||
53
spec/config/searchkick_spec.rb
Normal file
53
spec/config/searchkick_spec.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Searchkick do
|
||||
let(:initializer_path) { Rails.root.join('config/initializers/searchkick.rb') }
|
||||
|
||||
around do |example|
|
||||
original_client_options = described_class.client_options.deep_dup
|
||||
original_queue_name = described_class.queue_name
|
||||
original_aws_credentials = described_class.aws_credentials
|
||||
original_client = described_class.instance_variable_get(:@client)
|
||||
|
||||
example.run
|
||||
ensure
|
||||
described_class.client_options = original_client_options
|
||||
described_class.queue_name = original_queue_name
|
||||
described_class.instance_variable_set(:@aws_credentials, original_aws_credentials)
|
||||
described_class.instance_variable_set(:@client, original_client)
|
||||
end
|
||||
|
||||
it 'configures API key authorization from OPENSEARCH_API_KEY' do
|
||||
described_class.client_options = {}
|
||||
|
||||
with_modified_env OPENSEARCH_API_KEY: 'opensearch-api-key', ELASTICSEARCH_API_KEY: nil,
|
||||
OPENSEARCH_AWS_ACCESS_KEY_ID: nil, OPENSEARCH_AWS_SECRET_ACCESS_KEY: nil do
|
||||
load initializer_path
|
||||
end
|
||||
|
||||
expect(described_class.client_options).to eq(
|
||||
transport_options: {
|
||||
headers: {
|
||||
'Authorization' => 'ApiKey opensearch-api-key'
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'supports ELASTICSEARCH_API_KEY for Elastic Cloud credentials' do
|
||||
described_class.client_options = {}
|
||||
|
||||
with_modified_env OPENSEARCH_API_KEY: nil, ELASTICSEARCH_API_KEY: 'elastic-api-key',
|
||||
OPENSEARCH_AWS_ACCESS_KEY_ID: nil, OPENSEARCH_AWS_SECRET_ACCESS_KEY: nil do
|
||||
load initializer_path
|
||||
end
|
||||
|
||||
expect(described_class.client_options).to eq(
|
||||
transport_options: {
|
||||
headers: {
|
||||
'Authorization' => 'ApiKey elastic-api-key'
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user