Securing the web interface

Your question

Hi,

I’m setting up stalwart, and I’d like to further lock down the public web interface. As far as I can find /api shouldn’t really be exposed publicly, the rest seems fine (going by Overview | Stalwart )

I setup a separate admin-http listener bound to 127.0.0.1, and put a reverse proxy in front of it (so I still can have TLS enabled) which listens on port 8443, but I’m having a hard time restricting the flow to the public endpoint (443)

Trying to implement basically

{
  "allowedEndpoints": {
    "match": [
      {"if": "listener == 'admin-http' || contains(['jmap', 'robots.txt', '.well-known'], split(url_path, '/')[1])", "then": "200"}
    ],
    "else": "404"
  }
}
stalwart-cli get Http --url https://public-url  --api-key API_redacted
Response
  Headers:       <none>
  Redirect root: /account

Proxy
  Obtain remote IP from Forwarded header: Yes

Security
  Allowed endpoints:
    Expression
      Conditions:
        #  Condition                                                                                               Result
        0  "listener == 'admin-http' || contains(['jmap', 'robots.txt', '.well-known'], split(url_path, '/')[1])"  200   
      Default Value: 404
  Enable HTTP Strict Transport Security: No
  Permissive CORS policy:                No

Rate Limit
  Authenticated:
    Rate
      Count:  1000
      Period: 1 m
  Anonymous:
    Rate
      Count:  100
      Period: 1 m

Listeners:

Id            Name         Protocol     Bind addresses  Implicit TLS
i7qcfx0uabaa  admin-http   HTTP         127.0.0.1:8080  No          
i7lyonbeahab  https        HTTP         [::]:443        Yes         
i7lyonbeagqb  sieve        ManageSieve  [::]:4190       No          
i7lyonbeafqb  imaps        IMAP4        [::]:993        Yes         
i7lyonbeafab  submissions  SMTP         [::]:465        Yes         
i7lyonbeaeqb  smtp         SMTP         [::]:25         No       

doing simple tests like

curl https://<public hostname/api/schema

and

curl https://<internal hostname>:8443/api/schema

both keep returning 401, where i’d expect the public to return 404

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Well, putting the telemetry to TRACE helped me

The correct syntax is

listener == 'admin-http' || contains(['jmap', 'robots.txt', '.well-known'], split(url, '/')[1])

so url instead of url_path, drop the quotes.

The documentation needs to be updated - Access Control | Stalwart mentions url_path.