Skip to content

Latest commit

 

History

History
764 lines (629 loc) · 21.2 KB

0007-multiple-users.md

File metadata and controls

764 lines (629 loc) · 21.2 KB

0007: Multiple users in an event

  • Stage: 3 (finished)
  • Date: 2021-02-17

Many log events refer to more than one user at the same time. Examples of this are remote logons as someone else, user management and privilege escalation. ECS supports some of these situations already, via the fact that the "user" fields are reused inside other field sets (e.g. source.user.* and destination.user.*).

The purpose of this proposal is two-fold:

  1. Define additional places where the user fields can be used, to support situations that aren't currently covered.
  2. Review and clarify the purpose of all the places the user fields are currently defined. If some of them appear unneeded, we will also consider removing them.

Fields

As of ECS 1.6, user fields can be present in an event in all of the following places:

  • user.*
  • host.user.*
  • source.user.*
  • destination.user.*
  • client.user.*
  • server.user.*

The new fields discussed in this RFC are the following:

  • user.effective.*
  • user.target.*
  • user.changes.*

Notice that in these new additions, the user fields are now being nested as a different name. The purpose is to hint at their role when used in these locations.

It's also important to point out that the reuses of user inside other field sets are not meant to inherit these new subsections inside the user field set. For example: source.user.* will not contain source.user.effective.* and so on.

The current reusable locations user will be amended to include a few more entries, as demonstrated below.

# schemas/user.yml excerpt
  reusable:
    top_level: true
    expected:
      - client
      - destination
      - host
      - server
      - source
      # Added for this RFC
      - at: user
        as: target
      - at: user
        as: effective
      - at: user
        as: changes

The user field set contains 6 leaf fields, 2 of which have a .text multi-field, for a total of 8 fields. These 3 new nestings will therefore add a total of 24 fields. This can be seen in more detail on PR ecs#869.

Usage

The examples below will only populate user.name and sometimes user.id inside the various user nestings, for readability. However in implementations, unless otherwise noted, all user fields that can reasonably be populated in each location should be populated.

User fields at the Root of an Event

The user fields at the root of an event must be used to capture the user performing the main action described by the event. This is especially important when there's more than one user present on the event. user.* fields at the root of the event represent the user performing the action.

In many cases, events that only mention one user should populate the user fields at the root of the event, even if the user is not the one performing the action.

In cases where a purpose-specific user field such as url.username is populated, user.name should also be populated with the same user name.

Remote Logons

When users are crossing host boundaries, the users are captured at source.user and destination.user.

Examples of data sources where this is applicable:

  • Remote logons via ssh, kerberos
  • Firewalls observing network traffic

In order to align with ECS' design of having user at the root of the event as the user performing the action, all source.user fields should be copied to user at the root.

Here's an example where user "alice" logs on to another host as user "deus":

{
  "user": {
    "name": "alice"
  },
  "source": {
    "user": {
      "name": "alice"
    },
    "ip": "10.42.42.42"
  },
  "destination": {
    "user": {
      "name": "deus"
    },
    "ip": "10.42.42.43"
  }
}

Whenever an event source populates the client and server fields in addition to source and destination, the user fields should be copied accordingly as well.

Privilege Changes

The user.effective fields are relevant when there's a privilege escalation or demotion and it's possible to determine the user requesting/performing the escalation.

Use the user fields at the root to capture who is requesting the privilege change, and user.effective to capture the requested privilege level, whether or not the privilege change was successful.

Here are examples where this is applicable:

  • A user changing identity on a host.
    • Examples: sudo, su, Run as.
  • Running a program as a different user. Examples:
    • A trusted user runs a specific admin command as root via a mechanism such as the Posix setuid/setgid.
    • A service manager with administrator privileges starts child processes as limited users, for security purposes (e.g. root runs Apache HTTPD as user "apache")

In cases where the event source only gives information about the effective user and not who requested different privileges, the user fields at the root of the event should be used instead.

Here's an example of user "alice" running a command as root via sudo:

{
  "user": {
    "name": "alice",
    "id": "1001",
    "effective": {
      "name": "root",
      "id": "0"
    }
  }
}

When it's not possible (or it's prohibitive) to determine which user is requesting different privilege levels, it's acceptable to capture the effective user at the root of the event. Typically a privilege change event will already have happened, for example: bob "su" as root; and subsequent events will show the root user performing the actions.

Identity and Access Management

Whenever a user is performing an action that affects another user -- typically in IAM scenarios -- the user affected by the action is captured at user.target. The user performing the IAM activity is captured at the root of the event.

Examples of IAM activity include:

  • user-a creates or deletes user-b
  • user-a modifies user-b

In the create/delete scenarios, there's either no prior state (user creation) or no post state (user deletion). In these cases, only user at the root and user.target must be populated.

Example where "root" creates user "bob":

{
  "user": {
    "name": "root",
    "id": "0",
    "target": {
      "name": "bob",
      "id": "1002",
      ...
    }
  }
}

When there's a change of state to an existing user, user.target must be used to capture the prior state of the user, and user.changes should list only the changes that were performed.

Example where "root" renames user "bob" to "bob.barker":

{
  "user": {
    "name": "root",
    "id": "0",
    "target": {
      "name": "bob",
      "id": "1002"
    },
    "changes": {
      "name": "bob.barker"
    }
  }
}

You'll note in the example above that the user ID is not repeated under user.changes.*, since the ID didn't change.

Combining IAM and Privilege Escalation

We've covered above how user.target and user.changes can be used at the same time. If privilege escalation is captured in the same IAM event, user.effective should of course be used as well.

Here's the "rename" example from the IAM section above. In the following example, we know "alice" is escalating privileges as "root", in order to modify user "bob":

{
  "user": {
    "name": "alice",
    "id": "1001",
    "effective": {
      "name": "root",
      "id": "0"
    },
    "target": {
      "name": "bob",
      "id": "1002"
    },
    "changes": {
      "name": "bob.barker"
    }
  }
}

Pivoting via related.user

Any event that has user(s) in it should always populate the array field related.user with all usernames seen on the event. Note that this field is not a nesting of all user fields, it's a flat array meant to contain user identifiers.

Taking the example from user.changes again, and populating related.user as well, the event now looks like:

{
  "user": {
    "name": "alice",
    "id": "1001",
    "effective": {
      "name": "root",
      "id": "0"
    },
    "target": {
      "name": "bob",
      "id": "1002"
    },
    "changes": {
      "name": "bob.barker"
    }
  },
  "related": { "user": ["alice", "root", "bob", "bob.barker"] }
}

Source data

Here are some concrete examples of events with multiple users and user roles. Note that the design of these fields is meant to allow all of their use at the same time, when needed. However if events don't contain all user roles because they're spread out across events, only the fields relevant to each event should be used.

Linux IAM and privilege escalation

Here's a typical set of logs about a user creation on Linux.

Sep 29 19:55:09 localhost sudo: vagrant : TTY=pts/0 ; PWD=/home/vagrant ; USER=root ; COMMAND=/sbin/useradd test-user -p test-password
Sep 29 19:55:09 localhost sudo: pam_unix(sudo:session): session opened for user root by vagrant(uid=0)
Sep 29 19:55:09 localhost useradd[2097]: new group: name=test-user, GID=1001
Sep 29 19:55:09 localhost useradd[2097]: new user: name=test-user, UID=1001, GID=1001, home=/home/test-user, shell=/bin/bash
Sep 29 19:55:09 localhost sudo: pam_unix(sudo:session): session closed for user root

Logical events

A solution that coalesces log events to produce higher level logical events could capture them all in the following way.

Group creation:

{
  "event": {
    "kind": "event",
    "category": ["iam"],
    "type": ["group", "creation"]
  },
  "group": {
    "name": "test-user",
    "id": "1001"
  },
  "user": {
    "name": "vagrant",
    "id": "1000",
    "effective": {
      "name": "root",
      "id": "0"
    },
  },
  "related": { "user": ["vagrant", "root"] }
}

User creation:

{
  "event": {
    "kind": "event",
    "category": ["iam"],
    "type": ["user", "creation"]
  },
  "user": {
    "name": "vagrant",
    "id": "1000",
    "effective": {
      "name": "root",
      "id": "0"
    },
    "target": {
      "name": "test-user",
      "id": "1001",
      "group": {
        "name": "test-user",
        "id": "1001"
      }
    }
  },
  "related": { "user": ["vagrant", "root", "test-user"] }
}

Raw events

A solution that produces one event per log without coalescing would instead only represent users with the information available in the given log event.

event 1:

{
  "event": {
    "kind": "event",
    "category": ["process"],
    "type": "creation"
  },
  "user": {
    "name": "vagrant",
    "effective": {
      "name": "root"
    }
  },
  "process": {
    "name": "sudo",
    "command_line": "/sbin/useradd test-user -p test-password"
  }
}

event 2 (privilege escalation):

{
  "event": {
    "kind": "event",
    "category": ["session"],
    "type": ["creation"],
    "outcome": "success"
  },
  "user": {
    "name": "vagrant",
    "effective": {
      "name": "root"
    }
  },
  "process": {
    "name": "sudo"
  }
}

event 3 (IAM):

{
  "event": {
    "kind": "event",
    "category": ["iam"],
    "type": ["group", "creation"],
    "outcome": "success"
  },
  "group": {
    "name": "test-user",
    "id": "1001"
  },
  "process": {
    "name": "useradd",
    "pid": 2097
  }
}

event 4 (IAM):

{
  "event": {
    "kind": "event",
    "category": ["iam"],
    "type": ["user", "creation"]
  },
  "user": {
    "name": "test-user",
    "id": "1001"
  },
  "process": {
    "name": "useradd",
    "pid": 2097
  }
}

Notice: in the event above, since the log mentions only the user being created, we capture the user at the root of the event. We do this despite the fact that they are not the one performing the action.

event 5:

{
  "event": {
    "kind": "event",
    "category": ["session"],
    "type": ["end"]
  },
  "user": {
    "name": "root"
  },
  "process": {
    "name": "sudo"
  }
}

Windows privilege escalation

A successful local Windows Admin logon where user "testuser" escalates to Administrator:

<System>
  <Provider Name="Microsoft-Windows-Security-Auditing"...>
  <EventID>4624</EventID>
  ...
</System>
<EventData>
  <Data Name="SubjectUserSid">5-1-5-21-202424912787-2692429404-2351956786-1000</Data>
  <Data Name="SubjectUserName">testuser</Data>
  <Data Name="SubjectDomainName">TEST</Data>
  <Data Name="SubjectLogonId">0xb976c</Data>
  <Data Name="TargetUserSid">S-1-5-21-2024912787-2692429404-2351956786-500</Data>
  <Data Name="TargetUserName">Administrator</Data>
  <Data Name="TargetDomainName">TEST</Data>
  <Data Name="TargetLogonId">0x11b621</Data>
  ...
</EventData>

Would translate to

{
  "event": {
    "code": "4624",
    "provider": "Microsoft-Windows-Security-Auditing",
    "kind": "event",
    "category": ["authentication"],
    "type": ["start"],
    "outcome": "success"
  },
  "user": {
    "name": "testuser",
    "domain": "TEST",
    "id": "S-1-5-21-202424912787-2692429404-2351956786-1000",
    "effective": {
      "name": "Administrator",
      "domain": "TEST",
      "id": "S-1-5-21-2024912787-2692429404-2351956786-500"
    }
  },
  "related": { "user": ["testuser", "Administrator"] }
}

Windows IAM

Modifying an existing user account, where the administrator renames user John to John2:

<System>
  <Provider Name="Microsoft-Windows-Security-Auditing"...>
  <EventID>4781</EventID>
  ...
</System>
<EventData>
  <Data Name="SubjectUserSid">S-1-5-21-2024912787-2692429404-2351956786-500</Data>
  <Data Name="SubjectUserName">Administrator</Data>
  <Data Name="SubjectDomainName">TEST</Data>
  <Data Name="SubjectLogonId">0x11b621</Data>
  <Data Name="TargetUserSid">S-1-5-21-2024912787-2692429404-2351956786-1000</Data>
  <Data Name="OldTargetUserName">John</Data>
  <Data Name="NewTargetUserName">John2</Data>
  <Data Name="TargetDomainName">TEST</Data>
  ...
</EventData>

Would translate to

{
  "event": {
    "code": "4781",
    "provider": "Microsoft-Windows-Security-Auditing",
    "kind": "event",
    "category": ["iam"],
    "type": ["user", "change"],
    "outcome": "success"
  },
  "user": {
    "name": "Administrator",
    "domain": "TEST",
    "id": "S-1-5-21-2024912787-2692429404-2351956786-500",
    "target": {
      "name": "John",
      "id": "S-1-5-21-2024912787-2692429404-2351956786-1000",
      "domain": "TEST",
    },
    "changes": {
      "name": "John2"
    }
  },
  "related": { "user": ["John", "John2", "Administrator"] }
}

Cloud privilege escalation

Cloud systems also have privilege change concepts.

Here's an example using AWS' assume role, in the event where AWS user "JohnRole1" assumes the role of "DBARole". A simplified version of the Cloudtrail event could look like:

{
  "eventName": "AssumeRole",
  "requestParameters": {
    "roleArn": "arn:aws:iam::111111111111:role/JohnRole2",
  },
  "resources": [
    {
      "ARN": "arn:aws:iam::111122223333:role/JohnRole2",
      "accountId": "111111111111",
      "type": "AWS::IAM::Role"
    }
  ],
  "responseElements": {
    "assumedRoleUser": {
      "arn": "arn:aws:sts::111111111111:assumed-role/test-role/DBARole",
      "assumedRoleId": "AROAIFR7WHDTSOBEEFSTU:DBARole"
    },
    "userIdentity": {
      "accessKeyId": "AKIAI44QH8DHBEXAMPLE",
      "accountId": "111111111111",
      "arn": "arn:aws:sts::111111111111:assumed-role/JohnDoe/JohnRole1",
      "principalId": "AROAIN5ATK5U7KEXAMPLE:JohnRole1",
      "type": "AssumedRole"
    }
  }
}

And would translate to:

{
  "event": {
    "action": "AssumeRole",
    "kind": "event",
    "category": ["authentication"],
    "type": ["start"],
    "outcome": "success"
  },
  "user": {
    "id": "AROAIN5ATK5U7KEXAMPLE:JohnRole1",
    "effective": {
      "id": "AROAIFR7WHDTSOBEEFSTU:DBARole",
    }
  },
  "cloud": {
    "account": { "id": "111111111111" } ...
  },
  "related": { "user": ["AROAIN5ATK5U7KEXAMPLE:JohnRole1", "AROAIFR7WHDTSOBEEFSTU:DBARole"] }
}

Subsequent actions taken under this assumed role will have both the principal user and the assumed role in the userIdentity. This makes it easy to keep track of both the real user at user.* and the escalated privileges at user.effective.* in all subsequent activity after privilege escalation.

Scope of impact

New fields for IAM

The fields user.[changes|effective|target].* are net new fields, so they don't represent a breaking change. They are especially important for security-related data sources around IAM and audit logs. These event sources should be adjusted to populate these new fields, as they are very important in getting a complete picture of user management activity.

Some event sources for user management activity may have used user.* fields at the root to describe the user being modified, rather than the user performing the action. These sources will have to be modified to be consistent with the fact that user fields at the root are meant to represent who's performing the action.

New user field duplication guidance

In order to firmly establish the user fields at the root of the event as the user performing the action, this RFC introduces new guidance:

  • Remote logons source.user.* should be copied to user.*
  • Purpose-specific fields such as url.username should be copied at user.name

These came up while working on this RFC; this is not guidance that was given in the past. Data sources that populate these fields will need to be revisited and adjusted accordingly.

host.user fields are deprecated for removal

Seeing no use in the wild, it was decided to remove the reuse of the user fields at host.user.*. We will start by deprecating them in ECS 1.8, and will remove them at the next major version.

Please let us know before the next major ECS release if you disagree with this, and share how you're using them.

Concerns

Deprecating host.user fields

In past discussions and recent research, we have not identified a clear purpose for the user fields nested at host.user.*.

We are considering deprecating these fields with the intent to remove them completely.

Resolution

They will be marked as deprecated starting with ECS 1.8, and will be removed in the next ECS major release.

Documenting the purpose of each usage of the user fields

As of ECS 1.6, the ECS documentation doesn't have a good place to explain at length how to properly use the multiple nesting locations for user. This is already a problem for the usage of user at the root vs its 5 reuse locations. The addition of 3 new reuse locations adds to this situation.

Resolution

Adding a way to document field sets via free form text is being worked on independently of this proposal (ecs#943).

For now the guidance on the meaning of each location where user can be used is in the Usage section of this RFC. This guidance will be moved to the main ECS documentation when the appropriate mechanism is available.

Real-world implementations

People

The following are the people that consulted on the contents of this RFC.

  • @webmat | author
  • @jonathan-buttner | sponsor
  • @leehinman | subject matter expert
  • @janniten | subject matter expert
  • @willemdh | subject matter expert

References

RFC Pull Requests

Note: This RFC was initially proposed via a PR that targeted stage 2, given the amount of discussion that has already has happened on this subject.