mod_auth_gssapi
mod_auth_gssapi copied to clipboard
Cannot set an env var (GSSPROXY_SOCKET) that mod_auth_gssapi will use
I have multiple web applications running with different keytabs and gssproxy. I use gssproxy's sockets to differentiate between them. For that, I need to pass the GSSPROXY_SOCKET
environment variable to mod_auth_gssapi
, and I can't find a way to do it. I've tried:
- setting one in
/etc/systemd/system/httpd.service.d/
, that works fine but I can't differentiate between the web apps running in the same apache - using
SetEnv
, which is documented not to work, and indeed it doesn't - using
SetEnvIf
, it doesn't work either (I triedSetEnvIf Host app.example.com GSSPROXY_SOCKET=/var/lib/gssproxy/app.sock
) - using
RewriteRule
, and it doesn't work either. I triedRewriteCond %{HTTP_HOST} app.example.com \n RewriteRule .* - [E=GSSPROXY_SOCKET:/var/lib/gssproxy/app.sock]
. I did check with increased logging that the rule was matching on the request.
Is there a way to pass an environment variable to mod_auth_gssapi, that is dependent on the virtualhost or even the request path? If so, it would be great if it could be added to the docs (here and/or in gssproxy's Apache doc). Thanks!
The environment variable for GSSPROXY_SOCKET is observed by the gssproxy mechglue plugin in gssapi and mod_auth_gssapi is completely oblivious to that.
The env var is a process level variable and would require httpd to set this variable and fork before gssproxy client libs are ever used because gssproxy client libs tend to cache the file descriptor used to communicate to the server.
If you can force httpd to execute different virtualhosts as different users that will be easier to manage with a single socket and just configuration I believe.
If that will not work, I am afraid a gssproxy enhancement request need to be raised and some design done on that side.
Interesting, thanks. My app is a wsgi app and I can set it to run as a different user, but I think mod_auth_gssapi works before that, no? I tried with SuexecUserGroup, and adjusted the gssproxy config to distinguish on users and not socket, but it's still not picking up the right gssproxy service, it's picking up the one that is set for the generic apache user.
can you check gssproxy to see if new connections are being made or if apahce opened a connection early and then child processes just keep using the same connections they inherit from the parent ?
Uhm actually the client will detect a fork or a change in euid/egid and reopen the socket ... so it seem like apache is running the authentication code before handing the request to a forked process ?
Sure! When I run curl on the second app, I get 3 connections to the "ipa-httpd" service, which is the service for the apache user, not the one for the user the second app is running as (fasjson):
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [CID 14][2023/07/18 07:54:06]: Connection matched service ipa-httpd
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [CID 14][2023/07/18 07:54:06]: gp_rpc_execute: executing 6 (GSSX_ACQUIRE_CRED) for service "ipa-httpd", euid: 48,socket: (null)
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: GSSX_ARG_ACQUIRE_CRED( call_ctx: { "" [ ] } input_cred_handle: { "HTTP/[email protected]" [ { "HTTP/[email protected]" { 1 2 840 113554 1 2 2 } BOTH 85565 85565 } ] [ ......JJ..E.E...... ] 0 } add_cred: 0 desired_name: <Null> time_req: 4294967295 desired_mechs: { { 1 2 840 113554 1 2 2 } } cred_usage: BOTH initiator_time_req: 0 acceptor_time_req: 0 )
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: GSSX_RES_ACQUIRE_CRED( status: { 0 { 1 2 840 113554 1 2 2 } 0 "" "" [ ] } output_cred_handle: { "HTTP/[email protected]" [ { "HTTP/[email protected]" { 1 2 840 113554 1 2 2 } BOTH 85565 85565 } ] [ ......JJ..E.E...... ] 0 } )
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Total sent bytes: 158776
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Total received bytes: 151204
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Idle for: 0 seconds
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [CID 14][2023/07/18 07:54:06]: Connection matched service ipa-httpd
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [CID 14][2023/07/18 07:54:06]: gp_rpc_execute: executing 6 (GSSX_ACQUIRE_CRED) for service "ipa-httpd", euid: 48,socket: (null)
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: GSSX_ARG_ACQUIRE_CRED( call_ctx: { "" [ ] } input_cred_handle: { "HTTP/[email protected]" [ { "HTTP/[email protected]" { 1 2 840 113554 1 2 2 } BOTH 85565 85565 } ] [ ......JJ..E.E...... ] 0 } add_cred: 0 desired_name: <Null> time_req: 4294967295 desired_mechs: { { 1 2 840 113554 1 2 2 } } cred_usage: BOTH initiator_time_req: 0 acceptor_time_req: 0 )
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: GSSX_RES_ACQUIRE_CRED( status: { 0 { 1 2 840 113554 1 2 2 } 0 "" "" [ ] } output_cred_handle: { "HTTP/[email protected]" [ { "HTTP/[email protected]" { 1 2 840 113554 1 2 2 } BOTH 85565 85565 } ] [ ......JJ..E.E...... ] 0 } )
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Total sent bytes: 162276
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Total received bytes: 151208
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Idle for: 0 seconds
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Total received bytes: 156336
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Idle for: 0 seconds
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [CID 14][2023/07/18 07:54:06]: Connection matched service ipa-httpd
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [CID 14][2023/07/18 07:54:06]: gp_rpc_execute: executing 9 (GSSX_ACCEPT_SEC_CONTEXT) for service "ipa-httpd", euid: 48,socket: (null)
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: GSSX_ARG_ACCEPT_SEC_CONTEXT( call_ctx: { "" [ ] } context_handle: <Null> cred_handle: { "HTTP/[email protected]" [ { "HTTP/[email protected]" { 1 2 840 113554 1 2 2 } BOTH 85565 85565 } ] [ ......JJ..E.E...... ] 0 } input_token: [ ........H.......... ] input_cb: <Null> ret_deleg_cred: 1 )
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: GSSX_RES_ACCEPT_SEC_CONTEXT( status: { 851968 <None> 2529638947 "Unspecified GSS failure. Minor code may provide more information" "Request ticket server HTTP/[email protected] not found in keytab (ticket kvno 1)" [ ] } context_handle: <Null> output_token: <Null> delegated_cred_handle: <Null> )
Jul 18 07:54:06 auth.tinystage.test gssproxy[40907]: [2023/07/18 07:54:06]: Total sent bytes: 162528
In the Apache error log I get a message because the principal for fasjson is not found in IPA's keytab, of course: GSS ERROR In Negotiate Auth: gss_accept_sec_context() failed: [Unspecified GSS failure. Minor code may provide more information ( Request ticket server HTTP/[email protected] not found in keytab (ticket kvno 1))]
My apache config for FASJSON:
WSGISocketPrefix /run/httpd/wsgi
WSGIDaemonProcess fasjson \
user=fasjson group=fasjson \
processes=4 threads=1 maximum-requests=500 \
display-name=%{GROUP} socket-timeout=2147483647 \
lang=C.UTF-8 locale=C.UTF-8
WSGIImportScript /srv/fasjson.wsgi \
process-group=fasjson application-group=fasjson
WSGIScriptAlias /fasjson /srv/fasjson.wsgi
WSGIScriptReloading Off
<VirtualHost _default_:443>
ServerName fasjson.tinystage.test:443
ErrorLog logs/error_log
TransferLog logs/access_log
LogLevel info
[SSL stuff]
<LocationMatch "/fasjson/v[0-9]+/">
AuthType GSSAPI
AuthName "Kerberos Login"
GssapiUseSessions On
Session On
SessionCookieName fasjson_session path=/fasjson;httponly;secure;
SessionHeader FASJSONSESSION
GssapiSessionKey file:/run/fasjson/session.key
WSGIProcessGroup fasjson
WSGIApplicationGroup fasjson
GssapiImpersonate On
GssapiDelegCcacheDir /run/fasjson/ccaches
GssapiDelegCcachePerms mode:0660
GssapiUseS4U2Proxy on
GssapiAllowedMech krb5
Require valid-user
</LocationMatch>
</VirtualHost>
And the gssproxy config:
[service/fasjson-httpd]
mechs = krb5
cred_store = keytab:/var/lib/gssproxy/fasjson-http.keytab
cred_store = client_keytab:/var/lib/gssproxy/fasjson-http.keytab
allow_constrained_delegation = true
allow_client_ccache_sync = true
cred_usage = both
euid = fasjson
The HTTP and gssproxy configs for IPA are the default ones, I didn't change anything there.
Ah I see, you are running the WSGI app as a user, but auth happens always in apache way before stuff is send down to the pipe talking to the python app.
Should probbably look into apahce-mtm-itk which can run the whole apache's virtualhost handling as a different user.
Cool, thanks for the tip! I tried with mod_suexec
but that didn't work either. I'll try with mtm_itk and let you know.
Alright, it does work with mpm-itk, but it requires adjustments it a few places and I'd rather not change IPA's environment too much, so I'll stop here and put IPA in its own VM. Thanks for the help though! It would be great if mod_auth_gssapi somehow had a way to select the gssproxy socket that did not involve an environment variable... :-)
mod_auth_gssapi can't on its own, it would be a toggle somehow exposed by the gssproxy mechanism. But that mechanism is designed to be transparent to GSSAPI applications ... so ... not so easy.
This is how the thing works:
Httpd -> mod_auth_gssapi -> libgssapi -> [gssproxy-mechanism -> gssproxy-client] ===> gssproxy-daemon -> libgssapi -> krb5-mechanism
(Where -> means dynamic linking, and ===> means socket communication, and [] is the component that deals with the env var)
The thing that selects the socket is the gssproxy-mechanism/client part, which is a layered module that intercepts gssapi operations and shoves them into the gssproxy daemon. As you can see it is pretty deep into the chain, and wholly separated from what mod_auth_gssapi knows about.
There are ways though, in theory, feel free to open a RFE against gssproxy.
Thanks for the discussion it will be useful to others and for future plans.