Authentication

This document helps you get NGINX Instance Manager secured by utilizing authentication.

Note:
NGINX Plus is provided and intended only to be used with NGINX Instance Manager as a frontend. You should not use NGINX Plus for other web applications or instances. For external uses and other systems, contact your sales team to purchase additional subscriptions.

Prerequisites

  1. Install NGINX Instance Manager Server.
  2. Install NGINX or NGINX Plus.
  3. Start and Enable Instance Manager and NGINX Plus (or NGINX).

How it works

Instance Manager listens on two ports. The gRPC communication listens only on 127.0.0.1 and is on 10000 by default. The browser interface and API listen on 127.0.0.1 and is 11000 by default. By using NGINX we follow our own guidance for any web application. You may use NGINX Open Source (“NGINX OSS”) or NGINX Plus for the forward proxy. We provide an instance of NGINX Plus with NGINX Instance Manager. You can use it to proxy and secure NGINX Instance Manager.

We use the username and role headers to log to the audit log. You can configure the audit log by adding the option on the nginx-manager.conf file.

Note: Adding the audit log option will log every API call made to the API. It is recommended not to add this entry if you are not using the auditing log feature.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# /etc/nginx-manager/nginx-manager.conf
#

# Configuration file for NGINX Compass Server

# bind address for all service ports (default "localhost")
bind-address: 127.0.0.1
# gRPC service port for agent communication (default "10000")
grpc-port: 10000
# gRPC-gateway service port for API and UI (default "11000")
gateway-port: 11000

# SSL CN or servername for certs
server-name: nginx-manager.example.com
# path to x.509 certificate file (optional)
cert: /etc/ssl/nginx-manager/nginx-manager.crt
# path to x.509 certificate key file (optional)
key: /etc/ssl/nginx-manager/nginx-manager.key

# set log level (panic, fatal, error, info, debug, trace; default: info) (default "info")
log:
    level: info
    path: /var/log/nginx-manager/
# Metrics default storage path (default "/tmp/metrics") (directory must be already present)
metrics:
    storage-path: /var/nginx-manager/
# Path to license file
license: /etc/nginx-manager/nginx-manager.lic
# Audit Log
audit-log: /var/log/nginx-manager/audit.log

Authentication Options

The table below summarizes the key differences between NGINX Open Source and NGINX Plus (for authentication options with NGINX Instance Manager).

Security Method no proxy nginx-oss nginx-plus
Commercial Support N/A Included
Basic Authentication N/A Included Included
JWT Authentication N/A N/A Included
OpenID Connect/OAuth2 N/A N/A Supported
Denylisting IPs N/A N/A Supported
Rate-Limiting N/A Included Included

Common NGINX Snippets

Upstreams

The examples below make reference to an upstream group nginx-manager_servers. You can create the same with a conf file similar to the one below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# nginx-manager-upstreams.conf
# Upstreams for NGINX Instance Manager Server API/UI

upstream nginx-manager_servers {
        zone nginx-manager_servers 64k;
        server 127.0.0.1:11000;
        keepalive 64;
}

# vim: syntax=nginx

Status Page

NGINX Plus uses a status page. The following example shows a default configuration on port 8080. Adjust the port to your desired one and add SSL if wanted (or other restrictions like rate limiting).

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
# This sample NGINX Plus configuration enables the NGINX Plus API, for live 
# activity monitoring and the built-in dashboard, dynamic configuration of 
# upstream groups, and key-value stores. Keep in mind that any features 
# added to the API in future NGINX Plus releases will be enabled 
# automatically by this file.
# Created in May 2018 by NGINX, Inc. for NGINX Plus R14 and later.

# Documentation: 
# https://docs.nginx.com/nginx/admin-guide/monitoring/live-activity-monitoring/
# https://www.nginx.com/blog/live-activity-monitoring-nginx-plus-3-simple-steps

# To conform with the conventional configuration scheme, place this file in 
# the /etc/nginx/conf.d directory and add an 'include' directive that 
# references it in the main configuration file, /etc/nginx/nginx.conf, 
# either by name or with a wildcard expression. Then validate and reload
# the configuration, for example with this command:
#
#     nginx -t && nginx -s reload

# Note that additional directives are required in other parts of the 
# configuration:
#
# For metrics to be gathered for an HTTP or TCP/UDP virtual server, you must 
# include the 'status_zone' directive in its 'server' block. See: 
# http://nginx.org/r/status_zone
#
# Similarly, for metrics to be gathered for an upstream server group, you 
# must include the 'zone' directive in the 'upstream' block. See:
# http://nginx.org/r/zone
#
# For more information and instructions, see:
# https://docs.nginx.com/nginx/admin-guide/monitoring/live-activity-monitoring#status_data

# We strongly recommend that you restrict access to the NGINX Plus API so 
# that only authorized users can view metrics and configuration, change 
# configuration, or both. Here are a few options:
#
# (1) Configure your firewall to limit access to port 8080.
#
# (2) Use SSL/TLS client certificates. See:
#    https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/
#
# (3) Enable HTTP Basic authentication (RFC 7617) by uncommenting the 
#    'auth_basic*' directives in the 'server' block below. You can add users 
#    with an htpasswd generator, which is readily available, or reuse an 
#    existing htpasswd file (from an Apache HTTP Server, for example). See: 
#    http://nginx.org/en/docs/http/ngx_http_auth_basic_module.html
#
# (4) Enable access from a defined network and disable it from all others, 
#    by uncommenting the 'allow' and 'deny' directives in the 'server' block
#    below and specifying the appropriate network ranges. See: 
#    http://nginx.org/en/docs/http/ngx_http_access_module.html
#
# You can create further restrictions on write operations, to distinguish
# between users with read permission and those who can change configuration.
# Uncomment the sample 'limit_except' directive in the 'location api' 
# block below. In addition to the HTTP Basic authentication shown, other 
# authentication schemes are also supported. See: 
# http://nginx.org/r/limit_except

server {
    # Conventional port for the NGINX Plus API is 8080
    listen 8080;

    access_log off; # Don't log access here (test env)
    
    # Uncomment to use HTTP Basic authentication; see (3) above
    #auth_basic "NGINX Plus API";
    #auth_basic_user_file /etc/nginx/users;

    # Uncomment to use permissions based on IP address; see (4) above
    #allow 10.0.0.0/8;
    #deny all;

    # Conventional location for accessing the NGINX Plus API 
    location /api/ {
        # Enable in read-write mode
        api write=on;

        # Uncomment to further restrict write permissions; see note above
        #limit_except GET {
            #auth_basic "NGINX Plus API";
            #auth_basic_user_file /etc/nginx/admins;
        #}
    }

    # Conventional location of the NGINX Plus dashboard
    location = /dashboard.html {
        root /usr/share/nginx/html;
    }

    # Redirect requests for "/" to "/dashboard.html"
    location / {
        root /usr/share/nginx/html;
        index dashboard.html;
    }

    # Swagger-UI exposure
    location /swagger-ui {
        root /usr/share/nginx/html;
    }

    # Redirect requests for pre-R14 dashboard
    location /status.html {
        return 301 /dashboard.html;
    }
}

# vim: syntax=nginx

Stub Page

NGINX Open Source uses a stub status page. The following example shows a default configuration on port 8080. Adjust the port to your desired one and add SSL if wanted (or other restrictions like rate limiting).

Please note: You need to compile NGINX Open Source with the –with-http_stub_status_module parameter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# ngx_http_stub_status_module (Available in NGINX F/OSS)
# provides Basic Status information http://nginx.org/en/docs/http/ngx_http_stub_status_module.html

server {
    listen 127.0.0.1:80;
    server_name 127.0.0.1;
    access_log off; # Don't log access here (test env)
    location /nginx_status {
        stub_status on;
        allow 127.0.0.1;
        deny all;
    }
}

# vim: syntax=nginx

Basic Authentication

Basic auth is not secure and should not be used for production environments. This is not an effective way to secure or authenticate users.

Basic authentication uses a username and password that you can set locally in an .htpasswd file. The following example looks like the SSL example and also uses the .htpasswd file under the default location.

Follow the guide on nginx.com to create an .htpasswd file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# nginx-manager-basicauth.conf
# Proxy UI/API with basic auth to 127.0.0.1 on nginx-manager
# You must create the .htpasswd file and add user/password for this to work
# Include the nginx-manager-upstreams.conf for the proxy_pass to work

server {
    # listen  80;
    listen  443 ssl;

    status_zone nginx-manager_basicauth_https;
    server_name nginx-manager.example.com;

    # Optional log locations
    # access_log /var/log/nginx/nginx-manager-basic-access.log info;
    # error_log /var/log/nginx/nginx-manager-basic-error.log;

    # SSL certificates must be valid for the FQDN and placed in the correct directories
    ssl_certificate         /etc/ssl/nginx-manager/nginx-manager.crt;
    ssl_certificate_key     /etc/ssl/nginx-manager/nginx-manager.key;
    ssl_ciphers             EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

    location / {
        proxy_pass http://nginx-manager_servers;
        health_check uri=/swagger-ui/;

        ## Use htpasswd basic auth
        auth_basic "NGINX Instance Manager API";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_set_header Authorization  "";
        proxy_set_header username       $remote_user;
        proxy_set_header role           $remote_user;
    }

}

# vim: syntax=nginx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# nginx-manager-basicauth.conf
# Proxy UI/API with basic auth to 127.0.0.1 on nginx-manager
# You must create the .htpasswd file and add user/password for this to work
# Include the nginx-manager-upstreams.conf for the proxy_pass to work

server {
    # listen  80;
    listen  443 ssl;

    server_name nginx-manager.example.com;

    # Optional log locations
    # access_log /var/log/nginx/nginx-manager-basic-access.log info;
    # error_log /var/log/nginx/nginx-manager-basic-error.log;

    # SSL certificates must be valid for the FQDN and placed in the correct directories
    ssl_certificate         /etc/ssl/nginx-manager/nginx-manager.crt;
    ssl_certificate_key     /etc/ssl/nginx-manager/nginx-manager.key;
    ssl_ciphers             EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

    location / {
        proxy_pass http://nginx-manager_servers;

        ## Use htpasswd basic auth
        auth_basic "NGINX Instance Manager API";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_set_header Authorization  "";
        proxy_set_header username       $remote_user;
        proxy_set_header role           $remote_user;
    }

}

# vim: syntax=nginx

You can use different .htpasswd files in different locations, or even restrict by IP addresses, if desired. For more information about this feature, refer to the guide Restricting Access with HTTP Basic Authentication.

JWT Authentication

You can just JWT Authentication with NGINX Plus and Instance Manager. You need to create the JWT or use an identity provider (idP) to generate the JWT. For more examples on this, refer to the NGINX documentation Setting up JWT Authentication.

Below is an example NGINX conf for using JWT.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# nginx-manager-jwt.conf
# Proxy API with JWT to 127.0.0.1 on nginx-manager
# Include the nginx-manager-upstreams.conf for the proxy_pass to work
# Ensure you have permissions set in the directories
# More information is available <https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-jwt-authentication/>

log_format jwt '$remote_addr - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
               '$jwt_header_alg $jwt_claim_uid $jwt_claim_url' ;

# reverse proxy with jwt authentication
#
server {
    error_log /var/log/nginx/nginx-manager-jwt-error.log debug; # Reduce severity level as required   

    listen      443 ssl;

    status_zone nginx-manager_oauth_https;
    server_name nginx-manager.example.com;

    # SSL certificates must be valid for the FQDN and placed in the correct directories
    ssl_certificate         /etc/ssl/nginx-manager/nginx-manager.crt;
    ssl_certificate_key     /etc/ssl/nginx-manager/nginx-manager.key;
    ssl_ciphers             EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

    # Could change to /api for multiple methods of auth
    location / {
        # JWT validation
        auth_jwt "JWT Test Realm" token=$arg_myjwt;    # Change to realm you use or "" for no realm
        auth_jwt_key_file /etc/nginx/api_secret.jwk;

        if ( $jwt_status = "revoked" ) {
            return 403;
        }

        # Successfully authenticated users are proxied to the backend,
        # with 'sub' claim passed as HTTP header
        proxy_set_header username $jwt_claim_sub;
        proxy_set_header role $jwt_claim_sub;
        proxy_pass http://nginx-manager_servers;

        access_log /var/log/nginx/nginx-manager-jwt-access.log jwt;
    }
}

# vim: syntax=nginx

OpenID Connect/OAuth2

To use OpenID Connect and OAuth2 functions, follow the NGINX OpenID Connect guide. The following example file would function as the frontend.conf in the GitHub example.

Note:
You need to also include the njs module and follow the instructions from our openidconnect repo. https://github.com/nginxinc/nginx-openid-connect Please ensure you select the correct branch/tag for the NGINX Plus version you use. We default to the latest (R23 as of January 1, 2021). Adjust and add the files according to the instructions. Use the nginx-manager-oauth.conf for the frontend.conf section.

Hints:

  • Use private browsing or incognito mode for all testing.
  • Close and restart your browser for new sessions.
  • Check time and date on the server for expired token issues.
  • Pull the specific tag/branch for the NGINX Plus version on the git repo.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# nginx-manager-oauth.conf
# Proxy UI/API with Oauth2/OIDC to 127.0.0.1 on nginx-manager
# Include the nginx-manager-upstreams.conf for the proxy_pass to work
# Use files from <https://github.com/nginxinc/nginx-openid-connect> to complete
# Ensure you have permissions set in the directories
# Ensure you have included load_module modules/ngx_http_js_module.so; in nginx.conf 

log_format main_jwt '$remote_addr - $jwt_claim_sub [$time_local] "$request" $status '
                    '$body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';

# reverse proxy with OpenID Connect authentication
#
server {
    include conf.d/openid_connect.server_conf;              # Authorization code flow and Relying Party processing
    error_log /var/log/nginx/nginx-manager-oauth-error.log debug; # Reduce severity level as required

    listen  443 ssl;

    status_zone nginx-manager_oauth_https;
    server_name nginx-manager.example.com;

    # SSL certificates must be valid for the FQDN and placed in the correct directories
    ssl_certificate         /etc/ssl/nginx-manager/nginx-manager.crt;
    ssl_certificate_key     /etc/ssl/nginx-manager/nginx-manager.key;
    ssl_ciphers             EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

    location / {
        # This site is protected with OpenID Connect
        auth_jwt "" token=$session_jwt;
        error_page 401 = @do_oidc_flow;

        #auth_jwt_key_file $oidc_jwt_keyfile; # Enable when using filename
        auth_jwt_key_request /_jwks_uri; # Enable when using URL

        # Successfully authenticated users are proxied to the backend,
        # with 'sub' claim passed as HTTP header
        proxy_set_header username $jwt_claim_sub;
        proxy_set_header role $jwt_claim_sub;
        proxy_pass http://nginx-manager_servers;

        access_log /var/log/nginx/nginx-manager-oauth-access.log main_jwt;
    }
}

# vim: syntax=nginx

gRPC Metadata

You can use advanced NGINX Plus features such as JWT and gRPC by following the guides on the NGINX blog. Use the encryption guide for setting up gRPC on NGINX Instance Manager.

Rate-Limiting

Enabling rate-limiting can help mitigate and prevent DDoS attacks and should be enabled for the API and UI listeners. Using a configuration file similar to the one below can be leverage with other authentication and encryption methods.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# nginx-manager-jwt.conf
# Proxy API with JWT to 127.0.0.1 on nginx-manager
# Include the nginx-manager-upstreams.conf for the proxy_pass to work
# Ensure you have permissions set in the directories
# More information is available <https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-jwt-authentication/>

log_format jwt '$remote_addr - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
               '$jwt_header_alg $jwt_claim_uid $jwt_claim_url' ;

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

# reverse proxy with jwt authentication
#
server {
    error_log /var/log/nginx/nginx-manager-jwt-error.log debug; # Reduce severity level as required   

    listen      443 ssl;

    status_zone nginx-manager_oauth_https;
    server_name nginx-manager.example.com;

    # SSL certificates must be valid for the FQDN and placed in the correct directories
    ssl_certificate         /etc/ssl/nginx-manager/nginx-manager.crt;
    ssl_certificate_key     /etc/ssl/nginx-manager/nginx-manager.key;
    ssl_ciphers             EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

    # Could change to /api for multiple methods of auth
    location / {
        # JWT validation
        auth_jwt "JWT Test Realm" token=$arg_myjwt;    # Change to realm you use or "" for no realm
        auth_jwt_key_file /etc/nginx/api_secret.jwk;

        if ( $jwt_status = "revoked" ) {
            return 403;
        }

        # Successfully authenticated users are proxied to the backend,
        # with 'sub' claim passed as HTTP header
        proxy_set_header username $jwt_claim_sub;
        proxy_set_header role $jwt_claim_sub;
        proxy_pass http://nginx-manager_servers;

        access_log /var/log/nginx/nginx-manager-jwt-access.log jwt;

        limit_req zone=mylimit;
    }
}

# vim: syntax=nginx