Replacing UID with Username using lookup table

Before you post: Your responses to these questions will help the community help you. Please complete this template if you’re asking a support question.
Don’t forget to select tags to help index your topic!

Hello!

Our graylog server receives user commands on a Linux box. We don’t have a lot of users, but the commands output the user as an ID i.e. 191460003 instead of a username. We thought using a lookup_table with a CSV which has the mapping of the UID’s to usernames would work great, but we’re having issues getting it to replace the UID’s in the stream.

The client sending the logs is on RHEL 7 and our server is running Graylog 4.2.5

3. What steps have you already taken to try and solve the problem?

We have setup the lookup table and running the test lookup correctly shows the username instead of the UID, so we think this part is okay. Am having some issues understanding the pipeline portion. My understanding is that we create a pipeline rule and then attach it to our stream.

Ultimately we’d want the rule to replace any UID that matches in the CSV and replace it with the username but was trying with a single UID to simplify it.

rule "UID to Username"
when
    has_field("message") AND contains(to_string($message.uid),"1914600003")
then

    //Change UID to Username
    let update_source = lookup_value("lookup_username",$message.uid);

    set_field("message",update_source);
    
end

Was using this as reference as thought it closely resembled what we are trying to do:

Helpful Posting Tips: Tips for Posting Questions that Get Answers [Hold down CTRL and link on link to open tips documents in a separate tab]

Hello && Welcome @steveno

I have done something similar to what you want to do, except I have not used lookup_table.
What I can do is show my configurations and perhaps it will help.

Graylog uses UUID in rest.accesslog for user names, so what I had to do is get that UUID then create a field for it, then using a pipeline change the UUID into a human readable name.

Example:

My UUID is 5e224e7683d72eff75055199

Extractor type: Regular expression

I create a pipeline

rule "Graylog Web Access Greg"
when
    has_field("graylog_gui") AND contains(to_string($message.graylog_gui), "5e224e7683d72eff75055199")
then
    set_field("graylog_gui","greg.smith");
end

Results

Hope that helps

1 Like

Hi Greg,

Thanks for your suggestion, I will give this a go. The regular expression creation looks intimidating, but this looks promising.

Thanks,

Steven

Actually @tmacgbay can do this in one pipeline. He’s my Batman to my robin :laughing:

1 Like

The rule is close but you are referencing “message” which is the entire message…

Here is how I would set the rule up - all the other things you said make sense

rule "UID to Username"
when
    has_field("uid") 
then

    //Change UID to Username
    let update_source = lookup_value("lookup_username",to_string($message.uid));
    // note:  I think you can set the default value of a table if the lookup fails to USER_NOT_FOUND

    // set the field username to be the table results for uid
    set_field("username",update_source);
    
end

Or you if you use the @gsmith extractor method, you could spoof an if statement in the rule like this so that you would only have to change one rule when names or uid’s change:

rule "Graylog Web Access User Convert"
when
    has_field("graylog_gui")
then
   // all these will fail to replace except the one that has the correct data...or note that user was not found
    let new_field = "USER_NOT_FOUND";
    let new_field = replace(to_string($message.graylog_gui), "5e224e7683d72eff75055199", "greg.smith");
    let new_field = replace(to_string($message.graylog_gui), "100100110010011001001",    "tad.sherrill");
    let new_field = replace(to_string($message.graylog_gui), "987324e32874ff32892b2829", "steven.o");

    set_field("graylog_gui",new_field);
end
1 Like

1 Like

Thanks tmacgbay!

I also will try this suggestion as well. I think the issue is that “uid” isn’t a field in our log. The UID is just a string of numbers taken from the body of the message of the log file. I was hoping to find a way to have the pipeline convert this string to a username when the value matches in a lookup table. Our lookup table has fields “id,username” but I’m guessing that the pipeline only knows about these fields when using something like lookup_value.

If you post an example of the full message, we can modify the rule using rule functions like regex() or similar to pull the UID value out of the message and then compare it in the table…

1 Like

This is possible , I did a quick scan on the forum and found these examples.

EDIT What @tmacgbay said also :smiley:

Here’s a sample of the output, going to look through the links you posted too.

idm-client1 -bash: HISTORY: PID=1880 UID=1914600003 test 21

The following also works to convert the UID to username in a new field, “username” if unable to have it search the string for any matching values and do the conversion dynamically.

rule "UID to Username"
when
    has_field("message")
    then

//Change UID to Username
let update_source = lookup_value("lookup_username",to_string(1914600003),"USER_NOT_FOUND");

set_field("username",update_source);
    
end

Do you want to replace the UID int he message, add the username onto the message or have a separate field that contains the username?

I would write the rule so that if you need to add username/UID combinations you only need to change one rule or modify one table file - much easier to manage.

Ultimate goal would be to replace the UID with the username in the message itself. If unable, second best would be for it to be in a new field as we seem to sort of have it working now.

rule "Graylog Web Access User Convert"
when
    contains(to_string($message.message),"UID=")
then
    // create a local to make it slightly less intensive to work with
    let robin = to_string($message.message);
   
   // EDIT: deleted bad part

    let batman = replace(robin, "5e224e7683d72eff75055199", "greg.smith");
    let batman = replace(robin, "100100110010011001001",    "tad.sherrill");
    let batman = replace(robin, "987324e32874ff32892b2829", "steven.o");

    // replace the hexadecimal that follows UID= with USER_NOT_FOUND.... 
    //    the d+ means it will only be found and replaced if it's a series of digits that includes chars a thru f.
    //    the a-f part takes into account your UID may be base 16 hexidecimal like Gregs
    //    if you are sure it's just digits, you can just use "(?<=UID\\=)(?>\\d+)"
    //    might be dangerous if your username has only letters a-f
    let batman = regex_replace("(?<=UID\\=)(?>[\\da-f]+)",robin,"USER_NOT_FOUND",false);

    // replace the numbers that follows UID= with USER_NOT_FOUND
    // let batman = regex_replace("(?<=UID\\=)(?>\\d+)",robin,"USER_NOT_FOUND",false);

    set_field("message",batman);
end
1 Like

This is definitely looking closer, but it seems that its not able to correctly identify the string to replace it.

I slightly modified the code to use a test UID. Also, as you had suggested in your comments changed the “a-f” to “d+” since all of the UID’s will be numbers only.

rule "Graylog Web Access User Convert"
when
    contains(to_string($message.message),"UID=")
then
    // create a local to make it slightly less intensive to work with
    let robin = to_string($message.message);
   
   // replace the number that follows UID= with USER_NOT_FOUND
    let batman = regex_replace("(?<=UID\\=)(?>\\d+)",robin,"USER_NOT_FOUND",false);

    let batman = replace(robin, "1914600003", "steveno");
    let batman = replace(robin, "100100110010011001001",    "tad.sherrill");
    let batman = replace(robin, "987324e32874ff32892b2829", "steven.o");

    // replace the numbers that follows UID= with USER_NOT_FOUND
    let batman = regex_replace("(?<=UID\\=)(?>\\d+)",robin,"USER_NOT_FOUND",false);

    set_field("message",batman);
end

It is replacing the UID with USER_NOT_FOUND directly inline on the message which is what we had hoped for, but now just need to understand why it doesn’t identify the UID and replace it with the matching username as expected.

Ah, I think we’re in business now! It seems we needed to set “robin” instead of “batman” in the second section.

rule "Graylog Web Access User Convert"
when
    contains(to_string($message.message),"UID=")
then
    // create a local to make it slightly less intensive to work with
    let robin = to_string($message.message);
   
   // replace the number that follows UID= with USER_NOT_FOUND
    let batman = regex_replace("(?<=UID\\=)(?>\\d{10})",robin,"USER_NOT_FOUND",false);

    let robin = replace(robin,"1914600003", "steveno");
//  let batman = replace(robin, "1914600003", "steveno");
//  let batman = replace(robin, "100100110010011001001",    "tad.sherrill");
//  let batman = replace(robin, "987324e32874ff32892b2829", "steven.o");

    // replace the numbers that follows UID= with USER_NOT_FOUND
    let batman = regex_replace("(?<=UID\\=)(?>\\d{10})",robin,"USER_NOT_FOUND",false);

    set_field("message",batman);
end

I messed up - take out the first “user not found” that deletes the number you are looking for and screws the whole thing up! - I had deleted it in my test but messed up on the one I pasted in!!! so it should be:

rule "Graylog Web Access User Convert"
when
    contains(to_string($message.message),"UID=")
then
    // create a local to make it slightly less intensive to work with
    let robin = to_string($message.message);
   
    let batman = replace(robin, "1914600003", "steveno");
    let batman = replace(robin, "100100110010011001001",    "tad.sherrill");
    let batman = replace(robin, "987324e32874ff32892b2829", "steven.o");

   // changed the number of digits count to be required between 6 and 10   {6,10}
    let batman = regex_replace("(?<=UID\\=)(?>\\d{6,10})",robin,"USER_NOT_FOUND",false);

    set_field("message",batman);
end
1 Like

Thanks tmacgbay - that makes sense, when I update the code it still reports USER_NOT_FOUND unless I change the line

let batman = replace(robin, “1914600003”, “steveno”);

to

let robin = replace(robin, “1914600003”, “steveno”);

Here’s the rule in its entirety

rule "Graylog Web Access User Convert"
when
    contains(to_string($message.message),"UID=")
then
    // create a local to make it slightly less intensive to work with
    let robin = to_string($message.message);
   
    let batman = replace(robin,"1914600003", "steveno");
    //  let batman = replace(robin, "100100110010011001001",    "tad.sherrill");
    //  let batman = replace(robin, "987324e32874ff32892b2829", "steven.o");

    // replace the numbers that follows UID= with USER_NOT_FOUND
    let batman = regex_replace("(?<=UID\\=)(?>\\d{6,10})",robin,"USER_NOT_FOUND",false);

    set_field("message",batman);
end

@tmacgbay @steveno

I’m reading this post with the naming convention Batman & Robin. Love it :laughing:

Thanks so much to you both! @tmacgbay @gsmith

This solution does exactly what we needed. Your time and patience was appreciated. We’ve decided to forgo the “USER_NOT_FOUND” as it’s probably better to have it to show the UID anyway so that we can identify the user manually if we haven’t updated the table yet.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.