google cloud platform: cannot start java https ser

2019-08-22 11:32发布

问题:

The following simple program:

import com.sun.net.httpserver.HttpsServer;
import java.net.InetSocketAddress;

class SimpleServer {
  public static void main(String[] pArgs) {
    try {
      HttpsServer s = HttpsServer.create(new InetSocketAddress(443), 0);
      System.out.println(" " + s);
    } catch (Exception pE) {
      throw new RuntimeException("Could not create HTTPS server", pE);  
    }
  }
}

will not work inside a Debian VM hosted by google cloud platform (Google Compute Engine - IaaS):

Exception in thread "main" java.lang.RuntimeException: Could not create HTTPS server
    at SimpleServer.main(SimpleServer.java:10)
Caused by: java.net.SocketException: Permission denied
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:433)
    at sun.nio.ch.Net.bind(Net.java:425)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at sun.net.httpserver.ServerImpl.<init>(ServerImpl.java:100)
    at sun.net.httpserver.HttpsServerImpl.<init>(HttpsServerImpl.java:50)
    at sun.net.httpserver.DefaultHttpServerProvider.createHttpsServer(DefaultHttpServerProvider.java:39)
    at com.sun.net.httpserver.HttpsServer.create(HttpsServer.java:90)
    at SimpleServer.main(SimpleServer.java:7)

This example will work when running on the Windows desktop, and also if we change the port from 443 to something else. So how do we force google cloud to allow a server on 443? I've tried opening up the firewall, but that did not work (not that it really should have :-( since it's a separate issue).

The java version is (though I doubt this matters):

openjdk version "1.8.0_141"
OpenJDK Runtime Environment (build 1.8.0_141-8u141-b15-1~deb9u1-b15)
OpenJDK 64-Bit Server VM (build 25.141-b15, mixed mode)

回答1:

This is not a GCP issue but a linux/Unix security feature.

Ports below 1024 on linux/Unix are "privileged ports" which require elevated privileges to create.

As you are in GCP, you have several options.

Use a high port above 1024 as a non-privlaged user and:

  • Connect to that high port in your url https://foo:8443
  • Use the GCP network or HTTP/HTTPS load balancer to forward port 443 to a high port
  • Leverage IP tables to forward packets from 443 to a high port inside the VM instance
  • Run the service using suid, sudo or other method
  • Grant the _CAP_NET_BIND_SERVICE_ capabilities(7) to the process.

Those last two options have complex security implications and should be avoided if at all possible.

The following link will cover some of the above options, but the the first option will be the simplest while being much safer than the last two options.

https://debian-administration.org/article/386/Running_network_services_as_a_non-root_user.