web UI - init work on using docker-socket-proxy
This commit is contained in:
parent
ee178de6ab
commit
74fb015366
|
@ -294,8 +294,6 @@ docker service create --name anotherapp \
|
|||
|
||||
## Web UI
|
||||
|
||||
**This feature exposes, for now, a security risk because you need to mount the docker socket inside a container exposing a web application. You can test it but you should not use it in servers facing the internet.**
|
||||
|
||||
A dedicated image, *bunkerized-nginx-ui*, lets you manage bunkerized-nginx instances and services configurations through a web user interface. This feature is still in beta, feel free to open a new issue if you find a bug and/or you have an idea to improve it.
|
||||
|
||||
First we need a volume that will store the configurations :
|
||||
|
@ -320,6 +318,7 @@ docker run -p 80:8080 \
|
|||
-e AUTO_LETS_ENCRYPT=yes \
|
||||
-e REDIRECT_HTTP_TO_HTTPS=yes \
|
||||
-e DISABLE_DEFAULT_SERVER=yes \
|
||||
-e admin.domain.com_USE_MODSECURITY=no \
|
||||
-e admin.domain.com_SERVE_FILES=no \
|
||||
-e admin.domain.com_USE_AUTH_BASIC=yes \
|
||||
-e admin.domain.com_AUTH_BASIC_USER=admin \
|
||||
|
@ -331,7 +330,7 @@ docker run -p 80:8080 \
|
|||
bunkerity/bunkerized-nginx
|
||||
```
|
||||
|
||||
The `AUTH_BASIC` environment variables let you define a login/password that must be provided before accessing to the web UI. At the moment, there is no authentication mechanism integrated into bunkerized-nginx-ui.
|
||||
The `AUTH_BASIC` environment variables let you define a login/password that must be provided before accessing to the web UI. At the moment, there is no authentication mechanism integrated into bunkerized-nginx-ui so **using auth basic with a strong password coupled with a "hard to guess" URI is strongly recommended**.
|
||||
|
||||
We can now create the bunkerized-nginx-ui container that will host the web UI behind bunkerized-nginx :
|
||||
|
||||
|
|
|
@ -211,6 +211,37 @@ Here is the list of related environment variables and their default value :
|
|||
- `USE_BLACKLIST_REVERSE=yes` : enable/disable blacklisting by reverse DNS
|
||||
- `BLACKLIST_REVERSE_LIST=.shodan.io` : the list of reverse DNS suffixes to never trust
|
||||
|
||||
## Web UI
|
||||
|
||||
Mounting the docker socket in a container which is facing the network, like we do with the [web UI](https://bunkerized-nginx.readthedocs.io/en/latest/quickstart_guide.html#web-ui), is not a good security practice. In case of a vulnerability inside the application, attackers can freely use the Docker socket and the whole host can be compromised.
|
||||
|
||||
A possible workaround is to use the [tecnativa/docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) image which acts as a reverse proxy between the application and the Docker socket. It can allow/deny the requests made to the Docker API.
|
||||
|
||||
Before starting the web UI, you need to fire up the docker-socket-proxy (we also need a network because of inter-container communication) :
|
||||
|
||||
```shell
|
||||
docker network create mynet
|
||||
```
|
||||
|
||||
```shell
|
||||
docker run --name mysocketproxy \
|
||||
--network mynet \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
-e POST=1 \
|
||||
-e CONTAINERS=1 \
|
||||
tecnativa/docker-socket-proxy
|
||||
```
|
||||
|
||||
You can now start the web UI container and use the `DOCKER_HOST` environment variable to define the Docker API endpoint :
|
||||
|
||||
```shell
|
||||
docker run --network mynet \
|
||||
-v autoconf:/etc/nginx \
|
||||
-e ABSOLUTE_URI=https://my.webapp.com/admin/ \
|
||||
-e DOCKER_HOST=tcp://mysocketproxy:2375 \
|
||||
bunkerity/bunkerized-nginx-ui
|
||||
```
|
||||
|
||||
## Container hardening
|
||||
|
||||
### Drop capabilities
|
||||
|
|
|
@ -12,7 +12,6 @@ services:
|
|||
# don't forget to edit the permissions of the files and folders accordingly
|
||||
volumes:
|
||||
- ./letsencrypt:/etc/letsencrypt
|
||||
- ./web-files:/www:ro
|
||||
- autoconf:/etc/nginx
|
||||
environment:
|
||||
- SERVER_NAME=admin.website.com # replace with your domain
|
||||
|
@ -36,11 +35,23 @@ services:
|
|||
myui:
|
||||
image: bunkerity/bunkerized-nginx-ui
|
||||
restart: always
|
||||
depends_on:
|
||||
- mywww
|
||||
- myuiproxy
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- autoconf:/etc/nginx
|
||||
environment:
|
||||
- ABSOLUTE_URI=https://admin.website.com/admin/ # change it to your full URI
|
||||
- DOCKER_HOST=tcp://myuiproxy:2375
|
||||
|
||||
myuiproxy:
|
||||
image: tecnativa/docker-socket-proxy
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- POST=1
|
||||
- CONTAINERS=1
|
||||
|
||||
volumes:
|
||||
autoconf:
|
||||
|
|
|
@ -2,8 +2,8 @@ import docker
|
|||
|
||||
class Docker :
|
||||
|
||||
def __init__(self) :
|
||||
self.__client = docker.DockerClient(base_url='unix:///var/run/docker.sock')
|
||||
def __init__(self, docker_host) :
|
||||
self.__client = docker.DockerClient(base_url=docker_host)
|
||||
|
||||
def get_instances(self) :
|
||||
return self.__client.containers.list(all=True, filters={"label" : "bunkerized-nginx.UI"})
|
||||
|
|
|
@ -11,8 +11,11 @@ app = Flask(__name__, static_url_path="/", static_folder="static", template_fold
|
|||
ABSOLUTE_URI = ""
|
||||
if "ABSOLUTE_URI" in os.environ :
|
||||
ABSOLUTE_URI = os.environ["ABSOLUTE_URI"]
|
||||
DOCKER_HOST = "unix:///var/run/docker.sock"
|
||||
if "DOCKER_HOST" in os.environ :
|
||||
DOCKER_HOST = os.environ["DOCKER_HOST"]
|
||||
app.config["ABSOLUTE_URI"] = ABSOLUTE_URI
|
||||
app.config["DOCKER"] = Docker()
|
||||
app.config["DOCKER"] = Docker(DOCKER_HOST)
|
||||
app.config["CONFIG"] = Config()
|
||||
app.jinja_env.globals.update(env_to_summary_class=utils.env_to_summary_class)
|
||||
app.jinja_env.globals.update(form_service_gen=utils.form_service_gen)
|
||||
|
@ -46,15 +49,15 @@ def instances() :
|
|||
|
||||
# Do the operation
|
||||
if request.form["operation"] == "reload" :
|
||||
operation = app.config["DOCKER"].reload(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].reload_instance(request.form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "start" :
|
||||
operation = app.config["DOCKER"].start(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].start_instance(request.form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "stop" :
|
||||
operation = app.config["DOCKER"].stop(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].stop_instance(request.form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "restart" :
|
||||
operation = app.config["DOCKER"].restart(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].restart_instance(request.form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "delete" :
|
||||
operation = app.config["DOCKER"].delete(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].delete_instance(request.form["INSTANCE_ID"])
|
||||
|
||||
# Display instances
|
||||
instances = app.config["DOCKER"].get_instances()
|
||||
|
|
Loading…
Reference in New Issue