Skip to content

Commit 7f8b12c

Browse files
authored
Merge pull request #79 from microsoft/brian/updated-devenv
Developer environment improvements
2 parents 96da57d + 3571198 commit 7f8b12c

File tree

9 files changed

+263
-17
lines changed

9 files changed

+263
-17
lines changed

docs/install.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ Ensure you have the following installed:
2525

2626
### **1️⃣ Local Deployment**
2727

28+
> [!WARNING]
29+
> These local deployment instructions are not actively maintained and do not reflect the current structure of
30+
> the repository. It is recommended that you instead follow the devenv setup instructions from the `dusseldorf/`
31+
> directory [here](https://github.com/microsoft/dusseldorf/tree/main/dusseldorf).
32+
2833
For detailed local deployment instructions, navigate to the `docs/local` directory and refer to the `Readme.md` file.
2934

3035
#### **Step 1: Clone the Repository**

docs/local/Readme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# **Dusseldorf Local Deployment Guide**
22

3+
> [!WARNING]
4+
> These local deployment instructions are not actively maintained and do not reflect the current structure of
5+
> the repository. It is recommended that you instead follow the devenv setup instructions from the `dusseldorf/`
6+
> directory [here](https://github.com/microsoft/dusseldorf/tree/main/dusseldorf).
7+
38
This guide provides instructions for deploying the Dusseldorf system locally using Docker Compose.
49

510
---

dusseldorf/.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/node_modules

dusseldorf/README.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,68 @@
22

33
This folder contains all the components that make up the total platform. These include:
44

5-
65
- `api`: the control plane / API.
76
- `listener.dns`: the DNS listener for the data plane.
87
- `listener.http`: the HTTP/HTTPS listener in the data plane.
98
- `ui`: the source for the frontend web user interface.
109
- `zentralbibliothek`: a central library for listeners in the data plane.
1110

12-
Each component is explained in more details below:
11+
## Developer Environment Setup
12+
13+
### Prerequisites
14+
Please ensure that you have the following before starting:
15+
- An Azure AD tenant
16+
- An up-to-date version of Docker & Docker Compose
17+
- A terminal that supports bash (Note: If you are on Windows, it's recommended you use Ubuntu WSL and have your docker compose environment stored there.)
18+
19+
### Setup
20+
In your Azure AD tenant, [create an Azure AD application](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/CreateApplicationBlade/quickStartType~/null/isMSAApp~/false) with `http://localhost:8080/ui/` set as a redirect URI and `Single-page Application (SPA)` selected as the platform. Note the client ID and tenant ID of the newly created application.
21+
22+
Then, clone this repository and enter the `dusseldorf/` directory (the one with this README in it) inside of a Linux-based terminal (if on Windows, use WSL). Then, execute `./generate_devenv.sh` and input your client ID and tenant ID obtained from Azure.
23+
24+
To start your developer environment, ensure you have nothing running locally on port 8080 and run `docker compose up`. After it builds the containers, your environment should be up and running on `http://localhost:8080/ui/` and you should be able to login.
25+
26+
### Testing
27+
28+
Once your developer environment is running, the following services will be accessible on your computer:
29+
30+
- **API & UI server**: The API will be up and running on port 8080
31+
- **HTTPS listener**: The HTTPS listener runs on port 443 by default. This is modifiable in your .env file, but note that it will be overwritten by the generate devenv script.
32+
- **DNS listener**: The DNS listener runs on port 10053.
33+
34+
The API and UI are directly testable on http://localhost:8080/ui/ and you should be able to access them by logging in with an account on your Azure tenant that has access to the application.
35+
36+
To test the HTTPS listener, you can modify the following curl command:
37+
38+
```sh
39+
curl https://localhost:443/your-path-here -k \
40+
-H "Host: your-zone-here.dusseldorf.local"
41+
```
42+
43+
Make sure to keep the `-k` flag, which allows you to run the request without having to install the certificate. The Host header can be modified to be whatever host you are targeting to make a request to
44+
45+
To test the DNS listener, install the `dig` command in your local environment and use `dig your-zone-here.dusseldorf.local +tcp @localhost -p 10053` to make requests to the DNS server.
46+
47+
## Components
48+
49+
Here is some more information about the different components of this directory:
1350

14-
## API
51+
### API
1552
This is the control plane of Dusseldorf. This REST API allows an authenticated user to create, manage and delete zones, monitor the requests made to them and manage rules set on their zones. Calls to this API must be authenticated using an authentication token in each request.
1653

1754
This API is implemented using the FastAPI framework and provide CRUD functionality on zones, rules by interacting with a MongoDB database.
1855

1956
For more information about this API, please consult the [API docs](api/README.md).
2057

2158

22-
## DNS Listener
59+
### DNS Listener
2360
This is a network listener that responds to DNS traffic, and listens on port 53/udp for any DNS requests. The DNS (Domain Name System) protocol is responsible for translating hostnames to an IP address. By acting as a domains' DNS server, Dusseldorf is able to monitor any name resolutions for those subdomains on the Internet.
2461
By default, this permissive DNS server reponds with its own IP address(es) to a name resolution. This behaviour can be changed by assigning rules to your zone. Currently we only support custom `A`, `AAAA`, `CNAME` and `TXT` records.
2562

2663
Check the documentation for the DNS listener [here](listener.dns/README.md).
2764

2865

29-
## HTTP/HTTPS Listener
66+
### HTTP/HTTPS Listener
3067
This network listener can be setup to listen on cleartext HTTP traffic, or it can listen on HTTPS traffic, if you have the correct certificates available. For a cleartext setup, this listener accepts HTTP requests on port 80/tcp, and respond with default, or customized HTTP responses.
3168
Just like the DNS listener acts as a DNS server, this listener implements a very permissive HTTP server, or web server. Using rules, you can set custom content, headers and status codes.
3269

@@ -38,14 +75,14 @@ You can find more information on how to run this listener in the [HTTP documenta
3875

3976

4077

41-
## UI
78+
### UI
4279
This is the frontend web user interface. It is implemented in React using the amazing [Fluent2](https://fluent2.microsoft.design/) design framework and provides a modern single-page-application (SPA) to communicate with the Dusseldorf API.
4380

4481
These static pages are compiled and placed into a folder in the API, so it references a local `/api` endpoints, but can be setup to call another API endpoint altogether, too.
4582
The user interface's information can be found [here](ui/README.md).
4683

4784

48-
## Zentralbibliothek
85+
### Zentralbibliothek
4986
This is a central library which holds the rule engine, database logic and utility functions.
5087

5188

dusseldorf/api/src/api/main.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
from controllers.rules_controller import router as rules_router
2626
from controllers.zones_controller import router as zones_router
2727

28-
if not os.environ.get("API_TLS_CRT_FILE"):
29-
raise Exception("API_TLS_CRT_FILE not found in environment variables")
30-
if not os.environ.get("API_TLS_KEY_FILE"):
31-
raise Exception("API_TLS_KEY_FILE not found in environment variables")
28+
if os.environ.get("ENVIRONMENT") != "development":
29+
if not os.environ.get("API_TLS_CRT_FILE"):
30+
raise Exception("API_TLS_CRT_FILE not found in environment variables")
31+
if not os.environ.get("API_TLS_KEY_FILE"):
32+
raise Exception("API_TLS_KEY_FILE not found in environment variables")
3233

3334
dusseldorf = FastAPI()
3435

@@ -69,5 +70,7 @@ async def ui_redirect():
6970
dusseldorf.mount("/api", app)
7071
dusseldorf.mount("/ui", StaticFiles(directory="./ui", html=True), name="ui")
7172

72-
uvicorn.run(dusseldorf, host="0.0.0.0", port=int(os.environ.get("API_PORT", 10443)), ssl_keyfile=os.environ.get("API_TLS_KEY_FILE"), ssl_certfile=os.environ.get("API_TLS_CRT_FILE"))
73-
# uvicorn.run(dusseldorf, host="0.0.0.0", port=8000, ssl_keyfile="/app/key.pem", ssl_certfile="/app/cert.pem")
73+
if os.environ.get("ENVIRONMENT") == "development":
74+
uvicorn.run(dusseldorf, host="0.0.0.0", port=int(os.environ.get("API_PORT", 10443)))
75+
else:
76+
uvicorn.run(dusseldorf, host="0.0.0.0", port=int(os.environ.get("API_PORT", 10443)), ssl_keyfile=os.environ.get("API_TLS_KEY_FILE"), ssl_certfile=os.environ.get("API_TLS_CRT_FILE"))

dusseldorf/api_Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
1414
PYTHONUNBUFFERED=1 \
1515
ENVIRONMENT=production
1616
# Install system dependencies
17-
RUN tdnf -y update && tdnf -y install build-essential curl ca-certificates
17+
RUN tdnf -y update && tdnf -y install build-essential curl ca-certificates python3-devel
1818
# Install Python dependencies
1919
COPY api/src/api/requirements.txt .
2020
RUN pip install --no-cache-dir -r requirements.txt

dusseldorf/compose.yml

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
2+
services:
3+
mongodb:
4+
image: mongo:6.0
5+
container_name: mongodb
6+
ports:
7+
- "27017:27017"
8+
volumes:
9+
- ./env/mongo-data:/data/db
10+
- ./env/mongo-scripts/init.js:/docker-entrypoint-initdb.d/init.js:ro
11+
environment:
12+
MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME}
13+
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
14+
MONGO_INITDB_DATABASE: ${MONGO_DB_NAME}
15+
security_opt:
16+
- no-new-privileges:true
17+
tmpfs:
18+
- /tmp
19+
networks:
20+
- local_network
21+
22+
api-server:
23+
build:
24+
context: .
25+
dockerfile: api_Dockerfile
26+
container_name: api-server
27+
ports:
28+
- "8080:8080"
29+
environment:
30+
DSSLDRF_CONNSTR: "mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb:27017/${MONGO_DB_NAME}"
31+
API_VERSION: ${API_VERSION}
32+
API_PORT: 8080
33+
ENVIRONMENT: ${ENVIRONMENT}
34+
AZURE_CLIENT_ID: ${AZURE_CLIENT_ID}
35+
AZURE_TENANT_ID: ${AZURE_TENANT_ID}
36+
depends_on:
37+
- mongodb
38+
security_opt:
39+
- no-new-privileges:true
40+
networks:
41+
- local_network
42+
develop:
43+
watch:
44+
- action: sync
45+
path: ./api
46+
target: /app/api
47+
48+
listener-http:
49+
build:
50+
context: .
51+
dockerfile: http-listener_Dockerfile
52+
container_name: listener-http
53+
ports:
54+
- "${LSTNER_HTTP_PORT}:${LSTNER_HTTP_PORT}"
55+
environment:
56+
DSSLDRF_CONNSTR: "mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb:27017/${MONGO_DB_NAME}"
57+
DSSLDRF_TLS_CRT_FILE: /certs/tls.crt
58+
DSSLDRF_TLS_KEY_FILE: /certs/tls.key
59+
LSTNER_HTTP_PORT: ${LSTNER_HTTP_PORT}
60+
LSTNER_HTTP_INTERFACE: ${LSTNER_HTTP_INTERFACE}
61+
volumes:
62+
- ${DSSLDRF_TLS_CRT_FILE}:/certs/tls.crt
63+
- ${DSSLDRF_TLS_KEY_FILE}:/certs/tls.key
64+
depends_on:
65+
- mongodb
66+
security_opt:
67+
- no-new-privileges:true
68+
networks:
69+
local_network:
70+
ipv4_address: 172.18.0.9
71+
develop:
72+
watch:
73+
- action: sync
74+
path: ./listener.http/src
75+
target: /dusseldorf
76+
77+
78+
listener-dns:
79+
build:
80+
context: .
81+
dockerfile: dns-listener_Dockerfile
82+
container_name: listener-dns
83+
ports:
84+
- "10053:${LSTNER_DNS_PORT}"
85+
environment:
86+
DSSLDRF_CONNSTR: "mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb:27017/${MONGO_DB_NAME}"
87+
LSTNER_DNS_PORT: ${LSTNER_DNS_PORT}
88+
LSTNER_DNS_INTERFACE: ${LSTNER_DNS_INTERFACE}
89+
LSTNER_DNS_UDP: ${LSTNER_DNS_UDP}
90+
depends_on:
91+
- mongodb
92+
security_opt:
93+
- no-new-privileges:true
94+
networks:
95+
local_network:
96+
ipv4_address: 172.18.0.10
97+
develop:
98+
watch:
99+
- action: sync
100+
path: ./listener.dns/src
101+
target: /dusseldorf
102+
103+
# ui:
104+
# image: ${ACR_NAME}.azurecr.io/legacy-ui:latest
105+
# container_name: ui
106+
# ports:
107+
# - "3000:3000"
108+
# depends_on:
109+
# - api-server
110+
# security_opt:
111+
# - no-new-privileges:true
112+
# networks:
113+
# - local_network
114+
115+
networks:
116+
local_network:
117+
driver: bridge
118+
ipam:
119+
config:
120+
- subnet: 172.18.0.0/16
121+
gateway: 172.18.0.1

dusseldorf/generate_devenv.sh

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
echo "We are going to need some information to set up your development environment."
6+
echo "----------------------------------------------------"
7+
echo "We need the client ID and tenant ID of your Azure AD application that you want to use for your developer environment."
8+
read -p "Azure Client ID (example: dc1b6b75-8167-4baf-9e75-d3d1f755de1b): " AZURE_CLIENT_ID
9+
read -p "Azure Tenant ID (example: 72f988bf-86f1-41af-91ab-2d7cd011db47): " AZURE_TENANT_ID
10+
echo "----------------------------------------------------"
11+
echo "Setting up with client ID: $AZURE_CLIENT_ID and tenant ID: $AZURE_TENANT_ID"
12+
13+
mkdir -p env/
14+
mkdir -p env/certs/
15+
echo "Creating certificates..."
16+
openssl req -newkey rsa:2048 -nodes -keyout "env/certs/tls.key" -x509 -days 365 -out "env/certs/tls.crt" -subj "/CN=localhost"
17+
echo "Certificates created successfully."
18+
19+
echo "Making mongo files..."
20+
mkdir -p env/mongo-data/
21+
mkdir -p env/mongo-scripts/
22+
MONGO_PASSWORD=$(openssl rand -hex 12)
23+
cat <<EOF > env/mongo-scripts/init.js
24+
db = db.getSiblingDB("dusseldorf");
25+
db.createUser({
26+
user: "admin",
27+
pwd: "$MONGO_PASSWORD",
28+
roles: [{ role: "readWrite", db: "dusseldorf" }]
29+
});
30+
31+
db.createCollection("domains");
32+
db.createCollection("zones");
33+
db.createCollection("requests");
34+
db.createCollection("rules");
35+
36+
db.domains.createIndex({domain: 1}, { unique: true });
37+
db.zones.createIndex({fqdn: 1}, { unique: true });
38+
db.requests.createIndex({
39+
"zone": 1,
40+
"time": 1
41+
});
42+
db.domains.insertOne({"domain": "dusseldorf.local", "public_ips": ["172.18.0.9"], "owner": "dusseldorf"});
43+
EOF
44+
45+
echo "Generating .env file..."
46+
cat <<EOF > .env
47+
# Dusseldorf Environment Variables
48+
API_VERSION=1
49+
ENVIRONMENT=development
50+
AZURE_CLIENT_ID=$AZURE_CLIENT_ID
51+
AZURE_TENANT_ID=$AZURE_TENANT_ID
52+
53+
MONGO_USERNAME=admin
54+
MONGO_PASSWORD=$MONGO_PASSWORD
55+
MONGO_DB_NAME=dusseldorf
56+
MONGODB_DB_NAME=dusseldorf
57+
58+
DSSLDRF_TLS_CRT_FILE=./env/certs/tls.crt
59+
DSSLDRF_TLS_KEY_FILE=./env/certs/tls.key
60+
LSTNER_HTTP_PORT=443
61+
LSTNER_HTTP_INTERFACE=0.0.0.0
62+
63+
LSTNER_DNS_PORT=10053
64+
LSTNER_DNS_INTERFACE=0.0.0.0
65+
LSTNER_DNS_UDP=false
66+
EOF
67+
68+
echo "Generating react .env file..."
69+
cat <<EOF > ui/.env
70+
REACT_APP_CLIENT_ID=$AZURE_CLIENT_ID
71+
REACT_APP_TENANT_ID=$AZURE_TENANT_ID
72+
REACT_APP_API_HOST=http://localhost:8080/api
73+
EOF
74+
echo "Environment setup complete. You can now start running Dusseldorf with docker compose up."

dusseldorf/ui/src/DusseldorfConfig.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
// This is the hostname of the API we talk to.
1010
// To set a manual one, do the following
1111
// localStorage.setItem("api_host", "https://localhost:1337")
12-
const API_HOST = window.localStorage.getItem("api_host") ?? "/api";
12+
const API_HOST = process.env.REACT_APP_API_HOST ?? window.localStorage.getItem("api_host") ?? "/api";
1313

1414
const config = {
1515
// https://ms.portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/dc1b6b75-8167-4baf-9e75-d3d1f755de1b/isMSAApp/
16-
client_id: "dc1b6b75-8167-4baf-9e75-d3d1f755de1b",
17-
tenant_id: "72f988bf-86f1-41af-91ab-2d7cd011db47",
16+
client_id: process.env.REACT_APP_CLIENT_ID ?? "dc1b6b75-8167-4baf-9e75-d3d1f755de1b",
17+
tenant_id: process.env.REACT_APP_TENANT_ID ?? "72f988bf-86f1-41af-91ab-2d7cd011db47",
1818
appInsightsId: "3836b094-0c3a-42b1-a3b3-9a81133f64fb"
1919
}
2020

0 commit comments

Comments
 (0)