2

Securing Patroni REST API End Points - Part 1 - Percona Database Performance Blo...

 1 year ago
source link: https://www.percona.com/blog/securing-patroni-rest-api-end-points-part-1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Securing Patroni REST API End Points

In recent years, Patroni emerged as the number one HA framework for PostgreSQL, currently with 5K stars in its git repository. We blogged about how some of the extraordinary capabilities of Patroni to solve problems like Logical Replication Slot Failover.

One outstanding feature of Patroni is its powerful set of REST APIs. These APIs can be used for further automation, monitoring/healthchecks, and for integration with other systems. At the very least, the same APIs are useful for HAProxy integration for automatic connection routing, which is widely used.

Since the Patroni APIs won’t expose any data inside the PostgreSQL database and generally inbound traffic to database hosts is secured in most organizations, a large percentage of the Patroni users are happy with the default REST APIs over HTTP without any additional authentication. However, that may not be the case if the database hosts are potentially exposed to a broader network. A few organizations have blanket rules for raising any HTTP traffic as red flags. Sometimes, additional certificate verifications also become mandatory as per organization policies.

Safe and unsafe APIs

Patroni APIs can be broadly classified as Safe and Unsafe APIs.

Those APIs used for understanding the current state and topology of the Patroni cluster are widely used by monitoring and integration with other tools like load balancers or connection routers. They are basically “GET” requests. Those are considered “Safe APIs”.

There are other sets of APIs that can be used for administering the Patroni. They can be used for changing some of the PostgreSQL parameters, Triggering a switchover, etc. They are PUT, POST, PATCH, and DELETE requests, which can affect the state of the nodes. Those are considered unsafe APIs.

Protecting unsafe APIs

In this article, I am going to use the REST API : /reload as an example of an unsafe API that reloads the configuration.

This is the bare minimum to be achieved if traffic to the database/patroni host machine is not restricted by other means. Patroni provides a simple username and password mechanism by which all unsafe APIs can be protected.

Overall, the restapi: section of patroni configuration (yaml file) can have an entry like:

Shell
restapi:
  listen: 0.0.0.0:8008
  connect_address: pg1:8008
  authentication:
    username: patroniAdmin
    password: adminSecretPswd

An external unsafe request will result in an error:

Shell
$ curl -X POST http://pg1:8008/reload
no auth header received

But a Patroni admin can make a request by specifying the username and password:

Shell
$ curl -u patroniAdmin:adminSecretPswd -X POST http://pg1:8008/reload
reload scheduled

A request with the wrong credentials will be rejected:

Shell
$ curl -u patroniAdmin:adminSecretPswd0 -X POST http://pg0:8008/reload
not authenticated,

Unlike the curl command, patronictl from the database/patroni host will continue to function as normal (without prompting for passwords) because it has access to the password from the patroni configuration.

Caveats:

All nodes should select either HTTP or HTTPS. Mix and match of protocols can result in patronictl failures like:

Shell
Reload request received for member pg0 and will be processed within 10 seconds
Failed: reload for member pg1, status code=401, (no auth header received)

There is no restriction like each node having the same username and password. However, if passwords are different, patronictl from other nodes will fail with the message:

Shell
Reload request received for member pg0 and will be processed within 10 seconds
Failed: reload for member pg1, status code=401, (not authenticated)

So it is safe to use the same credentials across all nodes.

Switch to HTTPS

Patroni automatically switches to HTTPS if a certificate file is specified.  Please see the below sample configuration.

Shell
restapi:
  listen: 0.0.0.0:8008
  connect_address: pg0:8008
  authentication:
    username: patroniAdmin
    password: adminSecretPswd
  certfile: /etc/patroni/pg0.crt
  keyfile: /etc/patroni/pg0.key
  cafile: /etc/patroni/ca.crt

The meaning of each of these parameters is part of official Patroni documentation.

  • certfile: (optional): Specifies the file with the certificate in the PEM format. If the certfile is not specified or is left empty, the API server will work without SSL.
  • keyfile: (optional): Specifies the file with the secret key in the PEM format.
  • keyfile_password: (optional): Specifies a password for decrypting the keyfile.
  • cafile: (optional): Specifies the file with the CA_BUNDLE with certificates of trusted CAs to use while verifying client certs.

This change requires a restart of the Patroni service. Once restarted, Patroni comes up with listening to HTTPS on port 8008 instead of an HTTP request.

Obviously, the cafile (CA Certificate) is required for the client to verify the server certificate. The client, including the patronictl, can choose not to verify the server certificates.

This patronictl behavior can be specified using another ctl section in Patroni configuration:

Shell
  insecure: true

However, please expect warning messages from python libraries about skipping the certificate verification of patroni server, as follows.

Shell
Reload request received for member pg0 and will be processed within 10 seconds
2022-10-18 14:40:31,755 - WARNING - /usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'pg1'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  InsecureRequestWarning,
Reload request received for member pg1 and will be processed within 10 seconds

So, it is always good to have the server certificate verification on the client side.

Please remember that only the “Unsafe APIs” are protected using password authentication. Safe APIs will continue to function as it is. So the impact of this change on other tools like HAProxy which use those safe APIs is almost nil.

Shell
$ curl -k https://pg0:8008/cluster | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   302    0   302    0     0   2659      0 --:--:-- --:--:-- --:--:--  2672
  "members": [
      "name": "pg0",
      "role": "replica",
      "state": "running",
      "api_url": "https://pg0:8008/patroni",
      "host": "pg0",
      "port": 5432,
      "timeline": 39,
      "lag": 0
      "name": "pg1",
      "role": "leader",
      "state": "running",
      "api_url": "https://pg1:8008/patroni",
      "host": "pg1",
      "port": 5432,
      "timeline": 39

In this blog post, we discussed setting up password authentication and changing the REST API communication to HTTPS, which should safeguard the REST APIs and satisfy many organizations’ requirements. In the next part of this, we shall discuss how to set up a certificate authentication instead of password authentication and a few other aspects of security.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK