To configure NGINX Plus for PingIntelligence:

  1. Create a modules directory in NGINX Plus:
    # mkdir /etc/nginx/modules
  2. Download the NGINX Plus - PingIntelligence policy modules from the PingIntelligence Downloads site.
  3. Untar the downloaded file:
    # tar -xvzf pi-api-nginx-plus-policy-4.3.tar.gz
    
  4. Copy the three PingIntelligence modules files for Ubuntu to the modules directory of NGINX Plus and the pi-pf.conf file to /usr/local/nginx/conf/ directory.

    The three PingIntelligence modules are:

    • ngx_ase_integration_module.so
    • ngx_http_ase_integration_request_module.so
    • ngx_http_ase_integration_response_module.so

    The pi-pf.conf file has the OAuth policy details.

    
    # cp ngx_ase_integration_module.so /etc/nginx/modules
    # cp ngx_http_ase_integration_request_module.so /etc/nginx/modules
    # cp ngx_http_ase_integration_response_module.so /etc/nginx/modules
    # cp pi-pf.conf /usr/local/nginx/conf/
  5. Change to root user:
    # sudo su
  6. Export client credentials as environment variables.
    # export PF_ID=<ID>
    # export PF_SECRET=<SECRET>
    

    Here PF_ID and PF_SECRET are PingFederate client ID and secret.

  7. Edit the nginx.conf file to load the PingIntelligence modules.

    The following is a snippet of the nginx.conf file showing the loaded PingIntelligence modules:

    worker_processes  4;
    
    error_log  /usr/local/nginx/logs/error.log debug;
    worker_rlimit_core  500M;
    working_directory  /usr/local/nginx;
    
    pid        /usr/local/nginx/pid/nginx.pid;
    env PF_ID;
    env PF_SECRET;
    
    load_module modules/ngx_ase_integration_module.so;
    load_module modules/ngx_http_ase_integration_request_module.so;
    load_module modules/ngx_http_ase_integration_response_module.so;
    load_module modules/ndk_http_module.so;
    load_module modules/ngx_http_lua_module.so;
    
    
    events {
        worker_connections  1024;
    }
    truncated nginx.conf file
  8. Configure ASE primary and secondary node IP address by replacing IP:PORT in the nginx.conf file snippet shown below:
    http {
    
        keepalive_timeout  65;
        upstream ase.pi {
           server IP:PORT max_fails=1 max_conns=100 fail_timeout=10;
           server IP:PORT max_fails=1 max_conns=100 fail_timeout=10 backup;
           keepalive 32;
           #keepalive_timeout 3600s; # NOT allowed < 1.15.3
       }
    
    truncated nginx.conf file
  9. Configure introspect server IP address by replacing IP:PORT in the nginx.conf file snippet show below:
    upstream introspect_server {
            server IP:PORT max_fails=1 max_conns=100 fail_timeout=10;
            server IP:PORT max_fails=1 max_conns=100 fail_timeout=10 backup;
            keepalive 32;
        }
    
    truncated nginx.conf file
  10. Configure the username and client ID keys in nginx.conf.

    These are the keys for username and client ID that you have configured in PingFederate.

    
    set $oauth_username_key Username; 
    set $oauth_client_id_key ClientID;
    
    truncated nginx.conf file
  11. Configure the token parameter name after $arg_ and in ase/request:
    # Set the token parameter name below after $arg_ and inside /ase/request.
        set $oauth_key_param $arg_access_token;  
        set $oauth_token_param $arg_access_token;
    	#ASE Request Proxy Configuration
           location = /ase/request {
           internal;
           ase_integration https://test.ase.pi;
           ase_integration_method "POST";
           ase_integration_http_version 1.1;
           ase_integration_ase_token $ase_token;
           ase_integration_correlation_id $correlationid;
           ase_integration_host $ase_host;
           # set token key here.
           ase_integration_token_key access_token;
           ase_integration_ssl_trusted_certificate $certificate;
           ase_integration_ssl_verify    off;
           ase_integration_ssl_verify_depth 1;
           ase_integration_ssl_server_name off;
           ase_integration_ssl_name $ase_ssl_host;
           ase_integration_next_upstream error timeout non_idempotent;
        }
    
    truncated nginx.conf file
  12. Configure the URL of the introspection server:
    # Set introspection URL
        set $oauth_url https://introspect_server/as/introspect.oauth2;
    
    truncated nginx.conf file
  13. Configure the ASE sideband token.

    The sideband authentication token was created in step 4 of Preparing to deploy the PingIntelligence policy.

    The following is a snippet the showing certificate location and sideband authentication token:

     #ASE Token for sideband authentication
        set $ase_token <ASE_TOKEN>;
    
  14. Configure the ASE request and response API endpoints in nginx.conf.

    The following snippet of nginx.conf shows ASE request and response:

     #ASE Request Proxy Configuration
        location = /ase/request {
           internal;
           ase_integration https://test.ase.pi;
           ase_integration_method "POST";
           ase_integration_http_version 1.1;
           ase_integration_ase_token $ase_token;
           ase_integration_correlation_id $correlationid;
           ase_integration_host $ase_host;
           # set token key here.
           ase_integration_token_key access_token;
           ase_integration_ssl_trusted_certificate $certificate;
           ase_integration_ssl_verify    off;
           ase_integration_ssl_verify_depth 1;
           ase_integration_ssl_server_name off;
           ase_integration_ssl_name $ase_ssl_host;
           ase_integration_next_upstream error timeout non_idempotent;
        }
        #ASE Response Proxy Configuration
        location = /ase/response {
           internal;
           ase_integration https://test.ase.pi;
           ase_integration_method "POST";
           ase_integration_http_version 1.1;
           ase_integration_ase_token $ase_token;
           ase_integration_correlation_id $correlationid;
           ase_integration_host $ase_host;
           ase_integration_ssl_trusted_certificate $certificate;
           ase_integration_ssl_verify    off;
           ase_integration_ssl_verify_depth 1;
           ase_integration_ssl_server_name off;
           ase_integration_ssl_name $ase_ssl_host;
           ase_integration_next_upstream error timeout non_idempotent;
        }
    
    truncated nginx.conf file
  15. Apply the PingIntelligence policy either at the global level for all the APIs in your environment or for an individual API.
    Note:

    If the authorization header in the request has multiple tokens, the PingIntelligence policy extracts only the first valid bearer token from the authorization header.

    • To apply the PingIntelligence policy globally, add ase_integration_request and ase_integration_response in the server section of nginx.conf as shown below:
      server {
          listen              4443 ssl bind;
          server_name         localhost;
          ssl_certificate     /usr/local/nginx/ssl/cert.pem;
          ssl_certificate_key /usr/local/nginx/ssl/key.pem;
          ssl_password_file   /usr/local/nginx/ssl/password_file;
          ssl_protocols       TLSv1.2;
          ssl_ciphers         HIGH:!aNULL:!MD5;
          resolver 8.8.8.8 ipv6=off;
          ase_integration_request;
          ase_integration_response;
      
      
          # Set OAuth Client details
      
      truncated nginx.conf file
    • To apply the PingIntelligence policy for a specific API, configure location in nginx.conf.

      ase_integration_request should be the first and a ase_integration_response should be the last.

      Note: Comment-out the ase_integration_request and ase_integration_response that was configured to apply the PingIntelligence policy globally.
      location / {
             include /usr/local/nginx/conf/pi-pf.conf;
             ase_integration_request;
             proxy_pass http://localhost:8080/;
             ase_integration_response;
      }
      
      truncated nginx.conf file
  16. To verify the syntactical correctness of nginx.conf, run the following command:
    # /usr/local/nginx/sbin/nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
    
  17. Configure the PingIntelligence policy for NGINX Plus:
    1. Restart NGINX by entering the following command:
      
      # /usr/local/nginx/sbin/nginx -s stop
      # /usr/local/nginx/sbin/nginx
      
    2. Run the following command to verify if --with-compat and --with-http_ssl_module is in the list of flags under configured arguments:
      # sudo /usr/local/nginx/sbin/nginx -V
      nginx version: nginx/1.15.2 (nginx-plus-r16)
      built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
      built with OpenSSL 1.0.2g  1 Mar 2016
      TLS SNI support enabled
      configure arguments: --with-compat --with-http_ssl_module
      
    3. Verify that NGINX has restarted by entering the following command:
      # netstat -tulpn | grep 4443 
      

      The following is a sample nginx.conf file. Make sure that the PingIntelligence module and other configurations are added at the correct place in nginx.conf as shown in the sample file.

      worker_processes  4;
      
      error_log  /usr/local/nginx/logs/error.log debug;
      worker_rlimit_core  500M;
      working_directory  /usr/local/nginx;
      
      pid        /usr/local/nginx/pid/nginx.pid;
      env PF_ID;
      env PF_SECRET;
      
      load_module modules/ngx_ase_integration_module.so;
      load_module modules/ngx_http_ase_integration_request_module.so;
      load_module modules/ngx_http_ase_integration_response_module.so;
      load_module modules/ndk_http_module.so;
      load_module modules/ngx_http_lua_module.so;
      
      events {
          worker_connections  1024;
      }
      
      http {
      
          keepalive_timeout  65;
          upstream test.ase.pi {
             server IP:PORT max_fails=1 max_conns=100 fail_timeout=10;
             server IP:PORT max_fails=1 max_conns=100 fail_timeout=10 backup;
             keepalive 32;
      #      keepalive_timeout 3600s; # NOT allowed < 1.15.3
         }
      
          upstream introspect_server {
              server IP:PORT max_fails=1 max_conns=100 fail_timeout=10;
              server IP:PORT max_fails=1 max_conns=100 fail_timeout=10 backup;
              keepalive 32;
          }
      
          lua_shared_dict cache_dict 128m;
      
      server {
          listen              4443 ssl bind;
          server_name         localhost;
          ssl_certificate     /usr/local/nginx/ssl/cert.pem;
          ssl_certificate_key /usr/local/nginx/ssl/key.pem;
          ssl_password_file   /usr/local/nginx/ssl/password_file;
          ssl_protocols       TLSv1.2;
          ssl_ciphers         HIGH:!aNULL:!MD5;
          resolver 8.8.8.8 ipv6=off;
          ase_integration_request;
          ase_integration_response;
      
          # Set OAuth Client details
      
          # Set env variable PF_ID &PF_SECRET
          set_by_lua $client_id 'return os.getenv("PF_ID")';
          set_by_lua $client_secret 'return os.getenv("PF_SECRET")';
      
          # Uncomment next 2 lines to set client credentials here.
          # set $client_id nginx_client;
          # set $client_secret nginx_secret;
      
          set $oauth_username_key Username; 
          set $oauth_client_id_key ClientID;
      
          # Set the token parameter name below after $arg_ and inside /ase/request.
          set $oauth_key_param $arg_access_token;
          set $oauth_token_param $arg_access_token;
      
          # Set cache lifetime, default is 120s.
          set $oauth_cache_timeout 120;
      
          # Set introspection URL
          set $oauth_url https://introspect_server/as/introspect.oauth2;
      
          location /introspect {
              internal;
              proxy_method    POST;
              if ($arg_auth_token) {
                  set $auth_token $arg_auth_token;
              }
               if ($http_authorization ~* .*?(bearer)(\s+)([-a-zA-Z0-9._~+/]+)(,|\s|$)) {
                  set $auth_token $3;
              }
              proxy_set_header  Content-Type "application/x-www-form-urlencoded";
              proxy_set_body  "client_id=${client_id}&client_secret=${client_secret}&token=${auth_token}";
              proxy_pass_request_body off;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              proxy_pass      $oauth_url;
          }
      
          location /shop {
             include /usr/local/nginx/conf/pi-pf.conf;
             proxy_pass http://18.209.173.37:4100/shop;
             
          }
          #DO NOT EDIT BELOW VARIABLE
          set $correlationid $pid-$request_id-$server_addr-$remote_addr-$remote_port-$request_length-$connection;
          #Certificate location of ASE
          set $certificate /usr/local/nginx/ssl/test.ase.pi;
          #ASE Token for sideband authentication
          set $ase_token <ASE_TOKEN>;
          #Host header which should be send to ASE
          set $ase_host test.ase.pi;
          #SNI value to use for ASE
          set $ase_ssl_host test.ase.pi;
          #ASE Request Proxy Configuration
          location = /ase/request {
             internal;
             ase_integration https://test.ase.pi;
             ase_integration_method "POST";
             ase_integration_http_version 1.1;
             ase_integration_ase_token $ase_token;
             ase_integration_correlation_id $correlationid;
             ase_integration_host $ase_host;
             # set token key here.
             ase_integration_token_key access_token;
             ase_integration_ssl_trusted_certificate $certificate;
             ase_integration_ssl_verify    off;
             ase_integration_ssl_verify_depth 1;
             ase_integration_ssl_server_name off;
             ase_integration_ssl_name $ase_ssl_host;
             ase_integration_next_upstream error timeout non_idempotent;
          }
          #ASE Response Proxy Configuration
          location = /ase/response {
             internal;
             ase_integration https://test.ase.pi;
             ase_integration_method "POST";
             ase_integration_http_version 1.1;
             ase_integration_ase_token $ase_token;
             ase_integration_correlation_id $correlationid;
             ase_integration_host $ase_host;
             ase_integration_ssl_trusted_certificate $certificate;
             ase_integration_ssl_verify    off;
             ase_integration_ssl_verify_depth 1;
             ase_integration_ssl_server_name off;
             ase_integration_ssl_name $ase_ssl_host;
             ase_integration_next_upstream error timeout non_idempotent;
          }
      }
      
      }