Hi,
I was able to configure a docker setup of the ELK stack behind oauth2_proxy and nginx using search-guard as a authentication medium. Once a user is authenticated they are forwarded to kibana correctly. However it seems all users are assigned the internal kibana user and its associated role. I would like to be able to assign a user as an admin role, which to my understanding is done using the sg_roles_mapping.yml file, but it does not appear to be working correctly. I can see the headers are passed to Kibana but elasticsearch does not reflect this. I’d really appreciate any help. Thanks
nginx.conf
http {
server {
listen ${NGINX_PORT};
server_name localhost;
location ${BASE_PATH} {
proxy_pass http://kibana:5601/;
proxy_set_header Authorization "Basic ${DIGEST}";
proxy_set_header es-security-runas-user ${DOLLAR}http_x_forwarded_user;
proxy_set_header x-proxy-user ${DOLLAR}http_x_forwarded_user;
proxy_set_header x-proxy-roles user ${DOLLAR}http_x_forwarded_user;
rewrite /login http://localhost:4180/oauth2/sign_in redirect;
}
}
}
events {
worker_connections 1024;
}
Elastic search log entry
elasticsearch_1 | [2018-01-30T15:54:47,853][INFO ][c.f.s.c.PrivilegesEvaluator] No cluster-level perm match for User[name=kibana, roles=[kibana_user], requestedTenant=null] [IndexType [index=.kibana, type=*]] [Action [[indices:admin/template/put]]] [RolesChecked [kibana_user]]
elasticsearch_1 | [2018-01-30T15:54:47,854][INFO ][c.f.s.c.PrivilegesEvaluator] No permissions for {}
Kibana Log Entry
kibana_1 | {"type":"response","@timestamp":"2018-01-30T15:54:47Z","tags":[],"pid":28,"method":"post","statusCode":503,"req":{"url":"/api/saved_objects/index-pattern?overwrite=false","method":"post","headers":{"es-security-runas-user":"user_name","x-proxy-user":"user_name","x-proxy-roles":"admin","host":"kibana:5601","connection":"close","content-length":"66","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36","accept":"application/json, text/plain, */*","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9","content-type":"application/json;charset=UTF-8","kbn-version":"6.1.1","origin":"http://localhost:4180","referer":"http://localhost:4180/kibana/app/kibana","x-forwarded-email":"em...@email.com","x-forwarded-for":"172.19.0.1","x-forwarded-user":"user_name"},"remoteAddress":"172.19.0.2","userAgent":"172.19.0.2","referer":"http://localhost:4180/kibana/app/kibana"},"res":{"statusCode":503,"responseTime":32,"contentLength":9},"message":"POST /api/saved_objects/index-pattern?overwrite=false 503 32ms - 9.0B"}
sg_config.yml
searchguard:
dynamic:
http:
anonymous_auth_enabled: false
xff:
enabled: true
internalProxies: '.*'
remoteIpHeader: 'x-forwarded-for'
proxiesHeader: 'x-forwarded-by'
proxy_auth_domain:
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
authc:
basic_internal_auth:
enabled: true
order: 1
http_authenticator:
type: basic
challenge: true
authentication_backend:
type: internal
sg_roles_mapping.yml
admin:
backendroles:
- admin
host:
- "*"
users:
- elastic
- user_name
kibana_user:
backendroles:
- kibana_user
host:
- "*"
users:
- kibana
logstash_user:
backendroles:
- logstash_user
host:
- "*"
users:
- logstash
beats_user:
backendroles:
- beats_user
host:
- "*"
users:
- beats
sg_action_group.yml
# INDICES
READ:
- "indices:data/read*"
WRITE:
- "indices:data/write*"
CRUD:
- READ
- WRITE
CREATE_INDEX:
- "indices:admin/create*"
- "indices:admin/mapping/put"
DELETE_INDEX:
- "indices:admin/delete*"
INDEX_OWNER:
- CREATE_INDEX
- CRUD
INDEX_ALL:
- "indices:*"
# ELASTICSEARCH ENTRYPOINT
GET_TEMPLATE:
- "indices:admin/template/get"
PUT_TEMPLATE:
- "indices:admin/template/put"
TEMPLATE_OWNER:
- GET_TEMPLATE
- PUT_TEMPLATE
ES_INPUT:
- TEMPLATE_OWNER
- WRITE
- MONITOR
# MONITORING
MONITOR:
- "cluster:monitor*"
# SUPER POWERS
ALL:
- "*"
Search Guard: "20.1"
ElasticSearch:6.1.1
When asking questions, please provide the following information:
Hi,
I was able to configure a docker setup of the ELK stack behind oauth2_proxy and nginx using search-guard as a authentication medium. Once a user is authenticated they are forwarded to kibana correctly. However it seems all users are assigned the internal kibana user and its associated role. I would like to be able to assign a user as an admin role, which to my understanding is done using the sg_roles_mapping.yml file, but it does not appear to be working correctly. I can see the headers are passed to Kibana but elasticsearch does not reflect this. I’d really appreciate any help. Thanks
nginx.conf
http {
server {
listen ${NGINX_PORT};
server_name localhost;
location ${BASE_PATH} {
proxy_pass http://kibana:5601/;
proxy_set_header Authorization "Basic ${DIGEST}";
proxy_set_header es-security-runas-user ${DOLLAR}http_x_forwarded_user;
proxy_set_header x-proxy-user ${DOLLAR}http_x_forwarded_user;
proxy_set_header x-proxy-roles user ${DOLLAR}http_x_forwarded_user;
rewrite /login http://localhost:4180/oauth2/sign_in redirect;
}
}
}
events {
worker_connections 1024;
}
Elastic search log entry
elasticsearch_1 | [2018-01-30T15:54:47,853][INFO ][c.f.s.c.PrivilegesEvaluator] No cluster-level perm match for User[name=kibana, roles=[kibana_user], requestedTenant=null] [IndexType [index=.kibana, type=*]] [Action [[indices:admin/template/put]]] [RolesChecked [kibana_user]]
elasticsearch_1 | [2018-01-30T15:54:47,854][INFO ][c.f.s.c.PrivilegesEvaluator] No permissions for {}
Kibana Log Entry
kibana_1 | {"type":"response","@timestamp":"2018-01-30T15:54:47Z","tags":[],"pid":28,"method":"post","statusCode":503,"req":{"url":"/api/saved_objects/index-pattern?overwrite=false","method":"post","headers":{"es-security-runas-user":"user_name","x-proxy-user":"user_name","x-proxy-roles":"admin","host":"kibana:5601","connection":"close","content-length":"66","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36","accept":"application/json, text/plain, */*","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9","content-type":"application/json;charset=UTF-8","kbn-version":"6.1.1","origin":"http://localhost:4180","referer":"http://localhost:4180/kibana/app/kibana","x-forwarded-email":"email@email.com","x-forwarded-for":"172.19.0.1","x-forwarded-user":"user_name"},"remoteAddress":"172.19.0.2","userAgent":"172.19.0.2","referer":"http://localhost:4180/kibana/app/kibana"},"res":{"statusCode":503,"responseTime":32,"contentLength":9},"message":"POST /api/saved_objects/index-pattern?overwrite=false 503 32ms - 9.0B"}
# When this setting...s value is true Kibana uses the hostname specified in the server.host
# setting. When the value of this setting is false, Kibana uses the hostname of the host
# that connects to this Kibana instance.
#elasticsearch.preserveHost: true
# Kibana uses an index in Elasticsearch to store saved searches, visualizations and
# dashboards. Kibana creates a new index if the index doesn...t already exist.
#kibana.index: ".kibana"
# The default application to load.
#kibana.defaultAppId: "discover"
# Kibana is served by a back end server. This setting specifies the port to use.
server.port: 5601
# Specifies the address to which the Kibana server will bind. IP addresses and host names are both valid values.
# The default is 'localhost', which usually means remote machines will not be able to connect.
# To allow connections from remote users, set this parameter to a non-loopback address.
server.host: 0.0.0.0
# Enables you to specify a path to mount Kibana at if you are running behind a proxy. This only affects
# the URLs generated by Kibana, your proxy is expected to remove the basePath value before forwarding requests
# to Kibana. This setting cannot end in a slash.
server.basePath: /kibana
# The maximum payload size in bytes for incoming server requests.
#server.maxPayloadBytes: 1048576
# The Kibana server's name. This is used for display purposes.
#server.name: "your-hostname"
# The URL of the Elasticsearch instance to use for all your queries.
elasticsearch.url: http://elasticsearch:9200
# If your Elasticsearch is protected with basic authentication, these settings provide
# the username and password that the Kibana server uses to perform maintenance on the Kibana
# index at startup. Your Kibana users still need to authenticate with Elasticsearch, which
# is proxied through the Kibana server.
elasticsearch.username: "kibana"
elasticsearch.password: changeme
searchguard.cookie.password: "4fjNPloEVvrVj28BsVh3jI8t3pmv7Qg6"
# Paths to the PEM-format SSL certificate and SSL key files, respectively. These
# files enable SSL for outgoing requests from the Kibana server to the browser.
#server.ssl.cert: /path/to/your/server.crt
#server.ssl.key: /path/to/your/server.key
# Optional settings that provide the paths to the PEM-format SSL certificate and key files.
# These files validate that your Elasticsearch backend uses the same key files.
#elasticsearch.ssl.cert: /path/to/your/client.crt
#elasticsearch.ssl.key: /path/to/your/client.key
# Optional setting that enables you to specify a path to the PEM file for the certificate
# authority for your Elasticsearch instance.
elasticsearch.ssl.certificateAuthorities: /etc/elasticsearch/searchguard/ssl/ca/root-ca.pem
# To disregard the validity of SSL certificates, change this setting...s value to false.
elasticsearch.ssl.verificationMode: "certificate"
# Time in milliseconds to wait for Elasticsearch to respond to pings. Defaults to the value of
# the elasticsearch.requestTimeout setting.
#elasticsearch.pingTimeout: 1500
# Time in milliseconds to wait for responses from the back end or Elasticsearch. This value
# must be a positive integer.
#elasticsearch.requestTimeout: 30000
# List of Kibana client-side headers to send to Elasticsearch. To send *no* client-side
# headers, set this value to [] (an empty list).
elasticsearch.requestHeadersWhitelist: [ "authorization", "x-forwarded-for", "x-forwarded-by", "x-proxy-user", "x-proxy-roles" ]
searchguard.basicauth.enabled: false
# Header names and values that are sent to Elasticsearch. Any custom headers cannot be overwritten
# by client-side headers, regardless of the elasticsearch.requestHeadersWhitelist configuration.
#elasticsearch.customHeaders: {}
# Time in milliseconds for Elasticsearch to wait for responses from shards. Set to 0 to disable.
#elasticsearch.shardTimeout: 0
# Time in milliseconds to wait for Elasticsearch at Kibana startup before retrying.
#elasticsearch.startupTimeout: 5000
# Specifies the path where Kibana creates the process ID file.
#pid.file: /var/run/kibana.pid
# Enables you specify a file where Kibana stores log output.
#logging.dest: stdout
# Set the value of this setting to true to suppress all logging output.
#logging.silent: false
# Set the value of this setting to true to suppress all logging output other than error messages.
#logging.quiet: false
# Set the value of this setting to true to log all events, including system usage information
# and all requests.
#logging.verbose: false
# Set the interval in milliseconds to sample system and process performance
# metrics. Minimum is 100ms. Defaults to 5000.
#ops.interval: 5000
kibana_1 | {"type":"response","@timestamp":"2018-01-30T15:54:47Z","tags":[],"pid":28,"method":"post","statusCode":503,"req":{"url":"/api/saved_objects/index-pattern?overwrite=false","method":"post","headers":{"es-security-runas-user":"user_name","x-proxy-user":"user_name","x-proxy-roles":"admin","host":"kibana:5601","connection":"close","content-length":"66","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36","accept":"application/json, text/plain, */*","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9","content-type":"application/json;charset=UTF-8","kbn-version":"6.1.1","origin":"http://localhost:4180","referer":"http://localhost:4180/kibana/app/kibana","x-forwarded-email":"em...@email.com","x-forwarded-for":"172.19.0.1","x-forwarded-user":"user_name"},"remoteAddress":"172.19.0.2","userAgent":"172.19.0.2","referer":"http://localhost:4180/kibana/app/kibana"},"res":{"statusCode":503,"responseTime":32,"contentLength":9},"message":"POST /api/saved_objects/index-pattern?overwrite=false 503 32ms - 9.0B"}
Using the curl command I can clearly see the test user I’ve created is authenticating correctly, Please see below
bash-4.4# curl -sS http://elasticsearch:9200/_searchguard/authinfo -v -H "x-proxy-user: USERNAME" -H "x-proxy-roles: ROLE" -H "x-forwarded-for: 127.0.0.1"
* Trying 172.22.0.5...
* TCP_NODELAY set
* Connected to elasticsearch (172.22.0.5) port 9200 (#0)
> GET /_searchguard/authinfo HTTP/1.1
> Host: elasticsearch:9200
> User-Agent: curl/7.57.0
> Accept: */*
> x-proxy-user: USERNAME
> x-proxy-roles: ROLE
> x-forwarded-for: 127.0.0.1
>
< HTTP/1.1 200 OK
< content-type: application/json; charset=UTF-8
< content-length: 287
<
* Connection #0 to host elasticsearch left intact
{"user":"User [name= USERNAME, roles=[ ROLE], requestedTenant=null]","user_name":" USERNAME ","user_requested_tenant":null,"remote_address":"127.0.0.1:34730","backend_roles":[" ROLE "],"custom_attribute_names":[],"sg_roles":[" ROLE "],"sg_tenants":{" ROLE ":true},"principal":null,"peer_certificates":"0"}
However, each time the proxy user tries to authenticate from kibana this message appears.
elasticsearch_1 | [2018-02-05T19:14:07,991][DEBUG][c.f.s.a.BackendRegistry ] Try to extract auth creds from proxy http authenticator
elasticsearch_1 | [2018-02-05T19:14:07,991][DEBUG][c.f.s.a.BackendRegistry ] 'ElasticsearchSecurityException[xff not done]' extracting credentials from proxy http authenticator
elasticsearch_1 | org.elasticsearch.ElasticsearchSecurityException: xff not done
elasticsearch_1 | at com.floragunn.searchguard.http.HTTPProxyAuthenticator.extractCredentials(HTTPProxyAuthenticator.java:49) ~[search-guard-6-6.1.1-20.1.jar:6.1.1-20.1]
elasticsearch_1 | at com.floragunn.searchguard.auth.BackendRegistry.authenticate(BackendRegistry.java:380) [search-guard-6-6.1.1-20.1.jar:6.1.1-20.1]
elasticsearch_1 | at com.floragunn.searchguard.filter.SearchGuardRestFilter.checkAndAuthenticateRequest(SearchGuardRestFilter.java:122) [search-guard-6-6.1.1-20.1.jar:6.1.1-20.1]
elasticsearch_1 | at com.floragunn.searchguard.filter.SearchGuardRestFilter.access$000(SearchGuardRestFilter.java:47) [search-guard-6-6.1.1-20.1.jar:6.1.1-20.1]
elasticsearch_1 | at com.floragunn.searchguard.filter.SearchGuardRestFilter$1.handleRequest(SearchGuardRestFilter.java:74) [search-guard-6-6.1.1-20.1.jar:6.1.1-20.1]
And then it falls back to basic http authentication using the internal kibana user. Is this the expect behavior as I can curl successfully with the same headers? Can you send an example configure for a proxied user?
...