Skip to content

stnoonan/spnego-http-auth-nginx-module

Repository files navigation

Nginx module for HTTP SPNEGO auth

This module implements adds SPNEGO support to nginx(http://nginx.org). It currently supports only Kerberos authentication via GSSAPI

Prerequisites

Authentication has been tested with (at least) the following:

  • Nginx 1.2 through 1.15
  • Internet Explorer 8 and above
  • Firefox 10 and above
  • Chrome 20 and above
  • Curl 7.x (GSS-Negotiate), 7.x (SPNEGO/fbopenssl)

The underlying kerberos library used for these tests was MIT KRB5 v1.12.

Installation from source

  1. Download nginx source

  2. Extract to a directory

  3. Clone this module into the directory

  4. Follow the nginx install documentation and pass an --add-module option to nginx configure:

    ./configure --add-module=spnego-http-auth-nginx-module

Note that if it isn't clear, you do need KRB5 (MIT or Heimdal) header files installed. On Debian based distributions, including Ubuntu, this is the krb5-multidev, libkrb5-dev, heimdal-dev, or heimdal-multidev package depending on your environment. On other Linux distributions, you want the development libraries that provide gssapi_krb5.h.

Installation from distro packages

Binary packages are available from the following Linux distros:

  • Debian - apt-get install libnginx-mod-http-auth-spnego
  • Ubuntu - apt-get install libnginx-mod-http-auth-spnego

Configuration reference

You can configure GSS authentication on a per-location and/or a global basis:

The following options are mandatory:

  • auth_gss: on/off, for ease of unsecuring while leaving other options in the config file.

The following options are optional but commonly needed:

  • auth_gss_keytab: absolute path to the keytab file containing service credentials. Defaults to /etc/krb5.keytab.
  • auth_gss_service_name: service principal name to use when acquiring credentials. When the server is accessed via a DNS CNAME, this should be set to the full service/canonical-hostname form (e.g. HTTP/webserver01.example.com) matching the keytab entry and the A/AAAA record, not the CNAME alias — Kerberos clients typically resolve CNAMEs before requesting a service ticket.

The following option should normally not be necessary:

  • auth_gss_realm: Kerberos realm name. In most deployments this should not be set — the realm is negotiated automatically and misconfiguring it is a common source of authentication failures. If set, the realm is only included in the nginx variable $remote_user if it differs from this value. To override this behavior, set auth_gss_format_full to on in your configuration.

If you would like to authorize only a specific set of principals, you can use the auth_gss_authorized_principal and/or auth_gss_authorized_principal_regex options (multiple entries are supported, one per line):

  • auth_gss_authorized_principal: a principal name as a string, e.g. alice@EXAMPLE.COM.
  • auth_gss_authorized_principal_regex: a regex to match against, e.g. ^.*/admin@EXAMPLE.COM$.

The remote user header in nginx can only be set by doing basic authentication. Thus, this module sets a bogus basic auth header which will be visible to your backend application. The easiest way to hide this bogus header is to add the following configuration to your location config:

proxy_set_header Authorization "";

A future version of the module may make this behavior an option, but this should be a sufficient workaround for now.

If you would like to enable GSS local name rules to rewrite usernames, you can specify the auth_gss_map_to_local option.

Credential Delegation

User credentials can be delegated to nginx using the auth_gss_delegate_credentials directive. This directive will enable unconstrained delegation if the user chooses to delegate their credentials. Constrained delegation (S4U2proxy) can also be enabled using the auth_gss_constrained_delegation directive together with the auth_gss_delegate_credentials directive. To specify the ccache file name to store the service ticket used for constrained delegation, set the auth_gss_service_ccache directive. Otherwise, the default ccache name will be used.

auth_gss_service_ccache /tmp/krb5cc_0;
auth_gss_delegate_credentials on;
auth_gss_constrained_delegation on;

The delegated credentials will be stored within the systems tmp directory. Once the request is completed, the credentials file will be destroyed. The name of the credentials file will be specified within the nginx variable $krb5_cc_name. Usage of the variable can include passing it to a fcgi program using the fastcgi_param directive.

fastcgi_param KRB5CCNAME $krb5_cc_name;

Constrained delegation is currently only supported using the negotiate authentication scheme and has only been testing with MIT Kerberos (Use at your own risk if using Heimdal Kerberos).

Basic authentication fallback

The module falls back to basic authentication by default if no negotiation is attempted by the client. If you are using SPNEGO without SSL, it is recommended you disable basic authentication fallback, as the password would be sent in plaintext. This is done by setting auth_gss_allow_basic_fallback in the config file.

auth_gss_allow_basic_fallback off

These options affect the operation of basic authentication:

  • auth_gss_realm: Kerberos realm name. Basic authentication fallback requires either this to be set or a default_realm to be configured in krb5.conf (the latter being the recommended approach). If this is specified, the realm is only passed to the nginx variable $remote_user if it differs from this default. To override this behavior, set auth_gss_format_full to on in your configuration.
  • auth_gss_force_realm: Forcibly authenticate using the realm configured in auth_gss_realm or the system default realm if auth_gss_realm is not set. This will rewrite $remote_user if the client provided a different realm. If auth_gss_format_full is not enabled, $remote_user will not include a realm even if one was specified by the client.
  • The nginx core auth_delay directive is honored when an incorrect username/password is provided.

Optional Authentication

The SPNEGO protocol always begins with a 401 challenge from the server. Clients that lack Kerberos support, or choose not to authenticate, will stop at that 401 and never make a second request. The nginx error_page directive can be used to serve meaningful content on that 401 response — for instance, a login form provided by the same backend that handles authenticated requests. The backend receives the request with $remote_user unset and can present a login form accordingly.

location /app.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    auth_gss on;
    # ... other auth_gss directives ...
    error_page 401 @unauthenticated;
}

location @unauthenticated {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$uri;
}

Placing error_page 401 @unauthenticated in the server block rather than in individual location blocks causes it to apply to all locations that do not override it.

Channel Bindings

The auth_gss_channel_binding directive binds a Kerberos authentication exchange to the TLS session it travels over, preventing a man-in-the-middle attack where a valid Negotiate token is relayed to a different server. The directive requires TLS; configuring it on a plain HTTP connection will cause authentication to fail.

auth_gss_channel_binding off;              # default – existing behaviour
auth_gss_channel_binding server-end-point; # RFC 5929 – hash of server cert
auth_gss_channel_binding exporter;         # RFC 9266 – TLS keying material (tech demo)

server-end-point (RFC5929) hashes the server's TLS certificate. This is the only type supported by mainstream clients (see the table below).

exporter (RFC9266) derives 32 bytes from the TLS keying material. This type is provided for experimentation only; do not use it in production.

Client support

Client Support Notes
curl Yes curl ≥ 8.10.0 with OpenSSL (see curl PR #13098) and MIT Kerberos ≥ 1.19.
Firefox (Linux) No See Mozilla bug #563276
Chrome (Linux) No See the reference to GSS_C_NO_CHANNEL_BINDINGS in the source.
Windows clients Yes IE, Edge, Chrome, Firefox, etc support this automatically via SSPI.

Because Firefox and Chrome on Linux do not support channel bindings, setting auth_gss_channel_binding server-end-point will cause those browsers to fail. Restrict this directive to deployments where all clients are known to have proper support for channel bindings.

Troubleshooting

Check the logs. If you see a mention of NTLM, your client is attempting to connect using NTLMSSP, which is unsupported and insecure.

Verify that you have an HTTP principal in your keytab

MIT Kerberos utilities

$ KRB5_KTNAME=FILE:<path to your keytab> klist -k

or

$ ktutil
ktutil: read_kt <path to your keytab>
ktutil: list

Heimdal Kerberos utilities

$ ktutil -k <path to your keytab> list

Obtain an HTTP principal

If you find that you do not have the HTTP service principal, are running in an Active Directory environment, and are bound to the domain such that Samba tools work properly

$ env KRB5_KTNAME=FILE:<path to your keytab> net ads -P keytab add HTTP

If you are running in a different kerberos environment, you can likely run

$ env KRB5_KTNAME=FILE:<path to your keytab> krb5_keytab HTTP

Increase maximum allowed header size

In Active Directory environment, SPNEGO token in the Authorization header includes PAC (Privilege Access Certificate) information, which includes all security groups the user belongs to. This may cause the header to grow beyond default 8kB limit and causes following error message:

400 Bad Request
Request Header Or Cookie Too Large

For performance reasons, best solution is to reduce the number of groups the user belongs to. When this is impractical, you may also choose to increase the allowed header size by explicitly setting the number and size of Nginx header buffers:

large_client_header_buffers 8 32k;

Debugging

The module prints all sort of debugging information if nginx is compiled with the --with-debug option, and the error_log directive has a debug level.

NTLM

Note that the module does not support NTLMSSP in Negotiate. NTLM, both v1 and v2, is an exploitable protocol and should be avoided where possible.

Windows

For Windows KDC/AD environments, see the documentation here.

Help

If you're unable to figure things out, please feel free to open an issue on Github and I'll do my best to help you.

About

SPNEGO HTTP Authentication Module for nginx

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors