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:
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 isproduction
ordevelopment
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+F12ZITI_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 clientsZITI_BROWZER_BOOTSTRAPPER_KEY_PATH
: the associated key for the ZITI_BROWZER_BOOTSTRAPPER_CERTIFICATE_PATHZITI_BROWZER_RUNTIME_ORIGIN_TRIAL_TOKEN
: the token obtained from the origin trials prerequisiteZITI_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
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.
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…