Deploy OpenSearch with Helm
Use Helm to deploy an OpenSearch cluster on Kubernetes
What should you get after following the guide?
If you follow along with the instructions I have written here, you should have a set of 4 Kubernetes pods running 3 instances of the OpenSearch server software and 1 instance of the OpenSearch Dashboards software. OpenSearch should be configured for production usage with the security plugin enabled to provide authentication and TLS connections between cluster members.
I make no warranty or guarantee about the safety, security, or success of anyone who follows these instructions. Consult with an OpenSearch, security, or other expert on your particular use case.
What you need to follow these instructions?
You will need access to a Kubernetes cluster with Helm and cert-manager installed. I used k3s to run a single-node Kubernetes cluster on a virtual machine with 8 vCPUs, 24GB of RAM, and 80GB of storage. You could probably run this deployment on a smaller machine with fewer resources, but you will not be able to run very large or intensive workloads.
I used the built-in kubectl command to apply the secrets and cert-manager configuration to Kubernetes.
For installing Helm, I recommend following the official Helm installation guide for the platform on which you are running Helm.
For installing cert-manager, I recommend following the official cert-manager installation instructions.
Create SSL/TLS certificates using cert-manager and Kubernetes
If you have access to generating signed SSL/TLS certificates and know how to use them, you should use signed SSL/TLS certificates and skip this step. The cert-manager website has documentation on setting up an ACME issuer using Let's Encrypt to do this.
Creating simple self-signed certificates for OpenSearch is straightforward with cert-manager. The following example Kubernetes configuration file will provision:
- a self-signed Issuer
- a root Certificate Authority
- a Certificate Authority issuer
- two Certificate resources for OpenSearch nodes and the admin client to use
Self-signed certificates are suitable for demonstration purposes and for when you only need to encrypt traffic in transit without outside certificate validation. For this deployment, the OpenSearch cluster uses the CA certificate to validate the self-signed certificates were issued using the CA certificate created through cert-manager. I was fine with that for my needs because if someone can successfully intercept the node traffic and impersonate nodes using a self-signed certificate issued using the CA certificate then more serious problems have already occurred for me to address.
---
# Create a self-signed certificate issuer for issuing a self-signed root certificate
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
# Generate a self-signed certificate to function as the root signing certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ca-cert
spec:
secretName: ca-cert # cert-manager stores the signing certificate as a Kubernetes secret
duration: 87600h # Last for 10 years before expiring
renewBefore: 360h
isCA: true
privateKey:
size: 2048
algorithm: RSA
encoding: PKCS1
commonName: cacert
dnsNames:
- caroot
issuerRef:
name: selfsigned-issuer # User the self-signed issuer we declared first
---
# Create a CA cert-manager issuer using the self-signed signing certificate
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ca-issuer
spec:
ca:
secretName: ca-cert
---
# Generate self-signed node certificates for OpenSearch using the CA issuer
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: opensearch-cluster # Change to match your cluster name if needed
spec:
privateKey:
encoding: PKCS8 # You must use PKCS8 format for compatibility with Java, in which OpenSearch is written
secretName: opensearch-cluster-tls # cert-manager stores the certificates as Kubernetes secrets. Change the name if needed
usages:
- digital signature
- key encipherment
- server auth
- client auth
literalSubject: "CN=opensearch-cluster-master" # You can change this to what you want, but this must match your opensearch.yml config
dnsNames: # The dnsNames should include the DNS records your pods will use in Kuberentes to resolve pod IP addresses
- opensearch-cluster-master-0
- opensearch-cluster-master-1
- opensearch-cluster-master-2
- opensearch-cluster-master
issuerRef: # Use the CA issuer declared earlier
name: ca-issuer
kind: Issuer
---
# Generate a separate certificate to use to authenticate the OpenSearch security admin script with OpenSearch
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: opensearch-cluster-admin
spec:
privateKey:
encoding: PKCS8 # You must use PKCS8 format for compatibility with Java, in which OpenSearch is written
secretName: opensearch-cluster-admin-cert # cert-manager stores the certificate as a Kubernetes secret
usages:
- digital signature
- key encipherment
- server auth
- client auth
literalSubject: "CN=opensearch-cluster-admin" # You can change this value, but you must put the value in your opensearch.yml config later
dnsNames:
- opensearch-cluster-admin # You can change this value, but you must put the value in your opensearch.yml config later
issuerRef:
name: ca-issuer
kind: Issuer
To create the certificates through cert-manager, copy the configuration to a file in your local environment, and apply the configuration using kubectl apply -f or whatever you use to manage your Kubernetes cluster. If Kuberentes successfully applies the configuration you should have secrets available with the SSL/TLS certificate files, keys, and root CA certificate.
Here are the Helm charts, config files, and values you need to deploy OpenSearch using Helm to your Kubernetes cluster
OpenSearch Security Config Files
action_groups.yml secret declaration
The actions_groups.yml file defines Action Groups in OpenSearch. This deployment does not use Action Groups, and the secret defined below results in an empty configuration file.
If you are not using Action Groups you can skip this section.
If you want to use Action Groups, you can create a secret by extending the example below and applying the configuration using kubectl apply -f.
apiVersion: v1
kind: Secret
metadata:
name: opensearch-action-groups-config
type: Opaque
stringData:
action_groups.yml: |-
_meta:
type: "actiongroups"
config_version: 2
allowlist.yml secret declaration
This deployment relies on the default Helm configuration for the allowlist.yml file. The Helm chart for OpenSearch does not expose a way to define your own allowlist.yml file. If you want to customize this file you will have to expose the file to the pod by some other way.
audit.yml secret declaration
This deployment relies on the default Helm configuration for the audit.yml file. The Helm chart for OpenSearch does not expose a way to define your own audit.yml file. If you want to customize this file you will have to expose the file to the pod by some other way.
config.yml secret declaration
The configuration in this secret disables anonymous HTTP authentication for OpenSearch and only allows authentication using HTTP Basic authentication against the internal users database. The internal users database is the users defined in the internal_users.yml file.
apiVersion: v1
kind: Secret
metadata:
name: opensearch-security-config
type: Opaque
stringData:
config.yml: |-
_meta:
type: "config"
config_version: 2
config:
dynamic:
http:
anonymous_auth_enabled: false # Require HTTP authentication
xff: # explicitly disabled X-Forwarded-For for proxied requests
enabled: false
authc:
basic_internal_auth_domain:
description: "Authenticate via HTTP Basic against internal users database"
http_enabled: true
transport_enabled: true
order: 1
http_authenticator:
type: basic
challenge: true
authentication_backend:
type: internal
Copy the configuration below to a file and run kubectl apply -f <the-name-of-the-file>. Replace <the-name-of-the-file> with the actual name you gave the file. Kubernetes should create a secret named opensearch-security-config.
internal_users.yml secret declaration
The internal_users.yml file declares the internal user database for OpenSearch to use when authenticating HTTP requests against the internal database is enabled. The following configuration would create an admin user, a user for the OpenSearch Dashboard server, and a non-admin example user. The value of the hash key in each user declaration should be replaced with a hash from a password generated using the OpenSearch Security hash script. If you do not have a pod running OpenSearch yet with the OpenSearch Security hash script, you can use something else to produce a bcrypt hash of your password.
apiVersion: v1
kind: Secret
metadata:
name: opensearch-internal-users-config
type: Opaque
stringData:
internal_users.yml: |-
_meta:
type: "internalusers"
config_version: 2
admin:
hash: "some-password-hashed-using-the-opensearch-security-hash-script"
reserved: true
backend_roles: # backend roles are defined in roles.yml
- "admin"
description: "admin user"
kibanaserver: # Called Kibana for legacy compatibility reasons
hash: "some-password-hashed-using-the-opensearch-security-hash-script"
reserved: true
backend_roles:
- "kibana_server"
description: "OpenSearch Dashboards user"
someotheruser:
hash: "some-password-hashed-using-the-opensearch-security-hash-script"
reserved: false
backend_roles:
- "somebackendrole"
Copy the configuration below to a file and run kubectl apply -f <the-name-of-the-file>. Replace <the-name-of-the-file> with the actual name you gave the file.
Use htpasswd to generate a bcrypt hash of your password
You should not use websites that offer to generate bcrypt hashes for you for passwords or any other sensitive information. You cannot be certain the websites are not logging entries somewhere for later misuse.
You can use the htpasswd CLI library from the Apache web server project to generate a bcrypt hash of a password.
To install the htpasswd tool on RedHat, CentOS, Oracle Linux, Rocky Linux, AlmaLinux, and dnf/yum Linux distros install the httpd-tools package, such as by running dnf install httpd-tools or yum install httpd-tools. You may need to use sudo or login as root if your normal user does not have privileges for installing packages.
To install the htpasswd tool on Ubuntu, Debian, and apt/deb Linux distros install the apachd2-utils package, such as by running apt-get install apache2-utils. You may need to use sudo or login as root if your normal user does not have privileges for installing packages.
After you have installed htpasswd, you can generate a hashed password by running the following shell script:
read -s -p "Password to hash:" password && printf "\nHash: $(htpasswd -bnBC 10 "" $password | tr -d ':\n')\n"
This simple shell script executes two commands. The first command - read -s -p "Password to hash:" password - prompts for text input without showing what you type in. The input is stored in a variable called password. The second command - printf "\nHash: $(htpasswd -bnBC 10 "" $password | tr -d ':\n')\n" - actually comprises a command for printing output and another nested command for generating the bcrypt hash using the htpasswd tool. When the shell evaluates the second command, the shell first executes the nested htpasswd -bnBC 10 "" $password | tr -d ':\n' command first using the input stored in the password variable in the read command. The output from the nested command is then passed up to the printf command, which embeds the output from htpasswd in between the `"\nHash:" and the trailing "\n" new line character. If everything works well, the output should look something like:
~$ read -s -p "Password to hash:" password && printf "\nHash: $(htpasswd -bnBC 10 "" $password | tr -d ':\n')\n"
Password to hash:
Hash: $2y$10$PPfWs1vc51LfRMddY4ZTo.8tL33.M21lz6p6jQwjFhLT5khai8fAO
~$
The output after the word Hash: is the bcrypt hash of the input you provided when running the script. You should be able to use the hash (like $2y$10$PPfWs1vc51LfRMddY4ZTo.8tL33.M21lz6p6jQwjFhLT5khai8fAO from the example) as the value of the hash key in your internal_users.yml configuration.
Do not use $2y$10$PPfWs1vc51LfRMddY4ZTo.8tL33.M21lz6p6jQwjFhLT5khai8fAO from the example as your hash. Generate your own hash that you do not share with anyone.
nodes_dn.yml secret declaration
This deployment relies on the default Helm configuration for the nodes_dn.yml file. The Helm chart for OpenSearch does not expose a way to define your own nodes_dn.yml file. If you want to customize this file you will have to expose the file to the pod by some other way.
roles_mapping.yml secret declaration
OpenSearch Security uses the roles_mapping.yml file to associate specific permissions to specific users. The configuration below is based on the default OpenSearch Security configuration. This configuration defines a roles mapping for the admin user and default users for OpenSearch Dashboards and Logstash data ingestion.
apiVersion: v1
kind: Secret
metadata:
name: opensearch-internal-users-config
type: Opaque
stringData:
roles_mapping.yml: |-
_meta:
type: "rolesmapping"
config_version: 2
all_access:
reserved: true
hidden: false
backend_roles:
- "admin"
hosts: []
users: []
and_backend_roles: []
description: "Maps admin to all_access"
manage_snapshots:
reserved: true
hidden: false
backend_roles:
- "snapshotrestore"
hosts: []
users: []
and_backend_roles: []
logstash:
reserved: false
hidden: false
backend_roles:
- "logstash"
hosts: []
users: []
and_backend_roles: []
own_index:
reserved: false
hidden: false
backend_roles: []
hosts: []
users:
- "*"
and_backend_roles: []
description: "Allow full access to an index named like the username"
kibana_user:
reserved: false
hidden: false
backend_roles:
- "kibanauser"
hosts: []
users: []
and_backend_roles: []
description: "Maps kibanauser to kibana_user"
readall:
reserved: true
hidden: false
backend_roles:
- "readall"
hosts: []
users: []
and_backend_roles: []
kibana_server:
reserved: true
hidden: false
backend_roles: []
hosts: []
users:
- "kibanaserver"
and_backend_roles: []
Copy the configuration below to a file and run kubectl apply -f <the-name-of-the-file>. Replace <the-name-of-the-file> with the actual name you gave the file.
The roles.yml secret declaration
The roles.yml file declares all of the available OpenSearch Security roles using OpenSearch Security's permissions primitives. The roles I have included below are taken from the roles that OpenSearch Security generates when you initialize the demo configuration. The roles declarations do not do anything on their own. You must map the roles in the roles_mapping.yml file to individual users in order for the roles to have an effect on what users can and cannot access.
apiVersion: v1
kind: Secret
metadata:
name: opensearch-internal-users-config
type: Opaque
stringData:
roles.yml: |-
_meta:
type: "roles"
config_version: 2
# Restrict users so they can only view visualization and dashboard on OpenSearchDashboards
kibana_read_only:
reserved: true
# The security REST API access role is used to assign specific users access to change the security settings through the REST API.
security_rest_api_access:
reserved: true
security_rest_api_full_access:
reserved: true
cluster_permissions:
- "restapi:admin/actiongroups"
- "restapi:admin/allowlist"
- "restapi:admin/config/update"
- "restapi:admin/internalusers"
- "restapi:admin/nodesdn"
- "restapi:admin/roles"
- "restapi:admin/rolesmapping"
- "restapi:admin/ssl/certs/info"
- "restapi:admin/ssl/certs/reload"
- "restapi:admin/tenants"
# Allows users to view monitors, destinations and alerts
alerting_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/alerting/alerts/get"
- "cluster:admin/opendistro/alerting/destination/get"
- "cluster:admin/opendistro/alerting/monitor/get"
- "cluster:admin/opendistro/alerting/monitor/search"
- "cluster:admin/opensearch/alerting/comments/search"
- "cluster:admin/opensearch/alerting/findings/get"
- "cluster:admin/opensearch/alerting/remote/indexes/get"
- "cluster:admin/opensearch/alerting/workflow/get"
- "cluster:admin/opensearch/alerting/workflow_alerts/get"
# Allows users to view and acknowledge alerts
alerting_ack_alerts:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/alerting/alerts/*"
- "cluster:admin/opendistro/alerting/chained_alerts/*"
- "cluster:admin/opendistro/alerting/workflow_alerts/*"
- "cluster:admin/opensearch/alerting/comments/*"
# Allows users to use all alerting functionality
alerting_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/alerting/*"
- "cluster:admin/opensearch/alerting/*"
- "cluster:admin/opensearch/notifications/feature/publish"
- "cluster_monitor"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/aliases/get"
- "indices:admin/mappings/get"
- "indices_monitor"
# Allow users to read Anomaly Detection detectors and results
anomaly_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/ad/detector/info"
- "cluster:admin/opendistro/ad/detector/search"
- "cluster:admin/opendistro/ad/detector/validate"
- "cluster:admin/opendistro/ad/detectors/get"
- "cluster:admin/opendistro/ad/result/search"
- "cluster:admin/opendistro/ad/result/topAnomalies"
- "cluster:admin/opendistro/ad/tasks/search"
# Allows users to use all Anomaly Detection functionality
anomaly_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/ingest/pipeline/delete"
- "cluster:admin/ingest/pipeline/put"
- "cluster:admin/opendistro/ad/*"
- "cluster_monitor"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/aliases/get"
- "indices:admin/mappings/fields/get"
- "indices:admin/mappings/fields/get*"
- "indices:admin/mappings/get"
- "indices:admin/resolve/index"
- "indices:admin/setting/put"
- "indices:data/read/field_caps*"
- "indices:data/read/search"
- "indices_monitor"
# Allow users to execute read only k-NN actions
knn_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/knn_get_model_action"
- "cluster:admin/knn_search_model_action"
- "cluster:admin/knn_stats_action"
# Allow users to use all k-NN functionality
knn_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/knn_delete_model_action"
- "cluster:admin/knn_get_model_action"
- "cluster:admin/knn_remove_model_from_cache_action"
- "cluster:admin/knn_search_model_action"
- "cluster:admin/knn_stats_action"
- "cluster:admin/knn_training_job_route_decision_info_action"
- "cluster:admin/knn_training_job_router_action"
- "cluster:admin/knn_training_model_action"
- "cluster:admin/knn_update_model_graveyard_action"
- "cluster:admin/knn_warmup_action"
# Allow users to execute read only ip2geo datasource action
ip2geo_datasource_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/geospatial/datasource/get"
# Allow users to use all ip2geo datasource action
ip2geo_datasource_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/geospatial/datasource/*"
# Allows users to read Notebooks
notebooks_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/notebooks/get"
- "cluster:admin/opendistro/notebooks/list"
# Allows users to all Notebooks functionality
notebooks_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/notebooks/create"
- "cluster:admin/opendistro/notebooks/delete"
- "cluster:admin/opendistro/notebooks/get"
- "cluster:admin/opendistro/notebooks/list"
- "cluster:admin/opendistro/notebooks/update"
# Allows users to read observability objects
observability_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/observability/get"
# Allows users to all Observability functionality
observability_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/observability/create"
- "cluster:admin/opensearch/observability/delete"
- "cluster:admin/opensearch/observability/get"
- "cluster:admin/opensearch/observability/update"
# Allows users to all PPL functionality
ppl_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/ppl"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/mappings/get"
- "indices:data/read/search*"
- "indices:monitor/settings/get"
# Allows users to read and download Reports
reports_instances_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/reports/instance/get"
- "cluster:admin/opendistro/reports/instance/list"
- "cluster:admin/opendistro/reports/menu/download"
# Allows users to read and download Reports and Report-definitions
reports_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/reports/definition/get"
- "cluster:admin/opendistro/reports/definition/list"
- "cluster:admin/opendistro/reports/instance/get"
- "cluster:admin/opendistro/reports/instance/list"
- "cluster:admin/opendistro/reports/menu/download"
# Allows users to all Reports functionality
reports_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/reports/definition/create"
- "cluster:admin/opendistro/reports/definition/delete"
- "cluster:admin/opendistro/reports/definition/get"
- "cluster:admin/opendistro/reports/definition/list"
- "cluster:admin/opendistro/reports/definition/on_demand"
- "cluster:admin/opendistro/reports/definition/update"
- "cluster:admin/opendistro/reports/instance/get"
- "cluster:admin/opendistro/reports/instance/list"
- "cluster:admin/opendistro/reports/menu/download"
# Allows users to use all asynchronous-search functionality
asynchronous_search_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/asynchronous_search/*"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:data/read/search*"
# Allows users to read stored asynchronous-search results
asynchronous_search_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/asynchronous_search/get"
# Allows user to use all index_management actions - ism policies, rollups, transforms
index_management_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opendistro/ism/*"
- "cluster:admin/opendistro/rollup/*"
- "cluster:admin/opendistro/transform/*"
- "cluster:admin/opensearch/controlcenter/lron/*"
- "cluster:admin/opensearch/notifications/channels/get"
- "cluster:admin/opensearch/notifications/feature/publish"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/opensearch/ism/*"
- "indices:internal/plugins/replication/index/stop"
# Allows users to use all cross cluster replication functionality at leader cluster
cross_cluster_replication_leader_full_access:
reserved: true
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/plugins/replication/index/setup/validate"
- "indices:data/read/plugins/replication/changes"
- "indices:data/read/plugins/replication/file_chunk"
# Allows users to use all cross cluster replication functionality at follower cluster
cross_cluster_replication_follower_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/plugins/replication/autofollow/update"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/plugins/replication/index/pause"
- "indices:admin/plugins/replication/index/resume"
- "indices:admin/plugins/replication/index/setup/validate"
- "indices:admin/plugins/replication/index/start"
- "indices:admin/plugins/replication/index/status_check"
- "indices:admin/plugins/replication/index/stop"
- "indices:admin/plugins/replication/index/update"
- "indices:data/write/plugins/replication/changes"
# Allows users to use all cross cluster search functionality at remote cluster
cross_cluster_search_remote_full_access:
reserved: true
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/shards/search_shards"
- "indices:data/read/search"
# Allow users to operate query assistant
query_assistant_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/ml/config/get"
- "cluster:admin/opensearch/ml/execute"
- "cluster:admin/opensearch/ml/predict"
- "cluster:admin/opensearch/ppl"
# Allow users to read ML stats/models/tasks
ml_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/ml/config/get"
- "cluster:admin/opensearch/ml/connectors/get"
- "cluster:admin/opensearch/ml/connectors/search"
- "cluster:admin/opensearch/ml/controllers/get"
- "cluster:admin/opensearch/ml/memory/conversation/get"
- "cluster:admin/opensearch/ml/memory/conversation/interaction/search"
- "cluster:admin/opensearch/ml/memory/conversation/list"
- "cluster:admin/opensearch/ml/memory/conversation/search"
- "cluster:admin/opensearch/ml/memory/interaction/get"
- "cluster:admin/opensearch/ml/memory/interaction/list"
- "cluster:admin/opensearch/ml/memory/trace/get"
- "cluster:admin/opensearch/ml/model_groups/get"
- "cluster:admin/opensearch/ml/model_groups/search"
- "cluster:admin/opensearch/ml/models/get"
- "cluster:admin/opensearch/ml/models/search"
- "cluster:admin/opensearch/ml/profile/nodes"
- "cluster:admin/opensearch/ml/stats/nodes"
- "cluster:admin/opensearch/ml/tasks/get"
- "cluster:admin/opensearch/ml/tasks/search"
- "cluster:admin/opensearch/ml/tools/get"
- "cluster:admin/opensearch/ml/tools/list"
# Allows users to use all ML functionality
ml_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/ml/*"
- "cluster_monitor"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices_monitor"
# Allows users to use all Notifications functionality
notifications_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/notifications/*"
# Allows users to read Notifications config/channels
notifications_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/notifications/channels/get"
- "cluster:admin/opensearch/notifications/configs/get"
- "cluster:admin/opensearch/notifications/features"
# Allows users to use all snapshot management functionality
snapshot_management_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/notifications/feature/publish"
- "cluster:admin/opensearch/snapshot_management/*"
- "cluster:admin/repository/*"
- "cluster:admin/snapshot/*"
# Allows users to see snapshots, repositories, and snapshot management policies
snapshot_management_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/snapshot_management/policy/explain"
- "cluster:admin/opensearch/snapshot_management/policy/get"
- "cluster:admin/opensearch/snapshot_management/policy/search"
- "cluster:admin/repository/get"
- "cluster:admin/snapshot/get"
# Allows user to use point in time functionality
point_in_time_full_access:
reserved: true
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "manage_point_in_time"
# Allows users to see security analytics detectors and others
security_analytics_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/securityanalytics/alerts/get"
- "cluster:admin/opensearch/securityanalytics/correlationAlerts/get"
- "cluster:admin/opensearch/securityanalytics/correlations/findings"
- "cluster:admin/opensearch/securityanalytics/correlations/list"
- "cluster:admin/opensearch/securityanalytics/detector/get"
- "cluster:admin/opensearch/securityanalytics/detector/search"
- "cluster:admin/opensearch/securityanalytics/findings/get"
- "cluster:admin/opensearch/securityanalytics/logtype/search"
- "cluster:admin/opensearch/securityanalytics/mapping/get"
- "cluster:admin/opensearch/securityanalytics/mapping/view/get"
- "cluster:admin/opensearch/securityanalytics/rule/get"
- "cluster:admin/opensearch/securityanalytics/rule/search"
- "cluster:admin/opensearch/securityanalytics/threatintel/alerts/get"
- "cluster:admin/opensearch/securityanalytics/threatintel/iocs/findings/get"
- "cluster:admin/opensearch/securityanalytics/threatintel/iocs/list"
- "cluster:admin/opensearch/securityanalytics/threatintel/monitors/search"
- "cluster:admin/opensearch/securityanalytics/threatintel/sources/get"
- "cluster:admin/opensearch/securityanalytics/threatintel/sources/search"
# Allows users to use all security analytics functionality
security_analytics_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/securityanalytics/alerts/*"
- "cluster:admin/opensearch/securityanalytics/connections/*"
- "cluster:admin/opensearch/securityanalytics/correlationAlerts/*"
- "cluster:admin/opensearch/securityanalytics/correlations/*"
- "cluster:admin/opensearch/securityanalytics/detector/*"
- "cluster:admin/opensearch/securityanalytics/findings/*"
- "cluster:admin/opensearch/securityanalytics/logtype/*"
- "cluster:admin/opensearch/securityanalytics/mapping/*"
- "cluster:admin/opensearch/securityanalytics/rule/*"
- "cluster:admin/opensearch/securityanalytics/threatintel/*"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/mapping/put"
- "indices:admin/mappings/get"
# Allows users to view and acknowledge alerts
security_analytics_ack_alerts:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/securityanalytics/alerts/*"
- "cluster:admin/opensearch/securityanalytics/correlationAlerts/*"
- "cluster:admin/opensearch/securityanalytics/threatintel/alerts/*"
# Allows users to use all Flow Framework functionality
flow_framework_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/flow_framework/*"
- "cluster_monitor"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/aliases/get"
- "indices:admin/mappings/get"
- "indices_monitor"
# Allow users to read flow framework's workflows and their state
flow_framework_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/flow_framework/workflow/get"
- "cluster:admin/opensearch/flow_framework/workflow/search"
- "cluster:admin/opensearch/flow_framework/workflow_state/get"
- "cluster:admin/opensearch/flow_framework/workflow_state/search"
- "cluster:admin/opensearch/flow_framework/workflow_step/get"
# Allows users to use all query insights APIs
query_insights_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/insights/*"
index_permissions:
- index_patterns:
- "top_queries-*"
allowed_actions:
- "indices_all"
# Allow users to execute read only LTR actions
ltr_read_access:
reserved: true
cluster_permissions:
- cluster:admin/ltr/caches/stats
- cluster:admin/ltr/featurestore/list
- cluster:admin/ltr/stats
# Allow users to execute all LTR actions
ltr_full_access:
reserved: true
cluster_permissions:
- cluster:admin/ltr/*
# Allow users to use all Search Relevance functionalities
search_relevance_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/search_relevance/*"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/mappings/get"
- "indices:data/read/search*"
# Allow users to read Search Relevance resources
search_relevance_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/opensearch/search_relevance/experiment/get"
- "cluster:admin/opensearch/search_relevance/judgment/get"
- "cluster:admin/opensearch/search_relevance/queryset/get"
- "cluster:admin/opensearch/search_relevance/search_configuration/get"
# Allow users to read Forecast resources
forecast_read_access:
reserved: true
cluster_permissions:
- "cluster:admin/plugin/forecast/forecaster/info"
- "cluster:admin/plugin/forecast/forecaster/stats"
- "cluster:admin/plugin/forecast/forecaster/suggest"
- "cluster:admin/plugin/forecast/forecaster/validate"
- "cluster:admin/plugin/forecast/forecasters/get"
- "cluster:admin/plugin/forecast/forecasters/info"
- "cluster:admin/plugin/forecast/forecasters/search"
- "cluster:admin/plugin/forecast/result/topForecasts"
- "cluster:admin/plugin/forecast/tasks/search"
index_permissions:
- index_patterns:
- "opensearch-forecast-result*"
allowed_actions:
- "indices:admin/mappings/fields/get*"
- "indices:admin/resolve/index"
- "indices:data/read*"
# Allows users to use all Forecasting functionality
forecast_full_access:
reserved: true
cluster_permissions:
- "cluster:admin/plugin/forecast/*"
- "cluster:admin/settings/update"
- "cluster_monitor"
index_permissions:
- index_patterns:
- "*"
allowed_actions:
- "indices:admin/aliases/get"
- "indices:admin/mapping/get"
- "indices:admin/mapping/put"
- "indices:admin/mappings/fields/get*"
- "indices:admin/mappings/get"
- "indices:admin/resolve/index"
- "indices:data/read*"
- "indices:data/read/field_caps*"
- "indices:data/read/search"
- "indices:data/write*"
- "indices_monitor"
Copy the configuration below to a file and run kubectl apply -f <the-name-of-the-file>. Replace <the-name-of-the-file> with the actual name you gave the file.
The tenants.yml secret declaration
The tenants.yml file declares the tenants OpenSearch Security accepts. This configuration is helpful for isolating OpenSearch data from different groups of users, but defining tenants is not necessary unless you need to completely isolate data from groups of users. OpenSearch Dashboards enables multi-tenancy by default.
apiVersion: v1
kind: Secret
metadata:
name: opensearch-tenants-config
type: Opaque
stringData:
tenants.yml: |-
_meta:
type: "tenants"
config_version: 2
admin_tenant:
reserved: false
description: "Tenant for admin user"
Copy the configuration below to a file and run kubectl apply -f <the-name-of-the-file>. Replace <the-name-of-the-file> with the actual name you gave the file.
The Chart.yaml file
The Chart.yaml file defines a new Helm chart that deploys both OpenSearch and OpenSearch Dashboards through a single Helm run.
apiVersion: v2
name: OpenSearch
type: application
description: Deploy OpenSearch and OpenSearch Dashboards
version: 1.0.0 # The version of your Helm chart
dependencies:
- name: opensearch
version: 3.2.1 # Give the upstream Helm chart version you want to use
repository: https://opensearch-project.github.io/helm-charts/
- name: opensearch-dashboards
version: 3.2.1 # Give the upstream Helm chart version you want to use
repository: https://opensearch-project.github.io/helm-charts/
Create a folder and copy Chart.yaml into the folder. You will use this configuration later when running Helm.
The values.yaml file
The values.yaml file provides the configuration Helm will use to generate the Kubernetes configuration from the templates contained in the Helm charts. The following example values.yaml file has configuration for both OpenSearch and OpenSearch Dashboards. There are additional configuration options for the Helm charts. You can find the options listed on the repo for the OpenSearch Helm charts.
opensearch:
replicas: 3 # Create three OpenSearch pods in a StatefulSet
config:
opensearch.yml: |-
plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
plugins.security.ssl.transport.pemcert_filepath: ssl/tls.crt # Path to the node certificate. This should match the secretMount defined later in the values.yaml file
plugins.security.ssl.transport.pemkey_filepath: ssl/tls.key # Path to the node key. This should match the secretMount defined later in the values.yaml file
plugins.security.ssl.transport.pemtrustedcas_filepath: ssl/ca.crt # Path to the node CA certificate. This should match the secretMount defined later in the values.yaml file
plugins.security.ssl.http.pemcert_filepath: ssl/tls.crt # Path to the node certificate. This should match the secretMount defined later in the values.yaml file
plugins.security.ssl.http.pemkey_filepath: ssl/tls.key # Path to the node key. This should match the secretMount defined later in the values.yaml file
plugins.security.ssl.http.pemtrustedcas_filepath: ssl/ca.crt # Path to the node CA certificate. This should match the secretMount defined later in the values.yaml file
plugins.security.ssl.http.enabled: true # Enable HTTPS on REST API routes
plugins.security.allow_default_init_securityindex: false # Do not initialize default security settings if OpenSearch fails to load security settings on launch
plugins.security.audit.type: internal_opensearch
plugins.security.enable_snapshort_restore_privilege: true
plugins.security.check_snapshot_restore_write_privileges: true
plugins.security.system_indices.enabled: true
plugins.security.authcz.admin_dn: - 'CN=opensearch-cluster-admin' # Must match the name you set when making certificates
plugins.security.nodes_dn: - 'CN=opensearch-cluster-master\* # Must match the name you set when making certificates
extraEnvs:
- name: OPENSEARCH_INITIAL_ADMIN_PASSWORD
value: "your-admin-password-here" # Replace with a strong password
- name: "DISABLE_INSTALL_DEMO_CONFIG"
value: "true" # Stop OpenSearch Security from setting up demo certificates and users
resources: # Adjust resource requests to meet your needs
requests:
cpu: "1000m" # "1000m" is default upstream Helm chart config
memory: "2048Mi" # "100Mi" is the default upstream Helm chart config
securityConfig: # Give the Helm chart the path to opensearch-security config folder and the secrets to load for each config type
enabled: true
path: "/usr/share/opensearch/config/opensearch-security"
actionGroupsSecret: opensearch-action-groups-config
configSecret: opensearch-security-config
internalUsersSecret: opensearch-internal-users-config
rolesSecret: opensearch-roles-config
rolesMappingSecret: opensearch-roles-mapping-config
tenantsSecret: opensearch-tenants-config
secretMounts: # Mount the SSL/TLS certificates for the OpenSearch cluster traffic and for the admin client into the pod
- name: opensearch-ssl-certs
secretName: opensearch-cluster-tls
path: /usr/share/opensearch/config/ssl/
- name: opensearch-cluster-admin-cert
secretName: opensearch-cluster-admin-cert
path: /usr/share/openserach/config/admin-ssl/
opensearch-dashboards:
opensearchHosts: "https://opensearch-cluster-master:9200" # This is the default hostname of the cluster pods
replicaCount: 1
config:
opensearch_dashboards.yml: |-
server.host: 0.0.0.0
opensearch.hosts: ["https://opensearch-cluster-master:9200"] # This should be a domain name that resolves to OpenSearch pods in Kubernetes
opensearch.ssl.certificateAuthorities: [ "certs/ca.crt" ]
opensearch.username: "your-dashboard-server-username"
opensearch.password: "your-dashboard-username-password" # Enable verbose logging with the next two lines without a starting hash # logging.dest: stdout # logging.verbose: true
resources:
requests:
cpu: "200m"
memory: "4096Mi" # OpenSearch Dashboards ran out of memory, and I had memory kills for OpenSearch Dashboards with less memory than this
limits:
cpu: "200m"
memory: "4096Mi" # OpenSearch Dashboards ran out of memory, and I had memory kills for OpenSearch Dashboards with less memory than this
secretMount: # Mount the OpenSearch cluster SSL/TLS certificates for TLS between OpenSearch Dashboards and OpenSearch
- name: opensearch-ssl-certs
secretName: opensearch-cluster-tls
path: /usr/share/opensearch-dashboards/certs
Copy the configuration to the new directory you created with a name like values.yaml.
Deploying OpenSearch and OpenSearch Dashboards using Helm and all of the previous configuration
Build your chart's dependencies
Before you can install OpenSearch with Helm, you have to download the dependent Helm charts this deployment requires. If you copied the configuration to a local folder, you can run the following Helm command to download the dependencies Helm requires:
helm dependency build ./<your-folder-name>`
Helm will download the Helm charts for OpenSearch and OpenSearch Dashboards from the OpenSeach repos defined in the Chart.yaml file.
Deploy OpenSearch and OpenSearch Dashboards using Helm
At this point, if you have applied all the Kubernetes configuration for certificates and secrets, have downloaded the dependencies, and have copied the values.yaml file configuration, you should be ready to run Helm to deploy OpenSearch and OpenSearch Dashboards. Use the helm install command like in the following example:
helm install -f ./<your-directory-name>/values.yaml opensearch-cluster ./<your-directory-name>
When you run the install command, Helm will combine the values defined in your values.yaml file with the templates in the Helm charts to produce the configuration Kubernetes uses to deploy OpenSearch and OpenSearch Dashboards. You should be able to see the pods in your Kubernetes cluster (such as by running kubectl get pods).
Post-deployment steps
Run the securityadmin.sh script to apply the OpenSearch Security config
OpenSearch Security provides a script for applying the OpenSearch Security configuration to your cluster. You can run the script on the pod from where you run kubectl. The script requires several arguments to run:
1.-cacert: The path to the OpenSearch cluster root CA certificate 2.-cert: The path to the OpenSearch admin client SSL/TLS certificate 3.-key: The path to the OpenSearch admin client SSL/TLS certificate key 4.-h: The hostname address to use to connect to the OpenSearch cluster 5.-cn: The name of the OpenSearch cluster 6.-cd: The path to the OpenSearch Security configuration directory
Here is an example command running the securityadmin.sh script with the values and configuration from the examples from earlier in this post:
kubectl exec -it opensearch-cluster-master-0 -- ./plugins/opensearch-security/tools/securityadmin.sh \
-cacert ./config/admin-ssl/ca.crt \
-cert ./config/admin-ssl/tls.crt \
-key ./config/admin-ssl/tls.key \
-h opensearch-cluster-master-0 \
-cn opensearch-cluster \
-cd ./config/opensearch-security/
This command will use kubectl to execute the securityadmin.sh script on the pod named opensearch-cluster-master-0 at the path ./plugins/opensearch-security/tools/securityadmin.sh.