Custom scenario not triggering neither alert nor decision
Hello !
I installed Crowdsec with helm on my Google Kubernetes Cluster with this chart version : 0.14.1
I also deployed my custom parser, custom scenario (named
crowdsecurity/compte_xxx_login_error
) and custom profile.
When I run cscli metrics
command in one of the agent pod, I find out this information :
Scenario Metrics:
Scenario │ Current Count │ Overflows │ Instantiated │ Poured │ Expired
crowdsecurity/compte_xxx_login_error │ 1 │ 197 │ 198 │ 395 │ -
What does that line mean?
I guess my custom scenario was hit once. SO I don't understand why there is no triggered alert as well as no decision created by lapi.
Could you help me please ?
Kind regards,
Mathis56 Replies
Important Information
Thank you for getting in touch with your support request. To expedite a swift resolution, could you kindly provide the following information? Rest assured, we will respond promptly, and we greatly appreciate your patience. While you wait, please check the links below to see if this issue has been previously addressed. If you have managed to resolve it, please use run the command
/resolve
or press the green resolve button below.Log Files
If you possess any log files that you believe could be beneficial, please include them at this time. By default, CrowdSec logs to /var/log/, where you will discover a corresponding log file for each component.
Guide Followed (CrowdSec Official)
If you have diligently followed one of our guides and hit a roadblock, please share the guide with us. This will help us assess if any adjustments are necessary to assist you further.
Screenshots
Please forward any screenshots depicting errors you encounter. Your visuals will provide us with a clear view of the issues you are facing.
© Created By WhyAydan for CrowdSec ❤️

So it had 197 overflows, but any chance you can share the scenario file?
the main part for sceanrio is:
if this is not set or false then it wont trigger from profiles unless you have a custom one
Here are my custom parser, custom scenario and custom profile

ahhh I see the issue
you are grouping on a non IP adderss metric
yes I group on a the tls ja3 fingerprint
that I parse
is that a problem ?
Not a problem but non of our remediation know about ja3 unless you have a custom one
the http_x_client_ja3 is one of my static that I retrieve in the custom scenario
So firstly you can add this to the sceanrio:
this will set the value in the alert message and scope
then within the profiles you can remove the value and scope from the profile
Like this ?
type: leaky
name: crowdsecurity/compte_xxx_login_error
description: "Detect compte_xxx bruteforce logins"
filter: evt.Meta.log_type == "compte-xxx"
leakspeed: "10s"
capacity: 1
groupby: evt.Meta.http_x_client_ja3
scope:
type: Fingerprint
expression: evt.Meta.http_x_client_ja3
labels:
service: compte-xxx
type: login
remediation: true
Ye
I'm testing
it seems to be working
so it's gonna create one decision per alert, is that correct?
Yeah thats correct, but remember non our remediation can handle ja3 blocking but if its alerting yeah
sorry but I didn't get what you said
So the alerts will be under scope "Fingerprint" but none of our remediations know how to block these types of alerts
yes actually I stored the decisions in a postgresql database and I created a "bouncer" with a python docker image that retrieves the decisions in the database and that creates cloud armor rule depending on the values of the alert
Awesome! then yeah your good to go then 😄
Thank you ! Last question : how to retrieve the content of an alert ?
Well remediations/bouncer call the LAPI on
/decisions/stream
https://crowdsecurity.github.io/api_doc/lapi/
which sends all decisions no matter the scope or value.
this is the data struct
so type == Fingerprint and value will be the ja3 valueAlright, actually the value equals to "Fingerprint", doesn't sound like I would like to

huh
okay something off
what do you mean?
the value column should be
fingerprint:<value>
unless your TTY too small and it chopping if off
within the sceanario if you add to the filter http_x_client_ja3 != ''
does it stop working?I'm testing with it
what does TTY stand for?
oooh I see the isseu
my bad
following our friends over at F5 https://community.f5.com/kb/TechnicalArticles/ja4-part-2-detecting-and-mitigating-based-on-dynamic-ja4-reputation/328663
You need to add
so the scope was important
so in your case
Alright i'm testing
the type and the duration of the decision are well retrieved but still not the value
hello @iiamloz
hello there 🙂
apologise, I been off with illness the last week, can you let me know whats happening?
no worries
yes : actually I created my custom profiles and scenarios and parsers. And the value of the alert equals to "Fingerprint". The problem is that "Fingerprint" is the scope. So evt.Meta.http_x_client_ja3 seems to be empty.
as I mentionned here
Here are my custom profile and custom scenario:
name: ban_fingerprint_24h_for_compte_xxx_fr_login_error
filters:
- Alert.Remediation == true && Alert.GetScenario() == "crowdsecurity/compte_xxx_fr_login_error" && Alert.GetScope() == "Fingerprint"
decisions:
- type: ban
duration: 24h
scope: "Fingerprint"
on_success: continue
type: leaky
name: crowdsecurity/compte_xxx_fr_login_error
description: "Detect compte_xxx_fr bruteforce logins"
filter: evt.Meta.log_type == "compte-xxx-fr"
leakspeed: "10s"
capacity: 10
groupby: evt.Meta.http_x_client_ja3
scope:
type: Fingerprint
expression: evt.Meta.http_x_client_ja3
labels:
service: compte-xxx-fr
type: login
remediation: true
hmmm and the parser seems to be fine?
yes it does :


Idk why the "Fingerprint" value is passed as the scope
Even though it parsing it seems the expression to extract the ja3 hash is not working
so you believe that evt.Meta.http_x_client_ja3 is empty ?
Here is my parser configuration:
filter: evt.Line.Labels.type == "docker"
onsuccess: next_stage
name: crowdsecurity/compte-xxx-fr-logs
description: "Parse compte-xxx-fr logs"
debug: true
statics:
- target: evt.StrTime
expression: JsonExtract(evt.Line.Raw, "time")
- meta: remote_addr
expression: JsonExtractUnescape(evt.Line.Raw, "remote_addr")
- meta: request_method
expression: JsonExtractUnescape(evt.Line.Raw, "request_method")
- meta: request_uri
expression: JsonExtractUnescape(evt.Line.Raw, "request_uri")
- meta: status
expression: JsonExtractUnescape(evt.Line.Raw, "status")
- meta: http_user_agent
expression: JsonExtractUnescape(evt.Line.Raw, "http_user_agent")
- meta: http_x_client_ja3
expression: JsonExtractUnescape(evt.Line.Raw, "http_x_client_ja3")
- meta: log_type
value: "compte-xxx-fr"
what should I modify to pass the right value ?
to the alertSo I would firstly add a check to the sceanrio like
evt.Meta.http_x_client_ja3 != ''
to firstly check if the parser is setting the correct value
as even though your metrics say "parsed" this just simply means the filter passed as there no grok it doesnt ever fail technicallyOk when I add your filter, the alerts creation are more realistic
I had the impression that at each http_x_client_ja3 value it created an alert, that's not the case anymore
But when I want to trigger my scenario, it doesn't
then the parser is not setting the value correctly, do you have the json value?
the json value of the log ?
yes
Yes :
{"time": "2025-02-24T13:39:08+00:00","remote_addr": "34.xx.xx.xx","remote_user": "api","host": "compte-qlf.xxx.fr","request_method": "POST","request_uri": "/auth/realms/xxx.fr/protocol/openid-connect/token","status": "200","body_bytes_sent": "1562","http_referer": "","http_user_agent": "Java/11.0.16","http_x_forwarded_for": "xx.xx.xx.xx", 34.160.223.109","http_x_client_region": "BE","http_x_client_city": "Brussels","http_x_client_ja3": "2c7b42xxxxxx","http_x_cloud_trace_context": "d1111c38a98f357779acaabbd9c8f17b/2268093701284203453","realip_remote_addr": "130.211.1.128","request_time": "0.128","request_length": "652","upstream_response_time": "0.127","upstream_response_length": "1562","upstream_header_time": "0.127","upstream_status": "200","upstream_addr": "100.92.28.160:80","upstream_connect_time": "0.000"}
hmmm, and how are you defining the acquisition? cause the
evt.Line.Labels.type == "docker"
is odd
cause we recommend this
so what is the program set too?It is probably set to "docker"
These are the labels you recommend setting on the parser ?
Can you share what the acquisition is set too?
then I can change the parser to improve some aspects
you mean that, isn't it?
the container runtime is docker
well when you define the values, you setup the locations of where crowdsec find the files or namespaces
oh yes sure sorry
agent:
acquisition:
- namespace: "keycloakx"
podName: "keycloakx-"
program: "keycloakx"
- namespace: "keycloakx"
podName: "compte-xxx-fr-"
program: "compte-xxx-fr"
- namespace: "gravitee"
podName: "api-xxx-fr-*"
program: "api-xxx-fr"
okay, and you would say that
program: "compte-xxx-fr"
is what we aiming to parse?yes
correct
okay let me cook a new parser up
okay thank you
im struggling with the test data you provided @MTRYLA seems its invalid json as
"http_x_forwarded_for": "xx.xx.xx.xx", 34.160.223.109"
has an extra ,
and a quote
can you DM me the raw log line?yes
I grabbed it and deleted it 🙂
thank you
tell me if you find that strange
I dm'ed you the update parser and my debugging
to keep thread updated here is the updated parser
note from DM
to keep thread updates
so another issue was found that the
container_runtime
was set to docker
but it was containerd
upon changing the value the parser had to be updated UnmarshalJSON(evt.Parsed.message, evt.Unmarshaled, 'compte') in ['', nil]"
since containerd has some pre message stuff, we had to use the acutal message not the raw line
classing ticket as solved, but we already spoke in DM's about the other parsers the user has filter:1==1
these are not impacting right now but could be improved in futureResolving Custom scenario not triggering neither alert nor decision
This has now been resolved. If you think this is a mistake please run
/unresolve