• NGINX for S3 basic auth with PSQL

    02 September 2017
    Tags: cloud 


    Spin up a new EC2 Ubuntu 16.04 HVM instance.

    EC2 Get Started

    Assign an Elastic IP to your instance to allow for an IP based bucket policy to be created later.

    Elastic IP Addresses

    Setup an S3 bucket with an IP restriction to only your new EC2 instance (use the EC2 instance's elastic IP with a bucket policy to allow only that IP for GET/PUT). Also create an AWS IAM service account. You will need IAM credentials for your NGINX configuration and it is always best to use a service account with the minimal level of access (e.g. just access to the S3 bucket).

    S3 Get Started IAM Intro

    Create a PostgreSQL RDS instance to store credentials. Ensure your EC2 instance can access the database securely.

    PostgreSQL on RDS

    Setup PAM-PGSQL on your Ubuntu EC2 instance

    Setup pam-pgsql for Ubuntu using sudo apt-get install pam-pgsql and follow the pam-pgsql guide to create a table for users. You will use your AWS RDS instance to store this table.


    Make a note of the "service" name you choose when following the pam-pgsql guide, this will need to be referenced in your NGINX configuration.

    Deploy a custom NGINX

    Custom compile NGINX with HMAC S3 bucket signing and pam for basic http authentication as shown in this helpful guide.


    Below are the most important steps from the NGINX guide.

    Run the following as sudo -i on your Ubuntu EC2 instance.

    add-apt-repository ppa:nginx/unstable
    apt-get update
    cd /usr/src
    apt-get build-dep nginx
    apt-get source nginx

    You will need to add the source for the required modules to the nginx source you just downloaded. This module is required for HMAC signing: set-misc-nginx-module


    Don't forget to also add the development-kit source. It is required for set-misc-nginx-module. These modules need to go into the /usr/src/nginx-1.10.3/debian/modules subdirectory of the nginx source code.

    Update the NGINX build configuration to include the modules you'll need.

    extras_configure_flags := \
                        $(common_configure_flags) \
                        --with-http_addition_module \
                        --with-http_dav_module \
                        --with-http_flv_module \
                        --with-http_geoip_module \
                        --with-http_gzip_static_module \
                        --with-http_image_filter_module \
                        --with-http_mp4_module \
                        --with-http_perl_module \
                        --with-http_random_index_module \
                        --with-http_secure_link_module \
                        --with-http_spdy_module \
                        --with-http_sub_module \
                        --with-http_xslt_module \
                        --with-mail \
                        --with-mail_ssl_module \
                        --add-module=$(MODULESDIR)/nginx-auth-pam \
                        --add-module=$(MODULESDIR)/nginx-cache-purge \
                        --add-module=$(MODULESDIR)/nginx-dav-ext-module \
                        --add-module=$(MODULESDIR)/nginx-echo \
                        --add-module=$(MODULESDIR)/ngx-fancyindex \
                        --add-module=$(MODULESDIR)/nginx-http-push \
                        --add-module=$(MODULESDIR)/nginx-lua \
                        --add-module=$(MODULESDIR)/nginx-upload-progress \
                        --add-module=$(MODULESDIR)/nginx-upstream-fair \
                        --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module \
                        --add-module=$(MODULESDIR)/nginx-development-kit \

    Edit the change log

    dch --local (name your packages)


    dpkg-buildpackage -us -uc

    Install your custom packages

    Your file names might be different, use ls within /usr/src/ to find the exact package names.

    dpkg -i nginx-common_1.10.3-0ubuntu0.16.04.2_all.deb
    dpkg -i nginx-extras_1.10.3-0ubuntu0.16.04.2_amd64.deb

    Configure NGINX

    You will need to edit your /etc/nginx/sites-available default configuration file. http://nginx.org/en/docs/beginners_guide.html

    You need to add the auth service to use pam-pgsql for usernames and password. nginx-pgsql should match the service name you chose earlier in the pam-pgsql setup.

    auth_pam_service_name "nginx-psql";

    Then add the S3 location with signing support. Signing support is required to keep uploads secure if you want to allow users to put files into your bucket.

        location ~* ^/s3/(.*) {
            set $bucket           '<REPLACE WITH YOUR S3 BUCKET NAME>';
            set $aws_access       '<REPLACE WITH YOUR AWS ACCESS KEY>';
            set $aws_secret       '<REPLACE WITH YOUR AWS SECRET KEY>';
            set $url_full         "$1";
            set_by_lua $now       "return ngx.cookie_time(ngx.time())";
            set $string_to_sign   "$request_method\n\n\n\nx-amz-date:${now}\n/$bucket/$url_full";
            set_hmac_sha1          $aws_signature $aws_secret $string_to_sign;
            set_encode_base64      $aws_signature $aws_signature;
            resolver      valid=300s;
            resolver_timeout       10s;
            proxy_http_version     1.1;
            proxy_set_header       Host $bucket.s3.amazonaws.com;
            proxy_set_header       x-amz-date $now;
            proxy_set_header       Authorization "AWS $aws_access:$aws_signature";
            proxy_buffering        off;
            proxy_intercept_errors on;
            rewrite .* /$url_full break;
            proxy_pass             http://s3.amazonaws.com;

    Now you should have a secure proxy that can provide basic authentication. PostgreSQL will store you accounts so you can quickly rebuild your EC2 instance if anything goes wrong. Be sure to backup your EC2 with an AMI image so you can easily recover your work.