Experience with JSS and mod_proxy_ajp (or something like it)?

blinvisible
Contributor

Anyone have any experience with putting Tomcat behind an Apache proxy, using mod_proxy or mod_proxy_ajp or something similar with their JSS server?

While needing the JSS to be accessible both internally and externally, we'd rather not directly expose Tomcat to external networks if possible. Just wondering if anyone else has tried it out before I get my hands dirty with it.

1 ACCEPTED SOLUTION

blinvisible
Contributor

If anyone else is interested, here is how we configured Apache's mod_proxy and Tomcat to work successfully in our environment.

Background: our setup is on RHEL 6. We had already configured the JSS and SSL certificates. Clients were interacting with Tomcat on port 8443 directly. We did not want to expose Tomcat ports to external networks, and also did not want to create a separate JSS instance in a DMZ or create a load balancer. This solution allowed us to put Apache in front of Tomcat on the same host.

Assumptions: RHEL6 is your host, JSS is installed and configured, Apache and associated modules are already installed, you have a working httpd service, you've configured SSL and your certificate in Apache httpd, etc. and everything works apart from port 8443 being directly exposed.

Caveats: Our JSS is at version 9.11 and we've not tested on earlier versions. Also, I may use the words "JSS" and "Tomcat" somewhat interchangeably.

The process:

  1. In /etc/httpd/conf.d/ssl.conf we added, inside the <VirtualHost _default:443>* block:

    ProxyPreserveHost On
    ProxyPass / http://localhost:8443/
    ProxyPassReverse / https://yourcasperURL.domain.com/

    Working backwards:

  2. ProxyPassReverse will be what the JSS returns to clients. It should be your base JSS URL.

  3. ProxyPass is also the JSS, but here we use localhost instead of the full URL. This way the host can access its network data directly from memory without having to send it back out in another network query. It also has the port on which the JSS is actually listening, 8443.

  4. ProxyPreserveHost On ensures that the Host: header from the incoming request is passed to Tomcat without modification.

Restart httpd (/etc/init.d/httpd restart or service httpd restart) to apply changes.

  1. In /usr/local/jss/tomcat/conf/server.xml there are three Connector blocks for ports 8080, 8443 and 8009. In the block for 8443, we modified/added:

    <Connector proxyPort="443" proxyName="yourcasperURL.domain.com" port="8443" 
    SSLEnabled="false" secure="true" scheme="https" protocol="HTTP/1.1" 
    [...and a bunch of other stuff...] />

    Of interest here:

  2. proxyPort is the port clients will actually use to connect to the JSS. In our case, that was standard https port 443.

  3. proxyName is the JSS URL, and probably isn't strictly necessary in this circumstance.
  4. port is the port on which Tomcat is listening. This should already be here.
  5. SSLEnabled and secure are a little tricky here. Because the JSS and the proxy are the same machine. we're not concerned with encrypting traffic between the itself (the proxy) and itself (the Tomcat host). However, since we are doing this over https, SSL is expected. We worked around this by setting SSLEnabled to false but secure to true, basically saying to Tomcat, "Yeah, it's good, you're secure, don't worry about SSL, it's all good, trust us," but it's not, really, since SSL terminates at Apache before passing things to Tomcat. Ultimately this is only a problem for things that might connect to port 8443 directly, but configured as such, nothing should, and you can block port 8443 entirely at the firewall so nothing does.

The rest of the Connector block was left as-is, [for us] containing a bunch of SSL keystore and cipher information.

  1. Also in /usr/local/jss/tomcat/conf/server.xml inside the <Engine name="Catalina" defaultHost="localhost"> block, we added:
    <Valve className="org.apache.catalina.valves.RemoteIpValve" 
    internalProxies="127.0.0.1|::1|0:0:0:0:0:0:0:1" />
    This will configure Tomcat to trust certain proxy headers (e.g. X-Forwarded-For) coming from the known proxy IPv4/IPv6 addresses. Without this, all clients in the JSS will appear to be checking in via the same IP address, that of the localhost proxy.

Restart tomcat (/etc/init.d/jamf.tomcat7 restart) to apply changes.

Other things to note:

  • If you use curl in any Extension Attributes, such as in the JSS Certificate Validation template, straight-up curl commands may fail the TLSv1 handshake with this error:

    curl: (35) error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)

    If so, forcing SSLv3 by changing the command to curl -3 or curl --ssl3 will probably solve the problem.

  • If you are using iptables on the host to restrict client/web access to the JSS, you only need input rules for port 443 for whatever IPs or subnet blocks you want to grant access. Do not open port 8443 as it will be insecure as configured in step 2 above.

  • If you are serving static content, such as a distribution point, over HTTP instead of/in addition to Samba/CIFS, you'll need to add an exclusion to /etc/httpd/conf.d/ssl.conf so those requests aren't proxied to port 8443. This can be accomplished with the addition of

    ProxyPass /yourShareContext !

    to ssl.conf with your other ProxyPass statements. Once again, restart httpd (/etc/init.d/httpd restart or service httpd restart) to apply changes.

  • If you've already enrolled clients with https://yourcasperURL.domain.com:8443/, they'll need to be changed before you firewall port 8443. You can do this with a script, policy, or manually on each client, with the shell command:

    sudo jamf createConf -url https://yourcasperURL.domain.com/

    If you wish, you can verify the connection is working with:

    sudo jamf checkJSSConnection

    If you want a Smart Group in your JSS of clients with the old URL, create an extension attribute that echoes the return of

    defaults read /Library/Preferences/com.jamfsoftware.jamf jss_url | grep https://

    Then create a Smart Group with that Extension Attribute and a criterion of "like 8443" to collect those clients. You can then apply a script policy scoped to that group to update their JSS connection URL.

  • Updating the JSS using the JAMF JSS Installer for Linux may fail as it will determine port 8443 is in use, but unable to determine the JSS is running there:

    Checking if Tomcat is NOT installed...Port 8443 in use.
    Error: Found 8443 in use, but no JSS web app is running over the port. Aborting installer...
    Please shut down Tomcat and run the JSS Installer again.
    Port 8080 in use.
    Verified that the JSS web app is running over 8080.
    Stopping Tomcat for the upgrade...
    OK
    Aborting installation due to unsatisfied requirements.

    This can be worked around by first manually stopping Tomcat (/etc/init.d/jamf.tomcat7 stop) and running the installer again. Tomcat should restart automatically at the end of a successful installation.

If you have questions or other experiences with Casper and proxies, please share!

View solution in original post

1 REPLY 1

blinvisible
Contributor

If anyone else is interested, here is how we configured Apache's mod_proxy and Tomcat to work successfully in our environment.

Background: our setup is on RHEL 6. We had already configured the JSS and SSL certificates. Clients were interacting with Tomcat on port 8443 directly. We did not want to expose Tomcat ports to external networks, and also did not want to create a separate JSS instance in a DMZ or create a load balancer. This solution allowed us to put Apache in front of Tomcat on the same host.

Assumptions: RHEL6 is your host, JSS is installed and configured, Apache and associated modules are already installed, you have a working httpd service, you've configured SSL and your certificate in Apache httpd, etc. and everything works apart from port 8443 being directly exposed.

Caveats: Our JSS is at version 9.11 and we've not tested on earlier versions. Also, I may use the words "JSS" and "Tomcat" somewhat interchangeably.

The process:

  1. In /etc/httpd/conf.d/ssl.conf we added, inside the <VirtualHost _default:443>* block:

    ProxyPreserveHost On
    ProxyPass / http://localhost:8443/
    ProxyPassReverse / https://yourcasperURL.domain.com/

    Working backwards:

  2. ProxyPassReverse will be what the JSS returns to clients. It should be your base JSS URL.

  3. ProxyPass is also the JSS, but here we use localhost instead of the full URL. This way the host can access its network data directly from memory without having to send it back out in another network query. It also has the port on which the JSS is actually listening, 8443.

  4. ProxyPreserveHost On ensures that the Host: header from the incoming request is passed to Tomcat without modification.

Restart httpd (/etc/init.d/httpd restart or service httpd restart) to apply changes.

  1. In /usr/local/jss/tomcat/conf/server.xml there are three Connector blocks for ports 8080, 8443 and 8009. In the block for 8443, we modified/added:

    <Connector proxyPort="443" proxyName="yourcasperURL.domain.com" port="8443" 
    SSLEnabled="false" secure="true" scheme="https" protocol="HTTP/1.1" 
    [...and a bunch of other stuff...] />

    Of interest here:

  2. proxyPort is the port clients will actually use to connect to the JSS. In our case, that was standard https port 443.

  3. proxyName is the JSS URL, and probably isn't strictly necessary in this circumstance.
  4. port is the port on which Tomcat is listening. This should already be here.
  5. SSLEnabled and secure are a little tricky here. Because the JSS and the proxy are the same machine. we're not concerned with encrypting traffic between the itself (the proxy) and itself (the Tomcat host). However, since we are doing this over https, SSL is expected. We worked around this by setting SSLEnabled to false but secure to true, basically saying to Tomcat, "Yeah, it's good, you're secure, don't worry about SSL, it's all good, trust us," but it's not, really, since SSL terminates at Apache before passing things to Tomcat. Ultimately this is only a problem for things that might connect to port 8443 directly, but configured as such, nothing should, and you can block port 8443 entirely at the firewall so nothing does.

The rest of the Connector block was left as-is, [for us] containing a bunch of SSL keystore and cipher information.

  1. Also in /usr/local/jss/tomcat/conf/server.xml inside the <Engine name="Catalina" defaultHost="localhost"> block, we added:
    <Valve className="org.apache.catalina.valves.RemoteIpValve" 
    internalProxies="127.0.0.1|::1|0:0:0:0:0:0:0:1" />
    This will configure Tomcat to trust certain proxy headers (e.g. X-Forwarded-For) coming from the known proxy IPv4/IPv6 addresses. Without this, all clients in the JSS will appear to be checking in via the same IP address, that of the localhost proxy.

Restart tomcat (/etc/init.d/jamf.tomcat7 restart) to apply changes.

Other things to note:

  • If you use curl in any Extension Attributes, such as in the JSS Certificate Validation template, straight-up curl commands may fail the TLSv1 handshake with this error:

    curl: (35) error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)

    If so, forcing SSLv3 by changing the command to curl -3 or curl --ssl3 will probably solve the problem.

  • If you are using iptables on the host to restrict client/web access to the JSS, you only need input rules for port 443 for whatever IPs or subnet blocks you want to grant access. Do not open port 8443 as it will be insecure as configured in step 2 above.

  • If you are serving static content, such as a distribution point, over HTTP instead of/in addition to Samba/CIFS, you'll need to add an exclusion to /etc/httpd/conf.d/ssl.conf so those requests aren't proxied to port 8443. This can be accomplished with the addition of

    ProxyPass /yourShareContext !

    to ssl.conf with your other ProxyPass statements. Once again, restart httpd (/etc/init.d/httpd restart or service httpd restart) to apply changes.

  • If you've already enrolled clients with https://yourcasperURL.domain.com:8443/, they'll need to be changed before you firewall port 8443. You can do this with a script, policy, or manually on each client, with the shell command:

    sudo jamf createConf -url https://yourcasperURL.domain.com/

    If you wish, you can verify the connection is working with:

    sudo jamf checkJSSConnection

    If you want a Smart Group in your JSS of clients with the old URL, create an extension attribute that echoes the return of

    defaults read /Library/Preferences/com.jamfsoftware.jamf jss_url | grep https://

    Then create a Smart Group with that Extension Attribute and a criterion of "like 8443" to collect those clients. You can then apply a script policy scoped to that group to update their JSS connection URL.

  • Updating the JSS using the JAMF JSS Installer for Linux may fail as it will determine port 8443 is in use, but unable to determine the JSS is running there:

    Checking if Tomcat is NOT installed...Port 8443 in use.
    Error: Found 8443 in use, but no JSS web app is running over the port. Aborting installer...
    Please shut down Tomcat and run the JSS Installer again.
    Port 8080 in use.
    Verified that the JSS web app is running over 8080.
    Stopping Tomcat for the upgrade...
    OK
    Aborting installation due to unsatisfied requirements.

    This can be worked around by first manually stopping Tomcat (/etc/init.d/jamf.tomcat7 stop) and running the installer again. Tomcat should restart automatically at the end of a successful installation.

If you have questions or other experiences with Casper and proxies, please share!