diff --git a/docker-compose/owls/.env b/docker-compose/owls/.env index 631e389..868a197 100644 --- a/docker-compose/owls/.env +++ b/docker-compose/owls/.env @@ -3,19 +3,26 @@ COMPOSE_PROJECT_NAME=owls # Image tags # Currently main branches don't work - owlsui is not compatible with owls. #OWSEC_TAG=main -#OWLS_TAG=main #OWLSUI_TAG=master OWSEC_TAG=v2.9.0 -OWLS_TAG=v2.9.0 +OWFMS_TAG=v2.9.0 OWLSUI_TAG=v2.9.0 +OWLS_TAG=main + KAFKA_TAG=3.7-debian-12 +ACMESH_TAG=latest +TRAEFIK_TAG=v3.1.2 # Microservice root/config directories OWSEC_ROOT=/owsec-data OWSEC_CONFIG=/owsec-data +OWFMS_ROOT=/owfms-data +OWFMS_CONFIG=/owfms-data OWLS_ROOT=/owls-data OWLS_CONFIG=/owls-data # Microservice hostnames INTERNAL_OWSEC_HOSTNAME=owsec.wlan.local INTERNAL_OWLS_HOSTNAME=owls.wlan.local +INTERNAL_OWFMS_HOSTNAME=owfms.wlan.local +INTERNAL_OWLSUI_HOSTNAME=owls-ui.wlan.local diff --git a/docker-compose/owls/README.md b/docker-compose/owls/README.md index 711198d..9c453f6 100644 --- a/docker-compose/owls/README.md +++ b/docker-compose/owls/README.md @@ -14,3 +14,22 @@ Be aware that since the OWLS deployment partly exposes the same ports on the hos 10. In the Simulation tab, click on the + sign on the right side to add a load simulation. 11. Fill out the required fields. MAC prefix is used for the MAC addresses of the simulated devices, so you can use any six-digit hexadecimal number. Specify the remote address of your OpenWifi gateway in the Gateway field, for example `https://openwifi.wlan.local:15002`. Adapt the rest of the settings according to your needs. 12. Click on the floppy disk icon to save your load simulation. You can run it by clicking the play symbol in the table view. + +## Deployment with Let's Encrypt certificates +To run a load simulation you need to generate a specific Digicert-signed AP certificate which will be used to connect to the gateway. The certificate serial number has to start with the digits `53494d` since otherwise the gateway won't allow a load simulation. The rest of the serial number and the specified redirector URL can be chosen randomly. You only need to generate one AP certificate for your simulations. Be aware that since the OWLS deployment partly exposes the same ports on the host as the OpenWifi deployment, it is not intended that both run on the same host. +1. Copy or move your AP load simulation certificate into the `docker-compose/certs` directory. Don't forget to name the files `device-cert.pem` and `device-key.pem` or adapt the path names in the OWLS configuration if you're using different file names. +2. To be able to run load simulation tests against your OpenWifi SDK deployment, you'll have to [add the serial number of your generated AP certificate to the gateway configuration](https://github.com/Telecominfraproject/wlan-cloud-owls#prepare-your-openwifi-gateway). You can do that by either editing [owgw.env](../owgw.env) or doing the changes directly in your OWGW configuration file if it is exposed on your Docker host. +3. Switch into the project directory with `cd docker-compose/owls`. +4. Add an entry for `openwifi-owls.wlan.local` in your hosts file which points to `127.0.0.1` or whatever the IP of the host running the OWLS deployment is. +5. Create an alias `alias dcowls='docker-compose -f docker-compose.lb.letsencrypt.yml`. +6. Change SDKHOSTNAME in .env to the desired externally reachable host name. This name must resolve to the IP of the host. ie. SDKHOSTNAME=owls.example.com +7. Change in owls-ui.env: `REACT_APP_UCENTRALSEC_URL=https://owls.example.com:16001` +8. Change SYSTEM_URI_PUBLIC in owsec.env, owfms.env and owls.env. +ie. for owls.env: `SYSTEM_URI_PUBLIC=https://owls.example.com:16007 SYSTEM_URI_UI=https://owls.example.com`. Make sure you maintain the correct port for each service in SYSTEM_URI_PUBLIC. +9. Make sure the following ports are open: 80, 443, 16001, 16004, 16007 (80 is required by the initial Let's Encrypt challenge.) +10. Spin up the deployment with `dcowls up -d`. +11. Check if the containers are up and running with `dcowls ps`. +12. Login to the UI by visiting ie. https://owls.example.com and follow the instructions to change your default password. +13. In the Simulation tab, click on the + sign on the right side to add a load simulation. +14. Fill out the required fields. MAC prefix is used for the MAC addresses of the simulated devices, so you can use any six-digit hexadecimal number. Specify the remote address of your OpenWifi gateway in the Gateway field, for example `https://gw.sdk.example.com:15002`. Adapt the rest of the settings according to your needs. +15. Click on the floppy disk icon to save your load simulation. You can run it by clicking the play symbol in the table view. diff --git a/docker-compose/owls/docker-compose.lb.letsencrypt.yml b/docker-compose/owls/docker-compose.lb.letsencrypt.yml new file mode 100644 index 0000000..3c7f1b0 --- /dev/null +++ b/docker-compose/owls/docker-compose.lb.letsencrypt.yml @@ -0,0 +1,136 @@ +volumes: + kafka_data: + driver: local + +networks: + owls: + +services: + owsec: + image: "tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:${OWSEC_TAG}" + networks: + owls: + aliases: + - ${INTERNAL_OWSEC_HOSTNAME} + env_file: + - owsec.env + depends_on: + init-kafka: + condition: service_completed_successfully + restart: unless-stopped + volumes: + - "./owsec_data:${OWSEC_ROOT}" + - "../certs:/${OWSEC_ROOT}/certs" + + owfms: + image: "tip-tip-wlan-cloud-ucentral.jfrog.io/owfms:${OWFMS_TAG}" + networks: + owls: + aliases: + - ${INTERNAL_OWFMS_HOSTNAME} + env_file: + - owfms.env + depends_on: + init-kafka: + condition: service_completed_successfully + restart: unless-stopped + volumes: + - "./owfms_data:${OWFMS_ROOT}" + - "../certs:/${OWFMS_ROOT}/certs" + + owls: + image: "tip-tip-wlan-cloud-ucentral.jfrog.io/owls:${OWLS_TAG}" + networks: + owls: + aliases: + - ${INTERNAL_OWLS_HOSTNAME} + env_file: + - owls.env + depends_on: + owsec: + condition: service_started + init-kafka: + condition: service_completed_successfully + restart: unless-stopped + volumes: + - "./owls_data:${OWLS_ROOT}" + - "../certs:/${OWLS_ROOT}/certs" + + owls-ui: + image: "tip-tip-wlan-cloud-ucentral.jfrog.io/owls-ui:${OWLSUI_TAG}" + networks: + owls: + aliases: + - ${INTERNAL_OWLSUI_HOSTNAME} + env_file: + - owls-ui.env + depends_on: + - owsec + - owfms + - owls + restart: unless-stopped + volumes: + - "./owls-ui/default.conf:/etc/nginx/conf.d/default.conf" + - "../certs/restapi-cert.pem:/etc/nginx/restapi-cert.pem" + - "../certs/restapi-key.pem:/etc/nginx/restapi-key.pem" + + traefik: + image: "traefik:${TRAEFIK_TAG}" + networks: + owls: + env_file: + - traefik.env + depends_on: + - owsec + - owfms + - owls + - owls-ui + restart: unless-stopped + volumes: + - "./traefik/openwifi_letsencrypt.yaml:/etc/traefik/openwifi.yaml" + - "../certs/restapi-ca.pem:/certs/restapi-ca.pem" + - "./letsencrypt_certs:/letsencrypt" + entrypoint: + - /bin/sh + - -c + - | + timeout 10m sh -c 'until [[ "$$(getent hosts $SDKHOSTNAME)" ]]; do echo "Waiting until DNS record for $SDKHOSTNAME is resolvable"; sleep 5; done' \ + && ./entrypoint.sh traefik + ports: + - "80:80" + - "443:443" + - "8080:8080" + - "16001:16001" + - "16004:16004" + - "16007:16007" + + kafka: + image: "docker.io/bitnami/kafka:${KAFKA_TAG}" + networks: + owls: + env_file: + - kafka.env + restart: unless-stopped + volumes: + - kafka_data:/bitnami/kafka + + init-kafka: + image: "docker.io/bitnami/kafka:${KAFKA_TAG}" + networks: + owls: + depends_on: + - kafka + env_file: + - kafka.env + entrypoint: + - /bin/sh + - -c + - | + echo "Sleeping to allow kafka to start up..." + sleep 10 + echo "Creating all required Kafka topics..." + for topic in $$TOPICS; do + /opt/bitnami/kafka/bin/kafka-topics.sh \ + --create --if-not-exists --topic $$topic --replication-factor 1 \ + --partitions 1 --bootstrap-server kafka:9092 + done && echo "Successfully created Kafka topics, exiting." && exit 0 diff --git a/docker-compose/owls/docker-compose.yml b/docker-compose/owls/docker-compose.yml index 69660b9..1f3f93a 100644 --- a/docker-compose/owls/docker-compose.yml +++ b/docker-compose/owls/docker-compose.yml @@ -25,6 +25,25 @@ services: - "16001:16001" - "16101:16101" + owfms: + image: "tip-tip-wlan-cloud-ucentral.jfrog.io/owfms:${OWFMS_TAG}" + networks: + owls: + aliases: + - ${INTERNAL_OWFMS_HOSTNAME} + env_file: + - owfms.env + depends_on: + init-kafka: + condition: service_completed_successfully + restart: unless-stopped + volumes: + - "./owfms_data:${OWFMS_ROOT}" + - "../certs:/${OWFMS_ROOT}/certs" + ports: + - "16004:16004" + - "16104:16104" + owls: image: "tip-tip-wlan-cloud-ucentral.jfrog.io/owls:${OWLS_TAG}" networks: @@ -55,6 +74,7 @@ services: depends_on: - owsec - owls + - owfms restart: unless-stopped volumes: - "./owls-ui/default.conf:/etc/nginx/conf.d/default.conf" diff --git a/docker-compose/owls/environments/create_tip_deploy.sh b/docker-compose/owls/environments/create_tip_deploy.sh new file mode 100755 index 0000000..abcebc1 --- /dev/null +++ b/docker-compose/owls/environments/create_tip_deploy.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Create a deploy directory for a particular environment. +# Only support the letsencrypt setup here! +# Optionally copy it over. + +set -e +USAGE="$0 environment" + +env="$1" +if [ -z "$env" ] ; then + echo $USAGE + exit 1 +fi +dir="$env" +dhost="" +if [[ "$env" == "owls1" ]] ; then + hostname="owls1.lab.wlan.tip.build" + dhost="tipowlsls" + destdir="deploy-owls" +elif [[ "$env" == "owls2" ]] ; then + hostname="owls2.lab.wlan.tip.build" + dhost="tipowlsgw" + destdir="deploy-owls" +else + echo "Unknown environment: $env" + exit 1 +fi + +# need newer GNU sed (mac one isn't compatible) [on mac install sed using homebrew] +sed=$(command -v gsed) +[ -z "$sed" ] && sed="sed" + +set -x + + +echo +echo "Make sure you have created/updated the device-cert.pem and device-key.pem files!" +echo +url="https://$hostname" +[ -d "$dir" ] || mkdir "$dir" +cd "$dir" +mkdir -p owls-ui traefik certs/cas || true +cp ../../.env ../../*.env . +cp ../../docker-compose.lb.letsencrypt.yml docker-compose.yml +cp ../../owls-ui/default-lb.conf owls-ui/default.conf +cp ../../traefik/* traefik +cp ../../../certs/cas/* certs/cas 2>/dev/null || true +cp ../../../certs/*.pem certs +echo "SDKHOSTNAME=$hostname" >> .env +$sed -i "s~REACT_APP_UCENTRALSEC_URL=.*~REACT_APP_UCENTRALSEC_URL=$url:16001~" owls-ui.env +$sed -i "s~SYSTEM_URI_PUBLIC=.*~SYSTEM_URI_PUBLIC=$url:16001~" owsec.env +$sed -i "s~SYSTEM_URI_UI=.*~SYSTEM_URI_UI=$url~" owsec.env +$sed -i "s~SYSTEM_URI_PUBLIC=.*~SYSTEM_URI_PUBLIC=$url:16004~" owfms.env +$sed -i "s~SYSTEM_URI_UI=.*~SYSTEM_URI_UI=$url~" owfms.env +$sed -i "s~SYSTEM_URI_PUBLIC=.*~SYSTEM_URI_PUBLIC=$url:16007~" owls.env +$sed -i "s~SYSTEM_URI_UI=.*~SYSTEM_URI_UI=$url~" owls.env +$sed -i "s~../certs:~./certs:~" docker-compose.yml + + +if [[ -n "$dhost" && -n "$destdir" ]] ; then + rsync -avh --progress ./ $dhost:$destdir +fi diff --git a/docker-compose/owls/owfms.env b/docker-compose/owls/owfms.env new file mode 100644 index 0000000..637a798 --- /dev/null +++ b/docker-compose/owls/owfms.env @@ -0,0 +1,43 @@ +RUN_CHOWN=true +TEMPLATE_CONFIG=true +SELFSIGNED_CERTS=true + +OWFMS_ROOT=/owfms-data +OWFMS_CONFIG=/owfms-data + +#RESTAPI_HOST_ROOTCA=$OWFMS_ROOT/certs/restapi-ca.pem +#RESTAPI_HOST_PORT=16004 +#RESTAPI_HOST_CERT=$OWFMS_ROOT/certs/restapi-cert.pem +#RESTAPI_HOST_KEY=$OWFMS_ROOT/certs/restapi-key.pem +#RESTAPI_HOST_KEY_PASSWORD=mypassword +#INTERNAL_RESTAPI_HOST_ROOTCA=$OWFMS_ROOT/certs/restapi-ca.pem +#INTERNAL_RESTAPI_HOST_PORT=17004 +#INTERNAL_RESTAPI_HOST_CERT=$OWFMS_ROOT/certs/restapi-cert.pem +#INTERNAL_RESTAPI_HOST_KEY=$OWFMS_ROOT/certs/restapi-key.pem +#INTERNAL_RESTAPI_HOST_KEY_PASSWORD=mypassword +#SERVICE_KEY=$OWFMS_ROOT/certs/restapi-key.pem +#SERVICE_KEY_PASSWORD=mypassword +SYSTEM_DATA=$OWFMS_ROOT/persist +SYSTEM_URI_PRIVATE=https://owfms.wlan.local:17004 +SYSTEM_URI_PUBLIC=https://openwifi.wlan.local:16004 +SYSTEM_URI_UI=https://openwifi.wlan.local +#SECURITY_RESTAPI_DISABLE=false +#S3_BUCKETNAME=ucentral-ap-firmware +#S3_REGION=us-east-1 +S3_SECRET=b0S6EiR5RLIxoe7Xvz9YXPPdxQCoZ6ze37qunTAI +S3_KEY=AKIAUG47UZG7R6SRLD7F +#S3_BUCKET_URI=ucentral-ap-firmware.s3.amazonaws.com +#KAFKA_ENABLE=true +KAFKA_BROKERLIST=kafka:9092 +#STORAGE_TYPE=postgresql +#STORAGE_TYPE_POSTGRESQL_HOST=postgresql +#STORAGE_TYPE_POSTGRESQL_USERNAME=owfms +#STORAGE_TYPE_POSTGRESQL_PASSWORD=owfms +#STORAGE_TYPE_POSTGRESQL_DATABASE=owfms +#STORAGE_TYPE_POSTGRESQL_PORT=5432 +#STORAGE_TYPE_MYSQL_HOST=localhost +#STORAGE_TYPE_MYSQL_USERNAME=owfms +#STORAGE_TYPE_MYSQL_PASSWORD=owfms +#STORAGE_TYPE_MYSQL_DATABASE=owfms +#STORAGE_TYPE_MYSQL_PORT=3306 +STORAGE_TYPE=sqlite diff --git a/docker-compose/owls/owls-ui/default-lb.conf b/docker-compose/owls/owls-ui/default-lb.conf new file mode 100644 index 0000000..fba28d1 --- /dev/null +++ b/docker-compose/owls/owls-ui/default-lb.conf @@ -0,0 +1,41 @@ +server { + listen 80; + listen [::]:80; + + # Disable emitting nginx version + server_tokens off; + + #return 301 https://$host$request_uri; + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + # redirect server error pages to the static page /50x.html + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + + # Disable emitting nginx version + server_tokens off; + + ssl_certificate /etc/nginx/restapi-cert.pem; + ssl_certificate_key /etc/nginx/restapi-key.pem; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + # redirect server error pages to the static page /50x.html + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/docker-compose/owls/traefik.env b/docker-compose/owls/traefik.env new file mode 100644 index 0000000..f4301a0 --- /dev/null +++ b/docker-compose/owls/traefik.env @@ -0,0 +1,15 @@ +TRAEFIK_ENTRYPOINTS_OWLSUIHTTP_ADDRESS=:80 +TRAEFIK_ENTRYPOINTS_OWLSUIHTTP_HTTP_REDIRECTIONS_ENTRYPOINT_TO=owlsuihttps +TRAEFIK_ENTRYPOINTS_OWLSUIHTTPS_ADDRESS=:443 +TRAEFIK_ENTRYPOINTS_OWSECRESTAPI_ADDRESS=:16001 +TRAEFIK_ENTRYPOINTS_OWLSRESTAPI_ADDRESS=:16007 +TRAEFIK_ENTRYPOINTS_OWFMSRESTAPI_ADDRESS=:16004 +TRAEFIK_PROVIDERS_FILE_FILENAME=/etc/traefik/openwifi.yaml +TRAEFIK_CERTIFICATESRESOLVERS_OPENWIFI_ACME_EMAIL= +TRAEFIK_CERTIFICATESRESOLVERS_OPENWIFI_ACME_HTTPCHALLENGE=true +TRAEFIK_CERTIFICATESRESOLVERS_OPENWIFI_ACME_HTTPCHALLENGE_ENTRYPOINT=owlsuihttp +TRAEFIK_CERTIFICATESRESOLVERS_OPENWIFI_ACME_STORAGE=/letsencrypt/acme.json +TRAEFIK_SERVERSTRANSPORT_ROOTCAS=/certs/restapi-ca.pem +SDKHOSTNAME=owls2.lab.wlan.tip.build +TRAEFIK_LOG=true +TRAEFIK_LOG_LEVEL=DEBUG diff --git a/docker-compose/owls/traefik/openwifi_letsencrypt.yaml b/docker-compose/owls/traefik/openwifi_letsencrypt.yaml new file mode 100644 index 0000000..8275391 --- /dev/null +++ b/docker-compose/owls/traefik/openwifi_letsencrypt.yaml @@ -0,0 +1,50 @@ +log: + level: DEBUG +http: + services: + owls-ui: + loadBalancer: + servers: + - url: "http://owls-ui.wlan.local:80/" + owsec-restapi: + loadBalancer: + servers: + - url: "https://owsec.wlan.local:16001/" + owfms-restapi: + loadBalancer: + servers: + - url: "https://owfms.wlan.local:16004/" + owls-restapi: + loadBalancer: + servers: + - url: "https://owls.wlan.local:16007/" + + routers: + owls-ui-http: + entryPoints: "owlsuihttp" + service: "owls-ui" + rule: "Host(`{{ env "SDKHOSTNAME" }}`)" + owls-ui-https: + entryPoints: "owlsuihttps" + service: "owls-ui" + rule: "Host(`{{ env "SDKHOSTNAME" }}`)" + tls: + certResolver: "openwifi" + owls-restapi: + entryPoints: "owlsrestapi" + service: "owls-restapi" + rule: "Host(`{{ env "SDKHOSTNAME" }}`)" + tls: + certResolver: "openwifi" + owsec-restapi: + entryPoints: "owsecrestapi" + service: "owsec-restapi" + rule: "Host(`{{ env "SDKHOSTNAME" }}`)" + tls: + certResolver: "openwifi" + owfms-restapi: + entryPoints: "owfmsrestapi" + service: "owfms-restapi" + rule: "Host(`{{env "SDKHOSTNAME"}}`)" + tls: + certResolver: "openwifi"