Using a Proxy Server to Authorize the REST API
Note
These instructions have been tested on Ubuntu 18.04 (Bionic) only.
The Sawtooth REST API is designed to be a lightweight shim on top of internal communications. When the REST API receives a request, it passes that request to the validator without any authorization. While this behavior is appropriate for the public nature of blockchains, the lack of authorization might not be desirable in some situations. For these cases, you can configure the REST API to work behind a proxy server.
This section explains how the REST API handles proxy server issues, then shows how to set up an Apache proxy server for the REST API.
About Proxying the REST API
In general, putting the REST API behind a proxy server works as
expected. The REST API has the same behavior as if it were communicating
directly with a client. The notable exception is how URLs are handled;
specifically, the link
parameter that is sent back in the response
envelope, and the previous
and next
links that are sent back with a
paging response.
These URLs are a convenience for clients, but the proxy can destroy crucial URL information. For example, a correct link should look this this:
{
"link": "https://hyperledger.org/sawtooth/blocks?head=..."
}
Instead, the "destroyed" link might look like this:
{
"link": "http://localhost:8008/blocks?head=..."
}
The solution to this problem is to send the destroyed information with HTTP request headers. The Sawtooth REST API will properly recognize and parse information in both "X-Forwarded" and "Forwarded" headers.
"X-Forwarded" Headers
Although they aren't part of any standard, "X-Forwarded" headers are a common way to communicate information about a proxy. When the REST API builds a link, it looks for the following types of "X-Forwarded" headers:
-
X-Forwarded-Host
: Domain name of the proxy server (for example,hyperledger.org
) -
X-Forwarded-Proto
: Protocol/scheme used to make requests (for example,https
) -
X-Forwarded-Path
: Extra path information (for example,/sawtooth
). This uncommon header is implemented by the REST API. It is necessary only if the proxy endpoints do not map directly to the REST API endpoints, that is, whenhyperledger.org/sawtooth/blocks
does not map tolocalhost:8008/blocks
.
"Forwarded" Headers
This type of header is less common, but a single "Forwarded" header sends the same information as multiple "X-Forwarded" headers. The "Forwarded" header, which is standardized by RFC7239, contains semicolon-separated key-value pairs, as in this example:
Forwarded: for=196.168.1.1; host=proxy1.com, host=proxy2.com; proto="https"
When the REST API builds a response link, it looks for the following keys:
-
host
: Domain name of the proxy server (for example,host=hyperledger.org
) -
proto
: Protocol/scheme used to make requests (for example,proto=https
) -
path
: Extra path information (for example,path="/sawtooth"
). This non-standard key header is necessary only if the proxy endpoints do not map directly to the REST API endpoints, that is, whenhyperledger.org/sawtooth/blocks
does not map tolocalhost:8008/blocks
.
Note
Any key in a "Forwarded" header can be set multiple times, using commas to separate each setting. (See the
host
values in the example above.) Repeating a key allows a chain of proxy information to be traced. However, the REST API always uses the left-most value for a particular key so that it can produce an accurate link for the client.
Set Up an Apache Proxy Server for the REST API
This procedure sets up a simple Apache 2 proxy server that is secured with Basic Auth and https, then configures the proxy server for an instance of the Sawtooth REST API.
Note
This procedure covers only the information for Sawtooth configuration. It does not cover other Apache configuration or security settings.
-
Install the Apache web server and enable the required modules, then restart Apache to load these modules.
$ sudo apt-get update $ sudo apt-get install -y apache2 $ sudo a2enmod ssl $ sudo a2enmod headers $ sudo a2enmod proxy_http $ sudo systemctl restart apache2
-
Create a password file for the user
sawtooth
. Enter a new password when thehtpasswd
command prompts for it.$ sudo htpasswd -c /etc/apache2/.htpassword sawtooth
Tip
You can repeat this command to generate passwords for other users, but you must omit the
-c
option from thehtpasswd
command. You must also remember to authorize those users in the proxy configuration file (later in this procedure). -
Obtain or create an SSL certificate.
-
You can use
openssl
to build a self-signed SSL certificate. This certificate is not suitable for most HTTP clients, but it is good enough for testing purposes.$ sudo mkdir /etc/apache2/keys $ sudo openssl req -x509 -nodes -days 7300 -newkey rsa:2048 \ -subj /C=US/ST=MN/L=Mpls/O=Sawtooth/CN=sawtooth \ -keyout /etc/apache2/keys/.ssl.key \ -out /etc/apache2/keys/.ssl.crt
-
You can get a free trusted certificate from Let's Encrypt. Follow the instructions at letsencrypt.org/getting-started.
-
-
Configure the proxy with settings for the Sawtooth REST API.
a. Create an Apache configuration file.
``` console $ sudo vi /etc/apache2/sites-available/000-sawtooth-rest-api.conf ```
b. Add the following contents to this file.
``` apache <VirtualHost *:443> ServerName sawtooth ServerAdmin sawtooth@sawtooth DocumentRoot /var/www/html SSLEngine on SSLCertificateFile /etc/apache2/keys/.ssl.crt SSLCertificateKeyFile /etc/apache2/keys/.ssl.key RequestHeader set X-Forwarded-Proto "https" <Location /> Options Indexes FollowSymLinks AllowOverride None AuthType Basic AuthName "Enter password" AuthUserFile "/etc/apache2/.htpassword" Require user sawtooth Require all denied </Location> </VirtualHost> ProxyPass /sawtooth http://localhost:8008 ProxyPassReverse /sawtooth http://localhost:8008 RequestHeader set X-Forwarded-Path "/sawtooth" ```
Note
Apache automatically sets the "X-Forwarded-Host" header.
c. Run the following commands to disable the default Apache landing page and enable the new authenticated proxy configuration.
``` console $ sudo a2dissite 000-default.conf $ sudo a2ensite 000-sawtooth-rest-api.conf ```
d. Restart Apache to apply the changes.
``` console $ sudo systemctl restart apache2 ```
-
Send some test requests to verify the proxy configuration. This step uses
curl
to send requests to the REST API to make sure that everything works.a. Start by querying the REST API directly.
``` console $ curl http://localhost:8008/blocks ``` The response should look like this example: ``` json { "link": "http://localhost:8008/blocks?head=..." } ``` A failed request might mean that the REST API is not running. To restart the REST API as a service, see [Running Sawtooth as a Service](/docs/1.2/sysadmin_guide/setting_up_sawtooth_network.html#running-sawtooth-as-a-service).
b. Next, query the proxy without authorization. This command should return a
401
error.``` console $ curl https://localhost/sawtooth/blocks --insecure ```
Note
The
--insecure
flag forcescurl
to complete the request even if there isn't an official SSL certificate. It does not bypass basic authentication.c. Finally, send a properly authorized request. Replace
{password}
in the following example with the password for thesawtooth
user.``` console $ curl https://localhost/sawtooth/blocks --insecure -u sawtooth:{password} ``` The response is similar to a direct query response, but `link` shows the URL used to send this request. ``` json { "link": "https://localhost/sawtooth/blocks?head=..." } ```