Access an Elasticsearch server using Tailscale PAM
Tailscale PAM lets users connect to Elasticsearch using their Tailscale identity instead of sharing Elasticsearch credentials.
You can control who has access to the Elasticsearch server and keep an audit trail of sessions and queries. Users can continue using familiar tools such as curl or other Elasticsearch-compatible clients.
This guide walks you through creating an Elasticsearch PAM service, connecting to it, and reviewing the resulting session activity.
Prerequisites
Before you begin, confirm you have the following:
- A Tailscale PAM connector that is installed, online, and able to reach the Elasticsearch server.
- Tailscale installed and signed in on the device you'll use to connect.
- An Elasticsearch server that the connector can reach.
- Permission to update your tailnet policy file.
You can use your own Elasticsearch server or run a local Elasticsearch server with Docker.
If you're using your own Elasticsearch server, you'll need its hostname or IP address, port, username, and password.
Run a local Elasticsearch server with Docker
If you're using your own Elasticsearch server or the Tailscale PAM sandbox, skip to the next step.
For a quick local test, start a single-node Elasticsearch server with Docker:
docker run --name tailscale-pam-elasticsearch --rm \
-d -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e "ELASTIC_PASSWORD=<your-database-password>" \
docker.elastic.co/elasticsearch/elasticsearch:9.4.4
Replace <your-database-password> with a password of your choice.
Elastic publishes its Elasticsearch Docker images in the Elastic container registry. This example uses Elasticsearch 9.4.4.
This starts a single-node Elasticsearch server with the elastic user and the value you used for <your-database-password> as the password.
Before continuing, verify that you can connect to it:
curl -k -u elastic:<your-database-password> https://localhost:9200
If Elasticsearch returns information about the cluster, the server is ready.
If the Tailscale PAM connector runs on the same device as Docker, you can use localhost and port 9200 when you configure the PAM service. If the connector runs somewhere else, use an IP address or hostname that the connector can reach.
Create an Elasticsearch PAM service
To create a PAM service for your Elasticsearch server:
-
Open the Services page of the Tailscale admin console.
-
Select Add service.
-
Select PAM service.
-
Select Elasticsearch.
-
Select Continue.
-
Provide a name for your service.
Use a name that will make the database suitable for users to recognize when they browse the services they can access.
-
(Optional) Provide a display name for the service.
-
(Optional) Provide a description for the service.
-
Choose whether the Session Recording option is enabled or disabled.
-
Select the Tailscale PAM connector that can reach your Elasticsearch server.
-
Select Continue.
-
For Upstream hostname, enter the hostname or IP address of the Elasticsearch server.
-
For Port, enter the Elasticsearch port. The default is
9200. -
For Protocol, select HTTP or HTTPS.
-
For Authentication type, select Basic Auth.
Tailscale PAM currently uses HTTP Basic authentication for the upstream Elasticsearch connection.
If you used the local Docker example and the connector runs on the same device, use
localhost, port9200, usernameelastic, andyour-database-password.If you're using your own Elasticsearch server, enter the connection details and credentials for that server.
-
For Username, enter the username Tailscale PAM should use to connect to Elasticsearch.
-
For Password, enter the password for that user.
-
Select Save.
Your database service has been created. You can access it in the Services page.
Grant access to the Elasticsearch service
Before users can connect, make sure a Tailscale PAM grant gives them access to the service. For example, the following grant permits any source to connect to PAM database services:
"grants": [
{
"src": ["*"],
"dst": ["*"],
"ip": ["*"],
"app": {
"tailscale.com/cap/pam": [
{
"version": "v1",
"permissions": {
"database": {}
}
}
]
}
}
]
This is a broad grant that's useful for getting started. In a production environment, you can restrict the src and dst fields to control which users, groups, devices, or tags can access specific services.
Unlike MySQL and PostgreSQL PAM services, Elasticsearch services don't currently support query-level authorization or index-specific restrictions in Tailscale PAM. Once a user has access to the service, Tailscale PAM doesn't restrict which Elasticsearch queries they can submit or which indices they can access.
To limit what users can do after connecting, configure the upstream Elasticsearch user with the appropriate Elasticsearch roles and index privileges.
For more information about controlling access to PAM services, refer to Control access to Tailscale PAM services.
For information about editing grants, refer to Edit access control policies in your tailnet policy file.
You can use the visual policy editor to manage your tailnet policy file. Refer to the visual editor reference for guidance on using the visual editor.
Connect to the Elasticsearch server
The primary way to connect is through the Tailscale client and then use curl or your preferred Elasticsearch-compatible client.
Connect with your preferred Elasticsearch client
Use the Tailscale client to quickly open the database with an Elasticsearch client already installed on your device.
- Open the Tailscale client.
- Select Services.
- Select your Elasticsearch service.
- Use the name of the service as the hostname in your Elasticsearch client.
For example, you can connect with curl:
curl http://<service-name>:9200
Replace <service-name> with the name of your Elasticsearch PAM service.
You don't need to provide the upstream Elasticsearch username or password. Tailscale PAM uses your Tailscale identity to authorize the connection and manages the upstream Elasticsearch authentication on your behalf.
For example, you can add a document:
curl -X POST "http://<service-name>:9200/my_index/_doc/1" \
-H "Content-Type: application/json" \
-d '{
"title": "Hello World",
"content": "Elasticsearch is cool!"
}'
Then query the index:
curl "http://<service-name>:9200/my_index/_search?q=title:Hello"
Use http:// when connecting to the Elasticsearch PAM service. Traffic between your device and the Tailscale PAM connector is protected by WireGuard, so you don't need to use HTTPS for the client-side connection to the PAM service.
Connect from the browser
Because Elasticsearch exposes an HTTP API, you can also make basic requests directly from a browser on a device connected to Tailscale.
For example, open http://<service-name>:9200.
For querying, indexing, and other API operations, use curl or another Elasticsearch-compatible client.
Secure the upstream credentials
In the example above, the upstream Elasticsearch username and password are stored as part of the PAM service configuration. Tailscale stores these credentials in encrypted form, but for production environments we recommend keeping upstream credentials local to the connector whenever possible.
You can configure the connector to load credentials dynamically from a supported secret source instead of storing the credentials directly in the service configuration. For example, you can load credentials from an environment variable, a local file, or a secrets management system.
For more information, refer to Manage secrets and credentials.
Because Tailscale PAM doesn't currently enforce query-level or index-specific permissions for Elasticsearch, consider using a dedicated upstream Elasticsearch user instead of a highly privileged account. Use Elasticsearch roles to give that user access only to the indices and operations it needs.
Review session details and recordings
Tailscale PAM gives you visibility into connections to your Elasticsearch service.
Open the Sessions page of the admin console, then select a session for your Elasticsearch service. You can review information such as:
- The Tailscale identity that connected.
- The originating device.
- The connection time.
- The service that was accessed.
When session recording is enabled, you can also review the Elasticsearch queries for the session.
This gives you a direct answer to two useful questions: who accessed the Elasticsearch server, and what did they do while they were there?
Troubleshooting
If you can't connect to your Elasticsearch service, the most common issue is that the connector can't connect to the upstream Elasticsearch server.
First, confirm that the connector is online and can reach the Elasticsearch hostname and port. Also verify that the username and password in the service configuration are valid.
If you're using the Docker example, remember that localhost refers to the device running the connector. If your connector runs on a different device, use a hostname or IP address that is reachable from that device.
You can also test connectivity to the upstream server directly from the device running the connector. For the Docker example:
curl -k -u elastic:<your-database-password> https://localhost:9200
If none of the troubleshooting steps mentioned above resolve your issue, review the connector logs and the details for the failed session in the PAM session logs. Failed sessions often include information about why the connection couldn't be established, which can help narrow down whether the problem is network connectivity, authentication, or the upstream Elasticsearch server itself.