MrFoot fifer
MrFoot fifer

Reputation: 581

FastAPI how to allow endpoint access for specific IP only?

How to limit endpoint access only to specific IPs with FastAPI?

Upvotes: 15

Views: 17097

Answers (3)

John Moutafis
John Moutafis

Reputation: 23144

FastAPI provides a TrustedHostMiddleware that:

Enforces that all incoming requests have a correctly set Host header, in order to guard against HTTP Host Header attacks.

from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware

app = FastAPI()

app.add_middleware(
    TrustedHostMiddleware, allowed_hosts=["example.com","*.example.com"] 
)


@app.get("/")
async def main():
    return {"message": "Hello World"}

The following arguments are supported:

  • allowed_hosts - A list of domain names that should be allowed as hostnames. Wildcard domains such as *.example.com are supported for matching subdomains to allow any hostname either use allowed_hosts=["*"] or omit the middleware.

If an incoming request does not validate correctly then a 400 response will be sent.

Another solution would be to compose an IP whitelist for your deployment medium (ex: k8).

Upvotes: 11

Hossein Zareipour
Hossein Zareipour

Reputation: 1

You can use ufw

sudo ufw allow from IP proto tcp to any port PORT

Upvotes: -1

Rehmat
Rehmat

Reputation: 5071

The accepted answer makes use of the TrustedHostMiddleware but that can be easily spoofed using a reverse proxy, i.e. using NGINX or using any other technique. In my opinion, validating IP address in a custom middleware is more secure:

from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse


app = FastAPI()

# Whitelisted IPs
WHITELISTED_IPS = []

@app.middleware('http')
async def validate_ip(request: Request, call_next):
    # Get client IP
    ip = str(request.client.host)
    
    # Check if IP is allowed
    if ip not in WHITELISTED_IPS:
        data = {
            'message': f'IP {ip} is not allowed to access this resource.'
        }
        return JSONResponse(status_code=status.HTTP_400_BAD_REQUEST, content=data)

    # Proceed if IP is allowed
    return await call_next(request)

I'd maintain a list of whitelisted IPs and then I'd compare the client IP to the list and will return a 400 Bad Request error if the IP is not in the whitelisted IPs list.

Upvotes: 22

Related Questions