Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):
Using latest tag for all images in docker-compose.
OpenSearch/Dasboard 2.11.0
Nginx 1.25.2
Describe the issue:
I am trying to setup basic docker-compose of OpenSearch dashboards, which uses single node and Nginx as proxy,
and to use proxy based authentication.
Setup is based on Proxy-based authentication - OpenSearch documentation
First step that I did was to create docker-compose which works, where I can access OpenSearch dashboards
directly through port 5061, or via nginx proxy on port 8090. I used following docker-compose file, with only difference
that volume sections were commented-out (except for nginx configuration):
version: '3'
services:
opensearch:
image: opensearchproject/opensearch:latest
container_name: opensearch
environment:
- discovery.type=single-node
- OPENSEARCH_SECURITY_DISABLED=false # Temporarily, we'll disable security for simplicity.
ports:
- 9200:9200
- 9600:9600
networks:
- opensearch-net
volumes:
- ./config.yml:/usr/share/opensearch/config/opensearch-security/config.yml # Mounts the security configuration file to the container
opensearch-dashboards:
image: opensearchproject/opensearch-dashboards:latest
container_name: opensearch-dashboards
ports:
- 5601:5601
environment:
OPENSEARCH_HOSTS: 'https://opensearch:9200'
networks:
- opensearch-net
volumes:
- ./opensearch_dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml # Mount the configuration file to the container
nginx:
image: nginx:latest
container_name: nginx-proxy
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- 80:80
- 8090:8090
networks:
- opensearch-net
networks:
opensearch-net:
Everything works well, I was able to access dashboards both directly on 5601 or via proxy on 8090, of course with login screen.
Now next step was to add config.yml and opensearch_dashboards.yml, which I did by binding them as shown in docker-compose.yml file.
Content of config files is given in section below.
Configuration:
Content of config files is the following:
config.yml:
_meta:
type: "config"
config_version: 2
config:
dynamic:
http:
anonymous_auth_enabled: false
xff:
enabled: true
remoteIpHeader: "x-forwarded-for"
internalProxies: opensearch-dashboards
authc:
basic_internal_auth_domain:
description: "Authenticate via HTTP Basic against internal users database"
http_enabled: true
transport_enabled: true
order: 4
http_authenticator:
type: basic
challenge: true
authentication_backend:
type: intern
proxy_auth_domain:
description: "Authenticate via proxy"
http_enabled: true
transport_enabled: true
order: 0
http_authenticator:
type: proxy
challenge: false
config:
user_header: "x-proxy-user"
roles_header: "x-proxy-roles"
authentication_backend:
type: noop
opensearch_dashbards.yml
opensearch.hosts: [https://opensearch:9200]
opensearch.ssl.verificationMode: none
opensearch.username: kibanaserver
opensearch.password: kibanaserver
#opensearch.requestHeadersWhitelist: [authorization, securitytenant]
opensearch.requestHeadersAllowlist: ["securitytenant","Authorization","x-forwarded-for","x-proxy-user","x-proxy-roles"]
opensearch_security.auth.type: "proxy"
opensearch_security.proxycache.user_header: "x-proxy-user"
opensearch_security.proxycache.roles_header: "x-proxy-roles"
opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.readonly_mode.roles: [kibana_read_only]
# Use this setting if you are running opensearch-dashboards without https
opensearch_security.cookie.secure: false
server.host: '0.0.0.0'
Relevant Logs or Screenshots:
When accessing via browser, url:, response is:
{"statusCode":401,"error":"Unauthorized","message":"Authentication Exception"}
In log, following entry appears:
e[36mnginx-proxy |e[0m 192.168.208.1 - - [20/Oct/2023:07:54:12 +0000] "GET / HTTP/1.1" 401 78 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-"
e[32mopensearch-dashboards |e[0m {"type":"response","@timestamp":"2023-10-20T07:54:12Z","tags":[],"pid":1,"method":"get","statusCode":401,"req":{"url":"/","method":"get","headers":{"x-forwarded-for":"192.168.208.1","x-proxy-user":"kibanaro","x-proxy-roles":"kibanauser,readall","host":"opensearchdash","connection":"close","cache-control":"max-age=0","sec-ch-ua":"\"Google Chrome\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","sec-fetch-site":"none","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9,sr-RS;q=0.8,sr;q=0.7"},"remoteAddress":"192.168.208.4","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"},"res":{"statusCode":401,"responseTime":43,"contentLength":9},"message":"GET / 401 43ms - 9.0B"}
e[36mnginx-proxy |e[0m 192.168.208.1 - - [20/Oct/2023:07:54:12 +0000] "GET /favicon.ico HTTP/1.1" 401 78 "http://localhost:8090/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-"
e[32mopensearch-dashboards |e[0m {"type":"response","@timestamp":"2023-10-20T07:54:12Z","tags":[],"pid":1,"method":"get","statusCode":401,"req":{"url":"/favicon.ico","method":"get","headers":{"x-forwarded-for":"192.168.208.1","x-proxy-user":"kibanaro","x-proxy-roles":"kibanauser,readall","host":"opensearchdash","connection":"close","sec-ch-ua":"\"Google Chrome\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","sec-ch-ua-platform":"\"Windows\"","accept":"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8","sec-fetch-site":"same-origin","sec-fetch-mode":"no-cors","sec-fetch-dest":"image","referer":"http://localhost:8090/","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9,sr-RS;q=0.8,sr;q=0.7"},"remoteAddress":"192.168.208.4","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36","referer":"http://localhost:8090/"},"res":{"statusCode":401,"responseTime":5,"contentLength":9},"message":"GET /favicon.ico 401 5ms - 9.0B"}
It seems that all relevant headers are passed by Nignx, but 401 response appears every time.
Any idea why this does not work?