From 19bfb69d24a6318af679f853bc73e1c25e54a1ad Mon Sep 17 00:00:00 2001 From: Geoff Berl Date: Fri, 15 Sep 2023 14:12:46 -0400 Subject: [PATCH 1/6] Initial commit of quickstart walkthrough writeup --- .../network/help/list-edge-routers.png | Bin 0 -> 31087 bytes .../network/help/quickstart-walkthrough.md | 314 ++++++++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 docusaurus/docs/learn/quickstarts/network/help/list-edge-routers.png create mode 100644 docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md diff --git a/docusaurus/docs/learn/quickstarts/network/help/list-edge-routers.png b/docusaurus/docs/learn/quickstarts/network/help/list-edge-routers.png new file mode 100644 index 0000000000000000000000000000000000000000..50b56879a2f312571a84bf13d072bc93aa1bf727 GIT binary patch literal 31087 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 literal 0 HcmV?d00001 diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md new file mode 100644 index 000000000..03148af5f --- /dev/null +++ b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md @@ -0,0 +1,314 @@ +--- +title: Quickstart Walkthrough +id: quickstart-walkthrough +--- +The following will walk you through the manual process of creating an overlay network with your own PKI. These steps are the same steps that take place behind the scenes when running the OpenZiti Quickstart’s `expressInstall` function. + +## General Environment Setup + +### Declare Variables + +Some global variables used throughout the overlay setup. + +- `ZITI_HOME` is the directory where your network files will be stored, the directory will be created if it does not exist already. +- `ZITI_BIN_DIR` is the directory where the ziti binary will be downloaded and extracted +- `ZITI_PWD` is the password that will be used when logging into the controller as the default user (admin). +- `ZITI_HOSTNAME` is used throughout the setup for naming files, network elements, etc. + +```bash +export ZITI_HOME="${HOME}/.ziti" +export ZITI_BIN_DIR="${ZITI_HOME}/ziti_bin" +export ZITI_PWD=admin2 +export ZITI_HOSTNAME=$(hostname -s) +``` + +### Create Environment + +Create a directory where you will store your network files. + +```bash +mkdir -p "${ZITI_HOME}" +``` + +### Obtain Ziti Binary + +The ziti binary is required to setup the network. The exact URL will differ depending on your operating system and architecture. Visit the [releases](https://github.com/openziti/ziti/releases) page to get the appropriate URL. + +```bash +mkdir -p "${ZITI_BIN_DIR}" +curl -L -o "${ZITI_BIN_DIR}/ziti-bin.gz" +tar -xf "${ZITI_BIN_DIR}/ziti-bin.gz" --directory "${ZITI_BIN_DIR}" +chmod +x "${ZITI_BIN_DIR}/ziti" +``` + +## Create PKI + +You may use an existing PKI if you prefer, however, as part of the `expressInstall` a PKI is generated for you. The following will run through the process of generating your own PKI. + +### Setup + +Set some initial environment variables for setting up the PKI. The `CA_NAME` values can be any name of your choosing. + +- `ZITI_PKI` is the directory where your PKI files will be stored +- `ZITI_ROOT_CA_NAME` is the name of the root CA. +- `ZITI_EXTERNAL_CA_INTERMEDIATE_NAME` is the name of an intermediate CA. +- `ZITI_CTRL_CA_NAME` is the name of the control plane CA. +- `ZITI_EDGE_CA_NAME` is the name of the HTTP API CA +- `ZITI_SIGN_CA_NAME` is the name of the signer CA used to sign identities created for the network. + +```bash +export ZITI_PKI="${ZITI_HOME}/pki" +export ZITI_ROOT_CA_NAME="my.root.ca" +export ZITI_EXTERNAL_CA_INTERMEDIATE_NAME="intermediate.from.external.ca" +export ZITI_CTRL_CA_NAME="${ZITI_HOSTNAME}-network-components" +export ZITI_EDGE_CA_NAME="${ZITI_HOSTNAME}-edge" +export ZITI_SIGN_CA_NAME="${ZITI_HOSTNAME}-identities" +``` + +### Creating the Certificate Authorities + +The following creates all of the CAs and files using the environment variables set up previously. + +```bash +"${ZITI_BIN_DIR}/ziti" pki create ca \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_ROOT_CA_NAME}" \ + --ca-file "${ZITI_ROOT_CA_NAME}" + +"${ZITI_BIN_DIR}/ziti" pki create intermediate \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_ROOT_CA_NAME}" \ + --intermediate-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ + --intermediate-file "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ + --max-path-len "2" + +"${ZITI_BIN_DIR}/ziti" pki create intermediate \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ + --intermediate-name "${ZITI_CTRL_CA_NAME}" \ + --intermediate-file "${ZITI_CTRL_CA_NAME}" \ + --max-path-len "1" + +"${ZITI_BIN_DIR}/ziti" pki create intermediate \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ + --intermediate-name "${ZITI_EDGE_CA_NAME}" \ + --intermediate-file "${ZITI_EDGE_CA_NAME}" \ + --max-path-len "1" + +"${ZITI_BIN_DIR}/ziti" pki create intermediate \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ + --intermediate-name "${ZITI_SIGN_CA_NAME}" \ + --intermediate-file "${ZITI_SIGN_CA_NAME}" \ + --max-path-len "1" +``` + +### Create Server and Client Certs for the Control Plane + +Set up some initial values for the server and client certificates. + +- `ZITI_NETWORK_COMPONENTS_PKI_NAME` is the key file name. +- `ZITI_NETWORK_COMPONENTS_ADDRESSES` is a comma-separated list of DNS names to add to the SANs. +- `ZITI_NETWORK_COMPONENTS_IPS` is a comma-separated list of IPs to add to the SANs. + +```bash +ZITI_NETWORK_COMPONENTS_PKI_NAME="ziti.network.components" +ZITI_NETWORK_COMPONENTS_ADDRESSES="localhost,${ZITI_HOSTNAME},some.other.name,and.another.name" +ZITI_NETWORK_COMPONENTS_IPS="127.0.0.1,127.0.21.71,192.168.100.100" +``` + +Now we’ll create the key, client, and server certs for the control plane. + +```bash +"${ZITI_BIN_DIR}/ziti" pki create key \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_CTRL_CA_NAME}" \ + --key-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" + +"${ZITI_BIN_DIR}/ziti" pki create server \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_CTRL_CA_NAME}" \ + --key-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" \ + --server-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}-server" \ + --server-name "${ZITI_NETWORK_COMPONENTS_PKI_NAME}-server" \ + --dns "${ZITI_NETWORK_COMPONENTS_ADDRESSES}" \ + --ip "${ZITI_NETWORK_COMPONENTS_IPS}" + +"${ZITI_BIN_DIR}/ziti" pki create client \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_CTRL_CA_NAME}" \ + --key-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" \ + --client-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}-client" \ + --client-name "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" +``` + +### Create Server and Client Certs for the HTTP API + +Set up some initial values for the server and client certificates. As with the control plane, these are for the key file name, DNS, and IP SANs. The DNS and IP lists are reused from the control plane cert generation. + +```bash +ZITI_EDGE_API_PKI_NAME="ziti.edge.controller" +ZITI_EDGE_API_ADDRESSES="${ZITI_NETWORK_COMPONENTS_ADDRESSES}" +ZITI_EDGE_API_IPS="${ZITI_NETWORK_COMPONENTS_IPS}" +``` + +Now we’ll create the key, client, and server certs for the HTTP API. + +```bash +"${ZITI_BIN_DIR}/ziti" pki create key \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_EDGE_CA_NAME}" \ + --key-file "${ZITI_EDGE_API_PKI_NAME}" + +"${ZITI_BIN_DIR}/ziti" pki create server \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_EDGE_CA_NAME}" \ + --key-file "${ZITI_EDGE_API_PKI_NAME}" \ + --server-file "${ZITI_EDGE_API_PKI_NAME}-server" \ + --server-name "${ZITI_EDGE_API_PKI_NAME}-server" \ + --dns "${ZITI_EDGE_API_ADDRESSES}" \ + --ip "${ZITI_EDGE_API_IPS}" + +"${ZITI_BIN_DIR}/ziti" pki create client \ + --pki-root="${ZITI_PKI}" \ + --ca-name "${ZITI_EDGE_CA_NAME}" \ + --key-file "${ZITI_EDGE_API_PKI_NAME}" \ + --client-file "${ZITI_EDGE_API_PKI_NAME}-client" \ + --client-name "${ZITI_EDGE_API_PKI_NAME}" +``` + +### Update the CA Bundle + +Add the CAs to the CA bundle and make a copy for the HTTP API CA bundle. + +```bash +cat "${ZITI_PKI}/my.root.ca/certs/my.root.ca.cert" > "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" +cat "${ZITI_PKI}/my.root.ca/certs/intermediate.from.external.ca.cert" >> "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" +cp "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" "${ZITI_PKI}/${ZITI_HOSTNAME}-edge/edge.cas.pem" +``` + +## Create Controller + +### Setup + +Declare some environment variables used to generate the controller config file. Some environment variables used were already set previously. + +- `ZITI_CTRL_ADVERTISED_ADDRESS` is the address for the controller’s control plane +- `ZITI_CTRL_EDGE_ADVERTISED_ADDRESS` is the address for the HTTP API +- `ZITI_CTRL_ADVERTISED_PORT` is the port for the control plane +- `ZITI_CTRL_EDGE_ADVERTISED_PORT` is the port for the HTTP API + +The following are locations of PKI files. + +- `ZITI_PKI_CTRL_KEY` +- `ZITI_PKI_CTRL_SERVER_CERT` +- `ZITI_PKI_CTRL_CERT` +- `ZITI_PKI_CTRL_CA` +- `ZITI_PKI_EDGE_KEY` +- `ZITI_PKI_EDGE_SERVER_CERT` +- `ZITI_PKI_EDGE_CERT` +- `ZITI_PKI_EDGE_CA` +- `ZITI_PKI_SIGNER_KEY` +- `ZITI_PKI_SIGNER_CERT` + +```bash +export ZITI_CTRL_ADVERTISED_ADDRESS="${ZITI_HOSTNAME}" +export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${ZITI_HOSTNAME}" +export ZITI_CTRL_ADVERTISED_PORT=8440 +export ZITI_CTRL_EDGE_ADVERTISED_PORT=8441 + +export ZITI_PKI_CTRL_KEY="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/keys/${ZITI_NETWORK_COMPONENTS_PKI_NAME}.key" +export ZITI_PKI_CTRL_SERVER_CERT="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/certs/${ZITI_NETWORK_COMPONENTS_PKI_NAME}-server.chain.pem" +export ZITI_PKI_CTRL_CERT="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/certs/${ZITI_NETWORK_COMPONENTS_PKI_NAME}-client.cert" +export ZITI_PKI_CTRL_CA="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/cas.pem" + +export ZITI_PKI_EDGE_KEY="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/keys/${ZITI_EDGE_API_PKI_NAME}.key" +export ZITI_PKI_EDGE_SERVER_CERT="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/certs/${ZITI_EDGE_API_PKI_NAME}-server.chain.pem" +export ZITI_PKI_EDGE_CERT="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/certs/${ZITI_EDGE_API_PKI_NAME}-client.cert" +export ZITI_PKI_EDGE_CA="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/edge.cas.pem" + +export ZITI_PKI_SIGNER_KEY="${ZITI_PKI}/${ZITI_SIGN_CA_NAME}/keys/${ZITI_SIGN_CA_NAME}.key" +export ZITI_PKI_SIGNER_CERT="${ZITI_PKI}/${ZITI_SIGN_CA_NAME}/certs/${ZITI_SIGN_CA_NAME}.chain.pem" +``` + +### Create the Controller Config File + +The controller config file is populated based on the values of environment variables set up to this point. + +```bash +"${ZITI_BIN_DIR}/ziti" create config controller >${ZITI_HOME}/${ZITI_HOSTNAME}.yaml +``` + +### Initialize the Controller + +Initializing the controller sets up database files and some of the configuration values. + +```bash +mkdir ${ZITI_HOME}/db +"${ZITI_BIN_DIR}/ziti" controller edge init "${ZITI_HOME}/${ZITI_HOSTNAME}.yaml" -u "admin" -p $ZITI_PWD +``` + +### Run the Controller + +```bash +"${ZITI_BIN_DIR}/ziti" controller run ${ZITI_HOME}/${ZITI_HOSTNAME}.yaml &> ${ZITI_HOME}/${ZITI_HOSTNAME}.log & +``` + +### Wait for the Controller + +We want to ensure the controller is ready before creating a router, this mini loop + +```bash +while [[ "$(curl -w "%{http_code}" -m 1 -s -k -o /dev/null https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}/edge/client/v1/version)" != "200" ]]; do + echo "waiting for https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}" + sleep 1 +done +``` + +## Create Router + +### Create the Router Entity + +The router needs to be created through the controller. This will generate a one-time token to be used during enrollment. + +```bash +# We have to log in first +"${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y + +"${ZITI_BIN_DIR}/ziti" edge create edge-router ${ZITI_HOSTNAME}-edge-router -o ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.jwt -t -a public +``` + +### Create the Router Config File + +Just as with the controller, we need to create a router config file. The router config also uses values set in environment variables up to this point. + +```bash +"${ZITI_BIN_DIR}/ziti" create config router edge --routerName ${ZITI_HOSTNAME}-edge-router >${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml +``` + +### Enroll the Router with the Controller + +Enroll the router with the controller utilizing the config file and enrollment token previously generated. + +```bash +"${ZITI_BIN_DIR}/ziti" router enroll ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml --jwt ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.jwt +``` + +### Run the Router + +```bash +"${ZITI_BIN_DIR}/ziti" router run "${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml" &> ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.log & +``` + +## Confirm the Network is Up + +Log in and run a command to list the edge routers and we should see a single edge router showing `ONLINE`. + +```bash +# The session may have expired, log in just to be safe +"${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y +"${ZITI_BIN_DIR}/ziti" edge list edge-routers +``` + +![list-edge-routers.png](./list-edge-routers.png) \ No newline at end of file From b9e573d8a13b7f7221a1d53caa78cc1daf72d2d5 Mon Sep 17 00:00:00 2001 From: Geoff Berl Date: Fri, 15 Sep 2023 14:13:49 -0400 Subject: [PATCH 2/6] Removing bash specifier --- .../network/help/quickstart-walkthrough.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md index 03148af5f..03d687d51 100644 --- a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md +++ b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md @@ -15,7 +15,7 @@ Some global variables used throughout the overlay setup. - `ZITI_PWD` is the password that will be used when logging into the controller as the default user (admin). - `ZITI_HOSTNAME` is used throughout the setup for naming files, network elements, etc. -```bash +``` export ZITI_HOME="${HOME}/.ziti" export ZITI_BIN_DIR="${ZITI_HOME}/ziti_bin" export ZITI_PWD=admin2 @@ -26,7 +26,7 @@ export ZITI_HOSTNAME=$(hostname -s) Create a directory where you will store your network files. -```bash +``` mkdir -p "${ZITI_HOME}" ``` @@ -34,7 +34,7 @@ mkdir -p "${ZITI_HOME}" The ziti binary is required to setup the network. The exact URL will differ depending on your operating system and architecture. Visit the [releases](https://github.com/openziti/ziti/releases) page to get the appropriate URL. -```bash +``` mkdir -p "${ZITI_BIN_DIR}" curl -L -o "${ZITI_BIN_DIR}/ziti-bin.gz" tar -xf "${ZITI_BIN_DIR}/ziti-bin.gz" --directory "${ZITI_BIN_DIR}" @@ -56,7 +56,7 @@ Set some initial environment variables for setting up the PKI. The `CA_NAME` val - `ZITI_EDGE_CA_NAME` is the name of the HTTP API CA - `ZITI_SIGN_CA_NAME` is the name of the signer CA used to sign identities created for the network. -```bash +``` export ZITI_PKI="${ZITI_HOME}/pki" export ZITI_ROOT_CA_NAME="my.root.ca" export ZITI_EXTERNAL_CA_INTERMEDIATE_NAME="intermediate.from.external.ca" @@ -69,7 +69,7 @@ export ZITI_SIGN_CA_NAME="${ZITI_HOSTNAME}-identities" The following creates all of the CAs and files using the environment variables set up previously. -```bash +``` "${ZITI_BIN_DIR}/ziti" pki create ca \ --pki-root="${ZITI_PKI}" \ --ca-name "${ZITI_ROOT_CA_NAME}" \ @@ -112,7 +112,7 @@ Set up some initial values for the server and client certificates. - `ZITI_NETWORK_COMPONENTS_ADDRESSES` is a comma-separated list of DNS names to add to the SANs. - `ZITI_NETWORK_COMPONENTS_IPS` is a comma-separated list of IPs to add to the SANs. -```bash +``` ZITI_NETWORK_COMPONENTS_PKI_NAME="ziti.network.components" ZITI_NETWORK_COMPONENTS_ADDRESSES="localhost,${ZITI_HOSTNAME},some.other.name,and.another.name" ZITI_NETWORK_COMPONENTS_IPS="127.0.0.1,127.0.21.71,192.168.100.100" @@ -120,7 +120,7 @@ ZITI_NETWORK_COMPONENTS_IPS="127.0.0.1,127.0.21.71,192.168.100.100" Now we’ll create the key, client, and server certs for the control plane. -```bash +``` "${ZITI_BIN_DIR}/ziti" pki create key \ --pki-root="${ZITI_PKI}" \ --ca-name "${ZITI_CTRL_CA_NAME}" \ @@ -147,7 +147,7 @@ Now we’ll create the key, client, and server certs for the control plane. Set up some initial values for the server and client certificates. As with the control plane, these are for the key file name, DNS, and IP SANs. The DNS and IP lists are reused from the control plane cert generation. -```bash +``` ZITI_EDGE_API_PKI_NAME="ziti.edge.controller" ZITI_EDGE_API_ADDRESSES="${ZITI_NETWORK_COMPONENTS_ADDRESSES}" ZITI_EDGE_API_IPS="${ZITI_NETWORK_COMPONENTS_IPS}" @@ -155,7 +155,7 @@ ZITI_EDGE_API_IPS="${ZITI_NETWORK_COMPONENTS_IPS}" Now we’ll create the key, client, and server certs for the HTTP API. -```bash +``` "${ZITI_BIN_DIR}/ziti" pki create key \ --pki-root="${ZITI_PKI}" \ --ca-name "${ZITI_EDGE_CA_NAME}" \ @@ -182,7 +182,7 @@ Now we’ll create the key, client, and server certs for the HTTP API. Add the CAs to the CA bundle and make a copy for the HTTP API CA bundle. -```bash +``` cat "${ZITI_PKI}/my.root.ca/certs/my.root.ca.cert" > "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" cat "${ZITI_PKI}/my.root.ca/certs/intermediate.from.external.ca.cert" >> "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" cp "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" "${ZITI_PKI}/${ZITI_HOSTNAME}-edge/edge.cas.pem" @@ -212,7 +212,7 @@ The following are locations of PKI files. - `ZITI_PKI_SIGNER_KEY` - `ZITI_PKI_SIGNER_CERT` -```bash +``` export ZITI_CTRL_ADVERTISED_ADDRESS="${ZITI_HOSTNAME}" export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${ZITI_HOSTNAME}" export ZITI_CTRL_ADVERTISED_PORT=8440 @@ -236,7 +236,7 @@ export ZITI_PKI_SIGNER_CERT="${ZITI_PKI}/${ZITI_SIGN_CA_NAME}/certs/${ZITI_SIGN_ The controller config file is populated based on the values of environment variables set up to this point. -```bash +``` "${ZITI_BIN_DIR}/ziti" create config controller >${ZITI_HOME}/${ZITI_HOSTNAME}.yaml ``` @@ -244,14 +244,14 @@ The controller config file is populated based on the values of environment varia Initializing the controller sets up database files and some of the configuration values. -```bash +``` mkdir ${ZITI_HOME}/db "${ZITI_BIN_DIR}/ziti" controller edge init "${ZITI_HOME}/${ZITI_HOSTNAME}.yaml" -u "admin" -p $ZITI_PWD ``` ### Run the Controller -```bash +``` "${ZITI_BIN_DIR}/ziti" controller run ${ZITI_HOME}/${ZITI_HOSTNAME}.yaml &> ${ZITI_HOME}/${ZITI_HOSTNAME}.log & ``` @@ -259,7 +259,7 @@ mkdir ${ZITI_HOME}/db We want to ensure the controller is ready before creating a router, this mini loop -```bash +``` while [[ "$(curl -w "%{http_code}" -m 1 -s -k -o /dev/null https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}/edge/client/v1/version)" != "200" ]]; do echo "waiting for https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}" sleep 1 @@ -272,7 +272,7 @@ done The router needs to be created through the controller. This will generate a one-time token to be used during enrollment. -```bash +``` # We have to log in first "${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y @@ -283,7 +283,7 @@ The router needs to be created through the controller. This will generate a one- Just as with the controller, we need to create a router config file. The router config also uses values set in environment variables up to this point. -```bash +``` "${ZITI_BIN_DIR}/ziti" create config router edge --routerName ${ZITI_HOSTNAME}-edge-router >${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml ``` @@ -291,13 +291,13 @@ Just as with the controller, we need to create a router config file. The router Enroll the router with the controller utilizing the config file and enrollment token previously generated. -```bash +``` "${ZITI_BIN_DIR}/ziti" router enroll ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml --jwt ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.jwt ``` ### Run the Router -```bash +``` "${ZITI_BIN_DIR}/ziti" router run "${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml" &> ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.log & ``` @@ -305,7 +305,7 @@ Enroll the router with the controller utilizing the config file and enrollment t Log in and run a command to list the edge routers and we should see a single edge router showing `ONLINE`. -```bash +``` # The session may have expired, log in just to be safe "${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y "${ZITI_BIN_DIR}/ziti" edge list edge-routers From d147697593b3c47cc55d0338ecebce510b7252c6 Mon Sep 17 00:00:00 2001 From: Geoff Berl Date: Wed, 11 Oct 2023 15:16:12 -0400 Subject: [PATCH 3/6] Addressing some comments from the initial PR review. --- .../network/help/quickstart-walkthrough.md | 105 ++++++++++++------ 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md index 03d687d51..b2fbe95c9 100644 --- a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md +++ b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md @@ -2,29 +2,53 @@ title: Quickstart Walkthrough id: quickstart-walkthrough --- -The following will walk you through the manual process of creating an overlay network with your own PKI. These steps are the same steps that take place behind the scenes when running the OpenZiti Quickstart’s `expressInstall` function. +This page is intended to explain the steps that happen automatically when the expressInstall function is executed. +The [Local - No Docker](/docusaurus/docs/learn/quickstarts/network/local-no-docker.md), +[Local - With Docker](/docusaurus/docs/learn/quickstarts/network/local-with-docker.md), +[Local - Docker Compose](/docusaurus/docs/learn/quickstarts/network/local-docker-compose.md), and +[Host OpenZiti Anywhere](/docusaurus/docs/learn/quickstarts/network/hosted.md) quickstarts all run the `expressInstall` +function. Each version varies slightly. This page will focus on the Host OpenZiti Anywhere quickstart. + +## The General Process +1. Establish environment variables +2. Create a directory for network related files +3. Obtain the Ziti binary +4. Create a PKI +5. Create a Controller configuration +6. Initialize the Controller +7. Start the Controller +8. Create a Router configuration +9. Create a Router entity on the network (via the Controller) +10. Enroll the Router previously created +11. Run the Router +12. Add default Edge Router and Service Edge Router policies. ## General Environment Setup ### Declare Variables -Some global variables used throughout the overlay setup. +The first thing `expressInstall` will do is establish numerous environment variables used throughout the script. Some +important variables are listed below. -- `ZITI_HOME` is the directory where your network files will be stored, the directory will be created if it does not exist already. +- `ZITI_HOME` is the directory `expressInstall` will use to create and store the network files. The directory will be +created if it does not exist already. - `ZITI_BIN_DIR` is the directory where the ziti binary will be downloaded and extracted +- `ZITI_USER` is the username for the controller's admin user, this value defaults to `admin` - `ZITI_PWD` is the password that will be used when logging into the controller as the default user (admin). -- `ZITI_HOSTNAME` is used throughout the setup for naming files, network elements, etc. +- `ZITI_NETWORK` is used throughout the setup for naming files, network elements, etc. This value defaults to the +hostname of the device the network is being installed on. ``` export ZITI_HOME="${HOME}/.ziti" export ZITI_BIN_DIR="${ZITI_HOME}/ziti_bin" +export ZITI_USER=admin export ZITI_PWD=admin2 -export ZITI_HOSTNAME=$(hostname -s) +export ZITI_NETWORK=$(hostname -s) ``` -### Create Environment +### Create Directory -Create a directory where you will store your network files. +Create a directory where the network files will be stored. ``` mkdir -p "${ZITI_HOME}" @@ -32,7 +56,14 @@ mkdir -p "${ZITI_HOME}" ### Obtain Ziti Binary -The ziti binary is required to setup the network. The exact URL will differ depending on your operating system and architecture. Visit the [releases](https://github.com/openziti/ziti/releases) page to get the appropriate URL. +The ziti binary is required to set up the network. The `expressInstall` function will call `getZiti` to obtain the Ziti +binary. The `getZiti` function detects your OS type and architecture to craft the specific download URL for the binary. +The binary is downloaded, and extracted to the location specified by the `ZITI_BIN_DIR` environment variable. Visit the +[releases](https://github.com/openziti/ziti/releases) page to get the appropriate URL. +:::note +you don't have to always run expressInstall when running the quickstart. you can source the ziti-cli-function.sh file +and run getZiti to get the latest version of ziti installed quickly and easily +::: ``` mkdir -p "${ZITI_BIN_DIR}" @@ -43,7 +74,10 @@ chmod +x "${ZITI_BIN_DIR}/ziti" ## Create PKI -You may use an existing PKI if you prefer, however, as part of the `expressInstall` a PKI is generated for you. The following will run through the process of generating your own PKI. +As part of the `expressInstall` a PKI is generated automatically. The following represents the process of generating +the PKI. The PKI consists of a root CA, three intermediate CAs (one for each of the controller's config sections. +Additionally, an extra intermediate CA is created on the signing cert to demonstrate that arbitrary cert chain lengths +are acceptable.) ### Setup @@ -60,9 +94,9 @@ Set some initial environment variables for setting up the PKI. The `CA_NAME` val export ZITI_PKI="${ZITI_HOME}/pki" export ZITI_ROOT_CA_NAME="my.root.ca" export ZITI_EXTERNAL_CA_INTERMEDIATE_NAME="intermediate.from.external.ca" -export ZITI_CTRL_CA_NAME="${ZITI_HOSTNAME}-network-components" -export ZITI_EDGE_CA_NAME="${ZITI_HOSTNAME}-edge" -export ZITI_SIGN_CA_NAME="${ZITI_HOSTNAME}-identities" +export ZITI_CTRL_CA_NAME="${ZITI_NETWORK}-network-components" +export ZITI_EDGE_CA_NAME="${ZITI_NETWORK}-edge" +export ZITI_SIGN_CA_NAME="${ZITI_NETWORK}-identities" ``` ### Creating the Certificate Authorities @@ -114,7 +148,7 @@ Set up some initial values for the server and client certificates. ``` ZITI_NETWORK_COMPONENTS_PKI_NAME="ziti.network.components" -ZITI_NETWORK_COMPONENTS_ADDRESSES="localhost,${ZITI_HOSTNAME},some.other.name,and.another.name" +ZITI_NETWORK_COMPONENTS_ADDRESSES="localhost,${ZITI_NETWORK},some.other.name,and.another.name" ZITI_NETWORK_COMPONENTS_IPS="127.0.0.1,127.0.21.71,192.168.100.100" ``` @@ -180,12 +214,13 @@ Now we’ll create the key, client, and server certs for the HTTP API. ### Update the CA Bundle -Add the CAs to the CA bundle and make a copy for the HTTP API CA bundle. +The latest tunnelers require full and complete PKIs, not arbitrary trust anchors. Therefore, the root and intermediate +CAs must be added to the CA bundle. Additionally, the file is copied for the HTTP API CA bundle. ``` -cat "${ZITI_PKI}/my.root.ca/certs/my.root.ca.cert" > "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" -cat "${ZITI_PKI}/my.root.ca/certs/intermediate.from.external.ca.cert" >> "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" -cp "${ZITI_PKI}/${ZITI_HOSTNAME}-network-components/cas.pem" "${ZITI_PKI}/${ZITI_HOSTNAME}-edge/edge.cas.pem" +cat "${ZITI_PKI}/my.root.ca/certs/my.root.ca.cert" > "${ZITI_PKI}/${ZITI_NETWORK}-network-components/cas.pem" +cat "${ZITI_PKI}/my.root.ca/certs/intermediate.from.external.ca.cert" >> "${ZITI_PKI}/${ZITI_NETWORK}-network-components/cas.pem" +cp "${ZITI_PKI}/${ZITI_NETWORK}-network-components/cas.pem" "${ZITI_PKI}/${ZITI_NETWORK}-edge/edge.cas.pem" ``` ## Create Controller @@ -213,8 +248,8 @@ The following are locations of PKI files. - `ZITI_PKI_SIGNER_CERT` ``` -export ZITI_CTRL_ADVERTISED_ADDRESS="${ZITI_HOSTNAME}" -export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${ZITI_HOSTNAME}" +export ZITI_CTRL_ADVERTISED_ADDRESS="${ZITI_NETWORK}" +export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${ZITI_NETWORK}" export ZITI_CTRL_ADVERTISED_PORT=8440 export ZITI_CTRL_EDGE_ADVERTISED_PORT=8441 @@ -237,27 +272,27 @@ export ZITI_PKI_SIGNER_CERT="${ZITI_PKI}/${ZITI_SIGN_CA_NAME}/certs/${ZITI_SIGN_ The controller config file is populated based on the values of environment variables set up to this point. ``` -"${ZITI_BIN_DIR}/ziti" create config controller >${ZITI_HOME}/${ZITI_HOSTNAME}.yaml +"${ZITI_BIN_DIR}/ziti" create config controller >${ZITI_HOME}/${ZITI_NETWORK}.yaml ``` ### Initialize the Controller -Initializing the controller sets up database files and some of the configuration values. +Initializing the controller initializes the database. ``` mkdir ${ZITI_HOME}/db -"${ZITI_BIN_DIR}/ziti" controller edge init "${ZITI_HOME}/${ZITI_HOSTNAME}.yaml" -u "admin" -p $ZITI_PWD +"${ZITI_BIN_DIR}/ziti" controller edge init "${ZITI_HOME}/${ZITI_NETWORK}.yaml" -u $ZITI_USER -p $ZITI_PWD ``` ### Run the Controller ``` -"${ZITI_BIN_DIR}/ziti" controller run ${ZITI_HOME}/${ZITI_HOSTNAME}.yaml &> ${ZITI_HOME}/${ZITI_HOSTNAME}.log & +"${ZITI_BIN_DIR}/ziti" controller run ${ZITI_HOME}/${ZITI_NETWORK}.yaml &> ${ZITI_HOME}/${ZITI_NETWORK}.log & ``` ### Wait for the Controller -We want to ensure the controller is ready before creating a router, this mini loop +The controller is used to create the router identity and therefore, must be up and running, ready to receive commands. ``` while [[ "$(curl -w "%{http_code}" -m 1 -s -k -o /dev/null https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}/edge/client/v1/version)" != "200" ]]; do @@ -268,23 +303,23 @@ done ## Create Router -### Create the Router Entity +### Create the Router Config File -The router needs to be created through the controller. This will generate a one-time token to be used during enrollment. +Just as with the controller, we need to create a router config file. The router config also uses values set in environment variables up to this point. ``` -# We have to log in first -"${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y - -"${ZITI_BIN_DIR}/ziti" edge create edge-router ${ZITI_HOSTNAME}-edge-router -o ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.jwt -t -a public +"${ZITI_BIN_DIR}/ziti" create config router edge --routerName ${ZITI_NETWORK}-edge-router >${ZITI_HOME}/${ZITI_NETWORK}-edge-router.yaml ``` -### Create the Router Config File +### Create the Router Entity -Just as with the controller, we need to create a router config file. The router config also uses values set in environment variables up to this point. +The router needs to be created through the controller. This will generate a one-time token to be used during enrollment. ``` -"${ZITI_BIN_DIR}/ziti" create config router edge --routerName ${ZITI_HOSTNAME}-edge-router >${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml +# We have to log in first +"${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y + +"${ZITI_BIN_DIR}/ziti" edge create edge-router ${ZITI_NETWORK}-edge-router -o ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.jwt -t -a public ``` ### Enroll the Router with the Controller @@ -292,13 +327,13 @@ Just as with the controller, we need to create a router config file. The router Enroll the router with the controller utilizing the config file and enrollment token previously generated. ``` -"${ZITI_BIN_DIR}/ziti" router enroll ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml --jwt ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.jwt +"${ZITI_BIN_DIR}/ziti" router enroll ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.yaml --jwt ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.jwt ``` ### Run the Router ``` -"${ZITI_BIN_DIR}/ziti" router run "${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.yaml" &> ${ZITI_HOME}/${ZITI_HOSTNAME}-edge-router.log & +"${ZITI_BIN_DIR}/ziti" router run "${ZITI_HOME}/${ZITI_NETWORK}-edge-router.yaml" &> ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.log & ``` ## Confirm the Network is Up From b723d4b1a609e042d8aad3f4729b6d413a260dd3 Mon Sep 17 00:00:00 2001 From: Geoff Berl Date: Thu, 12 Oct 2023 09:05:01 -0400 Subject: [PATCH 4/6] Fixing link error --- .../quickstarts/network/help/quickstart-walkthrough.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md index b2fbe95c9..8691615d4 100644 --- a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md +++ b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md @@ -3,10 +3,10 @@ title: Quickstart Walkthrough id: quickstart-walkthrough --- This page is intended to explain the steps that happen automatically when the expressInstall function is executed. -The [Local - No Docker](/docusaurus/docs/learn/quickstarts/network/local-no-docker.md), -[Local - With Docker](/docusaurus/docs/learn/quickstarts/network/local-with-docker.md), -[Local - Docker Compose](/docusaurus/docs/learn/quickstarts/network/local-docker-compose.md), and -[Host OpenZiti Anywhere](/docusaurus/docs/learn/quickstarts/network/hosted.md) quickstarts all run the `expressInstall` +The [Local - No Docker](../local-no-docker.md), +[Local - With Docker](../local-with-docker.md), +[Local - Docker Compose](../local-docker-compose.md), and +[Host OpenZiti Anywhere](../hosted.md) quickstarts all run the `expressInstall` function. Each version varies slightly. This page will focus on the Host OpenZiti Anywhere quickstart. ## The General Process From 24100d09eeca83e6ada0e9ca3e4831afcee34002 Mon Sep 17 00:00:00 2001 From: Geoff Berl Date: Wed, 18 Oct 2023 09:25:37 -0400 Subject: [PATCH 5/6] Rewriting based on PR comments --- .../network/help/list-edge-routers.png | Bin 31087 -> 0 bytes .../network/help/quickstart-pki-full.png | Bin 0 -> 32669 bytes .../network/help/quickstart-walkthrough.md | 345 +++--------------- 3 files changed, 57 insertions(+), 288 deletions(-) delete mode 100644 docusaurus/docs/learn/quickstarts/network/help/list-edge-routers.png create mode 100644 docusaurus/docs/learn/quickstarts/network/help/quickstart-pki-full.png diff --git a/docusaurus/docs/learn/quickstarts/network/help/list-edge-routers.png b/docusaurus/docs/learn/quickstarts/network/help/list-edge-routers.png deleted file mode 100644 index 50b56879a2f312571a84bf13d072bc93aa1bf727..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31087 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 diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-pki-full.png b/docusaurus/docs/learn/quickstarts/network/help/quickstart-pki-full.png new file mode 100644 index 0000000000000000000000000000000000000000..6a1b878d6d5b2124232b7522194a68aa180099bf GIT binary patch literal 32669 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 literal 0 HcmV?d00001 diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md index 8691615d4..fbda86009 100644 --- a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md +++ b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md @@ -20,202 +20,74 @@ function. Each version varies slightly. This page will focus on the Host OpenZit 8. Create a Router configuration 9. Create a Router entity on the network (via the Controller) 10. Enroll the Router previously created -11. Run the Router -12. Add default Edge Router and Service Edge Router policies. +11. Add default Edge Router and Service Edge Router policies. ## General Environment Setup ### Declare Variables The first thing `expressInstall` will do is establish numerous environment variables used throughout the script. Some -important variables are listed below. +important customizable variables are listed below. + +- `EXTERNAL_DNS` is the externally accessible DNS name. This value is also added to the PKI SANs DNS field. +- `EXTERNAL_IP` is the externally accessible IP address. This value is also added to the PKI SANs IP field +- `ZITI_CTRL_EDGE_IP_OVERRIDE` is a custom IP for the Ziti Controller. This value is added to the PKI SANs IP field for +the controller's edge PKI trust chain. +- `ZITI_ROUTER_IP_OVERRIDE` is a custom IP for the Ziti Router. +- `ZITI_CTRL_EDGE_ADVERTISED_ADDRESS` is the publicly accessible Controller address used for the Edge/API plane. +- `ZITI_ROUTER_ADVERTISED_ADDRESS` is the advertised address of the Ziti Router. This defaults to the value in +`EXTERNAL_DNS` if set. Otherwise, the value in `EXTERNAL_IP` is used. +- `ZITI_CTRL_ADVERTISED_PORT` is the port used for the Controller's control plane address. +- `ZITI_CTRL_EDGE_ADVERTISED_PORT` is the port used for the Controller's Edge/API plane address. +- `ZITI_ROUTER_PORT` is the port used for the Router's advertised address. -- `ZITI_HOME` is the directory `expressInstall` will use to create and store the network files. The directory will be -created if it does not exist already. -- `ZITI_BIN_DIR` is the directory where the ziti binary will be downloaded and extracted -- `ZITI_USER` is the username for the controller's admin user, this value defaults to `admin` -- `ZITI_PWD` is the password that will be used when logging into the controller as the default user (admin). -- `ZITI_NETWORK` is used throughout the setup for naming files, network elements, etc. This value defaults to the -hostname of the device the network is being installed on. +:::note +It is highly recommended to use DNS over IP as this is a one time setup, if your IP changes, then your PKI is rendered +useless. +::: ``` -export ZITI_HOME="${HOME}/.ziti" -export ZITI_BIN_DIR="${ZITI_HOME}/ziti_bin" -export ZITI_USER=admin -export ZITI_PWD=admin2 -export ZITI_NETWORK=$(hostname -s) +export EXTERNAL_DNS="acme.example.com" +export EXTERNAL_IP="$(curl -s eth0.me)" +export ZITI_CTRL_EDGE_IP_OVERRIDE="${EXTERNAL_IP}" +export ZITI_ROUTER_IP_OVERRIDE="${EXTERNAL_IP}" +export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${EXTERNAL_DNS:-${EXTERNAL_IP}}" +export ZITI_ROUTER_ADVERTISED_ADDRESS="${EXTERNAL_DNS:-${EXTERNAL_IP}}" +export ZITI_CTRL_ADVERTISED_PORT=8440 +export ZITI_CTRL_EDGE_ADVERTISED_PORT=8441 +export ZITI_ROUTER_PORT=8442 ``` -### Create Directory - -Create a directory where the network files will be stored. - -``` -mkdir -p "${ZITI_HOME}" -``` +### Create the Root Network Directory +The first task the expressInstall will perform is creating a directory where the network files will be stored. ### Obtain Ziti Binary -The ziti binary is required to set up the network. The `expressInstall` function will call `getZiti` to obtain the Ziti -binary. The `getZiti` function detects your OS type and architecture to craft the specific download URL for the binary. -The binary is downloaded, and extracted to the location specified by the `ZITI_BIN_DIR` environment variable. Visit the -[releases](https://github.com/openziti/ziti/releases) page to get the appropriate URL. +Next, the `expressInstall` function will call `getZiti` to obtain the Ziti binary. The `getZiti` function detects your +OS type and architecture to craft the specific download URL for the binary. The binary is downloaded, and extracted to +a directory within the Ziti Network directory. :::note -you don't have to always run expressInstall when running the quickstart. you can source the ziti-cli-function.sh file -and run getZiti to get the latest version of ziti installed quickly and easily +The quickstart script isn't limited to `expressInstall`. You can source the `ziti-cli-function.sh` file and run any of +the many helpful functions. For example, you can source the `ziti-cli-functions.sh` script and run `getZiti` to get +the latest version of ziti installed quickly and easily. ::: -``` -mkdir -p "${ZITI_BIN_DIR}" -curl -L -o "${ZITI_BIN_DIR}/ziti-bin.gz" -tar -xf "${ZITI_BIN_DIR}/ziti-bin.gz" --directory "${ZITI_BIN_DIR}" -chmod +x "${ZITI_BIN_DIR}/ziti" -``` - ## Create PKI -As part of the `expressInstall` a PKI is generated automatically. The following represents the process of generating -the PKI. The PKI consists of a root CA, three intermediate CAs (one for each of the controller's config sections. -Additionally, an extra intermediate CA is created on the signing cert to demonstrate that arbitrary cert chain lengths -are acceptable.) - -### Setup - -Set some initial environment variables for setting up the PKI. The `CA_NAME` values can be any name of your choosing. - -- `ZITI_PKI` is the directory where your PKI files will be stored -- `ZITI_ROOT_CA_NAME` is the name of the root CA. -- `ZITI_EXTERNAL_CA_INTERMEDIATE_NAME` is the name of an intermediate CA. -- `ZITI_CTRL_CA_NAME` is the name of the control plane CA. -- `ZITI_EDGE_CA_NAME` is the name of the HTTP API CA -- `ZITI_SIGN_CA_NAME` is the name of the signer CA used to sign identities created for the network. - -``` -export ZITI_PKI="${ZITI_HOME}/pki" -export ZITI_ROOT_CA_NAME="my.root.ca" -export ZITI_EXTERNAL_CA_INTERMEDIATE_NAME="intermediate.from.external.ca" -export ZITI_CTRL_CA_NAME="${ZITI_NETWORK}-network-components" -export ZITI_EDGE_CA_NAME="${ZITI_NETWORK}-edge" -export ZITI_SIGN_CA_NAME="${ZITI_NETWORK}-identities" -``` - -### Creating the Certificate Authorities - -The following creates all of the CAs and files using the environment variables set up previously. - -``` -"${ZITI_BIN_DIR}/ziti" pki create ca \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_ROOT_CA_NAME}" \ - --ca-file "${ZITI_ROOT_CA_NAME}" - -"${ZITI_BIN_DIR}/ziti" pki create intermediate \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_ROOT_CA_NAME}" \ - --intermediate-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ - --intermediate-file "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ - --max-path-len "2" - -"${ZITI_BIN_DIR}/ziti" pki create intermediate \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ - --intermediate-name "${ZITI_CTRL_CA_NAME}" \ - --intermediate-file "${ZITI_CTRL_CA_NAME}" \ - --max-path-len "1" - -"${ZITI_BIN_DIR}/ziti" pki create intermediate \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ - --intermediate-name "${ZITI_EDGE_CA_NAME}" \ - --intermediate-file "${ZITI_EDGE_CA_NAME}" \ - --max-path-len "1" - -"${ZITI_BIN_DIR}/ziti" pki create intermediate \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_EXTERNAL_CA_INTERMEDIATE_NAME}" \ - --intermediate-name "${ZITI_SIGN_CA_NAME}" \ - --intermediate-file "${ZITI_SIGN_CA_NAME}" \ - --max-path-len "1" -``` - -### Create Server and Client Certs for the Control Plane +As part of the `expressInstall` a PKI is generated automatically. The PKI consists of a root CA, four intermediate +CAs; one for each of the controller's config sections (control, edge/API, identity) and an arbitrary CA. Additionally, +an extra intermediate CA is created on the signing cert chain to demonstrate that arbitrary cert chain lengths +are acceptable. -Set up some initial values for the server and client certificates. +Once the CAs are generated, a key, server cert, and client cert are generated for each of the controller's config +sections. The following image represents the overall PKI architecture. -- `ZITI_NETWORK_COMPONENTS_PKI_NAME` is the key file name. -- `ZITI_NETWORK_COMPONENTS_ADDRESSES` is a comma-separated list of DNS names to add to the SANs. -- `ZITI_NETWORK_COMPONENTS_IPS` is a comma-separated list of IPs to add to the SANs. - -``` -ZITI_NETWORK_COMPONENTS_PKI_NAME="ziti.network.components" -ZITI_NETWORK_COMPONENTS_ADDRESSES="localhost,${ZITI_NETWORK},some.other.name,and.another.name" -ZITI_NETWORK_COMPONENTS_IPS="127.0.0.1,127.0.21.71,192.168.100.100" -``` - -Now we’ll create the key, client, and server certs for the control plane. - -``` -"${ZITI_BIN_DIR}/ziti" pki create key \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_CTRL_CA_NAME}" \ - --key-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" - -"${ZITI_BIN_DIR}/ziti" pki create server \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_CTRL_CA_NAME}" \ - --key-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" \ - --server-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}-server" \ - --server-name "${ZITI_NETWORK_COMPONENTS_PKI_NAME}-server" \ - --dns "${ZITI_NETWORK_COMPONENTS_ADDRESSES}" \ - --ip "${ZITI_NETWORK_COMPONENTS_IPS}" - -"${ZITI_BIN_DIR}/ziti" pki create client \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_CTRL_CA_NAME}" \ - --key-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" \ - --client-file "${ZITI_NETWORK_COMPONENTS_PKI_NAME}-client" \ - --client-name "${ZITI_NETWORK_COMPONENTS_PKI_NAME}" -``` - -### Create Server and Client Certs for the HTTP API - -Set up some initial values for the server and client certificates. As with the control plane, these are for the key file name, DNS, and IP SANs. The DNS and IP lists are reused from the control plane cert generation. - -``` -ZITI_EDGE_API_PKI_NAME="ziti.edge.controller" -ZITI_EDGE_API_ADDRESSES="${ZITI_NETWORK_COMPONENTS_ADDRESSES}" -ZITI_EDGE_API_IPS="${ZITI_NETWORK_COMPONENTS_IPS}" -``` - -Now we’ll create the key, client, and server certs for the HTTP API. - -``` -"${ZITI_BIN_DIR}/ziti" pki create key \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_EDGE_CA_NAME}" \ - --key-file "${ZITI_EDGE_API_PKI_NAME}" - -"${ZITI_BIN_DIR}/ziti" pki create server \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_EDGE_CA_NAME}" \ - --key-file "${ZITI_EDGE_API_PKI_NAME}" \ - --server-file "${ZITI_EDGE_API_PKI_NAME}-server" \ - --server-name "${ZITI_EDGE_API_PKI_NAME}-server" \ - --dns "${ZITI_EDGE_API_ADDRESSES}" \ - --ip "${ZITI_EDGE_API_IPS}" - -"${ZITI_BIN_DIR}/ziti" pki create client \ - --pki-root="${ZITI_PKI}" \ - --ca-name "${ZITI_EDGE_CA_NAME}" \ - --key-file "${ZITI_EDGE_API_PKI_NAME}" \ - --client-file "${ZITI_EDGE_API_PKI_NAME}-client" \ - --client-name "${ZITI_EDGE_API_PKI_NAME}" -``` +![quickstart-pki-full.png](./quickstart-pki-full.png) ### Update the CA Bundle The latest tunnelers require full and complete PKIs, not arbitrary trust anchors. Therefore, the root and intermediate -CAs must be added to the CA bundle. Additionally, the file is copied for the HTTP API CA bundle. +CAs must be added to the CA bundle. Additionally, the file is copied for the Edge/API CA bundle. ``` cat "${ZITI_PKI}/my.root.ca/certs/my.root.ca.cert" > "${ZITI_PKI}/${ZITI_NETWORK}-network-components/cas.pem" @@ -223,127 +95,24 @@ cat "${ZITI_PKI}/my.root.ca/certs/intermediate.from.external.ca.cert" >> "${ZITI cp "${ZITI_PKI}/${ZITI_NETWORK}-network-components/cas.pem" "${ZITI_PKI}/${ZITI_NETWORK}-edge/edge.cas.pem" ``` -## Create Controller - -### Setup - -Declare some environment variables used to generate the controller config file. Some environment variables used were already set previously. +## Controller Creation and Configuration -- `ZITI_CTRL_ADVERTISED_ADDRESS` is the address for the controller’s control plane -- `ZITI_CTRL_EDGE_ADVERTISED_ADDRESS` is the address for the HTTP API -- `ZITI_CTRL_ADVERTISED_PORT` is the port for the control plane -- `ZITI_CTRL_EDGE_ADVERTISED_PORT` is the port for the HTTP API +A controller configuration file is generated using the Ziti CLI binary. After the configuration is created, the +controller is initialized. The process of initialization initializes the database. -The following are locations of PKI files. +The controller is then started up and the quickstart waits for the controller to finish starting up before continuing +as the controller is necessary to create the Edge Router which is the next step. -- `ZITI_PKI_CTRL_KEY` -- `ZITI_PKI_CTRL_SERVER_CERT` -- `ZITI_PKI_CTRL_CERT` -- `ZITI_PKI_CTRL_CA` -- `ZITI_PKI_EDGE_KEY` -- `ZITI_PKI_EDGE_SERVER_CERT` -- `ZITI_PKI_EDGE_CERT` -- `ZITI_PKI_EDGE_CA` -- `ZITI_PKI_SIGNER_KEY` -- `ZITI_PKI_SIGNER_CERT` +## Default Policies -``` -export ZITI_CTRL_ADVERTISED_ADDRESS="${ZITI_NETWORK}" -export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${ZITI_NETWORK}" -export ZITI_CTRL_ADVERTISED_PORT=8440 -export ZITI_CTRL_EDGE_ADVERTISED_PORT=8441 +Two policies are generated to simplify the process of getting started with the network. An [Edge Router Policy](../../../core-concepts/security/authorization/policies/overview#edge-router-policies) +is created to allow all identities to connect to a router with a `#public` attribute. The router created during the +`expressInstall` is populated with this attribute. A [Service Edge Router Policy](../../../core-concepts/security/authorization/policies/overview#service-edge-router-policies) +is also created, allowing all services to use routers with the `#public` attribute. -export ZITI_PKI_CTRL_KEY="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/keys/${ZITI_NETWORK_COMPONENTS_PKI_NAME}.key" -export ZITI_PKI_CTRL_SERVER_CERT="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/certs/${ZITI_NETWORK_COMPONENTS_PKI_NAME}-server.chain.pem" -export ZITI_PKI_CTRL_CERT="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/certs/${ZITI_NETWORK_COMPONENTS_PKI_NAME}-client.cert" -export ZITI_PKI_CTRL_CA="${ZITI_PKI}/${ZITI_CTRL_CA_NAME}/cas.pem" +## Router Creating and Configuration -export ZITI_PKI_EDGE_KEY="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/keys/${ZITI_EDGE_API_PKI_NAME}.key" -export ZITI_PKI_EDGE_SERVER_CERT="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/certs/${ZITI_EDGE_API_PKI_NAME}-server.chain.pem" -export ZITI_PKI_EDGE_CERT="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/certs/${ZITI_EDGE_API_PKI_NAME}-client.cert" -export ZITI_PKI_EDGE_CA="${ZITI_PKI}/${ZITI_EDGE_CA_NAME}/edge.cas.pem" - -export ZITI_PKI_SIGNER_KEY="${ZITI_PKI}/${ZITI_SIGN_CA_NAME}/keys/${ZITI_SIGN_CA_NAME}.key" -export ZITI_PKI_SIGNER_CERT="${ZITI_PKI}/${ZITI_SIGN_CA_NAME}/certs/${ZITI_SIGN_CA_NAME}.chain.pem" -``` - -### Create the Controller Config File - -The controller config file is populated based on the values of environment variables set up to this point. - -``` -"${ZITI_BIN_DIR}/ziti" create config controller >${ZITI_HOME}/${ZITI_NETWORK}.yaml -``` - -### Initialize the Controller - -Initializing the controller initializes the database. - -``` -mkdir ${ZITI_HOME}/db -"${ZITI_BIN_DIR}/ziti" controller edge init "${ZITI_HOME}/${ZITI_NETWORK}.yaml" -u $ZITI_USER -p $ZITI_PWD -``` - -### Run the Controller - -``` -"${ZITI_BIN_DIR}/ziti" controller run ${ZITI_HOME}/${ZITI_NETWORK}.yaml &> ${ZITI_HOME}/${ZITI_NETWORK}.log & -``` - -### Wait for the Controller - -The controller is used to create the router identity and therefore, must be up and running, ready to receive commands. - -``` -while [[ "$(curl -w "%{http_code}" -m 1 -s -k -o /dev/null https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}/edge/client/v1/version)" != "200" ]]; do - echo "waiting for https://${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT}" - sleep 1 -done -``` - -## Create Router - -### Create the Router Config File - -Just as with the controller, we need to create a router config file. The router config also uses values set in environment variables up to this point. - -``` -"${ZITI_BIN_DIR}/ziti" create config router edge --routerName ${ZITI_NETWORK}-edge-router >${ZITI_HOME}/${ZITI_NETWORK}-edge-router.yaml -``` - -### Create the Router Entity - -The router needs to be created through the controller. This will generate a one-time token to be used during enrollment. - -``` -# We have to log in first -"${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y - -"${ZITI_BIN_DIR}/ziti" edge create edge-router ${ZITI_NETWORK}-edge-router -o ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.jwt -t -a public -``` - -### Enroll the Router with the Controller - -Enroll the router with the controller utilizing the config file and enrollment token previously generated. - -``` -"${ZITI_BIN_DIR}/ziti" router enroll ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.yaml --jwt ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.jwt -``` - -### Run the Router - -``` -"${ZITI_BIN_DIR}/ziti" router run "${ZITI_HOME}/${ZITI_NETWORK}-edge-router.yaml" &> ${ZITI_HOME}/${ZITI_NETWORK}-edge-router.log & -``` - -## Confirm the Network is Up - -Log in and run a command to list the edge routers and we should see a single edge router showing `ONLINE`. - -``` -# The session may have expired, log in just to be safe -"${ZITI_BIN_DIR}/ziti" edge login ${ZITI_CTRL_ADVERTISED_ADDRESS}:${ZITI_CTRL_EDGE_ADVERTISED_PORT} -u admin -p $ZITI_PWD -y -"${ZITI_BIN_DIR}/ziti" edge list edge-routers -``` +Just as with the controller, a config file is generated for the router. The router also needs to be created through the +controller. This will generate a one-time token (OTT) to be used during router enrollment. -![list-edge-routers.png](./list-edge-routers.png) \ No newline at end of file +The router is then enrolled using the router configuration along with the router's OTT. \ No newline at end of file From 128f459690dbf2680444c706d35e0bee9dc3c647 Mon Sep 17 00:00:00 2001 From: Geoff Berl Date: Wed, 6 Dec 2023 15:32:32 -0500 Subject: [PATCH 6/6] Addressed some comments, rearranged structure --- .../network/help/quickstart-walkthrough.md | 164 +++++++++--------- 1 file changed, 86 insertions(+), 78 deletions(-) diff --git a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md index fbda86009..603781211 100644 --- a/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md +++ b/docusaurus/docs/learn/quickstarts/network/help/quickstart-walkthrough.md @@ -2,91 +2,53 @@ title: Quickstart Walkthrough id: quickstart-walkthrough --- -This page is intended to explain the steps that happen automatically when the expressInstall function is executed. -The [Local - No Docker](../local-no-docker.md), -[Local - With Docker](../local-with-docker.md), -[Local - Docker Compose](../local-docker-compose.md), and -[Host OpenZiti Anywhere](../hosted.md) quickstarts all run the `expressInstall` -function. Each version varies slightly. This page will focus on the Host OpenZiti Anywhere quickstart. -## The General Process -1. Establish environment variables -2. Create a directory for network related files -3. Obtain the Ziti binary -4. Create a PKI -5. Create a Controller configuration -6. Initialize the Controller -7. Start the Controller -8. Create a Router configuration -9. Create a Router entity on the network (via the Controller) -10. Enroll the Router previously created -11. Add default Edge Router and Service Edge Router policies. - -## General Environment Setup - -### Declare Variables - -The first thing `expressInstall` will do is establish numerous environment variables used throughout the script. Some -important customizable variables are listed below. - -- `EXTERNAL_DNS` is the externally accessible DNS name. This value is also added to the PKI SANs DNS field. -- `EXTERNAL_IP` is the externally accessible IP address. This value is also added to the PKI SANs IP field -- `ZITI_CTRL_EDGE_IP_OVERRIDE` is a custom IP for the Ziti Controller. This value is added to the PKI SANs IP field for -the controller's edge PKI trust chain. -- `ZITI_ROUTER_IP_OVERRIDE` is a custom IP for the Ziti Router. -- `ZITI_CTRL_EDGE_ADVERTISED_ADDRESS` is the publicly accessible Controller address used for the Edge/API plane. -- `ZITI_ROUTER_ADVERTISED_ADDRESS` is the advertised address of the Ziti Router. This defaults to the value in -`EXTERNAL_DNS` if set. Otherwise, the value in `EXTERNAL_IP` is used. -- `ZITI_CTRL_ADVERTISED_PORT` is the port used for the Controller's control plane address. -- `ZITI_CTRL_EDGE_ADVERTISED_PORT` is the port used for the Controller's Edge/API plane address. -- `ZITI_ROUTER_PORT` is the port used for the Router's advertised address. +The following explains the steps that happen automatically when the expressInstall function is executed. +The [Local - No Docker](../local-no-docker.md), [Local - With Docker](../local-with-docker.md), +[Local - Docker Compose](../local-docker-compose.md), and [Host OpenZiti Anywhere](../hosted.md) quickstarts all run +the `expressInstall` function. Each version varies slightly. This page will focus on the +[Local - No Docker](../local-no-docker.md) quickstart. -:::note -It is highly recommended to use DNS over IP as this is a one time setup, if your IP changes, then your PKI is rendered -useless. -::: +## The General Process -``` -export EXTERNAL_DNS="acme.example.com" -export EXTERNAL_IP="$(curl -s eth0.me)" -export ZITI_CTRL_EDGE_IP_OVERRIDE="${EXTERNAL_IP}" -export ZITI_ROUTER_IP_OVERRIDE="${EXTERNAL_IP}" -export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${EXTERNAL_DNS:-${EXTERNAL_IP}}" -export ZITI_ROUTER_ADVERTISED_ADDRESS="${EXTERNAL_DNS:-${EXTERNAL_IP}}" -export ZITI_CTRL_ADVERTISED_PORT=8440 -export ZITI_CTRL_EDGE_ADVERTISED_PORT=8441 -export ZITI_ROUTER_PORT=8442 -``` +1. Obtain the OpenZiti binary +2. Create a PKI +3. Create a Controller configuration +4. Initialize the Controller +5. Start the Controller +6. Create a Router configuration +7. Create a Router entity on the network (via the Controller) +8. Enroll the Router previously created +9. Add default Edge Router and Service Edge Router policies. -### Create the Root Network Directory -The first task the expressInstall will perform is creating a directory where the network files will be stored. +## General Environment Setup -### Obtain Ziti Binary +### Obtain the OpenZiti Binary -Next, the `expressInstall` function will call `getZiti` to obtain the Ziti binary. The `getZiti` function detects your -OS type and architecture to craft the specific download URL for the binary. The binary is downloaded, and extracted to -a directory within the Ziti Network directory. +The `expressInstall` function will call `getZiti` to obtain the Ziti binary. The `getZiti` function detects your +OS type and architecture to craft the specific download URL for the binary. The binary is downloaded, and extracted to +a directory within the OpenZiti Network directory. :::note -The quickstart script isn't limited to `expressInstall`. You can source the `ziti-cli-function.sh` file and run any of -the many helpful functions. For example, you can source the `ziti-cli-functions.sh` script and run `getZiti` to get -the latest version of ziti installed quickly and easily. +The quickstart script isn't limited to `expressInstall`. You can source the `ziti-cli-function.sh` file and run any of +the many helpful functions. For example, you can run `getZiti` to get the latest version of OpenZiti downloaded quickly +and easily. ::: -## Create PKI +### Create a PKI -As part of the `expressInstall` a PKI is generated automatically. The PKI consists of a root CA, four intermediate -CAs; one for each of the controller's config sections (control, edge/API, identity) and an arbitrary CA. Additionally, +As part of the `expressInstall` a PKI is generated automatically. The PKI consists of a root CA, four intermediate +CAs; one for each of the controller's config sections (control, edge/API, identity) and an arbitrary CA. Additionally, an extra intermediate CA is created on the signing cert chain to demonstrate that arbitrary cert chain lengths are acceptable. -Once the CAs are generated, a key, server cert, and client cert are generated for each of the controller's config +Once the CAs are generated, a key, server cert, and client cert are generated for each of the controller's config sections. The following image represents the overall PKI architecture. ![quickstart-pki-full.png](./quickstart-pki-full.png) ### Update the CA Bundle -The latest tunnelers require full and complete PKIs, not arbitrary trust anchors. Therefore, the root and intermediate +The latest tunnelers require full and complete PKIs, not arbitrary trust anchors. Therefore, the root and intermediate CAs must be added to the CA bundle. Additionally, the file is copied for the Edge/API CA bundle. ``` @@ -95,24 +57,70 @@ cat "${ZITI_PKI}/my.root.ca/certs/intermediate.from.external.ca.cert" >> "${ZITI cp "${ZITI_PKI}/${ZITI_NETWORK}-network-components/cas.pem" "${ZITI_PKI}/${ZITI_NETWORK}-edge/edge.cas.pem" ``` -## Controller Creation and Configuration +### Controller Creation and Configuration -A controller configuration file is generated using the Ziti CLI binary. After the configuration is created, the -controller is initialized. The process of initialization initializes the database. +A controller configuration file is generated using the OpenZiti CLI binary. After the configuration is created, the +controller is initialized. The process of initialization also initializes the database. -The controller is then started up and the quickstart waits for the controller to finish starting up before continuing -as the controller is necessary to create the Edge Router which is the next step. +The controller is then started and the quickstart waits for the controller to finish starting up before continuing as +the controller is necessary to create the Edge Router which happens in the next steps. -## Default Policies +### Default Policies -Two policies are generated to simplify the process of getting started with the network. An [Edge Router Policy](../../../core-concepts/security/authorization/policies/overview#edge-router-policies) -is created to allow all identities to connect to a router with a `#public` attribute. The router created during the -`expressInstall` is populated with this attribute. A [Service Edge Router Policy](../../../core-concepts/security/authorization/policies/overview#service-edge-router-policies) +Two policies are generated to simplify the process of getting started with the network. +An [Edge Router Policy](../../../core-concepts/security/authorization/policies/overview#edge-router-policies) +is created to allow all identities to connect to a router with a `#public` attribute. The router created during the +`expressInstall` is populated with this attribute. +A [Service Edge Router Policy](../../../core-concepts/security/authorization/policies/overview#service-edge-router-policies) is also created, allowing all services to use routers with the `#public` attribute. -## Router Creating and Configuration +### Router Creating and Configuration -Just as with the controller, a config file is generated for the router. The router also needs to be created through the +Just as with the controller, a config file is generated for the router. The router also needs to be created through the controller. This will generate a one-time token (OTT) to be used during router enrollment. -The router is then enrolled using the router configuration along with the router's OTT. \ No newline at end of file +The router is then enrolled using the router configuration along with the router's OTT. + +## Customization + +The quickstart offers numerous environment variables for use in customizing your unique situation. Here is a list of +the most commonly used environment variables and their descriptions. + +By default, the quickstart PKI is set up with `127.0.0.1` as the default IP. The `*_IP_OVERRIDE` variables allow you +to add an IP the PKI will be valid for. + +- `ZITI_CTRL_EDGE_IP_OVERRIDE` an additional IP for the OpenZiti Controller. This value is added to the PKI SANs IP + field for + the controller's edge PKI trust chain. +- `ZITI_ROUTER_IP_OVERRIDE` is a custom IP for the OpenZiti Router. + +Here are a few more common variables. + +- `ZITI_CTRL_EDGE_ADVERTISED_ADDRESS` is the valid name for the Controller address used in the PKI. +- `ZITI_ROUTER_ADVERTISED_ADDRESS` is the advertised address of the OpenZiti Router. This defaults to the value in + `EXTERNAL_DNS` if set. Otherwise, the value in `EXTERNAL_IP` is used. +- `ZITI_CTRL_ADVERTISED_PORT` is the port used for the Controller's control plane address. +- `ZITI_CTRL_EDGE_ADVERTISED_PORT` is the port used for the Controller's Edge/API plane address. +- `ZITI_ROUTER_PORT` is the port used for the Router's advertised address. + +The following are PKI related customization variables +:::caution PKI Generation Only Happens Once +It is extremely important that quickstart has the relevant information to set up your PKI. This generation is only +performed once so, if it is incorrect, the entire PKI needs to be regenerated. +::: +:::caution DNS is Preferred Over IP +It is highly recommended to use DNS over IP as this is a one time setup, if your IP changes, then your PKI is rendered +useless. +::: + +``` +export EXTERNAL_DNS="acme.example.com" +export EXTERNAL_IP="$(curl -s eth0.me)" +export ZITI_CTRL_EDGE_IP_OVERRIDE="${EXTERNAL_IP}" +export ZITI_ROUTER_IP_OVERRIDE="${EXTERNAL_IP}" +export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${EXTERNAL_DNS:-${EXTERNAL_IP}}" +export ZITI_ROUTER_ADVERTISED_ADDRESS="${EXTERNAL_DNS:-${EXTERNAL_IP}}" +export ZITI_CTRL_ADVERTISED_PORT=8440 +export ZITI_CTRL_EDGE_ADVERTISED_PORT=8441 +export ZITI_ROUTER_PORT=8442 +```