Archive > 20.7 Legacy Series

HAProxy Help Needed -- Authenticated Access to Minecraft Server

(1/2) > >>

randomwalk:
I have a personal Minecraft server on the LAN that I run for my kids.  They want to allow cousins / school friends to play on our server.  For security reasons, I don't want to just port forward and allow public access to the Minecraft server, nor do I want these people access to my network via VPN.  I want an in between solution where people can access the Minecraft server after HTTPS user / password authentication.  I thought HAProxy would work for this, but have not gotten it to work.  Any guidance would be greatly appreciated!

End Goal:  I want people to go to some web address (e.g., https://minecraft.domain.xyz:12345) and authenticate using a user / password that I give them.  After that, they are able to connect to my server by connecting to minecraft.domain.xyz inside Minecraft.  If people do not first go to the URL to authenticate, they should not be able to connect via Minecraft.  I understand Minecraft uses port 25565.

Here is my set up so far:

1)  I installed the Let's Encrypt plugin.  I purchased my own domain (domain.xyz) and have successfully issued a wildcard certificate for domain.xyz and *.domain.xyz.  In the Let's Encrypt plugin, I do NOT check "HAProxy Integration" because I understand that is only needed if I use HTTP-01 validation and I don't use that method.

2)  I use Dynamic DNS to set domain.xyz and minecraft.domain.xyz to equal my WAN IP address.

3)  Here are my HAProxy settings:

Real Server
Enabled:  Checked
Name:  Minecraft
IP:  192.168.1.90
Port:  25565
Mode:  active [default]
SSL:  Unchecked

Backend Pool
Enabled:  Checked
Name:  Minecraft
Mode:  TCP (Layer 4)  --> my understanding is that this should be set to TCP because Minecraft is not a webserver
Balancing Algorithm:  Source-IP Hash [default]
Servers:  Minecraft
Enable Health Checking:  Checked
Health Monitor:  None
Persistence Type:  Stick-table persistence [default]
Stick-table persistence table type:  Source-IP [default]

Users / Group
I created a single test user / password.
I added this single user to a test group.

Conditions
Name:  Host_Minecraft
Condition type:  Host matches
Host string:  minecraft.domain.xyz

Name:  Auth_User
Condition type:  HTTP Basic Auth:  username/password from client matches selected user/group
Parameters:  matches to my test group.

Rules
Name:  Minecraft
Test type:  IF [default]
Selected conditions:  Auth_User AND Host_Minecraft
Execute function:  Use specified Backend Pool
Use backend pool:  Minecraft

Public Service
Name:  Frontend
Listen Addresses:  0.0.0.0:12345  I don't know if 0.0.0.0 is the right address to use here
Type:  HTTP / HTTPS (SSL offloading) [default]
Default Backend Pool:  none
Enable SSL offloading:  Checked

SSL Offloading:
Certificates:  wildcard certificate from Let's Encrypt
Default certificate:  wildcard certificate from Let's Encrypt
Enable Advanced Settings:  Unchecked

HTTP(S) settings:
Enable HTTP/2:  Checked
HTTP/2 Without TLS:  Unchecked

Basic Authentication:
Enabled:  Checked
Allowed Groups:  my test group

Firewall rules
On the WAN, I allow IPv4 TCP/UDP protocol to pass at port 12345.

Here is what happens:

1)  Using my browser, I am able to go to https://minecraft.domain.xyz:12345, it gets a user/password prompt, and I able to "login" using my test user credentials.  The connection is properly secured using the Let's Encrypt certificate.  After login, the browser shows an error message because there is no webserver at that location.  But I don't care.  I just want to satisfy the Auth_User condition.

2)  I open Minecraft and add the server minecraft.domain.xyz, and I try to connect, but it does not work.  I thought this would work because I thought this would satisfy the Host_Minecraft condition.

So what am I doing wrong?  I am able to get the user authentication working, but HAProxy is not correctly passing traffic to my Minecraft server.  I am guessing something is wrong with my "Public Server" settings, but am not sure what.

randomwalk:
One thing I noticed that is in my "Public Service" settings, I did not set anything under "Select Rules".  But when I try to select "Minecraft" rule inside that setting, HAProxy says there is a critical configuration error: 

http frontend 'Frontend' (/usr/local/etc/haproxy.conf:48) tries to use incompatible tcp backend 'Minecraft' (/usr/local/etc/haproxy.conf:81) in a 'use_backend' rule (see 'mode').

I am guessing this means that the Public Service "Type" should be set to something else, rather than "HTTP / HTTPS (SSL offloading) [default]"?  But I don't know  how to set this up.  I want to keep the HTTPS user authentication, but pass through TCP traffic.

randomwalk:
After some searching, it seems that because Minecraft does not use HTTP, you cannot use Host_Minecraft condition.  That is, you can't depend on hostname = minecraft.domain.xyz to trigger the rule.

As a result, I have changed the rule Minecraft to equal IF Auth_User (i.e., the user successfully authenticates).

I think the solution must involving setting up a second frontend:

Public Service
Name:  Frontend_Minecraft
Listen Addresses:  0.0.0.0:25565
Type:  TCP
Default Backend Pool:  none
Rule:  Minecraft (this is basically just equal to IF Auth_User)

Unfortunately, the above does not seem to work.  I am able to connect to the Minecraft server from outside the network if I change the above public service to have Default Backend Pool = Minecraft.  But if I do that, then you are able to connect to the server regardless of whether you authenticated.

What I can't figure out is how to link the two Public Services.  I have one public service at port 12345 that just does HTTP authentication, and that works correctly and uses a proper SSL certificate.  I have another public service at port 25565 that connects to the Minecraft backend.  It works too, but I am not able to make the Minecraft backend conditional on authenticating with the first Public Service.

Any ideas on how to do this?

cmdr.adama:
So, First thing's first.

You won't be able to do this with HAProxy.

Really the only way you can achieve what you want is to sit the MC server behind a VPN.

So, you'll need to set up a VPN server, OpenVPN, WireGuard, etc.
Shift your MC server to sit in a DMZ, if you haven't already and then point all VPN connections to the DMZ.

If you want, you can also configure unbound to allow the users connecting to the VPN to use hostnames instead of IP addresses.

randomwalk:
Yes, I am coming to the conclusion that this cannot be done using HAProxy after additional searching.  The main issue is that Minecraft is not an HTTP protocol, and you cannot authenticate using a TCP proxy.  This seems strange to me as I would think you can authenticate via HTTP, then remember the IP address that authenticated, and then allow only that IP address to go through the TCP proxy.  It seems like this would be a desired function as not everything is HTTP.

I'm aware that this can be done with VPN and I can lock it down with firewall rules so that users can only access the Minecraft server.  I already have an OpenVPN server running for my own remote access.  But I do not want to give VPN access to my kids' school friends because (1) it's too complicated, I would have to issue them certificates and they would have to set it up on their end, (2) hard to cut people off if I want to; I'd have to revoke their certificates (vs. just deleting their user account).  This is why I would prefer a user / password scheme rather than a VPN that requires certificates and complicated set up. 

I'm not looking to give users fully secured / encrypted access to the internal network -- I just don't want the whole world to have access to the Minecraft server.

So are there alternatives to VPN?  Are there VPNs that don't require certificates?  Is there like a scheme where you have port forwarding conditional on user authentication? 



--- Quote from: cmdr.adama on December 09, 2020, 10:42:19 am ---So, First thing's first.

You won't be able to do this with HAProxy.

Really the only way you can achieve what you want is to sit the MC server behind a VPN.

So, you'll need to set up a VPN server, OpenVPN, WireGuard, etc.
Shift your MC server to sit in a DMZ, if you haven't already and then point all VPN connections to the DMZ.

If you want, you can also configure unbound to allow the users connecting to the VPN to use hostnames instead of IP addresses.

--- End quote ---

Navigation

[0] Message Index

[#] Next page

Go to full version