Skip to content

Commit b5aeed7

Browse files
authored
feat: Support optional anonymous authentication (opensearch-project#114)
* Add Anonymous auth for OpenSearch as an option Signed-off-by: Ashish Agrawal <ashisagr@amazon.com> * fix permissions Signed-off-by: Ashish Agrawal <ashisagr@amazon.com> * Clean up issues Signed-off-by: Ashish Agrawal <ashisagr@amazon.com> * resolve comments Signed-off-by: Ashish Agrawal <ashisagr@amazon.com> --------- Signed-off-by: Ashish Agrawal <ashisagr@amazon.com>
1 parent a826bb0 commit b5aeed7

13 files changed

Lines changed: 316 additions & 4 deletions

File tree

.env

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ OPENSEARCH_PORT=9200
2323
OPENSEARCH_PROTOCOL=https
2424
OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g
2525

26+
# Anonymous Authentication
27+
# Set to true to allow access to OpenSearch/Dashboards without login
28+
OPENSEARCH_ANONYMOUS_AUTH=false
29+
2630
# OpenSearch Dashboards Configuration
2731
OPENSEARCH_DASHBOARDS_VERSION=3.6.0
2832
OPENSEARCH_DASHBOARDS_HOST=opensearch-dashboards

AGENTS.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ OPENSEARCH_PASSWORD='My_password_123!@#'
205205
OPENSEARCH_HOST=opensearch
206206
OPENSEARCH_PORT=9200
207207
208+
# Anonymous Authentication
209+
# Set to true to allow access to OpenSearch/Dashboards without login
210+
OPENSEARCH_ANONYMOUS_AUTH_ENABLED=false
211+
208212
# OpenTelemetry Collector Configuration
209213
OTEL_COLLECTOR_VERSION=0.143.0
210214
OTEL_COLLECTOR_HOST=otel-collector
@@ -937,13 +941,31 @@ When modifying OpenSearch credentials:
937941

938942
Data Prepper uses a template (`pipelines.template.yaml`) with placeholders processed at container startup via `command:` in docker-compose.yml. No manual credential edits needed in pipeline configs.
939943

944+
### Anonymous Authentication
945+
946+
Anonymous auth is controlled by `OPENSEARCH_ANONYMOUS_AUTH_ENABLED` in `.env` (default: `false`). When enabled, users can access OpenSearch Dashboards without logging in.
947+
948+
The setting is injected at container startup via `sed` into two templates:
949+
- `docker-compose/opensearch/opensearch-security/config.template.yml` → OpenSearch security plugin config
950+
- `docker-compose/opensearch-dashboards/opensearch_dashboards.template.yml` → Dashboards config
951+
952+
Additionally, `savedObjects.permission.enabled` is conditionally set in the Dashboards config at container startup: `false` when anonymous auth is enabled (so anonymous users can access workspaces created by the init script), and `true` (the default) when anonymous auth is disabled. This version of OSD does not support per-workspace permission grants via the API, so without disabling this setting anonymous users get 403 on all workspace-scoped API calls.
953+
954+
The init script sets the `defaultWorkspace` UI setting after creating the Observability Stack workspace, so all users (including anonymous) land directly in the workspace instead of seeing a workspace picker.
955+
956+
Anonymous users can browse data, view, create, and modify saved objects (visualizations, dashboards, saved queries), explore traces and service maps, run queries, and access the REST API without credentials. They cannot delete existing saved objects or perform admin operations.
957+
958+
Modify access is required because Dashboards persists UI settings on every page load via `update` and `bulk` writes to its system indices. Without these permissions the page fails with 403 errors. Since UI settings and saved objects share the same indices, this also allows modification of existing saved objects.
959+
960+
**Important**: Toggling `OPENSEARCH_ANONYMOUS_AUTH_ENABLED` requires `docker compose down -v` (not just `restart`) because OpenSearch applies security configuration to an internal index on first startup. The `-v` flag removes all stored data (traces, logs, saved dashboards) to force reinitialization.
961+
940962
### Configuration File Locations
941963

942-
- **OpenSearch**: No custom config file - uses environment variables in docker-compose.yml
964+
- **OpenSearch**: Environment variables in docker-compose.yml + `docker-compose/opensearch/opensearch-security/config.template.yml` (anonymous auth injected at startup)
943965
- **OpenTelemetry Collector**: `docker-compose/otel-collector/config.yaml`
944966
- **Data Prepper**: `docker-compose/data-prepper/pipelines.template.yaml` (credentials injected at startup) and `docker-compose/data-prepper/data-prepper-config.yaml`
945967
- **Prometheus**: `docker-compose/prometheus/prometheus.yml`
946-
- **OpenSearch Dashboards**: `docker-compose/opensearch-dashboards/opensearch_dashboards.yml`
968+
- **OpenSearch Dashboards**: `docker-compose/opensearch-dashboards/opensearch_dashboards.template.yml` (credentials, anonymous auth, and `savedObjects.permission.enabled` injected at startup)
947969
- **Environment Variables**: `.env` file in repository root
948970

949971
### Index Management
@@ -967,6 +989,7 @@ When adding new services, consider adding health checks if they depend on other
967989

968990
Development configuration includes:
969991
- OpenSearch security enabled with default admin/admin credentials
992+
- Anonymous authentication disabled by default (enable via `OPENSEARCH_ANONYMOUS_AUTH_ENABLED=true` in `.env`)
970993
- SSL certificate verification disabled for development
971994
- CORS enabled for all origins
972995
- No network isolation

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,42 @@ The interactive installer prompts "Customize OpenSearch credentials?" — enter
310310

311311
**How it works:** `.env` is the single source of truth for credentials. OpenSearch, Dashboards, and the init script read from `.env` via environment variables. Data Prepper uses a [template](docker-compose/data-prepper/pipelines.template.yaml) with `OPENSEARCH_USER`/`OPENSEARCH_PASSWORD` placeholders that are injected via `sed` at container startup — no manual config edits needed. OpenSearch uses HTTPS with self-signed certificates, so use `-k` flag with curl commands.
312312

313+
### Anonymous Authentication
314+
315+
By default, OpenSearch Dashboards requires login with credentials. You can enable anonymous authentication to allow users to access Dashboards without a login prompt — useful for demos, workshops, or shared development environments.
316+
317+
**To enable anonymous access**, set in `.env`:
318+
```env
319+
OPENSEARCH_ANONYMOUS_AUTH_ENABLED=true
320+
```
321+
322+
Then restart the stack:
323+
```bash
324+
docker compose down -v
325+
docker compose up -d
326+
```
327+
328+
> **Warning:** The `-v` flag removes all stored data (traces, logs, saved dashboards). This is required because OpenSearch applies security configuration (roles, role mappings) to an internal index on first startup — restarting without `-v` won't update the security settings.
329+
330+
**What anonymous users can do:**
331+
- Browse and search all data (traces, logs, metrics)
332+
- View existing dashboards, visualizations, and saved queries
333+
- Create and modify visualizations, dashboards, saved queries, and index patterns
334+
- Explore trace analytics and service maps
335+
- Run PPL and SQL queries
336+
- Access the OpenSearch REST API without credentials (e.g., `curl -k https://localhost:9200/_cat/indices`)
337+
338+
**What anonymous users cannot do:**
339+
- Delete existing dashboards, visualizations, or saved objects
340+
- Write data to OpenSearch indices
341+
- Perform admin operations (cluster settings, security configuration, user management)
342+
343+
> **Why modify is allowed:** OpenSearch Dashboards requires `update` and `bulk` write permissions on its system indices to persist UI settings (theme, date format, default index) on every page load. Without these permissions the page fails with 403 "Unable to update UI setting" errors. Because UI settings and saved objects share the same system indices, granting the permissions Dashboards needs to function also allows modification of existing saved objects. Deletion is still blocked.
344+
345+
Admin operations still require full credentials. When disabled (the default), all users must authenticate via the login page.
346+
347+
**Toggling back to require login:** Set `OPENSEARCH_ANONYMOUS_AUTH_ENABLED=false` in `.env` and restart with `docker compose down -v && docker compose up -d`. Note that the `-v` flag removes all stored data (traces, logs, saved dashboards) — this is required because OpenSearch applies security configuration to an internal index on first startup.
348+
313349
## Resource Requirements
314350

315351
| Configuration | Memory Usage | Recommended Minimum |

docker-compose.local-opensearch-dashboards.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ services:
1717
pull_policy: always
1818
command: >
1919
/bin/bash -c "
20+
ANON_AUTH='${OPENSEARCH_ANONYMOUS_AUTH_ENABLED}';
21+
if [ \"$$ANON_AUTH\" != 'true' ]; then ANON_AUTH='false'; fi;
22+
if [ \"$$ANON_AUTH\" = 'true' ]; then SO_PERM='false'; else SO_PERM='true'; fi;
2023
cp /tmp/opensearch_dashboards.template.yml /tmp/opensearch_dashboards.yml &&
24+
sed -i 's|OPENSEARCH_ANONYMOUS_AUTH_ENABLED|'$$ANON_AUTH'|g' /tmp/opensearch_dashboards.yml &&
25+
sed -i 's|SAVED_OBJECTS_PERMISSION_ENABLED|'$$SO_PERM'|g' /tmp/opensearch_dashboards.yml &&
2126
sed -i 's|OPENSEARCH_HOSTS|${OPENSEARCH_PROTOCOL}://${OPENSEARCH_HOST}:${OPENSEARCH_PORT}|g' /tmp/opensearch_dashboards.yml &&
22-
sed -i 's|OPENSEARCH_USER|${OPENSEARCH_USER}|g' /tmp/opensearch_dashboards.yml &&
2327
sed -i 's|OPENSEARCH_PASSWORD|${OPENSEARCH_PASSWORD}|g' /tmp/opensearch_dashboards.yml &&
28+
sed -i 's|OPENSEARCH_USER|${OPENSEARCH_USER}|g' /tmp/opensearch_dashboards.yml &&
2429
cp /tmp/opensearch_dashboards.yml /usr/share/opensearch-dashboards/config/opensearch_dashboards.yml &&
2530
cd /usr/share/opensearch-dashboards &&
2631
exec ./opensearch-dashboards-docker-entrypoint.sh opensearch-dashboards"

docker-compose.local-opensearch.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,20 @@ services:
3030
# Initial admin password (required for OpenSearch 2.12+)
3131
- "OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_PASSWORD}"
3232
- plugins.query.datasources.encryption.masterkey=BTqK4Ytdz67La1kShIKV3Pu9
33+
command: >
34+
/bin/bash -c "
35+
ANON_AUTH='${OPENSEARCH_ANONYMOUS_AUTH_ENABLED}';
36+
if [ \"$$ANON_AUTH\" != 'true' ]; then ANON_AUTH='false'; fi;
37+
cp /tmp/opensearch-security/config.template.yml /usr/share/opensearch/config/opensearch-security/config.yml &&
38+
sed -i 's|OPENSEARCH_ANONYMOUS_AUTH_ENABLED|'$$ANON_AUTH'|g' /usr/share/opensearch/config/opensearch-security/config.yml &&
39+
exec ./opensearch-docker-entrypoint.sh"
3340
volumes:
3441
# Persist data across container restarts
3542
- opensearch-data:/usr/share/opensearch/data
43+
# Custom security config for anonymous authentication (template processed at startup)
44+
- ./docker-compose/opensearch/opensearch-security/config.template.yml:/tmp/opensearch-security/config.template.yml
45+
- ./docker-compose/opensearch/opensearch-security/roles.yml:/usr/share/opensearch/config/opensearch-security/roles.yml
46+
- ./docker-compose/opensearch/opensearch-security/roles_mapping.yml:/usr/share/opensearch/config/opensearch-security/roles_mapping.yml
3647
ports:
3748
# REST API endpoint
3849
- "${OPENSEARCH_PORT}:9200"

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ services:
181181
- OPENSEARCH_DASHBOARDS_PROTOCOL=${OPENSEARCH_DASHBOARDS_PROTOCOL}
182182
- PROMETHEUS_HOST=${PROMETHEUS_HOST}
183183
- PROMETHEUS_PORT=${PROMETHEUS_PORT}
184+
- OPENSEARCH_ANONYMOUS_AUTH_ENABLED=${OPENSEARCH_ANONYMOUS_AUTH_ENABLED}
184185
volumes:
185186
- ./docker-compose/opensearch-dashboards/init/init-opensearch-dashboards.py:/init.py
186187
- ./docker-compose/opensearch-dashboards/saved-queries-traces.yaml:/config/saved-queries-traces.yaml

docker-compose/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,30 @@ Then access your cloud Dashboards URL directly — no local container needed.
299299

300300
For production environments with valid certificates, enable verification in each of these places.
301301

302+
## Anonymous Authentication
303+
304+
By default, users must log in to access OpenSearch Dashboards. To skip the login page (useful for demos or workshops), enable anonymous authentication in `.env`:
305+
306+
```env
307+
OPENSEARCH_ANONYMOUS_AUTH_ENABLED=true
308+
```
309+
310+
Then restart:
311+
```bash
312+
docker compose down -v
313+
docker compose up -d
314+
```
315+
316+
> **Warning:** The `-v` flag removes all stored data (traces, logs, saved dashboards). This is required because OpenSearch applies security configuration (roles, role mappings) to an internal index on first startup. Without `-v`, the security settings are not reinitialized and the change won't take effect.
317+
318+
Anonymous users can browse all data, view, create, and modify saved objects (visualizations, dashboards, saved queries, index patterns), explore traces and service maps, run queries, and access the OpenSearch REST API without credentials. They cannot delete existing saved objects or perform admin operations — those still require credentials.
319+
320+
> **Note:** Modify access is required because OpenSearch Dashboards persists UI settings (theme, date format, default index) on every page load via `update` and `bulk` writes to its system indices. Without these permissions the page fails with 403 errors. Since UI settings and saved objects share the same indices, this also allows modification of existing saved objects. Deletion is still blocked.
321+
322+
Set `OPENSEARCH_ANONYMOUS_AUTH_ENABLED=false` (the default) to require login for all users. Restart with `docker compose down -v && docker compose up -d` to apply. Note that the `-v` flag removes all stored data (traces, logs, saved dashboards) — this is required because OpenSearch applies security configuration to an internal index on first startup.
323+
324+
**Troubleshooting:** If toggling `OPENSEARCH_ANONYMOUS_AUTH_ENABLED` doesn't take effect, make sure you used `docker compose down -v` (not just `docker compose restart` or `docker compose down` without `-v`). The `-v` flag is required to reinitialize OpenSearch's security configuration.
325+
302326
## Security Warning
303327

304328
⚠️ **This configuration is for development only!**
@@ -308,13 +332,15 @@ Security considerations:
308332
- SSL certificate verification is disabled for development ease
309333
- Permissive CORS settings
310334
- No network isolation between services
335+
- Anonymous authentication is disabled by default (enable via `OPENSEARCH_ANONYMOUS_AUTH_ENABLED=true` in `.env`)
311336

312337
For production use:
313338
- Change default passwords
314339
- Enable proper SSL/TLS with valid certificates
315340
- Configure proper authentication and authorization
316341
- Implement network policies
317342
- Review and harden all security settings
343+
- Keep anonymous authentication disabled
318344

319345
Never use this configuration in production without proper hardening.
320346

docker-compose/opensearch-dashboards/init/init-opensearch-dashboards.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
PROMETHEUS_PORT = os.getenv("PROMETHEUS_PORT", "9090")
1616
_opensearch_protocol = os.getenv("OPENSEARCH_PROTOCOL", "https")
1717
OPENSEARCH_ENDPOINT = f"{_opensearch_protocol}://{os.getenv('OPENSEARCH_HOST', 'opensearch')}:{os.getenv('OPENSEARCH_PORT', '9200')}"
18+
ANONYMOUS_AUTH_ENABLED = os.getenv("OPENSEARCH_ANONYMOUS_AUTH_ENABLED", "false").lower() == "true"
1819

1920
def wait_for_dashboards():
2021
"""Wait for OpenSearch Dashboards to be ready"""
@@ -232,7 +233,7 @@ def create_prometheus_datasource(workspace_id):
232233

233234
payload = {
234235
"name": datasource_name,
235-
"allowedRoles": [],
236+
"allowedRoles": ["all_access", "opendistro_security_anonymous_role"] if ANONYMOUS_AUTH_ENABLED else ["all_access"],
236237
"connector": "prometheus",
237238
"properties": {
238239
"prometheus.uri": prometheus_endpoint,
@@ -427,6 +428,45 @@ def create_opensearch_datasource(workspace_id):
427428
return None
428429

429430

431+
def set_default_workspace(workspace_id):
432+
"""Set the default workspace so all users land here on login.
433+
434+
When workspace.enabled is true, users see a workspace picker on first load.
435+
Setting defaultWorkspace directs all users (including anonymous) straight
436+
to the Observability Stack workspace instead.
437+
438+
Returns True on success, False on failure or skip.
439+
"""
440+
if not workspace_id or workspace_id == "default":
441+
print("⏭️ Skipping default workspace (using default)")
442+
return False
443+
444+
print(f"⭐ Setting default workspace: {workspace_id}")
445+
446+
url = f"{BASE_URL}/api/opensearch-dashboards/settings"
447+
payload = {"changes": {"defaultWorkspace": workspace_id}}
448+
449+
try:
450+
response = requests.post(
451+
url,
452+
auth=(USERNAME, PASSWORD),
453+
headers={"Content-Type": "application/json", "osd-xsrf": "true"},
454+
json=payload,
455+
verify=False,
456+
timeout=10,
457+
)
458+
459+
if response.status_code == 200:
460+
print("✅ Default workspace set")
461+
return True
462+
else:
463+
print(f"⚠️ Failed to set default workspace: {response.status_code} {response.text}")
464+
return False
465+
except requests.exceptions.RequestException as e:
466+
print(f"⚠️ Error setting default workspace: {e}")
467+
return False
468+
469+
430470
def set_default_index_pattern(workspace_id, pattern_id):
431471
"""Set the default index pattern"""
432472
print(f"⭐ Setting default index pattern: {pattern_id}")
@@ -1253,6 +1293,9 @@ def main():
12531293
else:
12541294
workspace_id = create_workspace()
12551295

1296+
# Direct all users (including anonymous) to this workspace on login
1297+
set_default_workspace(workspace_id)
1298+
12561299
# Create index patterns (idempotent - will skip if already exist)
12571300
# Titles must match exactly what the APM plugin expects
12581301
logs_schema_mappings = '{"otelLogs":{"timestamp":"time","traceId":"traceId","spanId":"spanId","serviceName":"resource.attributes.service.name"}}'

docker-compose/opensearch-dashboards/opensearch_dashboards.template.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ opensearch.pingTimeout: 3000
3131
# Allow requests from any origin for development
3232
opensearch.requestHeadersAllowlist: [authorization, securitytenant]
3333

34+
# Anonymous authentication - skip login page for browse access
35+
# Anonymous users can view all data and create/modify saved objects (visualizations, dashboards, saved queries)
36+
# but cannot delete existing saved objects or perform admin operations
37+
# Modify access is required — Dashboards persists UI settings via update/bulk writes on page load
38+
# Set OPENSEARCH_ANONYMOUS_AUTH_ENABLED=true in .env to enable
39+
opensearch_security.auth.anonymous_auth_enabled: OPENSEARCH_ANONYMOUS_AUTH_ENABLED
40+
3441
# Multi-tenancy configuration
3542
# Disabled for simpler development setup
3643
opensearch_security.multitenancy.enabled: false
@@ -79,6 +86,14 @@ explore.discoverTraces.enabled: true
7986
explore.discoverMetrics.enabled: true
8087
explore.agentTraces.enabled: true
8188
workspace.enabled: true
89+
# Saved-object-level permission checks.
90+
# When anonymous auth is enabled, this must be false so anonymous users can access
91+
# workspaces created by the init script. Without this, only the workspace owner (admin)
92+
# can access workspace-scoped API calls — anonymous users get 403.
93+
# This version of OSD does not support per-workspace permission grants via the API.
94+
# When anonymous auth is disabled, this is true (default) to preserve workspace permissions.
95+
# Value is computed at container startup from OPENSEARCH_ANONYMOUS_AUTH_ENABLED.
96+
savedObjects.permission.enabled: SAVED_OBJECTS_PERMISSION_ENABLED
8297
data_source.enabled: true
8398
data_source.ssl.verificationMode: none
8499
datasetManagement.enabled: true
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# OpenSearch Security Plugin Configuration
2+
# Controls anonymous authentication for OpenSearch Dashboards access without login
3+
# Set OPENSEARCH_ANONYMOUS_AUTH_ENABLED=true in .env to enable
4+
# NOTE: Applying partial config.yml is not supported. Must include entire default config.
5+
# Only anonymous_auth_enabled and basic_internal_auth_domain are active;
6+
# unused auth domains (kerberos, proxy, JWT, client cert, LDAP) have been removed.
7+
8+
_meta:
9+
type: "config"
10+
config_version: 2
11+
config:
12+
dynamic:
13+
http:
14+
anonymous_auth_enabled: OPENSEARCH_ANONYMOUS_AUTH_ENABLED
15+
xff:
16+
enabled: false
17+
internalProxies: "192\\.168\\.0\\.10|192\\.168\\.0\\.11"
18+
authc:
19+
basic_internal_auth_domain:
20+
description: "Authenticate via HTTP Basic against internal users database"
21+
http_enabled: true
22+
transport_enabled: true
23+
order: 4
24+
http_authenticator:
25+
type: "basic"
26+
challenge: true
27+
authentication_backend:
28+
type: "intern"

0 commit comments

Comments
 (0)