Skip to content

Conversation

@brbzull0
Copy link
Contributor

So there are two changes here, I have them both in the same PR as the last one depends on the first one.

1 - We needed a way to let the handler to pass information to the registration which at some point later on could be validated or used in any way, so this is a base change for further checks(like client's socket credentials). This defines a new type in the apidefs.h.in because this will eventually be used from the Plugin API.
Please check this commit to see this changes only.

There is also a documentation update here in this commit

2 - The main driver for this change: adding peer's credentials check on rpc calls.

Context:

When moved from traffic_manger admin socket to the new JSONRPC api, the management api restrictions were left out, the only restriction in place was related to the creation of the jsonrpc unix socket(either 700 or 777) just at user level losing the original capability to check the socket’s peers credentials and allow or deny certain operations, like read only calls(record lookup) vs operation that can change the state of ATS(like a record set). This was a useful method to allow some non-root users to perform some actions while we leave root users to have full access to the API. So this PR also includes the same feature but now on the JSONRPC node.

Please check this commit to see this changes only.


This is an example of the output you will get when if request an unauthorized rpc method:

$ traffic_ctl config reload
Server Error found:
[10] Unauthorized action
- [2] Denied privileged API access for uid=1001 gid=1001

The raw json would look like:

   {
      "jsonrpc": "2.0",
      "error":{
         "code": 10,
         "message": "Unauthorized action",
         "data":[
            {
               "code": 2,
               "message":"Denied privileged API access for uid=XXX gid=XXX"
            }
         ]
      },
      "id":"5e273ec0-3e3b-4a81-90ec-aeee3d38073f"
   }

@brbzull0 brbzull0 self-assigned this May 25, 2022
@brbzull0 brbzull0 added JSONRPC JSONRPC 2.0 related work. Documentation labels May 25, 2022
@brbzull0 brbzull0 requested a review from SolidWallOfCode May 25, 2022 15:39
@brbzull0 brbzull0 linked an issue May 25, 2022 that may be closed by this pull request
@brbzull0 brbzull0 marked this pull request as ready for review May 26, 2022 10:38
@brbzull0 brbzull0 requested review from bryancall and zwoop as code owners May 26, 2022 10:38
structure.

File `jsonrpc.yaml` is a YAML format. The default configuration is:
File `jsonrpc.yaml` is a YAML format. The default configuration looks like:
Copy link
Contributor

Choose a reason for hiding this comment

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

So it's like a default imposter?

int restricted; ///< Tells the RPC Manager if the call can be delivered or not based on the config rules.
} auth;
} TSRPCHandlerOptions;

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this in apidefs.h ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So can be directly used from both sides(core & plugins). isn't that the point of apidefs.h?

Copy link
Contributor

Choose a reason for hiding this comment

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

OK but I don't see this used as the type of any parameter to any TS API function.

Copy link
Contributor Author

@brbzull0 brbzull0 Jun 7, 2022

Choose a reason for hiding this comment

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

Although it sets the base, this change does not include any changes on the plugin API. We have a separated PR for that, which still didn't make it into 10-Dev. I will update that PR after we agree on this.

Copy link
Contributor

Choose a reason for hiding this comment

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

So you're saying it's for future use?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So you're saying it's for future use?

short answer: yes.

long asnwer:
The future is here: #8630, I will update 8630 after this one is done.
At yahoo we are running the rpc TS API in production since quite some time now, so all this changes will get into our yahoo ats as well very soon.

[this](std::string_view const &id, const YAML::Node &req) -> ts::Rv<YAML::Node> {
return get_files_registry_rpc_endpoint(id, req);
},
&rpc::core_ats_rpc_service_provider_handle, {{rpc::NON_RESTRICTED_API}});
Copy link
Contributor

@ywkaras ywkaras Jun 3, 2022

Choose a reason for hiding this comment

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

Seems dangerous, capturing the this pointer, tricky to keep it from not becoming stale due to object destruction:

wkaras ~/REPOS/MISC/LAMBDA_THIS
$ cat x.cc
#include <iostream>

struct A;

A *ga;

struct A
{
    int i = 5;

    auto f() { return [this]() -> A & { return *this; }; }

    auto g()
    {
        A a{*this};

        return [a]() -> int { return a.i; };
    }
};

int main()
{
    ga = new A;

    auto lambda_f = ga->f();
    auto lambda_g = ga->g();

    delete ga;

    if (&lambda_f() == ga)
    {
        std::cout << "Dangling pointer!\n";
    }

    std::cout << lambda_g() << '\n';

    return 0;
}
wkaras ~/REPOS/MISC/LAMBDA_THIS
$ gcc -Wall -Wextra -pedantic x.cc -lstdc++
wkaras ~/REPOS/MISC/LAMBDA_THIS
$ ./a.out
Dangling pointer!
5
wkaras ~/REPOS/MISC/LAMBDA_THIS
$ 

The g() member function shows a safe way to capture an object whose class the function is a member of.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

FileManager is now a singleton class, by the time it's gone it shouldn't dangle.

Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest then that you make the FileManager constructor private.

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 don't want to add unrelated changes to this PR -> #8888 @ywkaras

static constexpr auto logTag = "rpc";
static constexpr auto logTagMsg = "rpc.msg";
// --- Helpers
std::pair<ts::Errata, error::RPCErrorCode>
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't pair kinda deprecated is favor of tuple?

Copy link
Member

Choose a reason for hiding this comment

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

Meh. The better question is, why pair instead of the struct Error defined earlier.

template <typename Func>
inline bool
add_method_handler(const std::string &name, Func &&call, const RPCRegistryInfo *info = nullptr)
add_method_handler(const std::string &name, Func &&call, const RPCRegistryInfo *info, TSRPCHandlerOptions const &opt)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this seems to get called with a string literal, you could avoid a heap allocation if the type was std::string_view.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks Walt.
yes, I would probably have them constant defined and not use the name as literal in the call anyway, I wasn't very worry about this as it only happens at startup and at the end it will allocate to hold it internally.
I may add a new pr with some tweaks I have noted, takling this too possibly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@brbzull0 brbzull0 force-pushed the jsonrpc-add-context-handler-option-and-client-peer-checks branch from f60613c to b3151ff Compare June 7, 2022 13:28
@brbzull0
Copy link
Contributor Author

brbzull0 commented Jun 7, 2022

[approve ci autest]

2 similar comments
@bneradt
Copy link
Contributor

bneradt commented Jun 8, 2022

[approve ci autest]

@brbzull0
Copy link
Contributor Author

brbzull0 commented Jun 8, 2022

[approve ci autest]

@brbzull0 brbzull0 added this to the 10-Dev milestone Jun 9, 2022
@brbzull0 brbzull0 force-pushed the jsonrpc-add-context-handler-option-and-client-peer-checks branch from b3151ff to 0be22ba Compare June 10, 2022 09:37

namespace rpc
{
const bool RESTRICTED_API{true};
Copy link
Member

Choose a reason for hiding this comment

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

Why not constexpr?

/// @param options Registered handler options.
/// @return ts::Errata The errata will be filled by each of the registered checkers, if there was any issue validating the
/// call, then the errata reflects that.
ts::Errata any_blockers(TSRPCHandlerOptions const &options) const;
Copy link
Member

Choose a reason for hiding this comment

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

Might be better named "is_blocked".


struct RPCResponseInfo {
RPCResponseInfo(std::optional<std::string> const &id_) : id(id_) {}
RPCResponseInfo(std::optional<std::string> const &id_) : id{id_} {}
Copy link
Member

Choose a reason for hiding this comment

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

Why use std::optional with std::string? Isn't an empty string the same as not having one?

struct RPCResponseInfo {
RPCResponseInfo(std::optional<std::string> const &id_) : id(id_) {}
RPCResponseInfo(std::optional<std::string> const &id_) : id{id_} {}
RPCResponseInfo(std::error_code const &ec_) : error{ec_, {}} {}
Copy link
Member

Choose a reason for hiding this comment

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

std::optional is even odder if you have these overloads - why not have a constructor with no parameters at all?

RPCHandlerResponse callResult;
std::error_code rpcError;
struct Error {
std::error_code ec;
Copy link
Member

Choose a reason for hiding this comment

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

We can fix this once we switch to swoc::Errata. It supports embedding the ec in the Errata.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this is on my TODO list once we have libswoc in our private repo.

brbzull0 added 3 commits June 16, 2022 11:32
… a new JSON-RPC endpoint handler.

To support this a new class Context is introduced as well as a Handler option class, this changes sets the base for
future work around the handler registration and the Plugin API.
…ration. It also fixes some bad links and typos.
…can now decide if they want to be administrative restricted or not.

Add documentation support for this.
@brbzull0 brbzull0 force-pushed the jsonrpc-add-context-handler-option-and-client-peer-checks branch from 0be22ba to 80d52bf Compare June 20, 2022 14:25
@brbzull0 brbzull0 force-pushed the jsonrpc-add-context-handler-option-and-client-peer-checks branch from 80d52bf to f532c93 Compare June 21, 2022 13:58
@brbzull0 brbzull0 merged commit ddcb091 into apache:10-Dev Jun 21, 2022
@zwoop zwoop modified the milestones: 10-Dev, 10.0.0 Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Documentation JSONRPC JSONRPC 2.0 related work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use JSON-RPC based interface for administrative API.

5 participants