elastic / beats

:tropical_fish: Beats - Lightweight shippers for Elasticsearch & Logstash
https://www.elastic.co/products/beats
Other
109 stars 4.93k forks source link

[Metricbeat] MSSQL module cannot parse username if domain is included within the host string #13364

Open geekpete opened 5 years ago

geekpete commented 5 years ago

Please include configurations and logs if available.

For confirmed bugs, please report:

Using a domain within the username in credentials doesn't seem to parse regardless of escaping.

Typical configuration example might look like:

------------
# Module: mssql
# Docs: https://www.elastic.co/guide/en/beats/metricbeat/7.3/metricbeat-module-mssql.html

- module: mssql
  metricsets:
    - "transaction_log"
    - "performance"
  hosts: ["sqlserver://sa@localhost"]
  period: 10s

But when attempting to use an Active Domain user rather than the SA service account, there doesn't seem to be a way to specify the domain within the hosts connection string and have it work.

Examples of what doesn't work:

hosts: ["sqlserver://domain\user:password@server01"]
hosts: ["sqlserver://domain\\user:password@server01"]
hosts: ["sqlserver://domain/user:password@server01"]
hosts: ["sqlserver://domain\/user:password@server01"]
hosts: ["domain\user:password@server01"]
hosts: ["domain\\user:password@server01"]
hosts: ["domain/user:password@server01"]
hosts: ["domain\/user:password@server01"]

Example errors

When trying with domain:

2019-08-28T12:54:59.661+1200    ERROR   instance/beat.go:802    Exiting: 1 error: 2 errors: host parsing failed for mssql-transaction_log: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo; host parsing failed for mssql-performance: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo

Exiting: 1 error: 2 errors: host parsing failed for mssql-transaction_log: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo; host parsing failed for mssql-performance: error parsing URL: parse sqlserver://mydomain\user:password@server01: net/url: invalid userinfo

If leaving the domain out, the error is that the native user with that name cannot log in as the user with access is the domain user with that name not a native user:

2019-08-28T12:56:25.383+1200    ERROR   instance/beat.go:802    Exiting: 1 error: 2 errors: could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'.; could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'. 

Exiting: 1 error: 2 errors: could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'.; could not create connection to db: error doing ping to db: Login error: mssql: Login failed for user 'user'.

Interestingly the domain credentials can be made to work if set separately via:

metricbeat.modules:
- module: mssql
  metricsets:
    - "transaction_log"
    - "performance"
  hosts: ["sqlserver://localhost"]
  username: domain\username
  password: verysecurepassword
  period: 10s

Related:

elasticmachine commented 3 years ago

Pinging @elastic/integrations (Team:Integrations)

botelastic[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

ManojS-shetty commented 2 years ago

@geekpete

Please try out the below:

hosts: ["sqlserver://domain//user:password@server01"]

and ignore the username and password in config.yml

ManojS-shetty commented 2 years ago

@geekpete Any update on the above suggestion?

ManojS-shetty commented 2 years ago

@geekpete Any Update here?

geekpete commented 2 years ago

Sorry, I'm still working to follow up on this one.

ManojS-shetty commented 2 years ago

@geekpete Any update on the suggested method?

ManojS-shetty commented 2 years ago

@geekpete Any inputs so that we can proceed with the further about this?

geekpete commented 2 years ago

So in the original testing for this issue it looks like we'd tried everything except the way you're suggesting:

hosts: ["sqlserver://domain\user:password@server01"]
hosts: ["sqlserver://domain\\user:password@server01"]
hosts: ["sqlserver://domain/user:password@server01"]
hosts: ["sqlserver://domain\/user:password@server01"]

but not with two forward slashes after the domain

hosts: ["sqlserver://domain//user:password@server01"]

I'll see if I can get this tested and report back.

ManojS-shetty commented 2 years ago

So in the original testing for this issue it looks like we'd tried everything except the way you're suggesting:

hosts: ["sqlserver://domain\user:password@server01"]
hosts: ["sqlserver://domain\\user:password@server01"]
hosts: ["sqlserver://domain/user:password@server01"]
hosts: ["sqlserver://domain\/user:password@server01"]

but not with two forward slashes after the domain

hosts: ["sqlserver://domain//user:password@server01"]

I'll see if I can get this tested and report back.

Thank you @geekpete

efd6 commented 2 years ago

The issue here is that the \ character is not a valid character for userinfo. This can be worked around by percent encoding the backslash (See https://play.golang.com/p/ldyqlqiG8f7). url.PathEscape should be used on the username prior to constructing the connection URL. This looks like it can be done like this:

diff --git a/metricbeat/mb/parse/url.go b/metricbeat/mb/parse/url.go
index c0b23f421d..5c2ff19e86 100644
--- a/metricbeat/mb/parse/url.go
+++ b/metricbeat/mb/parse/url.go
@@ -71,6 +71,8 @@ func (b URLHostParserBuilder) Build() mb.HostParser {
                } else {
                        user = b.DefaultUsername
                }
+               user = url.PathEscape(user)
+
                t, ok = conf["password"]
                if ok {
                        pass, ok = t.(string)
geekpete commented 1 year ago

Until the codebase is adjusted to automatically escape/encode the slash, it's also likely you can configure the string without the slash by manually passing the encoded value %5C directly instead of "\" in the domain user name.

ie for domain user: domain%5Cusername eg: sqlserver://domain%5Cusername:pass@ip

geekpete commented 1 year ago

Related issue to sanitize input in Kibana https://github.com/elastic/integrations/issues/5213