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 Solution][Case] Case connector supporting session based authentication webhook #94518

Closed
zez3 opened this issue Mar 12, 2021 · 17 comments
Labels
Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. triage_needed

Comments

@zez3
Copy link

zez3 commented Mar 12, 2021

Please allow generic JSON-RPC based Connectors that generate session based tokens

Describe the feature:
At this moment(7.11.2)
there are only a few Connectors possible
image

We need a generic JSON-RPC based connector that could support session based tokens

Perhaps similar to this:
#56874
also related
#86233
#93246

Describe a specific use case for the feature:

A specific use case is FortiManager

image
No auth used
image
After the initial POST request
a response looks like


{
    "id": 1,
    "result": [
        {
            "status": {
                "code": 0,
                "message": "OK"
            },
            "url": "/sys/login/user"
        }
    ],
    "session": "DoBXSd4WDWk40xNZ5+PJE8GmLLjg8Le24P7xuz6oMNqkUExFcaDFMKWG99xC56RHbDlRA/9Owx6mQ=="
}

The session token then needs to be used in all next requests:

e.g. a firewall policy add request

{
    "method": "add",
    "params": [
        {
            "url": "pm/config/adom/{{ADOM_NAME}}/pkg/{{VDOM_NAME}}/firewall/policy",
            "data": {
                "status": 1,
                "srcintf": [
                    "any"
                ],
                "srcaddr": [
                    "some_test_attacker_ip"
                ],
                "dstintf": [
                    "any"
                ],
                "dstaddr": [
                    "all"
                ],
                "internet-service": 0,
                "internet-service-src": 0,
                "service": [
                    "ALL"
                ],
                "schedule": [
                    "always"
                ],
                "action": 0,
                "policyid": -1,
                "name": "ES_SIEM_test2",
                "comments": "2021.03.10 fs ES_SIEM_test" 
            }
        }
    ],
    "session": "{{Session_ID}}"
}
@zez3
Copy link
Author

zez3 commented Mar 12, 2021

@lukeelmers lukeelmers added the Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. label Mar 15, 2021
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

@cnasikas cnasikas added the Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) label Mar 16, 2021
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-alerting-services (Team:Alerting Services)

@pmuellr
Copy link
Member

pmuellr commented Mar 26, 2021

Sounds like we would need similar support as indicated in the OAuth issue #79372 . Specifically, there are out-of-band networking requests being made, and data persisted between calls (stored in a saved object somewhere).

We need a generic JSON-RPC based connector that could support session based tokens

I'm not familiar with these session-based tokens as part of JSON-RPC, and am a little worried that there isn't a "generic" protocol for this, like there is with OAuth. Does each service that support this sort of protocol have it's own definition of how it works? So we'd have to develop code for each of these protocols. Or is there a spec'd version of this we can write once and then reuse across multiple connectors? Open questions like how long do the sessions live, do we know how long the sessions live so we can deal with expiration proactively, etc.

In terms of getting this to work today, without direct support for it, I'd say the only way is to write your own web service which deals with all this stuff, but provides a simpler user/pass authentication and passes the incoming requests to the url it's supposed to be going to, with the proper auth bits.

@zez3
Copy link
Author

zez3 commented Mar 27, 2021

@zez3
Copy link
Author

zez3 commented Mar 27, 2021

More specific
"To communicate with a FortiManager via the API, a client program must send HTTP POST request to https://<fmg_ip>/jsonrpc, where <fmg_ip> is the IP address or FQDN of the FortiManager.

Message Format

The format of JSON request:

{
    "id": 1,
    "method": "...",
    "params": [ ... ],
    "session": "..."
}

id: digital identifier of JSON request or response message. id in a JSON request is always same as the id in the response.
method: could be get, add, set, update, delete, move, clone, exec
params: contains parameters of JSON request, such as JSON URL and object attributes.
session: contains the authentication token that is dynamically generated by FortiManager.

The format of JSON response:


{
    "id": 1,
    "result": [
        "data": [ ... ],
        "status": {
            "code": 0,
            "message": "OK"
        },
        "url": "..."
    ],
    "session": "..."
}

data: may not exist if there is no any object attribute is returned
code: code of the API request execution, 0 means success
message: text message for the API request execution
"

"
Session ID

To make the API requests from the tool of your choice, you need a session ID. A login operation is required to get the session ID. This session ID can be used in all subsequent FortiManager JSON API requests.

To login, you can use the FortiManager API admin user you created in the previous section. The software tool you use must send HTTP POST request to https://<fmg_ip>/jsonrpc, where <fmg_ip> is the IP address or FQDN of the FortiManager.

The API request & response are like this:

request = 
{
    "id": 1,
    "method": "exec",
    "params": [
        {
            "data": {
                "passwd": "",
                "user": "admin"
            },
            "url": "/sys/login/user"
        }
    ]
}

response = {
    "id": 1,
    "result": [
        {
            "status": {
                "code": 0,
                "message": "OK"
            },
            "url": "/sys/login/user"
        }
    ],
    "session": "657qeHLS1sFMulxiS2yY2Da9uPMuV+66mAzFSSJg77kNLIIHNZlm1dipfoPB8Xzq3HtfTU/Ct5yTQCmNYqG6fg=="
}

The session ID we have from the request is:

657qeHLS1sFMulxiS2yY2Da9uPMuV+66mAzFSSJg77kNLIIHNZlm1dipfoPB8Xzq3HtfTU/Ct5yTQCmNYqG6fg==

We will be using this session ID for our first API request to get all firewall address objects from the root ADOM below
Request 1 - Return all firewall addresses

request = {
  "id": 1
  "method": "get",
  "params": [
    {
      "url": "/pm/config/adom/root/obj/firewall/address"
    }
  ],
  "session": "657qeHLS1sFMulxiS2yY2Da9uPMuV+66mAzFSSJg77kNLIIHNZlm1dipfoPB8Xzq3HtfTU/Ct5yTQCmNYqG6fg==",
}

response = {...}

Logout FortiManager

After you finish all your API requests, it is always a good practice to log out FortiManager:

request = {
    "id": 1,
    "method": "exec",
    "params": [
        {
            "url": "/sys/logout"
        }
    ],
    "session": "657qeHLS1sFMulxiS2yY2Da9uPMuV+66mAzFSSJg77kNLIIHNZlm1dipfoPB8Xzq3HtfTU/Ct5yTQCmNYqG6fg=="
}

response = {
    "id": 1,
    "result": [
        {
            "status": {
                "code": 0,
                "message": "OK"
            },
            "url": "/sys/logout"
        }
    ]
}

"
Does this help?

@zez3
Copy link
Author

zez3 commented Mar 27, 2021

Regarting session lifetime, we can customize this to our own preference. There is a default value but you might prefer to do a logout instead of relying on that. See the above Logout example.

As a workaround now during the PoC I use flask/python to listen to a incoming Elastic SIEM webhook, extract from json the attacker IP and send it to the FortiManager.
It kind of works.

@pmuellr
Copy link
Member

pmuellr commented Mar 29, 2021

So this session support in JSON-RPC is specific to FortiManager? Or is there some JSON-RPC extension that describes it? There's a lot of overhead involved here to support a single persistent session token, for a specific connector.

Or can we just create a new session when running the command, then delete it after the command is complete? Then we can put that all in the connector, so we don't need to maintain a persistent connection. We'd use the user/passwd as the secrets for the connector.

Or is there an interest in having the user maintain the token, pasting it in as a connector secret, but creating / destroying with some separate non-Kibana workflow?

@pmuellr
Copy link
Member

pmuellr commented Mar 29, 2021

cc: @aris - another connector type for consideration

@zez3
Copy link
Author

zez3 commented Mar 29, 2021

So this session support in JSON-RPC is specific to FortiManager? Or is there some JSON-RPC extension that describes it? There's a lot of overhead involved here to support a single persistent session token, for a specific connector.

Not really something specific here. JSON-RPC is used by many cloud or non cloud Apps.
Take confluence as example:
They support both SOAP and JSON-RPC auth methods
https://developer.atlassian.com/server/confluence/confluence-json-rpc-apis/

Or can we just create a new session when running the command, then delete it after the command is complete? Then we can put that all in the connector, so we don't need to maintain a persistent connection. We'd use the user/passwd as the secrets for the connector.

That creation part using user/apss is already working (Action success)
I give the user and pass inside the json body.
See my third picture in the initial post:
https://user-images.githubusercontent.com/22619253/110919249-539c3080-831c-11eb-9739-855a958a2f1d.png

I need a way to store the resulting session ID and use it in a later(second) body request.
If you allow me to do that for every request and/or chain more than one action requests and/or pass some variable between, that could also work.

@pmuellr
Copy link
Member

pmuellr commented Mar 29, 2021

The JSON-RPC docs you point to for confluence specifically mention:

Your RPC client must log in via basic auth, OAuth or piggybacking on an existing login session.

... and later ...

JSON-RPC clients must acquire a valid login either by running in the browser of someone who is already logged in (session authentication), or must log in via basic auth or OAuth.

That session authentication bit is vague, but guessing it's implying the session id is sent via a cookie, not explicitly as part of the request.

In any case, I'm trying to find a JSON-RPC spec where it talks about this "session" aspect, and can't find anything, so it looks like it's specific to FortiManager, vs some generic JSON-RPC capability. If that's true, it's going to be expensive to add a persistence layer just for this connector, to save the sessions in. We have some work in progress on supporting OAuth, wondering if FortiManager supports that.

It also seems like service providers are phasing JSON-RPC out, in general. The doc to the Confluence APIs notes that it was deprecated in v 5.5, which came out in 2014. So again, wondering if FortiManager has something more "modern" that we have planned support for, versus having to write some new code.

And it's not clear if creating / using / deleting a session for each connector execution is problematic - it seems like that should work. Is it extremely slow or something?

@cnasikas
Copy link
Member

cnasikas commented Mar 30, 2021

To my understanding, JSON-RPC is a communication protocol like REST. The request and the response are implementation details. For that reason, there is no "session" aspect described by the protocol. The authentication is implemented by the application. It seems to me that this "session" is FortiManager specific and another service that uses JSON-RPC to communicate with the clients may use another attribute or way for authentication.

@pmuellr
Copy link
Member

pmuellr commented Mar 30, 2021

Yes, Christos has re-worded my concerns in a better way than I tried, thx :-)

Basically, it's going to be expensive to maintain a special persistent token service for a specific action type, which is what I think we would have to do here. That's why I'm wondering if FortiManager has something more "modern" like a REST/OAuth story, which we are already planning on supporting.

@zez3
Copy link
Author

zez3 commented Mar 31, 2021

The FortiManager GUI yes it does support other types of auth but for the REST API I am not aware. I will ask to get an official answer.
e.g.
https://docs.fortinet.com/document/fortimanager/6.4.5/administration-guide/981386/saml-admin-authentication

@zez3
Copy link
Author

zez3 commented Apr 30, 2021

I dug a bit dipper and you where right,

I found this discussion and shared it with the Fortinet representative person:

https://groups.google.com/g/json-rpc/c/YDLSE668ZZ8/m/3W4xDjcUAAAJ

"
...
I don't think authorization has any place in JSON-RPC. If you have a durable connection over which to pass JSON-RPC messages, the creds should have been passed as part of establishing the connection. And if you're using HTTP, the HTTP Headers are the established and well-spec'd place to pass authorization tokens.
...
"

I pointed out that the JSON-RPC auth user&pass session is not adhering to standards and the person that I spoke with agreed that this is indeed true.
Now I am not sure when or if there is a API changed planned but I will follow up the case that I have with them.

The FortiGate on the otherside uses a standard API so the suggestion was that they will implement a similar one on the FMG side.

Let's see what happens in the next release but my hope is that we will get this eventually implemented so that I don't need to play the middleman here with my own python implementation of a webhook.

@zez3
Copy link
Author

zez3 commented Apr 30, 2021

I will close this issue for now

@zez3 zez3 closed this as completed Apr 30, 2021
@kobelb kobelb added the needs-team Issues missing a team label label Jan 31, 2022
@botelastic botelastic bot removed the needs-team Issues missing a team label label Jan 31, 2022
@zez3
Copy link
Author

zez3 commented Sep 13, 2022

Good news

It will be coming with FMG 7.2.2.

This is how it will work:

  1. Create an api user:

config system admin user
edit "api_user"
set profileid "Super_User"
set user_type api
set rpc-permit read-write
next
end

  1. Generate a key for the api user:

FMG-VM64 # exe api-user generate-key api_user
New API key: y9z36zzqibbgoinz6jtog6ksohyec3d8

  1. REST api request by 'access_token':
    curl https://172.16.78.45/jsonrpc?access_token=y9z36zzqibbgoinz6jtog6ksohyec3d8 -ksS -d '{"id":2,"method":"get","params":[{"url": "/cli/global/system/status"}]}'

  2. Another way to request by 'Authorization:Bearer':
    curl https://172.16.78.45/jsonrpc -H'Authorization:Bearer y9z36zzqibbgoinz6jtog6ksohyec3d8' -ksS -d '{"id":2,"method":"get","params":[{"url": "/cli/global/system/status"}]}'

As you can see, the JSON RPC payload is no longer having a session attribute.
"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. triage_needed
Projects
None yet
Development

No branches or pull requests

6 participants