skip to Main Content

Here’s my goal:

admin.domain.com is where we have a Magento 2 instance setup. It’s locked down in Nginx for a white-list of IPs.

api.domain.com has its own white-list, and it ultimately goes to admin.domain.com/rest/..., preferably without the requester being able to see.

The idea is to enforce all API integrations to go through the api subdomain, and to hide our admin domain entirely. Note – This is inside a Docker container, not directly on a server.

Currently, how I am attempting to accomplish this is using proxy_pass and setting the allow and deny blocks accordingly. Here is a snippet of our Nginx configs

server {
    server_name admin.domain.com;
    # other stuff

    location ~ /(index.php/rest|rest) {
        allow $DOCKER_IP; # Seems to come from Docker Gateway IP as of now
        deny all;
        # other stuff
    }

    location / {
        # other stuff
    }
}

server {
    server_name api.domain.com;
    # other stuff

    location ~ /(index.php/rest|rest) {
        proxy_set_header Host admin.domain.com;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://admin.domain.com;
    }
    location / {
        return 403;
    }
}

In theory, this should work. From testing this I noticed that all requests to api.domain.com are forwarded to admin.domain.com and admin sees the request from the Docker container’s Gateway IP as the source IP. So, I can add the Gateway IP in the allow $DOCKER_IP line. The main problem here is finding a dependable way to get this IP since it changes every time the container is recreated (on each release).

Alternatively, if there’s a more simple way to do this, I would prefer that. I’m trying not to over-complicate this, but I’m a little over my head here with Nginx configurations.

So, my Questions are this:

  1. Am I way over-complicating this, and is there a recommendation of a different approach to look into?
  2. If not, is there a dependable way to get the Docker container’s Gateway IP in Nginx, or maybe in entrypoint so that I can set it as a variable and place it into the nginx config?

2

Answers


  1. Chosen as BEST ANSWER

    This is how I have solved this for now. I'm still interested in better solutions if possible, but for now this is what I'm doing.

    This is a snippet of the Nginx config for the API domain. It has its own whitelist for API access, and then reverse proxy to the real domain where M2 is hosted.

    server {
        server_name api.domain.com;
        # other stuff
    
        location ~ /(index.php/rest|rest) {
            # specific whitelist for API access
            include /etc/nginx/conf.d/api.whitelist;
            proxy_set_header Host admin.domain.com;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass https://admin.domain.com;
        }
        location / {
            return 403;
        }
    }
    

    And then in the final domain (admin.domain.com) we are this location block to only allow traffic to the API (/rest) that comes from the Proxy so nobody can request our API directly at this domain.

    server {
        server_name admin.domain.com;
        # other stuff
    
        location ~ /(index.php/rest|rest) {
            include /etc/nginx/conf.d/proxy.whitelist;
            allow $DOCKER_IP; # Seems to come from Docker Gateway IP as of now
            deny all;
            # other stuff
        }
    
        location / {
            # other stuff
        }
    }
    

    So, in order to accomplish the restriction for the proxy traffic, the file /etc/nginx/conf.d/proxy.whitelist is generated in entrypoint.sh of the docker container. I'm using a template file proxy.whitelist.template that looks like

    # Docker IP
    allow $DOCKER_IP;
    

    I did this because there are a couple other hard-coded IPs we have in that file already.

    Then, in entrypoint I use the following to find the Gateway IP of the Docker container.

    export DOCKER_IP=$(route -n | awk '{if($4=="UG")print $2}')
    envsubst < "/etc/nginx/conf.d/proxy.whitelist.template" > "/etc/nginx/conf.d/proxy.whitelist"
    

    And so far that seems to be working for me.


  2. Since the Docker container is ephemeral and the IP can change every time (and it’s very hard to pass the user’s real IP address all the way through a proxy to the Docker container), it may be a lot simpler to control this with code.

    I’d create a new module with a config value for the IP address, which would allow you to edit the IP address from the admin. This is architecturally more scalable as you don’t need to rely on a hard-coded IP.

    Within this module you’ll want to create an event observer on something like the controller_action_predispatch event. You can detect an admin route, and check/prevent access to that route based on the value of the configuration object for the IP address. This way you aren’t relying on Docker at all and you would have an admin-editable value to control the IP address/range.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search