From basic_internal_auth_domain to jwt_auth_domain FAILED

77 views
Skip to first unread message

Lech Szczecinski

unread,
Aug 8, 2018, 9:52:13 AM8/8/18
to search...@googlegroups.com
* Search Guard and Elasticsearch version 6.2.4
* Win10

I'd like to change authentication in SG from basic (user/password) to jwt (token). I've made following changes in sg_config.yml:

 
     basic_internal_auth_domain:
        http_enabled
: false
        transport_enabled
: true
        order
: 4
        http_authenticator
:
          type
: basic
          challenge
: true
        authentication_backend
:
          type
: intern

     jwt_auth_domain
:
        http_enabled
: true
        transport_enabled
: false
        order
: 0
        http_authenticator
:
          type
: jwt
          challenge
: false
          config
:
            signing_key
: "endocedKey="
            jwt_header
: "Authorization"
            jwt_url_parameter
: "jwtoken"
            roles_key
: null
            subject_key
: "login"
        authentication_backend
:
          type
: noop

  I've restarted ES and Kibana, but nothing has happend - I can login to Kibana using user/password still but not using URL like that:

http://localhost:5601?jwtoken=eyJhbGciOiJI???cCI6IkpXVCJ9.eyJsb2dpb???0IjoxNTE2MjM5MDI1fQ.g8mW0eCCYIszi???hIoA1YGYg0n7pN1tZqbIKO8

  What I've done wrong? Any additonal action needed?

  JWT authentication is the only one with http_enabled: true

Lech Szczecinski

unread,
Aug 8, 2018, 10:11:36 AM8/8/18
to search...@googlegroups.com
Partialy solved: sgadmin script has to be run to apply changes.

But I cannot login into Kibana now :( Yesterday I've extended my trial license to end of August. Now I receive message

The Search Guard license key is not valid for this cluster. Please contact your system administrator.

Problem is that I'm admin of this machine :) I've valid trial license, but
1. this license is for basic auth only or
2. sgadmin has reseted it

Cause I've no access to Kibana I don't know where put license I've received from SG

UPDATED:

Reverting to basic authentication has showed that there were no license key. So sgadmin is resetting it. How to prevent sgadmin not to do that?

Lech Szczecinski

unread,
Aug 8, 2018, 10:44:02 AM8/8/18
to Search Guard Community Forum
Another UPDATE:

I've set both authentications: basic and jwt and reapplied license key.

Now I can login via basic, but trying to login via jwt has no result: no logged in and no any error message

Jochen Kressin

unread,
Aug 8, 2018, 11:01:04 AM8/8/18
to Search Guard Community Forum
Passing a JWT to Kibana as URL param is a bit tricky. While you can attach arbitrary HTTP headers for every call from Kibana to Elasticsearch, you cannot add GET parameters.

The solution is that the Kibana plugin can grab the JWT from the GET parameter and then add it again as HTTP header when talking to ES/SG. The jwt_url_parameter  in sg_config.yml is only relevant when issuing direct requests to ES, without Kibana.

So for the setup to work, tell the Kibana plugin where it can find the JWT in the URL, and to which HTTP header it shall copy it to:

searchguard.jwt.url_param: "jwtoken"
searchguard
.jwt.header: "authorization"

Then in sg_config.yml just configure the HTTP header:

     jwt_auth_domain:
        http_enabled
: true
        transport_enabled
: false
        order
: 0
        http_authenticator
:
          type
: jwt
          challenge
: false
          config
:
            signing_key
: "endocedKey="

            jwt_header
: "authorization"

            roles_key
: null
            subject_key
: "login"
        authentication_backend
:
          type
: noop

I would also change the order of the authentication domains: Set the Basic Authenticator first (this is the one the internal Kibana user uses) and make sure to set challenge to false:

     basic_internal_auth_domain: 
        http_enabled
: false
        transport_enabled
: true

        order
: 0
        http_authenticator
:
          type
: basic
          challenge
: false
        authentication_backend
:
          type
: intern

And then have the JWT auth domain second in the chain.

Lech Szczecinski

unread,
Aug 8, 2018, 11:10:12 AM8/8/18
to search...@googlegroups.com
What about searchguard.jwt.enabled: true in kibana.yml? Is it necessary? Or I can ommit it?

--
You received this message because you are subscribed to the Google Groups "Search Guard Community Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to search-guard...@googlegroups.com.
To post to this group, send email to search...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/search-guard/87843e38-706f-48ae-970a-1b6da7af33bf%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jochen Kressin

unread,
Aug 8, 2018, 12:19:21 PM8/8/18
to Search Guard Community Forum
No, you need to disable basic auth and enable JWT instead. For SG KI Plugin up to v13:

searchguard.basicauth.enabled: false
searchguard.jwt.enabled: true
searchguard.jwt.url_param: "..."
searchguard
.jwt.header: "..."

Since v14-beta:

searchguard.auth.type: "jwt"
searchguard.jwt.url_param: "urltoken"
searchguard.jwt.header: "authorization"




To unsubscribe from this group and stop receiving emails from it, send an email to search-guard+unsubscribe@googlegroups.com.

Jochen Kressin

unread,
Aug 8, 2018, 2:18:46 PM8/8/18
to Search Guard Community Forum
This is a known issue and was fixed in the latest Search Guard release (22.3 / compliance-2). sgadmin would overwrite the license if it is not configured in sg_config.yml.

Lech Szczecinski

unread,
Aug 9, 2018, 4:25:25 AM8/9/18
to search...@googlegroups.com
Nothing happend :(

To make sure that I've done everything correct:
* sg_config.yml

searchguard:
 
dynamic:
    kibana
:
      multitenancy_enabled
: true
      server_username
: 'kibanaserver'
      index
: '.kibana'
      do_not_fail_on_forbidden
: false
    license
:  LS0tLS1CRUdJTiBQR1AgU0lHTkVEIE1FU1NBR0UtLS0tLQpIYXNoOiBTSEE1MTIKCnsKICAgICJ1aWQiOiAiN0RDMTBGNjItMEY1RC00QzI1LTg0OTktQjEwQUFEODgxNDdCIiwKICAgICJ0eXBlIjogIlRSSUFMIiwKICAgICJpc3N1ZWRfZGF0ZSI6ICIyMDE4LTA1LTA0IiwKI...6ZlFnMlJrMy9PZmdtVWVFZ1lkMnkwZU0KPTRWUTMKLS0tLS1FTkQgUEdQIFNJR05BVFVSRS0tLS0tCg==
    http
:
      anonymous_auth_enabled
: false
      xff
:
        enabled
: false
        internalProxies
: '192\.168\.0\.10|192\.168\.0\.11' # regex pattern
        remoteIpHeader
:  'x-forwarded-for'
        proxiesHeader
:   'x-forwarded-by'
    authc
:
      kerberos_auth_domain
:
        http_enabled
: false
        transport_enabled
: false
        order
: 6
        http_authenticator
:
          type
: kerberos # NOT FREE FOR COMMERCIAL USE
          challenge
: true
          config
:
           
# If true a lot of kerberos/security related debugging output will be logged to standard out
            krb_debug
: false
           
# If true then the realm will be stripped from the user name
            strip_realm_from_principal
: true
        authentication_backend
:
          type
: noop
      basic_internal_auth_domain
:
        http_enabled
: true

        transport_enabled
: true
        order
: 0
        http_authenticator
:
          type
: basic
          challenge
: false
        authentication_backend
:
          type
:
intern
      proxy_auth_domain
:
        http_enabled
: false
        transport_enabled
: false
        order
: 3
        http_authenticator
:
          type
: proxy
          challenge
: false
          config
:
            user_header
: "x-proxy-user"
            roles_header
: "x-proxy-roles"
        authentication_backend
:
          type
: noop
      jwt_auth_domain
:
        http_enabled
: true
        transport_enabled
: false
        order
: 1

        http_authenticator
:
          type
: jwt
          challenge
: false
          config
:

            signing_key
: "R2gjZzYzaDgkNXZEXzZHMzg="
            jwt_header
: "Authorization"

            roles_key
: null
            subject_key
: "login"
        authentication_backend
:
          type
:
noop
      clientcert_auth_domain
:
        http_enabled
: false
        transport_enabled
: false
        order
: 2
        http_authenticator
:
          type
: clientcert
          config
:
            username_attribute
: cn #optional, if omitted DN becomes username
          challenge
: false
        authentication_backend
:
          type
: noop
      ldap
:
        http_enabled
: false
        transport_enabled
: false
        order
: 5

        http_authenticator
:
          type
: basic
          challenge
: false
        authentication_backend
:
          type: ldap # NOT FREE FOR COMMERCIAL USE
          config
:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts
:
             
- localhost:8389
            bind_dn
: null
            password
: null
            userbase
: 'ou=people,dc=example,dc=com'
            usersearch: '(sAMAccountName={0})'
            username_attribute: null
    authz
:    
      roles_from_myldap
:
        http_enabled
: false
        transport_enabled
: false
        authorization_backend
:
          type: ldap # NOT FREE FOR COMMERCIAL USE
          config
:
            enable_ssl: false
            enable_start_tls: false
            enable_ssl_client_auth: false
            verify_hostnames: true
            hosts
:
             
- localhost:8389
            bind_dn
: null
            password
: null
            rolebase
: 'ou=groups,dc=example,dc=com'

            rolesearch
: '(member={0})'
            userroleattribute: null
            userrolename: disabled
            rolename: cn
            resolve_nested_roles: true
            userbase
: 'ou=people,dc=example,dc=com'
            usersearch: '(uid={0})'
      roles_from_another_ldap:
        enabled
: false
        authorization_backend
:
          type
: ldap # NOT FREE FOR COMMERCIAL USE
         
#config goes here ...

 
* elasticsearch.yml
 
bootstrap.memory_lock: false
cluster
.name: elasticsearch
http
.port: 9200
node
.data: true
node
.ingest: false
node
.master: true
node
.name: DESKTOP-7DELR8K
path
.data: D:\Program Files\Elastic\ElasticSearch\6.2.4\data
path
.logs: D:\Program Files\Elastic\ElasticSearch\6.2.4\logs
transport
.tcp.port: 9300
script
.max_compilations_rate: 150/5m
searchguard
.ssl.transport.pemcert_filepath: esnode.pem
searchguard
.ssl.transport.pemkey_filepath: esnode-key.pem
searchguard
.ssl.transport.pemtrustedcas_filepath: root-ca.pem
searchguard
.ssl.transport.enforce_hostname_verification: false
searchguard
.ssl.http.enabled: true
searchguard
.ssl.http.pemcert_filepath: esnode.pem
searchguard
.ssl.http.pemkey_filepath: esnode-key.pem
searchguard
.ssl.http.pemtrustedcas_filepath: root-ca.pem
searchguard
.allow_unsafe_democertificates: true
searchguard
.allow_default_init_sgindex: true
searchguard
.authcz.admin_dn:
 
- CN=kirk,OU=client,O=client,L=test,C=de
 
- CN=spock,OU=client,O=client,L=test,C=de
searchguard
.enterprise_modules_enabled: true
searchguard
.restapi.roles_enabled: ["sg_all_access", ...]

* kibana.yml

server.port: 5601

elasticsearch
.url: "https://localhost:9200"

kibana
.index: ".kibana"
kibana
.defaultAppId: "dashboard/27c5ef70-93e4-11e8-ad0a-0dcabb9df641"

elasticsearch
.username: "kibanaserver"
elasticsearch
.password: "kibanaserver"

elasticsearch
.ssl.certificateAuthorities: "D:/Program Files/Elastic/ElasticSearch/6.2.4/config/root-ca.pem"
elasticsearch
.ssl.verificationMode: full

elasticsearch
.pingTimeout: 1500

elasticsearch
.requestTimeout: 30000
elasticsearch
.requestHeadersWhitelist: ["sgtenant", "Authorization"]

searchguard
.basicauth.enabled: false
searchguard
.jwt.enabled: true
searchguard
.jwt.header: "Authorization"
searchguard
.jwt.url_param: "jwtoken"
searchguard
.multitenancy.enabled: true
searchguard
.multitenancy.enable_filter: true
searchguard
.multitenancy.tenants.enable_global: false
searchguard
.multitenancy.tenants.enable_private: false
searchguard
.multitenancy.tenants.preferred: ["nTenant","bTenant",]

searchguard
.basicauth.enabled: true
searchguard
.basicauth.forbidden_usernames: ["kibanaserver", "logstash"]

searchguard
.cookie.password: "jkkhk...87ad"

searchguard
.readonly_mode.roles: ["sg_Users", "sg_nUsers"]

I can login via user/password, but cannot via something like that:
http://localhost:5601/login?jwtoken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDI1fQ.g8mW0eCCYIszivhOsEqZhIoA1YGYg0n7pN1tZqbIKO8

What I'm doing wrong? Please, any advise, I really need login via JWT.

BTW: what's proper URL for logging into Kibana using jwtoken in query?

Lech Szczecinski

unread,
Aug 9, 2018, 5:41:58 AM8/9/18
to search...@googlegroups.com
Made updatein sg_config.yml; ES and Kibana restarted after update:

      basic_internal_auth_domain:        
        http_enabled: false
        transport_enabled
: true

        order
: 0
        http_authenticator
:
          type
: basic
          challenge
: false

        authentication_backend
:
          type
: intern
      jwt_auth_domain
:
        http_enabled
: true
        transport_enabled
: false

        order
: 1

        http_authenticator
:
          type
: jwt
          challenge
: false
          config
:

            signing_key
: "R2gjZzYzaDgkNXZEXzZHMzg="
            jwt_header
: "Authorization"

            roles_key
: null
            subject_key
: "login"
        authentication_backend
:

          type
: noop

Lech Szczecinski

unread,
Aug 9, 2018, 6:33:08 AM8/9/18
to Search Guard Community Forum
https://localhost:9200/_searchguard/authinfo -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDI1fQ.g8mW0eCCYIszivhOsEqZhIoA1YGYg0n7pN1tZqbIKO8"

returns


{
 
"user": "User [name=admin, roles=[], requestedTenant=null]",
 
"user_name": "admin",
 
"user_requested_tenant": null,
 
"remote_address": "127.0.0.1:57741",
 
"backend_roles": [],
 
"custom_attribute_names": [
 
"attr.jwt.iat",
 
"attr.jwt.login"
 
],
 
"sg_roles": [
 
"sg_own_index"
 
],
 
"sg_tenants": {
 
"admin": true
 
},
 
"principal": null,
 
"peer_certificates": "0"
}



So for me it means that problem is only on Kibana side.



Lech Szczecinski

unread,
Aug 10, 2018, 3:54:50 AM8/10/18
to Search Guard Community Forum
I've done all I need I suppose. But still have no possitive result. Any tip, help, advice?
To unsubscribe from this group and stop receiving emails from it, send an email to search-guard...@googlegroups.com.

Lech Szczecinski

unread,
Aug 10, 2018, 6:56:49 AM8/10/18
to Search Guard Community Forum
Now I've proper answer from ES both usinh Authorization/Bearer and parameter in URL (the same in both cases).

{ "user": "User [name=admin, roles=[], requestedTenant=null]", "user_name": "admin", "user_requested_tenant": null, "remote_address": "127.0.0.1:50521", "backend_roles": [], "custom_attribute_names": [ "attr.jwt.iat", "attr.jwt.login" ], "sg_roles": [ "sg_own_index" ], "sg_tenants": { "admin": true }, "principal": null, "peer_certificates": "0" }




Trying log into Kibana with:

http://localhost:5601/login?jwtoken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDI1fQ.g8mW0eCCYIszivhOsEqZhIoA1YGYg0n7pN1tZqbIKO8


(this token works for ES) I receive:

statusCode: 404 error: "Not Found" message: "Not Found"

So comunication is established, but still unproper.

Please, help with getting access to Kibana with JWT authentication via token in URL.

Lech Szczecinski

unread,
Aug 10, 2018, 7:36:03 AM8/10/18
to search...@googlegroups.com
I've prepared small piece of code to test logging into Kibana using header authorization:

            string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDI1fQ.g8mW0eCCYIszivhOsEqZhIoA1YGYg0n7pN1tZqbIKO8";
           
string path = "http://localhost:5601";
           
Uri uri = new Uri(path);
           
WebRequest wr = WebRequest.Create(uri);
           
HttpWebRequest req = (HttpWebRequest)wr;
            req
.PreAuthenticate = true;
            req
.Headers.Add("Authorization", "Bearer " + token);
            req
.Accept = "application/json";
           
WebResponse res = req.GetResponse();
           
Stream stream = res.GetResponseStream();
           
if(stream == null)
               
return;

           
StreamReader sr = new StreamReader(stream, Encoding.Default);
           
string json = sr.ReadToEnd();

I've received following answer:

<script>var hashRoute = '/app/kibana';
var defaultRoute = '/app/kibana';

var hash = window.location.hash;
if (hash.length) {
  window
.location = hashRoute + hash;
} else {
  window
.location = defaultRoute;
}</script>

Is it Ok or not?

But when I've changed logon process to URL:

path += "/login?jwtoken=" + token;

And added no header authorization, I've received:

Error: 404; message: "Not Found"

What's the difference between those 2 calls?



Jochen Kressin

unread,
Aug 10, 2018, 12:13:35 PM8/10/18
to Search Guard Community Forum
Can you try a header name that does not overlap with the HTTP Basic Authorization header? This was tested with 6.2.x and 6.3.x:

kibana.yml:

searchguard.basicauth.enabled: false
searchguard.jwt.enabled: "true"
searchguard.jwt.url_param: "..."
searchguard.jwt.header: "jwtheader"

# 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", "sgtenant", "jwtheader" ]

sg_config.yml:

searchguard:
  dynamic:
    kibana:
      do_not_fail_on_forbidden: true
    composite_enabled: true
    http:
      anonymous_auth_enabled: false
      xff:
        enabled: true
        #internalProxies: '192\.168\.0\.10|192\.168\.0\.11' # regex pattern
        internalProxies: '.*' # trust all internal proxies, regex pattern
        remoteIpHeader:  'x-forwarded-for'
        proxiesHeader:   'x-forwarded-by'
        trustedProxies: '.*' # trust all external proxies, regex pattern
        ###### more information about XFF https://en.wikipedia.org/wiki/X-Forwarded-For
        ###### and here https://tools.ietf.org/html/rfc7239
    authc:
      basic_internal_auth_domain:
        enabled: true
        order: 0
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: intern
      jwt_auth_domain:
        enabled: true
        order: 1
        http_authenticator:
          type: jwt
          challenge: false
          config:
            signing_key: "..."
            jwt_header: "jwtheader"
            roles_key: roles
            subject_key: username
        authentication_backend:
          type: noop

Lech Szczecinski

unread,
Aug 13, 2018, 2:59:34 AM8/13/18
to search...@googlegroups.com
I've changed SG config & applied it: I can get ES config via https://localhost:9200/_searchguard/authinfo with header jwtheader Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6Im...

I've changed kibana.yml & via http://localhost:5601 with header jwtheader Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6Im...  I received:

<script>var hashRoute = '/app/kibana';
var defaultRoute = '/app/kibana';

var hash = window.location.hash;
if (hash.length) {
  window.location = hashRoute + hash;
} else {
  window.location = defaultRoute;
}</script>

So when I call it form iframe I can (at least) login into Kibana, but see nothing. Account if for admin but I cannot see any tenants which are in Kibana.

sg_roles_mapping.yml

sg_all_access:
 
readonly: true
  backendroles
:
   
- admin

sg_internal_users.yml

admin:
  username
: Administrator
 
readonly: true
  hash
: $2a$12$VcCDg.TOG
  roles
:
   
- admin

sg_roles.yml

sg_all_access:
 
readonly: true
  cluster
:
   
- UNLIMITED
  indices
:
   
'*':
     
'*':
       
- UNLIMITED
  tenants
:
    admin_tenant
: RW

I think that is lack of something....





Reply all
Reply to author
Forward
0 new messages