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

How do I secure pyctuator endpoints with basic auth (FastAPI)? #67

Closed
thurse93 opened this issue Oct 5, 2021 · 14 comments
Closed

How do I secure pyctuator endpoints with basic auth (FastAPI)? #67

thurse93 opened this issue Oct 5, 2021 · 14 comments

Comments

@thurse93
Copy link

thurse93 commented Oct 5, 2021

In the API of the Pyctuator object I did not find a way to secure the provided endpoints with BasicAuth. What would be the most straightforward way of doing this using FastAPI?

Also, how can i communicate the credentials to Spring Boot Admin?

If I understood https://codecentric.github.io/spring-boot-admin/current/#spring-boot-admin-client right, I can use something like:

    metadata={
        "user.name": "foo",
        "user.password": "bar"
    }

In the metadata arg of Pyctuator. Is that correct?

@michaelyaakoby
Copy link
Member

Your reference is for the java spring-boot-admin-client.
In Pyctuator, see https://github.com/SolarEdgeTech/pyctuator#spring-boot-admin-using-basic-authentication

@thurse93
Copy link
Author

thurse93 commented Oct 6, 2021

Your reference is for the java spring-boot-admin-client. In Pyctuator, see https://github.com/SolarEdgeTech/pyctuator#spring-boot-admin-using-basic-authentication

Oh, I think there was a missunderstanding. I do not want to authenticate against a protected Spring Boot Admin Instance. Instead I want to secure the Endpoints of the App itself. Custom health providers could leak sensitive information, so I want some kind of BasicAuth-Mechanism for every route under /pyctuator.

@michaelyaakoby
Copy link
Member

Hi @thurse93,

In the case of protecting the /pyctuator paths, I think it should be the responsibility of the app developer to protect the app's API.
I mean, there so many ways to protect an API (starting with basic-auth, oauth2, client-certificate, adding all kinds of RBAC etc), that it doesn't make sense for Pyctuator to support all of them.

However, after you figure out how to protect your web app using FastAPI, it would be great if you could share an example here or even submit a pull-request with the example added to the examples folder.

Thanks

@thurse93
Copy link
Author

thurse93 commented Oct 6, 2021

Hey @michaelyaakoby ,

100% agree with that. But atm securing the FastAPI endpoints normally happens on a per-endpoint / per-router basis, see: https://fastapi.tiangolo.com/advanced/security/http-basic-auth/ Since the Routing definition is taking place in pyctuator, the should be some kind of API to add at least the most basic kind of authentication.

More importantly, again referring to the spring boot admin docs: https://codecentric.github.io/spring-boot-admin/current/#_securing_client_actuator_endpoints
If I understand this section correctly SBA has builtin support for BasicAuth against the clients Endpoints. So on registration with SBA the client application can provide the metadata credentials (see https://codecentric.github.io/spring-boot-admin/current/#_sba_client / initial comment) needed for SBA to access its endpoints. If this is correct I think pyctuator should provide some kind of interface for this functionality.

@michaelyaakoby
Copy link
Member

Oh, now I see the issue - reopening and lets try to find a way to configure FastAPI security using a "path" and not a specific function.

@michaelyaakoby michaelyaakoby reopened this Oct 7, 2021
@michaelyaakoby
Copy link
Member

Might be possible to inject the auth dependency to the router, see https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter.
I'll try this later.

@thurse93
Copy link
Author

thurse93 commented Oct 11, 2021

I made a proof of concept, just for FastAPI: thurse93@146d2ba

(Since I changed the signature of your core classes, updated FastAPI and did not adjust the tests its far from a PR)

Minimal working example would be as follows (assuming SBA runs on http://localhost:8090):

import uvicorn
from fastapi import FastAPI

from pyctuator.auth import BasicAuth
from pyctuator.pyctuator import Pyctuator

app = FastAPI()

pyctuator = Pyctuator(
    app,
    app.title,
    "http://localhost:8080",
    "http://localhost:8080/pyctuator",
    "http://localhost:8090/instances",
    pyctuator_endpoint_auth=BasicAuth(username="foo", password="bar")
)

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8080)

SBA gets the credentials via the registration metadata (fields are user.name and user.password literal, no nesting) and successfully authenticated itself against the pyctuator endpoints.

I think its quite straightforward to do. Unfortunately I dont know much about the other web frameworks you're using so I can't provide much help there.

@michaelyaakoby
Copy link
Member

Thanks @thurse93, its a good start.

I see you were using the approach of including the credentials in the registration request as described here.

Somehow it feels wrong that Pyctuator would be responsible for securing its own routes - I think its better if we can find a way to do this from outside Pyctuator and only have Pyctuator include the credentials in the metadata of the registration.

I'm trying to see if its possible with FastAPI to secure a path instead of using the dependency parameter - if we figure this out, than all you need to do is to add the credentials to the metadata which is already supported.

Anyways, yours is a good direction - i'll be digging too, and please do write if you find a way of enabling authentication "from outside".

@thurse93
Copy link
Author

@michaelyaakoby Alright, I'll get your point. Unfortunately I didn't find a clean way to do this.

One option of course would be to add a middleware for the whole application which seems kind of overkill.

Another one may be to crawl the routes attribute of the FastAPI Object after registration of the APIRouter (FastAPI uses starlette and its routing system under the hood). But even if you follow this rather hacky path I don't see a way of alternating the routing information afterwards.

I think the problem with FastAPI is that it was designed as a very easy way of providing well-documented Restful APIs for various backends. So it makes a lot of assumptions how APIs should be built. Everything source I found expects you to define your security mechanisms at the endpoint or routing level.

@michaelyaakoby
Copy link
Member

Was a busy week, starting to dig now, will update.

michaelyaakoby pushed a commit that referenced this issue Oct 15, 2021
The customizer allows for web-framework specific customiztion.
For example, it can be used to add authentication to pyctuator running with FastAPI.

See #67
@michaelyaakoby
Copy link
Member

michaelyaakoby commented Oct 15, 2021

@thurse93, i've chaned Pyctuator to accept an optional customizer function which in case of FastAPI is receiving the router as a parameter.

See #70

WDYT?

Of course I need to document this.

michaelyaakoby pushed a commit that referenced this issue Oct 16, 2021
The customizer allows for web-framework specific customiztion.
For example, it can be used to add authentication to pyctuator running with FastAPI.

See #67
michaelyaakoby pushed a commit that referenced this issue Oct 16, 2021
The customizer allows for web-framework specific customiztion.
For example, it can be used to add authentication to pyctuator running with FastAPI.

See #67
@michaelyaakoby
Copy link
Member

I've tidied up and completed the example in #70.
Once this will be reviewed, i'll merge and release.

@thurse93
Copy link
Author

@michaelyaakoby That looks great! Sorry for the late reply, I was on vacation. Thank you very much for the realization :)

michaelyaakoby pushed a commit that referenced this issue Oct 21, 2021
The customizer allows for web-framework specific customiztion.
For example, it can be used to add authentication to pyctuator running with FastAPI.

See #67
@michaelyaakoby
Copy link
Member

Done. 0.17.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants