Skip to main content
Star us on GitHub Star

BrowZer

BrowZer is a set of technologies which is capable of bootstrapping zero trust connectivity entirely in a browser, and without the need to install any client-side software! To enable BrowZer on your network the ziti-browzer-bootstrapper will need to be deployed. This pages outlines the steps needed to deploy BrowZer to your own overlay. For an example of enabling BrowZer, see the Example Enabling BrowZer subpage showing the steps in more detail.

Prerequisites

To deploy and enable BrowZer on your network, you will need to have:

  • an OpenZiti Overlay Network is available and has been configured with alternative server certs
  • an OIDC Provider and the ability to define applications/clients for the provider
  • a wildcard certificate from a 3rd party verifiable CA
  • you have signed up with Chrome's "origin trials" to allow the BrowZer bootstrapper to automatically enable JSPI for your BrowZer users. See the chrome-origin-trials for more detail

OIDC Prerequisites

Enabling BrowZer will require configuring the network to delegate authentication to an OIDC provider. Every OIDC provider is different and understanding OIDC flows is beyond this guide. There are numerous, excellent posts to find and read about OIDC. The OIDC concepts you will want to understand are:

  • how to create/obtain the client id the network will use
  • how to learn/find/discover the OIDC discovery endpoint
  • what audience the OIDC provider will add to the bearer token
  • what field or claim the OIDC provider will add to the bearer token which will be used to locate matching identities

Configuring the Network

With the OIDC information in hand, the next step is to actually configure OpenZiti to allow the delegation of authentication. To do this you will need to:

  • create an external jwt signer
  • create an authentication policy and associate the external jwt signer
  • associate identities with the authentication policy delegating the authentication to the specified OIDC provider

Creating the External JWT Signer

To create the external jwt signer, you will need to have the OIDC discovery endpoint and the audience values handy. Using the OIDC discovery endpoint, discover the issuer and jwks_uri from the discovery endpoint. Using the ziti CLI, create the external jwt. Shown below is a bash example. Replace the values accordingly. Capture the returned identity, it will be necessary after creating the external jwt signer:

issuer="__issuer_id_here__"
jwks_uri="__jwks_uri_here__"
audience="__audience_here__"
claims_property="email"
ziti edge create ext-jwt-signer \
"ext-jwt-signer-name-here" "${issuer}" \
--jwks-endpoint "${jwks_uri}" \
--audience "${audience}" \
--claims-property ${claims_property}

Creating the Authentication Policy

Authentication policies configure the network to delegate authentication one or more OIDC providers. To create the authentication policy you only need the id of the external jwt signer (from above). Shown below is a bash example. Replace the values accordingly. Capture the returned identity, it will be necessary after creating the external jwt signer:

note

Shown below is an example creating a new authentication policy and allowing it to be used for primary authentication. This means the associated external jwt signer (OIDC provider) is allowed to provide a document that OpenZiti will validate, and use for authentication. You can also choose to modify the default policy if you decide to. You do not need to create a new policy. If this is your first time using BrowZer it is recommended you start with a new authentication policy, as shown. Once you understand how authentication policies work and how BrowZer works, then you can make an informed decision if you want to modify the default authentication policy or not

ext_jwt_signer="__ext_jwt_signer_id_from_above__"
ziti edge create auth-policy \
"auth-policy-name-here" \
--primary-ext-jwt-allowed \
--primary-ext-jwt-allowed-signers ${ext_jwt_signer}

Associate Identities to the Authentication Policy

With an auth policy created and associated to the external jwt signer, you are now ready to create or modify identities to use this new authentication policy. To allow a given identity to be enabled for BrowZer, you will need to first update (or create) the identity with an externalId and you will need to associate the identity with the authentication policy.

In this example, a new identity will be created and the associated OIDC provider will be expected to provide a bearer token which has an email claim with the value ziggy@openziti.io and names the identity openziti_ziggy:

identity_name="openziti_ziggy"
auth_policy="__auth_policy_id_from_above__"
external_id="ziggy@openziti.io"
ziti edge create identity user "${identity_name}" \
--auth-policy ${auth_policy} \
--external-id "${external_id}" \
-a docker.whale.dialers

Running the Ziti BrowZer Bootstrapper

Running the Ziti BrowZer Bootstrapper can be done directly using NodeJS or with a container engine such as Docker. Either way you choose to run it, you will need to establish some environment variables. If you are using NodeJS, you'll export them. To run using Docker, you can either reference the environment variables (shown below) or use an .env file.

  • NODE_ENV: controls if the environment is production or development
  • ZITI_BROWZER_RUNTIME_LOGLEVEL: the log level for the Ziti BrowZer Runtime (ZBR) to use. trace|debug|info|warn|error
  • ZITI_BROWZER_RUNTIME_HOTKEY: the hotkey to activate the BrowZer settings dialog modal. default: alt+F12
  • ZITI_CONTROLLER_HOST: the "alternative" address for the OpenZiti controller. example: ctrl.openziti.io
  • ZITI_CONTROLLER_PORT: the port to find the OpenZiti controller at. example: 8441
  • ZITI_BROWZER_BOOTSTRAPPER_LOGLEVEL: the log level for the ziti-browzer-bootstrapper to log at. silly|debug|info|warn|error
  • ZITI_BROWZER_BOOTSTRAPPER_HOST: the address the ziti-browzer-bootstrapper is available at. example: browzer.openziti.io
  • ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT: the port the ziti-browzer-bootstrapper is available at. example: 443
  • ZITI_BROWZER_BOOTSTRAPPER_SCHEME: the scheme to use to access the ziti-browzer-bootstrapper. http|https (https by default)
  • ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH: the path to the certificate the ziti-browzer-bootstrapper presents to clients
  • ZITI_BROWZER_BOOTSTRAPPER_KEY_PATH: the associated key for the ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH
  • ZITI_BROWZER_RUNTIME_ORIGIN_TRIAL_TOKEN: the token obtained from the origin trials prerequisite
  • ZITI_BROWZER_BOOTSTRAPPER_TARGETS: A json block representing the services to enable BrowZer for.
      NODE_ENV: production
ZITI_BROWZER_RUNTIME_LOGLEVEL: debug
ZITI_BROWZER_RUNTIME_HOTKEY: alt+F12
ZITI_CONTROLLER_HOST: ${ZITI_CTRL_EDGE_ALT_ADVERTISED_ADDRESS}
ZITI_CONTROLLER_PORT: ${ZITI_CTRL_EDGE_ADVERTISED_PORT}
ZITI_BROWZER_BOOTSTRAPPER_LOGLEVEL: debug
ZITI_BROWZER_BOOTSTRAPPER_HOST: ${ZITI_BROWZER_HTTP_AGENT_ADDRESS}
ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT: ${ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT}
ZITI_BROWZER_BOOTSTRAPPER_SCHEME: https
ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH: /etc/letsencrypt/live/your.fqdn.here/fullchain.pem
ZITI_BROWZER_BOOTSTRAPPER_KEY_PATH: /etc/letsencrypt/live/your.fqdn.here/privkey.pem
ZITI_BROWZER_RUNTIME_ORIGIN_TRIAL_TOKEN=__the_token_you_received_from_the_jspi_orgin_trial_prerequisite__
ZITI_BROWZER_BOOTSTRAPPER_TARGETS: __more on this below__

Set these values accordingly. Also shown is the reuse of certificates provisioned in this case by LetsEncrypt. BrowZer requires a wildcard certificate to be provisioned that aligns to the ZITI_BROWZER_BOOTSTRAPPER_HOST value used. For example, if you had set ZITI_BROWZER_BOOTSTRAPPER_HOST=my.custom.network, the certificate must be valid for *.my.custom.network

note

If you use Certbot/LetsEncrypt, the certificate created is likely to be accessible by root only. You will need to modify the folder/files accordingly. accordingly.

Cloning From GitHub

Once the environment variables are set, to start the Ziti BrowZer Bootstrapper perform the following:

  • clone the repository and checkout the desired tag/version. main should be fine:
    git clone https://github.com/openziti/ziti-browzer-bootstrapper.git $ZITI_HOME/ziti-browzer-bootstrapper
  • cd to the cloned location: cd $ZITI_HOME/ziti-browzer-bootstrapper
  • ensure the proper version of node and yarn are installed and run yarn install: yarn install
  • start the node server:
    NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node index.js

Running via Docker

Running the Ziti BrowZer Bootstrapper using Docker is similar to running with NodeJS. Establish the environment variables then run the agent with a command as shown. Note that this is running in the foreground. It's up to you to decide to put this into daemon mode, to use docker compose, etc.

note

To work around the LetsEncrypt issue mentioned above (the certs only visible to root), this example explicitly sets the --user the container runs as to a group id of 2171. Not shown was the creation of this group prior to running in Docker. In the Docker host OS, a group was added using a command such as: sudo groupadd -g 2171 zitiweb. Then the LetsEncrypt folder containing the certificates/keys was chown'ed: sudo chown -R root:zitiweb /etc/letsencrypt/. This allows the Docker container that will run the bootstrapper to access the files

Understanding the exact mechanics of why/how this works is beyond the scope of this page and is more relevant to Linux/Docker system administration.

Example Docker Command

docker run \
--name ziti-browzer-bootstrapper \
--rm -v /etc/letsencrypt:/etc/letsencrypt \
--user "${UID}:2171" \
-p ${ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT}:${ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT} \
-e NODE_ENV="${NODE_ENV}" \
-e ZITI_BROWZER_BOOTSTRAPPER_LOGLEVEL="${ZITI_BROWZER_BOOTSTRAPPER_LOGLEVEL}" \
-e ZITI_BROWZER_RUNTIME_LOGLEVEL="${ZITI_BROWZER_RUNTIME_LOGLEVEL}" \
-e ZITI_BROWZER_RUNTIME_HOTKEY="${ZITI_BROWZER_RUNTIME_HOTKEY}" \
-e ZITI_CONTROLLER_HOST="${ZITI_CONTROLLER_HOST}" \
-e ZITI_CONTROLLER_PORT="${ZITI_CONTROLLER_PORT}" \
-e ZITI_BROWZER_BOOTSTRAPPER_HOST="${ZITI_BROWZER_BOOTSTRAPPER_HOST}" \
-e ZITI_BROWZER_BOOTSTRAPPER_SCHEME="${ZITI_BROWZER_BOOTSTRAPPER_SCHEME}" \
-e ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH="${ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATH}" \
-e ZITI_BROWZER_BOOTSTRAPPER_KEY_PATH="${ZITI_BROWZER_BOOTSTRAPPER_KEY_PATH}" \
-e ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT="${ZITI_BROWZER_BOOTSTRAPPER_LISTEN_PORT}" \
-e ZITI_BROWZER_RUNTIME_ORIGIN_TRIAL_TOKEN="${ZITI_BROWZER_RUNTIME_ORIGIN_TRIAL_TOKEN}" \
-e ZITI_BROWZER_BOOTSTRAPPER_TARGETS="${ZITI_BROWZER_BOOTSTRAPPER_TARGETS}" \
ghcr.io/openziti/ziti-browzer-bootstrapper:latest

Enabling BrowZer with Systemd

If you want the BrowZer Bootstrap Agent to start when the machine starts or if the process fails for some reason and you have systemd on your system, you can enable the BrowZer Bootstrap Agent to start automatically on failure or reboot.

If you have used the Local - No Docker or the "host it anywhere" quickstart quickstarts, you would have sourced the
ziti-cli-function.sh helper script. If not, you can add the function to your shell or inspect the function and replicate the output it produces. Find the function here: https://get.openziti.io/ziti-cli-functions.sh

As with any script hosted on the internet, you are encouraged to download or preview the script from a browser before sourcing it. Once you are comfortable with the script, you can source it directly if you wish by running:

source /dev/stdin <<< "$(wget -qO- https://get.openziti.io/ziti-cli-functions.sh)"

You should also ensure you have the appropriate environment variable ($ZITI_HOME) in your shell before running the function as it's used when creating the file or you'll see:

  * ERROR: ZITI_HOME is not set

Also, if node is not on the path you'll see:

ERROR: missing executable 'node'

You can file: createBrowZerSystemdFile. Execute this now and you'll see something like:

Ziti BrowZer Bootstrapper systemd file written to: /home/ubuntu/.ziti/quickstart/ip-172-31-47-200/browzer-bootstrapper.service

Once created, you can copy that file and enable the unit with systemd:

createBrowZerSystemdFile
sudo cp "${ZITI_HOME}/browzer-bootstrapper.service" /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable --now browzer-bootstrapper
Verify BrowZer Started
systemctl status browzer-bootstrapper --no-pager --lines 0
Example systemctl Output

You should see output that looks similar to this. Notice the "Active" status is (running) and not failed/restarting etc:

● browzer-bootstrapper.service - A systemd unit file for the Ziti BrowZer Bootstrapper
Loaded: loaded (/etc/systemd/system/browzer-bootstrapper.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2023-08-18 12:52:54 UTC; 1min 24s ago
Main PID: 54770 (node)
Tasks: 11 (limit: 2316)
Memory: 42.9M
CPU: 2.269s
CGroup: /system.slice/browzer-bootstrapper.service
└─54770 /usr/local/bin/node /home/ubuntu/.ziti/quickstart/ip-172-31-47-200/ziti-browzer-bootstra…