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:
- Am I way over-complicating this, and is there a recommendation of a different approach to look into?
- 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
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.
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.So, in order to accomplish the restriction for the proxy traffic, the file
/etc/nginx/conf.d/proxy.whitelist
is generated inentrypoint.sh
of the docker container. I'm using a template fileproxy.whitelist.template
that looks likeI 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.
And so far that seems to be working for me.
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.