diff --git a/docs/reference/ssl/compose-example.yaml b/docs/reference/ssl/compose-example.yaml new file mode 100644 index 00000000..c4f9255f --- /dev/null +++ b/docs/reference/ssl/compose-example.yaml @@ -0,0 +1,265 @@ +version: "3.3" +services: + traefik: + image: traefik:v2.1.3 + container_name: "traefik" + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge=true" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge.entrypoint=web" + - "--certificatesresolvers.myhttpchallenge.acme.email=" + - "--certificatesresolvers.myhttpchallenge.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "./letsencrypt:/letsencrypt" + - "/var/run/docker.sock:/var/run/docker.sock" + networks: + - functions + placement: + constraints: [node.role == manager] + + gateway: + ports: + - 8080:8080 + image: openfaas/gateway:0.18.10 + networks: + - functions + labels: + - "traefik.enable=true" + - "traefik.http.routers.gateway.rule=Host(`gw.example.com`)" + - "traefik.http.routers.gateway.entrypoints=websecure" + - "traefik.http.routers.gateway.tls.certresolver=myhttpchallenge" + environment: + functions_provider_url: "http://faas-swarm:8080/" + read_timeout: "5m5s" # Maximum time to read HTTP request + write_timeout: "5m5s" # Maximum time to write HTTP response + upstream_timeout: "5m" # Maximum duration of upstream function call - should be more than read_timeout and write_timeout + dnsrr: "true" # Temporarily use dnsrr in place of VIP while issue persists on PWD + faas_nats_address: "nats" + faas_nats_port: 4222 + direct_functions: "true" # Functions are invoked directly over the overlay network + direct_functions_suffix: "" + basic_auth: "${BASIC_AUTH:-false}" + secret_mount_path: "/run/secrets/" + scale_from_zero: "true" # Enable if you want functions to scale from 0/0 to min replica count upon invoke + max_idle_conns: 1024 + max_idle_conns_per_host: 1024 + auth_proxy_url: "${AUTH_URL:-}" + auth_proxy_pass_body: "false" + deploy: + resources: + # limits: # Enable if you want to limit memory usage + # memory: 200M + reservations: + memory: 100M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + placement: + constraints: + - "node.platform.os == linux" + secrets: + - basic-auth-user + - basic-auth-password + + # auth service provide basic-auth plugin for system APIs + basic-auth-plugin: + image: openfaas/basic-auth-plugin:0.18.10 + networks: + - functions + environment: + secret_mount_path: "/run/secrets/" + user_filename: "basic-auth-user" + pass_filename: "basic-auth-password" + deploy: + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + resources: + # limits: # Enable if you want to limit memory usage + # memory: 100M + reservations: + memory: 50M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + secrets: + - basic-auth-user + - basic-auth-password + + # Docker Swarm provider + faas-swarm: + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + image: openfaas/faas-swarm:0.8.2 + networks: + - functions + environment: + read_timeout: "5m5s" # set both here, and on your functions + write_timeout: "5m5s" # set both here, and on your functions + DOCKER_API_VERSION: "1.30" + basic_auth: "${BASIC_AUTH:-false}" + secret_mount_path: "/run/secrets/" + deploy: + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + resources: + # limits: # Enable if you want to limit memory usage + # memory: 100M + reservations: + memory: 100M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + secrets: + - basic-auth-user + - basic-auth-password + + nats: + image: nats-streaming:0.11.2 + # Uncomment the following port mappings if you wish to expose the + # NATS client and/or management ports you must also add `-m 8222` to the command + # ports: + # - 4222:4222 + # - 8222:8222 + command: "--store memory --cluster_id faas-cluster" + networks: + - functions + deploy: + resources: + limits: + memory: 125M + reservations: + memory: 50M + placement: + constraints: + - "node.platform.os == linux" + + queue-worker: + image: openfaas/queue-worker:0.8.4 + networks: + - functions + environment: + max_inflight: "1" + ack_wait: "5m5s" # Max duration of any async task / request + basic_auth: "${BASIC_AUTH:-false}" + secret_mount_path: "/run/secrets/" + gateway_invoke: "true" + faas_gateway_address: "gateway" + deploy: + resources: + limits: + memory: 50M + reservations: + memory: 20M + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 20 + window: 380s + placement: + constraints: + - "node.platform.os == linux" + secrets: + - basic-auth-user + - basic-auth-password + + # End services + + # Start monitoring + + prometheus: + image: prom/prometheus:v2.11.0 + environment: + no_proxy: "gateway" + configs: + - source: prometheus_config + target: /etc/prometheus/prometheus.yml + - source: prometheus_rules + target: /etc/prometheus/alert.rules.yml + command: + - "--config.file=/etc/prometheus/prometheus.yml" + # - '-storage.local.path=/prometheus' + ports: + - 9090:9090 + networks: + - functions + deploy: + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + resources: + limits: + memory: 500M + reservations: + memory: 200M + + alertmanager: + image: prom/alertmanager:v0.18.0 + environment: + no_proxy: "gateway" + command: + - "--config.file=/alertmanager.yml" + - "--storage.path=/alertmanager" + networks: + - functions + # Uncomment the following port mapping if you wish to expose the Prometheus + # Alertmanager UI. + # ports: + # - 9093:9093 + deploy: + resources: + limits: + memory: 50M + reservations: + memory: 20M + placement: + constraints: + - "node.role == manager" + - "node.platform.os == linux" + configs: + - source: alertmanager_config + target: /alertmanager.yml + secrets: + - basic-auth-password + +configs: + prometheus_config: + file: ./prometheus/prometheus.yml + prometheus_rules: + file: ./prometheus/alert.rules.yml + alertmanager_config: + file: ./prometheus/alertmanager.yml + +networks: + functions: + driver: overlay + attachable: true + labels: + - "openfaas=true" + +secrets: + basic-auth-user: + external: true + basic-auth-password: + external: true + +volumes: + letsencrypt: diff --git a/docs/reference/ssl/swarm-with-traefik.md b/docs/reference/ssl/swarm-with-traefik.md new file mode 100644 index 00000000..33532a7f --- /dev/null +++ b/docs/reference/ssl/swarm-with-traefik.md @@ -0,0 +1,186 @@ +# SSL on Docker Swarm with Traefik + +To help secure your OpenFaaS installation, you need TLS. On [Docker Swarm](docs/reference/ssl/kubernetes-with-cert-manager.md), you can do this easily with [Traefik](https://traefik.io/) and [Let's Encrypt](https://letsencrypt.org/). Traefik is a reverse proxy that comes with TLS support via Let's Encrypt. In this tutorial we will show you how to deploy OpenFaaS with Traefik. + + +### Create a DNS record + +Determine the public IP address that can be used to access your cluster. +If your domain is `.example.com` then create an A record using your DNS administration panel such as `gw.example.com`. + +> The required steps will vary depending on your domain provider and your cluster provider. For example; [on Google Cloud DNS](https://cloud.google.com/kubernetes-engine/docs/tutorials/configuring-domain-name-static-ip) or [with Route53 using AWS](https://kubernetes.io/docs/setup/custom-cloud/kops/#2-5-create-a-route53-domain-for-your-cluster). + +Once created, verify that what you entered into your DNS control-panel worked with `ping`: + +```sh +ping gw.example.com +``` + +You should now see the value you entered. Sometimes DNS can take 1-5 minutes to propagate. + +## Update the Compose configuration + +A complete example `docker-compose.yaml` can be found [here](./compose-example.yaml) + +### Configure Traefik +To use Traefik with OpenFaaS, you need to modify the OpenFaaS deployment manifest to include Traefik and configuring OpenFaaS to communicate through Traefik instead of directly exposing its services publicly. + +Clone OpenFaaS and then checkout the latest stable release: + + ```bash + $ git clone https://github.com/openfaas/faas && cd faas + ``` + +Add the `traefik` service to the `docker-compose.yaml`. + +To start, open `docker-compose.yaml` in your favorite editor and add a `traefik` service like this: + + +```yaml +version: "3.3" +services: + traefik: + image: traefik:v2.1.3 + container_name: "traefik" + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge=true" + - "--certificatesresolvers.myhttpchallenge.acme.httpchallenge.entrypoint=web" + - "--certificatesresolvers.myhttpchallenge.acme.email=" + - "--certificatesresolvers.myhttpchallenge.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "./letsencrypt:/letsencrypt" + - "/var/run/docker.sock:/var/run/docker.sock" + networks: + - functions + placement: + constraints: [node.role == manager] + + gateway: + ... +``` + +This configuration does a few important things: + +* The `--providers.docker.*` flags tell Traefik to use Docker and specify that it's running in a Docker Swarm cluster. +* The `--entryPoints` flags define entry points and protocols to be used. In our case this includes HTTP on port 80 and HTTPS on port 443. +* The `--certificatesresolvers.*` flags configure Traefik to use the ACME protocol to generate Let's Encrypt certificates to secure your OpenFaaS cluster with SSL. +Make sure to set your own email within the `certificatesresolvers.myhttpchallenge.acme.email` command line argument of the traefik service. +* Expose the ports required for Traefik. Traefik uses port `8080` for its operations and UI, while in the last step we configured ports `80` and `443` and entrypoints for internet traffic. These will be used / proxied to OpenFaaS +* Binds the docker socket to the traefik container so that it can communicate with the Docker API and dertermine the number of containers and their IP addressess. +* Adds `traefik` to the `functions network so that it can communicate with the OpenFaaS components. +* Ensures that Traefik is only deployed on the Docker Swarm manager. + + +### Configure OpenFaaS +By default, the original `docker-compose.yaml` file exposes the OpenFaaS `gateway` on port `8080`. This conflicts with the configuration of Traefik, additionally, we want all communication to safely pass through Traefik. To do this you must make two modifications to the `gateway` service. + +First, remove the `ports` section. + +Next, add the following `labels` directive to the gateway service. + +```yaml + gateway: + image: ... + networks: + ... + environment: + ... + labels: + - "traefik.enable=true" + - "traefik.http.routers.gateway.rule=Host(`gw.example.com`)" + - "traefik.http.routers.gateway.entrypoints=websecure" + - "traefik.http.routers.gateway.tls.certresolver=myhttpchallenge" + deploy: + ... + secrets: + ... + ... +``` + +Traefik uses reads these labels from the Docker API to detect and configure the routing for the gateway. + +### Configure data volumes + +Finally, while configuring Traefik, you mounted a volume called `letsencrypt`. You must now define the `letsencrypt` volume used for storing Let's Encrypt certificates. We can define an empty volume, meaning data will not persist if you destroy the container. If you destroy the container, the certificates will be regenerated the next time you start Traefik. + +Add the following volumes directive on the last line of the file: + +```yaml +... +volumes: + letsencrypt: +``` + +A complete example `docker-compose.yaml` can be found [here](./compose-example.yaml) + +## Install OpenFaaS + +With all of the modifications in place, you can now deploy using the standard deployment scripts. On Mac and Linux: `deploy_stack.sh` and on Windows use `deploy_stack.ps1`. This script will deploy all of the required resources (services, configuration files, networks, and secrets) for your OpenFaaS cluster as they are defined in the `docker-compose.yaml` file. + +First, make sure that Docker will execute commands on your Swarm manager node: + +```bash +eval $(docker-machine env ) +``` + +Then, run your deployment script. A successful install will look like this: + +```bash +$ ./deploy_stack.sh +Attempting to create credentials for gateway.. +adadsf809adf098adfajlk12g +mb1jl213nlkmqfadsaokv68lh +[Credentials] + username: admin + password: + echo -n | faas-cli login --username=admin --password-stdin + +Enabling basic authentication for gateway.. + +Deploying OpenFaaS core services +Creating network func_functions +Creating config func_alertmanager_config +Creating config func_prometheus_config +Creating config func_prometheus_rules +Creating service func_alertmanager +Creating service func_traefik +Creating service func_gateway +Creating service func_faas-swarm +Creating service func_nats +Creating service func_queue-worker +Creating service func_prometheus +``` + +## Deploy and Invoke a function + +In your projects containing OpenFaaS functions, you can now deploy using your domain as the gateway. + +### Deploy from the CLI +```sh +faas-cli login --gateway https://gw.example.com --username admin --password +faas-cli deploy --gateway https://gw.example.com +``` +Replace `gw.example.com` with your domain as well as adding the username `admin` and secure random password that the deploy script created for you when you deployed OpenFaaS. + +### Use the web UI +You can use the web UI to see the functions deployed to your cluster or to deploy functions from the Store. In your web browser, go to https://gw.example.com/ui/. Note that the trailing slash is required. + +On your first visit, the HTTP authentication dialogue box will open, you can login with the username `admin` and secure random password that the deploy script created for you when you deployed OpenFaaS. + +## Verify and Debug + +- If you want to tail the Traefik logs, you can use +```sh +$ docker service logs -f traefik +``` +You can see internet traffic logs as well as logs related to the Let's Encrypt certificate process. + diff --git a/mkdocs.yml b/mkdocs.yml index dceb9881..24924d94 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -126,6 +126,7 @@ nav: - Jenkins: ./reference/cicd/jenkins.md - SSL: - Kubernetes: ./reference/ssl/kubernetes-with-cert-manager.md + - Docker Swarm: ./reference/ssl/swarm-with-traefik.md - Secrets: ./reference/secrets.md - Async: ./reference/async.md - Triggers: ./reference/triggers.md