Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SECURITY] add telemetry on authentication type #119371

Closed
wants to merge 12 commits into from

Conversation

XavierM
Copy link
Contributor

@XavierM XavierM commented Nov 22, 2021

Summary

Resolves: #117517

To Verify

  1. Run this branch and login with different authentication type
  2. Go to https://localhost:5601/api/stats?extended=true&legacy=true and verify that usage counters have been updated with the expected numbers. Usage counter section will look something like this:
{
  "usage": {
    "usage_counters": {
      "dailyEvents": [
        {
          "domainId": "security",
          "counterName": "realm",
          "counterType": "SecurityAuthType",
          "lastUpdatedAt": "2021-08-16T02:01:16.786Z",
          "fromTimestamp": "2021-08-16T00:00:00Z",
          "total": 1
        },
        {
          "domainId": "security",
          "counterName": "token",
          "counterType": "SecurityAuthType",
          "lastUpdatedAt": "2021-08-16T02:01:56.790Z",
          "fromTimestamp": "2021-08-16T00:00:00Z",
          "total": 1
        }
      ]
    }
  }
}

Checklist

@XavierM XavierM added Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! v8.0.0 release_note:skip Skip the PR/issue when compiling release notes auto-backport Deprecated - use backport:version if exact versions are needed v8.1.0 v7.16.1 labels Nov 22, 2021
@XavierM XavierM self-assigned this Nov 22, 2021
@XavierM XavierM marked this pull request as ready for review November 29, 2021 20:01
@XavierM XavierM requested a review from a team as a code owner November 29, 2021 20:01
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-security (Team:Security)

@jportner jportner self-requested a review November 29, 2021 21:45
Copy link
Contributor

@jportner jportner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job on this, a weird problem with a not-so-straightforward solution. A few nits below, main thing is I am concerned we are not recording all of the data that we need.

x-pack/plugins/security/public/telemetry/index.ts Outdated Show resolved Hide resolved
x-pack/plugins/security/public/telemetry/index.ts Outdated Show resolved Hide resolved
x-pack/plugins/security/server/plugin.ts Outdated Show resolved Hide resolved
oldAuthType !== authUser?.authentication_type)
) {
usageCounter.incrementCounter({
counterName: authUser?.authentication_type,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source issue (#117517) suggests recording more data points:

If an interactive session is detected, then we want to record the following from the AuthenticatedUser model:

  • authentication_realm.type
  • lookup_realm.type
  • authentication_provider.type
  • authentication_type

I might not be in the loop though. Did you intentionally leave the the other ones out, or was that an oversight?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not even sure, let's talk to @legrego about it when he is back. I will put back the PR in progress to avoid slack/notification.

@XavierM XavierM marked this pull request as draft November 30, 2021 16:08
@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
security 401 402 +1

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
security 50.1KB 51.4KB +1.3KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @XavierM

this.securityFeaturesSubscription = this.securityLicense.features$.subscribe(
({ allowRbac }) => {
if (allowRbac) {
getCurrentUser().then(() => this.recordAuthTypeUsageCollection(http));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we do in the event of a promise rejection? I think it's fine to ignore it, but we probably want to explicitly ignore it with a .catch block.

oldAuthType !== authUser?.authentication_type)
) {
usageCounter.incrementCounter({
counterName: authUser?.authentication_type,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authentication_type won't tell us whether or not the user was authenticated via proxy. For that, I think we need the authentication_provider from the user (users who authenticate via the http provider are proxy-based)

Additionally, in order to satisfy this example, we need to extract the authentication scheme used (basic, bearer, ApiKey, etc.)

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authentication_type won't tell us whether or not the user was authenticated via proxy. For that, I think we need the authentication_provider from the user (users who authenticate via the http provider are proxy-based)

Ah, Xavier and I were discussing this offline --
I think where we were getting tripped up is that we were looking at the docs for Kibana's configurable authentication providers, and "http" is not an authentication provider according to the config.

However, in the implementation, "http" is an authentication provider: https://github.com/elastic/kibana/blob/6ecffcc57c9a5b0328257cd25b737140a8471dda/x-pack/plugins/security/server/authentication/providers/http.ts

Additionally, in order to satisfy this example, we need to extract the authentication scheme used (basic, bearer, ApiKey, etc.)

Ah, so it looks like the scheme is not stored in the AuthenticatedUser, so we'll have to grab it from the request object by parsing the authorization header:

const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request);
if (authorizationHeader == null) {
this.logger.debug('Authorization header is not presented.');
return AuthenticationResult.notHandled();
}
if (!this.supportedSchemes.has(authorizationHeader.scheme.toLowerCase())) {
this.logger.debug(`Unsupported authentication scheme: ${authorizationHeader.scheme}`);
return AuthenticationResult.notHandled();
}

I was wondering if we could combine all the info we need into a single string value so we can still use the Core usage collector for this, but it sounds like we might want to be able to analyze these things separately. So maybe that's not a good idea, WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering if we could combine all the info we need into a single string value so we can still use the Core usage collector for this, but it sounds like we might want to be able to analyze these things separately. So maybe that's not a good idea, WDYT?

I think it depends™️. If we constrain the schemes to Basic, Bearer, ApiKey, and Custom, and only report for the http provider, then we could accomplish this using the Core usage collector if we were comfortable using 4 distinct objects (one for each scheme). If that's asking too much of the usage collector, or if we feel that's too limiting for potential future use-cases, then we might want to move forward with a bespoke implementation.

My gut feeling is that the Core usage collector may be too limiting. We wouldn't be able to add any more information to this in the future, and we'd likely need to do something custom for the next authentication data point we want to collect. I'm also cognizant that we may never need this flexibility, but I suspect we will.

Copy link
Contributor

@jportner jportner Dec 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also recently heard a question about how to measure Daily Active Users (DAU), which we don't have a good way to do right now.

We currently have 7 auth providers in Kibana (not including the "http" provider). Are we interested in comparing usage of these?

We could define our own saved object type with separate counters like this:

{
  authLoginUsage: {
    providerTypes: {
      basic: number;
      token: number;
      saml: number;
      oidc: number;
      kerberos: number;
      pki: number;
      anonymous: number;
      total: number;
    },
    realmTypes: {
      reserved: number;
      native: number;
      ldap: number;
      activeDirectory: number;
      pki: number;
      file: number;
      saml: number;
      oidc: number;
      kerberos: number;
      total: number;
    },
    httpAuthSchemes: {
      basic: number;
      bearer: number;
      apiKey: number;
      custom: number;
      total: number;
    }
}

However, we would lose some fidelity here because we don't know which providers were used with which realms.

Also, I like how the Core usage collector bins these into separate days so we can measure how these things change over time.

If we don't really need to know what realms are being used, I'm leaning towards suggesting that we define two different Core usage counters:

  1. Auth providers types used (including HTTP):
    {
      "counterName": "basic" | "token" | "saml" | "oidc" | "kerberos" | "pki" | "anonymous" | "http",
      "counterType": "SecurityAuthProviderType",
    }
    (Note: I edited counterName above according to [SECURITY] add telemetry on authentication type #119371 (comment))
  2. HTTP auth schemes used:
    {
      "counterName": "basic" | "bearer" | "apiKey" | "custom",
      "counterType": "SecurityAuthHttpScheme",
    }

If the user is authenticating using an HTTP header (e.g., sessionless), we'd record both metrics. Otherwise, we'd record only the auth provider type.

This has a few advantages, namely:

  • The implementation is almost done, just need a few tweaks
  • We get metrics binned on a daily basis for free
  • Easy to visualize comparisons like the example above without adding runtime fields

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't really need to know what realms are being used, I'm leaning towards suggesting that we define two different Core usage counters

This approach looks reasonable to me!

If the user is authenticating using an HTTP header (e.g., sessionless), we'd record both metrics. Otherwise, we'd record only the auth provider type

This is true only if we expand SecurityAuthProviderType to include the http pseudo-provider as a distinct counterName. If you authenticate to Kibana using an Authorization header, then you will always go through the http provider, regardless of what type of credentials you end up providing.

This statement might become less true with the introduction of header-based PKI auth (to support PKI on ESS), but we can cross that bridge when we get there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to analyze what combinations of providers, realms and HTTP headers would give us more insight into how Kibana's authentication subsystem is used and ended up with two different lists: minimal and verbose.

It seems we haven't discussed setup when Kibana is used in conjunction with the custom Elasticsearch realms, especially via HTTP authentication. I included counters for these setups too.

I know it's a lot of counters and I still need to check if it's easy to consume this type of data, but I wanted to check with you first if there was reason to not pursue this option initially @jportner @legrego ?

Minimal (19 counters, excluded least probable and combined least useful):

Provider (Kibana) Realm (Elasticsearch) Usage Counter
Basic Native/File/AD/LDAP/Reserved Basic
Basic Custom Custom
Token Native/File/AD/LDAP/Reserved Token
Token Custom Token_Custom
SAML SAML SAML
OIDC OIDC OIDC
Kerberos Kerberos Kerberos
PKI PKI PKI
Anonymous Native/File/AD/LDAP/Reserved Anonymous
Anonymous Anonymous Anonymous_PLEASE_NO
Anonymous Custom Anonymous_Custom
Anonymous ApiKey Anonymous_ApiKey
HTTP Basic Native/File/AD/LDAP/Reserved HTTP_Basic
HTTP Basic Custom HTTP_Basic_Custom
HTTP Bearer SAML/OIDC/Kerberos/PKI HTTP_Bearer
HTTP Bearer Custom HTTP_Bearer_Custom
HTTP ApiKey ApiKey HTTP_ApiKey
HTTP Custom JWT HTTP_Custom_JWT
HTTP Custom * HTTP_Custom

Verbose (42 counters, almost all possible combinations):

Provider (Kibana) Realm (Elasticsearch) Usage Counter
Basic Native Native
Basic File File
Basic LDAP LDAP
Basic AD AD
Basic Reserved Reserved
Basic Custom Custom
Token Native Token_Native
Token File Token_File
Token LDAP Token_LDAP
Token AD Token_AD
Token Reserved Token_Reserved
Token Custom Token_Custom
SAML SAML SAML
SAML Custom SAML_Custom
OIDC OIDC OIDC
OIDC Custom OIDC_Custom
Kerberos Kerberos Kerberos
Kerberos Custom Kerberos_Custom
PKI PKI PKI
PKI Custom PKI_Custom
Anonymous Native Anonymous_Native
Anonymous File Anonymous_File
Anonymous LDAP Anonymous_LDAP
Anonymous AD Anonymous_AD
Anonymous Reserved Anonymous_Reserved
Anonymous Anonymous Anonymous_PLEASE_NO
Anonymous Custom Anonymous_Custom
Anonymous ApiKey Anonymous_ApiKey
HTTP Basic Native HTTP_Basic_Native
HTTP Basic File HTTP_Basic_File
HTTP Basic LDAP HTTP_Basic_LDAP
HTTP Basic AD HTTP_Basic_AD
HTTP Basic Reserved HTTP_Basic_Reserved
HTTP Basic Custom HTTP_Basic_Custom
HTTP Bearer SAML HTTP_Bearer_SAML
HTTP Bearer OIDC HTTP_Bearer_OIDC
HTTP Bearer Kerberos HTTP_Bearer_Kerberos
HTTP Bearer PKI HTTP_Bearer_PKI
HTTP Bearer Custom HTTP_Bearer_Custom
HTTP ApiKey ApiKey HTTP_ApiKey
HTTP Custom JWT HTTP_Custom_JWT
HTTP Custom * HTTP_Custom

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azasypkin thanks for putting these tables together.

It seems we haven't discussed setup when Kibana is used in conjunction with the custom Elasticsearch realms, especially via HTTP authentication. I included counters for these setups too.

Great idea!

I know it's a lot of counters and I still need to check if it's easy to consume this type of data, but I wanted to check with you first if there was reason to not pursue this option initially

If the telemetry team is OK with the number of proposed counters, then I don't have any concerns with the expanded set.

Do you think we would get a lot of benefit from reporting basic and token auth providers under different counters? Could we report those under the same set of counters, since each cluster can only run either basic or token? From a metrics perspective, we can still detect how many clusters are choosing token/`basic

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we would get a lot of benefit from reporting basic and token auth providers under different counters? Could we report those under the same set of counters, since each cluster can only run either basic or token?

Yeah, it's a good point, I always forget that they cannot be used together (and we consider merging them in the future too). I agree, we can combine these counters.

If the telemetry team is OK with the number of proposed counters, then I don't have any concerns with the expanded set.

I'll check with the telemetry team!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, I don't think the verbose approach is problematic at all... Especially bearing in mind that one instance of Kibana will use just a few of those.

I just wish I had completed #121992 by 8.2 so you could leverage it instead for this use case. Unfortunately, it'll slip to 8.3.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@afharo this PR also won't make 8.2 -- so if we are both targeting 8.3 for this, then would it make more sense to use #121992 for these metrics?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed release_note:skip Skip the PR/issue when compiling release notes Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! v8.3.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Collect usage data on proxy-based authentication mechanisms
8 participants