mirror of
https://github.com/openziti/zrok.git
synced 2024-12-22 06:40:50 +01:00
Merge remote-tracking branch 'origin/main' into node-sdk
This commit is contained in:
commit
240fadfa4b
3
.flake8
Normal file
3
.flake8
Normal file
@ -0,0 +1,3 @@
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
exclude = zrok_api, build
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
77
.github/workflows/build-wheels.yml
vendored
Normal file
77
.github/workflows/build-wheels.yml
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
name: build wheels
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
build_wheels:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: sdk/python/sdk/zrok
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
spec:
|
||||
- { name: 'linux x86_64', runner: ubuntu-20.04, target: manylinux_2_27_x86_64 }
|
||||
- { name: 'macOS x86_64', runner: macos-11, target: macosx_10_14_x86_64 }
|
||||
- { name: 'Windows x86_64', runner: windows-2019, target: win_amd64 }
|
||||
name: building ${{ matrix.spec.name }}
|
||||
runs-on: ${{ matrix.spec.runner }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Python Tools
|
||||
run: python -m pip install -U pip setuptools
|
||||
|
||||
- name: Build distro
|
||||
env:
|
||||
ZROK_VERSION: ${{ github.event.release.tag_name }}
|
||||
ZROK_PY_NAME: ${{ vars.ZROK_PY_NAME || null }}
|
||||
run: |
|
||||
python setup.py sdist
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: startsWith(matrix.spec.name, 'linux')
|
||||
with:
|
||||
name: zrok_sdk
|
||||
path: ${{ github.workspace }}/sdk/python/sdk/zrok/dist/*
|
||||
|
||||
publish:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [ build_wheels ]
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: download
|
||||
|
||||
- name: check
|
||||
run: |
|
||||
ls -lR download
|
||||
mkdir dist
|
||||
cp download/*/* dist
|
||||
|
||||
- name: Publish wheels (TestPYPI)
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
packages_dir: dist
|
||||
skip_existing: true
|
||||
verbose: true
|
||||
|
||||
- name: Publish wheels (PyPI)
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages_dir: dist
|
||||
verbose: true
|
13
.github/workflows/ci-build.yml
vendored
13
.github/workflows/ci-build.yml
vendored
@ -51,6 +51,19 @@ jobs:
|
||||
shell: bash
|
||||
run: go test -v ./...
|
||||
|
||||
- name: setup python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: python deps
|
||||
shell: bash
|
||||
run: python -m pip install -U pip flake8
|
||||
|
||||
- name: python lint
|
||||
shell: bash
|
||||
run: flake8 sdk/python/sdk/zrok
|
||||
|
||||
- name: solve GOBIN
|
||||
id: solve_go_bin
|
||||
shell: bash
|
||||
|
94
.github/workflows/deploy-doc-site.yml
vendored
94
.github/workflows/deploy-doc-site.yml
vendored
@ -1,47 +1,47 @@
|
||||
name: Deploy Doc Site
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# allow GITHUB_TOKEN to be used by the peaceiris/actions-gh-pages action to push to gh-pages branch
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
name: setup npm
|
||||
with:
|
||||
node-version: 16
|
||||
check-latest: true
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
|
||||
- name: Run a multi-line script
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: website
|
||||
|
||||
# Popular action to deploy to GitHub Pages:
|
||||
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Build output to publish to the `gh-pages` branch:
|
||||
publish_dir: ./website/build
|
||||
# The following lines assign commit authorship to the official
|
||||
# GH-Actions bot for deploys to `gh-pages` branch:
|
||||
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
|
||||
# The GH actions bot is used by default if you didn't specify the two fields.
|
||||
# You can swap them out with your own user credentials.
|
||||
#user_name: github-actions[bot]
|
||||
#user_email: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
name: Deploy Doc Site
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# allow GITHUB_TOKEN to be used by the peaceiris/actions-gh-pages action to push to gh-pages branch
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
name: setup npm
|
||||
with:
|
||||
node-version: 18
|
||||
check-latest: true
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
|
||||
- name: Run a multi-line script
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
working-directory: website
|
||||
|
||||
# Popular action to deploy to GitHub Pages:
|
||||
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Build output to publish to the `gh-pages` branch:
|
||||
publish_dir: ./website/build
|
||||
# The following lines assign commit authorship to the official
|
||||
# GH-Actions bot for deploys to `gh-pages` branch:
|
||||
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
|
||||
# The GH actions bot is used by default if you didn't specify the two fields.
|
||||
# You can swap them out with your own user credentials.
|
||||
#user_name: github-actions[bot]
|
||||
#user_email: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
|
7
.github/workflows/publish-docker-images.yml
vendored
7
.github/workflows/publish-docker-images.yml
vendored
@ -72,11 +72,12 @@ jobs:
|
||||
|
||||
- name: Set Up Container Image Tags for zrok CLI Container
|
||||
env:
|
||||
RELEASE_REPO: openziti/zrok
|
||||
ZROK_VERSION: ${{ steps.semver.outputs.zrok_semver }}
|
||||
ZROK_CONTAINER_IMAGE_REPO: ${{ vars.ZROK_CONTAINER_IMAGE_REPO || 'openziti/zrok' }}
|
||||
ZROK_CONTAINER_IMAGE_TAG: ${{ steps.semver.outputs.zrok_semver }}
|
||||
id: tagprep_cli
|
||||
run: |
|
||||
echo DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest" | tee -a $GITHUB_OUTPUT
|
||||
echo DOCKER_TAGS="${ZROK_CONTAINER_IMAGE_REPO}:${ZROK_CONTAINER_IMAGE_TAG},${ZROK_CONTAINER_IMAGE_REPO}:latest" \
|
||||
| tee -a $GITHUB_OUTPUT
|
||||
|
||||
# this is the CLI image with the Linux binary for each
|
||||
# arch that was downloaded in ./dist/
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -16,6 +16,8 @@ dist/
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
|
||||
sdk/python/sdk/build/
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
@ -24,7 +26,10 @@ dist/
|
||||
.env.production.local
|
||||
go.work
|
||||
go.work.sum
|
||||
zrok-venv
|
||||
|
||||
# cache used by local dev cross-build script
|
||||
/.npm
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
256
.markdownlint.yaml
Normal file
256
.markdownlint.yaml
Normal file
@ -0,0 +1,256 @@
|
||||
# Example markdownlint YAML configuration with all properties set to their default value
|
||||
|
||||
# Default state for all rules
|
||||
default: true
|
||||
|
||||
# Path to configuration file to extend
|
||||
extends: null
|
||||
|
||||
# MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time
|
||||
MD001: true
|
||||
|
||||
# deprecated in favor of MD041
|
||||
# MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading
|
||||
|
||||
# MD003/heading-style/header-style - Heading style
|
||||
MD003:
|
||||
# Heading style
|
||||
style: "consistent"
|
||||
|
||||
# MD004/ul-style - Unordered list style
|
||||
MD004:
|
||||
# List style
|
||||
style: "consistent"
|
||||
|
||||
# MD005/list-indent - Inconsistent indentation for list items at the same level
|
||||
MD005: true
|
||||
|
||||
# MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line
|
||||
MD006: true
|
||||
|
||||
# MD007/ul-indent - Unordered list indentation
|
||||
MD007:
|
||||
# Spaces for indent
|
||||
indent: 2
|
||||
# Whether to indent the first level of the list
|
||||
start_indented: false
|
||||
# Spaces for first level indent (when start_indented is set)
|
||||
start_indent: 2
|
||||
|
||||
# MD009/no-trailing-spaces - Trailing spaces
|
||||
MD009: false
|
||||
# # Spaces for line break
|
||||
# br_spaces: 2
|
||||
# # Allow spaces for empty lines in list items
|
||||
# list_item_empty_lines: false
|
||||
# # Include unnecessary breaks
|
||||
# strict: false
|
||||
|
||||
# MD010/no-hard-tabs - Hard tabs
|
||||
MD010:
|
||||
# Include code blocks
|
||||
code_blocks: true
|
||||
# Fenced code languages to ignore
|
||||
ignore_code_languages: []
|
||||
# Number of spaces for each hard tab
|
||||
spaces_per_tab: 1
|
||||
|
||||
# MD011/no-reversed-links - Reversed link syntax
|
||||
MD011: true
|
||||
|
||||
# MD012/no-multiple-blanks - Multiple consecutive blank lines
|
||||
MD012:
|
||||
# Consecutive blank lines
|
||||
maximum: 1
|
||||
|
||||
# MD013/line-length - Line length
|
||||
line_length: false
|
||||
# MD013:
|
||||
# # Number of characters
|
||||
# line_length: 80
|
||||
# # Number of characters for headings
|
||||
# heading_line_length: 80
|
||||
# # Number of characters for code blocks
|
||||
# code_block_line_length: 80
|
||||
# # Include code blocks
|
||||
# code_blocks: true
|
||||
# # Include tables
|
||||
# tables: true
|
||||
# # Include headings
|
||||
# headings: true
|
||||
# # Include headings
|
||||
# headers: true
|
||||
# # Strict length checking
|
||||
# strict: false
|
||||
# # Stern length checking
|
||||
# stern: false
|
||||
|
||||
# MD014/commands-show-output - Dollar signs used before commands without showing output
|
||||
MD014: true
|
||||
|
||||
# MD018/no-missing-space-atx - No space after hash on atx style heading
|
||||
MD018: true
|
||||
|
||||
# MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading
|
||||
MD019: true
|
||||
|
||||
# MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading
|
||||
MD020: true
|
||||
|
||||
# MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading
|
||||
MD021: true
|
||||
|
||||
# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines
|
||||
MD022:
|
||||
# Blank lines above heading
|
||||
lines_above: 1
|
||||
# Blank lines below heading
|
||||
lines_below: 1
|
||||
|
||||
# MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line
|
||||
MD023: true
|
||||
|
||||
# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
|
||||
MD024:
|
||||
# Only check sibling headings
|
||||
allow_different_nesting: false
|
||||
# Only check sibling headings
|
||||
siblings_only: false
|
||||
|
||||
# MD025/single-title/single-h1 - Multiple top-level headings in the same document
|
||||
MD025:
|
||||
# Heading level
|
||||
level: 1
|
||||
# RegExp for matching title in front matter
|
||||
front_matter_title: "^\\s*title\\s*[:=]"
|
||||
|
||||
# MD026/no-trailing-punctuation - Trailing punctuation in heading
|
||||
MD026:
|
||||
# Punctuation characters
|
||||
punctuation: ".,;:!。,;:!"
|
||||
|
||||
# MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol
|
||||
MD027: true
|
||||
|
||||
# MD028/no-blanks-blockquote - Blank line inside blockquote
|
||||
MD028: true
|
||||
|
||||
# MD029/ol-prefix - Ordered list item prefix
|
||||
MD029:
|
||||
# List style
|
||||
style: "one_or_ordered"
|
||||
|
||||
# MD030/list-marker-space - Spaces after list markers
|
||||
MD030:
|
||||
# Spaces for single-line unordered list items
|
||||
ul_single: 1
|
||||
# Spaces for single-line ordered list items
|
||||
ol_single: 1
|
||||
# Spaces for multi-line unordered list items
|
||||
ul_multi: 1
|
||||
# Spaces for multi-line ordered list items
|
||||
ol_multi: 1
|
||||
|
||||
# MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines
|
||||
MD031:
|
||||
# Include list items
|
||||
list_items: true
|
||||
|
||||
# MD032/blanks-around-lists - Lists should be surrounded by blank lines
|
||||
MD032: true
|
||||
|
||||
# MD033/no-inline-html - Inline HTML
|
||||
MD033:
|
||||
# Allowed elements
|
||||
allowed_elements: []
|
||||
|
||||
# MD034/no-bare-urls - Bare URL used
|
||||
MD034: true
|
||||
|
||||
# MD035/hr-style - Horizontal rule style
|
||||
MD035:
|
||||
# Horizontal rule style
|
||||
style: "consistent"
|
||||
|
||||
# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading
|
||||
MD036:
|
||||
# Punctuation characters
|
||||
punctuation: ".,;:!?。,;:!?"
|
||||
|
||||
# MD037/no-space-in-emphasis - Spaces inside emphasis markers
|
||||
MD037: true
|
||||
|
||||
# MD038/no-space-in-code - Spaces inside code span elements
|
||||
MD038: true
|
||||
|
||||
# MD039/no-space-in-links - Spaces inside link text
|
||||
MD039: true
|
||||
|
||||
# MD040/fenced-code-language - Fenced code blocks should have a language specified
|
||||
MD040: true
|
||||
|
||||
# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading
|
||||
MD041:
|
||||
# Heading level
|
||||
level: 1
|
||||
# RegExp for matching title in front matter
|
||||
front_matter_title: "^\\s*title\\s*[:=]"
|
||||
|
||||
# MD042/no-empty-links - No empty links
|
||||
MD042: true
|
||||
|
||||
# disabled because many Markdown files are partials without headings and intended for transclusion
|
||||
# MD043/required-headings/required-headers - Required heading structure
|
||||
# MD043:
|
||||
# # List of headings
|
||||
# headings: []
|
||||
# # List of headings
|
||||
# headers: []
|
||||
|
||||
# MD044/proper-names - Proper names should have the correct capitalization
|
||||
MD044:
|
||||
# List of proper names
|
||||
names: []
|
||||
# Include code blocks
|
||||
code_blocks: true
|
||||
# Include HTML elements
|
||||
html_elements: true
|
||||
|
||||
# MD045/no-alt-text - Images should have alternate text (alt text)
|
||||
MD045: true
|
||||
|
||||
# MD046/code-block-style - Code block style
|
||||
MD046:
|
||||
# Block style
|
||||
style: "consistent"
|
||||
|
||||
# MD047/single-trailing-newline - Files should end with a single newline character
|
||||
MD047: true
|
||||
|
||||
# MD048/code-fence-style - Code fence style
|
||||
MD048:
|
||||
# Code fence style
|
||||
style: "consistent"
|
||||
|
||||
# MD049/emphasis-style - Emphasis style should be consistent
|
||||
MD049:
|
||||
# Emphasis style should be consistent
|
||||
style: "consistent"
|
||||
|
||||
# MD050/strong-style - Strong style should be consistent
|
||||
MD050:
|
||||
# Strong style should be consistent
|
||||
style: "consistent"
|
||||
|
||||
# MD051/link-fragments - Link fragments should be valid
|
||||
MD051: true
|
||||
|
||||
# MD052/reference-links-images - Reference links and images should use a label that is defined
|
||||
MD052: true
|
||||
|
||||
# MD053/link-image-reference-definitions - Link and image reference definitions should be needed
|
||||
MD053:
|
||||
# Ignored definitions
|
||||
ignored_definitions: [
|
||||
"//"
|
||||
]
|
92
ACKNOWLEDGEMENTS.md
Normal file
92
ACKNOWLEDGEMENTS.md
Normal file
@ -0,0 +1,92 @@
|
||||
# ACKNOWLEDGEMENTS
|
||||
|
||||
## github.com/openziti/zrok/endpoints/socks
|
||||
|
||||
Portions of the `socks` package is based on code from `https://github.com/tailscale/tailscale/blob/v1.58.2/net/socks5/socks5.go`, which included the following license:
|
||||
|
||||
> BSD 3-Clause License
|
||||
>
|
||||
> Copyright (c) 2020 Tailscale Inc & AUTHORS.
|
||||
>
|
||||
> Redistribution and use in source and binary forms, with or without
|
||||
> modification, are permitted provided that the following conditions are met:
|
||||
>
|
||||
> 1. Redistributions of source code must retain the above copyright notice, this
|
||||
> list of conditions and the following disclaimer.
|
||||
>
|
||||
> 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
> this list of conditions and the following disclaimer in the documentation
|
||||
> and/or other materials provided with the distribution.
|
||||
>
|
||||
> 3. Neither the name of the copyright holder nor the names of its
|
||||
> contributors may be used to endorse or promote products derived from
|
||||
> this software without specific prior written permission.
|
||||
>
|
||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## github.com/openziti/zrok/drives/davServer
|
||||
|
||||
The `davServer` package is based on code from `https://cs.opensource.google/go/go/`, which included the following license:
|
||||
|
||||
> Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
>
|
||||
> Redistribution and use in source and binary forms, with or without
|
||||
> modification, are permitted provided that the following conditions are
|
||||
> met:
|
||||
>
|
||||
> * Redistributions of source code must retain the above copyright
|
||||
> notice, this list of conditions and the following disclaimer.
|
||||
> * Redistributions in binary form must reproduce the above
|
||||
> copyright notice, this list of conditions and the following disclaimer
|
||||
> in the documentation and/or other materials provided with the
|
||||
> distribution.
|
||||
> * Neither the name of Google Inc. nor the names of its
|
||||
> contributors may be used to endorse or promote products derived from
|
||||
> this software without specific prior written permission.
|
||||
>
|
||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
> A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
> OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
> SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
> LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
> DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
> THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||
|
||||
## github.com/openziti/zrok/drives/davClient
|
||||
|
||||
The `davClient` package is based on code from `github.com/emersion/go-webdav`, which included the following license:
|
||||
|
||||
> The MIT License (MIT)
|
||||
>
|
||||
> Copyright (c) 2020 Simon Ser
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all
|
||||
> copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
> SOFTWARE.
|
122
CHANGELOG.md
122
CHANGELOG.md
@ -1,5 +1,127 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.4.27
|
||||
|
||||
CHANGE: Update to OpenZiti SDK (`github.com/openziti/sdk-golang`) at `v0.23.10`.
|
||||
|
||||
FIX: Also update the Python SDK to include the permission mode and access grants fields on the `ShareRequest` (https://github.com/openziti/zrok/issues/432)
|
||||
|
||||
FIX: Add a way to find the username on Linux when /etc/passwd and stdlib can't resolve the UID (https://github.com/openziti/zrok/issues/454)
|
||||
|
||||
## v0.4.26
|
||||
|
||||
FEATURE: New _permission modes_ available for shares. _Open permission mode_ retains the behavior of previous zrok releases and is the default setting. _Closed permission mode_ (`--closed`) only allows a share to be accessed (`zrok access`) by users who have been granted access with the `--access-grant` flag. See the documentation at (https://docs.zrok.io/docs/guides/permission-modes/) (https://github.com/openziti/zrok/issues/432)
|
||||
|
||||
CHANGE: The target for a `socks` share is automatically set to `socks` to improve web console display.
|
||||
|
||||
CHANGE: Enhancements to the look and feel of the account actions tab in the web console. Textual improvements.
|
||||
|
||||
FIX: The regenerate account token dialog incorrectly specified the path `${HOME}/.zrok/environments.yml`. This, was corrected to be `${HOME}/.zrok/environments.json`.
|
||||
|
||||
FIX: Align zrok frontdoor examples and Linux package (`zrok-share`) with the new OAuth email flag `--oauth-email-address-patterns` introduced in v0.4.25.
|
||||
|
||||
FIX: Reloading the web console when logged in no longer provokes the user to the login page.
|
||||
|
||||
## v0.4.25
|
||||
|
||||
FEATURE: New action in the web console that allows changing the password of the logged-in account (https://github.com/openziti/zrok/issues/148)
|
||||
|
||||
FEATURE: The web console now supports revoking your current account token and generating a new one (https://github.com/openziti/zrok/issues/191)
|
||||
|
||||
CHANGE: When specifying OAuth configuration for public shares from the `zrok share public` or `zrok reserve` public commands, the flags and functionality for restricting the allowed email addresses of the authenticating users has changed. The old flag was `--oauth-email-domains`, which took a string value that needed to be contained in the user's email address. The new flag is `--oauth-email-address-patterns`, which accepts a glob-style filter, using https://github.com/gobwas/glob (https://github.com/openziti/zrok/issues/413)
|
||||
|
||||
CHANGE: Creating a reserved share checks for token collision and returns a more appropriate error message (https://github.com/openziti/zrok/issues/531)
|
||||
|
||||
CHANGE: Update UI to add a 'true' value on `reserved` boolean (https://github.com/openziti/zrok/issues/443)
|
||||
|
||||
CHANGE: OpenZiti SDK (github.com/openziti/sdk-golang) updated to version `v0.22.29`, which introduces changes to OpenZiti API session handling
|
||||
|
||||
FIX: Fixed bug where a second password reset request would for any account would fail (https://github.com/openziti/zrok/issues/452)
|
||||
|
||||
## v0.4.24
|
||||
|
||||
FEATURE: New `socks` backend mode for use with private sharing. Use `zrok share private --backend-mode socks` and then `zrok access private` that share from somewhere else... very lightweight VPN-like functionality (https://github.com/openziti/zrok/issues/558)
|
||||
|
||||
FEATURE: New `zrok admin create account` command that allows populating accounts directly into the underlying controller database (https://github.com/openziti/zrok/issues/551)
|
||||
|
||||
CHANGE: The `zrok test loopback public` utility to report non-`200` errors and also ensure that the listening side of the test is fully established before starting loopback testing.
|
||||
|
||||
CHANGE: The OpenZiti SDK for golang (https://github.com/openziti/sdk-golang) has been updated to version `v0.22.28`
|
||||
|
||||
## v0.4.23
|
||||
|
||||
FEATURE: New CLI commands have been implemented for working with the `drive` share backend mode (part of the "zrok Drives" functionality). These commands include `zrok cp`, `zrok mkdir` `zrok mv`, `zrok ls`, and `zrok rm`. These are initial, minimal versions of these commands and very likely contain bugs and ergonomic annoyances. There is a guide available at (`docs/guides/drives/cli.md`) that explains how to work with these tools in detail (https://github.com/openziti/zrok/issues/438)
|
||||
|
||||
FEATURE: Python SDK now has a decorator for integrating with various server side frameworks. See the `http-server` example.
|
||||
|
||||
FEATURE: Python SDK share and access handling now supports context management.
|
||||
|
||||
FEATURE: TLS for `zrok` controller and frontends. Add the `tls:` stanza to your controller configuration (see `etc/ctrl.yml`) to enable TLS support for the controller API. Add the `tls:` stanza to your frontend configuration (see `etc/frontend.yml`) to enable TLS support for frontends (be sure to check your `public` frontend template) (#24)(https://github.com/openziti/zrok/issues/24)
|
||||
|
||||
CHANGE: Improved OpenZiti resource cleanup resilience. Previous resource cleanup would stop when an error was encountered at any stage of the cleanup process (serps, sps, config, service). New cleanup implementation logs errors but continues to clean up anything that it can (https://github.com/openziti/zrok/issues/533)
|
||||
|
||||
CHANGE: Instead of setting the `ListenOptions.MaxConnections` property to `64`, use the default value of `3`. This property actually controls the number of terminators created on the underlying OpenZiti network. This property is actually getting renamed to `ListenOptions.MaxTerminators` in an upcoming release of `github.com/openziti/sdk-golang` (https://github.com/openziti/zrok/issues/535)
|
||||
|
||||
CHANGE: Versioning for the Python SDK has been updated to use versioneer for management.
|
||||
|
||||
CHANGE: Python SDK package name has been renamed to `zrok`, dropping the `-sdk` postfix. [pypi](https://pypi.org/project/zrok).
|
||||
|
||||
## v0.4.22
|
||||
|
||||
FIX: The goreleaser action is not updated to work with the latest golang build. Modifed `go.mod` to comply with what goreleaser expects
|
||||
|
||||
## v0.4.21
|
||||
|
||||
FEATURE: The web console now supports deleting `zrok access` frontends (https://github.com/openziti/zrok/issues/504)
|
||||
|
||||
CHANGE: The web console now displays the frontend token as the label for any `zrok access` frontends throughout the user interface (https://github.com/openziti/zrok/issues/504)
|
||||
|
||||
CHANGE: Updated `github.com/rubenv/sql-migrate` to `v1.6.0`
|
||||
|
||||
CHANGE: Updated `github.com/openziti/sdk-golang` to `v0.22.6`
|
||||
|
||||
FIX: The migration `sqlite3/015_v0_4_19_share_unique_name_constraint.sql` has been adjusted to delete the old `shares_old` table as the last step of the migration process. Not sure exactly why, but SQLite is unhappy otherwise (https://github.com/openziti/zrok/issues/504)
|
||||
|
||||
FIX: Email addresses have been made case-insensitive. Please note that there is a migration included in this release (`016_v0_4_21_lowercase_email.sql`) which will attempt to ensure that all email addresses in your existing database are stored in lowercase; **if this migration fails you will need to manually remediate the duplicate account entries** (https://github.com/openziti/zrok/issues/517)
|
||||
|
||||
FIX: Stop sending authentication cookies to non-authenticated shares (https://github.com/openziti/zrok/issues/512)
|
||||
|
||||
## v0.4.20
|
||||
|
||||
CHANGE: OpenZiti SDK updated to `v0.21.2`. All `ziti.ListenOptions` listener options configured to use `WaitForNEstablishedListeners: 1`. When a `zrok share` client or an `sdk.Share` client are connected to an OpenZiti router that supports "listener established" events, then listen calls will not return until the listener is fully established on the OpenZiti network. Previously a `zrok share` client could report that it is fully operational and listening before the listener is fully established on the OpenZiti network; in practice this produced a very small window of time when the share would not be ready to accept requests. This change eliminates this window of time (https://github.com/openziti/zrok/issues/490)
|
||||
|
||||
FIX: Require the JWT in a zrok OAuth cookie to have an audience claim that matches the public share hostname. This prevents a cookie from one share from being use to log in to another share.
|
||||
|
||||
## v0.4.19
|
||||
|
||||
FEATURE: Reserved shares now support unique names ("vanity tokens"). This allows for the creation of reserved shares with identifiable names rather than generated share tokens. Includes basic support for profanity checking (https://github.com/openziti/zrok/issues/401)
|
||||
|
||||
CHANGE: The `publicProxy` endpoint implementation used in the `zrok access public` frontend has been updated to use the new `RefreshService(serviceName)` call instead of `RefreshServices()`. This should greatly improve the performance of requests against missing or non-responsive zrok shares (https://github.com/openziti/zrok/issues/487)
|
||||
|
||||
CHANGE: The Python SDK has been updated to properly support the "reserved" flag on the `ShareRequest` passed to `CreateShare`
|
||||
|
||||
CHANGE: Dependency updates; `github.com/openziti/sdk-golang@v0.20.145`; `github.com/caddyserver/caddy/v2@2.7.6`; indirect dependencies
|
||||
|
||||
## v0.4.18
|
||||
|
||||
FEATURE: Python SDK added. Can be found on [pypi](https://test.pypi.org/project/zrok-sdk). `pastebin` example illustrates basic SDK usage (see `sdk/python/examples/README.md` for details) (https://github.com/openziti/zrok/issues/401)
|
||||
|
||||
CHANGE: Moved the golang zrok sdk into `sdk/golang/sdk` to normalize location for future SDK's.
|
||||
|
||||
CHANGE: add restart policies to docker compose samples used by the guide docs, e.g., reserved public share should auto-start on boot, temp public share should not.
|
||||
|
||||
## v0.4.17
|
||||
|
||||
CHANGE: Replaced most in-line shell scripts in Docker Compose projects with installed scripts that are shared between the Docker and Linux service. This normalizes the operational configuration of both Docker shares and Linux service, i.e., to use the same env vars.
|
||||
|
||||
CHANGE: Upgrade to Docusaurus v3 for documentation.
|
||||
|
||||
FIX: Some Docker shares had broken env mountpoints
|
||||
|
||||
## v0.4.16
|
||||
|
||||
FEATURE: Publish Linux packages for `zrok` CLI and a systemd service for running a reserved public share (`zrok-share`).
|
||||
|
||||
## v0.4.15
|
||||
|
||||
CHANGE: Updated the code signing and notarization process for macos binaries. The previous release process used the `gon` utility to handle both code signing and notarization. Apple changed the requirements and the `gon` utility no longer properly functions as of 2023-11-01. The `goreleaser` process has been adjusted to use the `notarytool` utility that ships with XCode to sign and notarize the binary (https://github.com/openziti/zrok/issues/435)
|
||||
|
@ -4,3 +4,52 @@ NetFoundry welcomes all and any contributions. All open source projects managed
|
||||
[guide for contributions](https://netfoundry.github.io/policies/CONTRIBUTING.html).
|
||||
|
||||
If you are eager to contribute to a NetFoundry-managed open source project please read and act accordingly.
|
||||
|
||||
## Project Styles
|
||||
|
||||
This project uses several programming languages. Each language has its own style guide specifying any language-specific
|
||||
conventions and idioms. The log formatting examples for Go are applicable to all languages.
|
||||
|
||||
### Markdown
|
||||
|
||||
+ This project uses [GitHub Flavored Markdown](https://github.github.com/gfm/).
|
||||
+ Wrap lines at 120 characters if the audience is expected to read the source.
|
||||
+ Do not wrap lines if the audience is expected to read the rendered output as HTML.
|
||||
+ Use [Markdownlint](https://github.com/DavidAnson/markdownlint) with [the configuration file](.markdownlint.yaml) committed to this repository to find formatting problems.
|
||||
|
||||
### Go
|
||||
|
||||
+ This project uses [Go](https://golang.org/) language conventions.
|
||||
+ Organize imports as a single block in alphabetical order without empty lines.
|
||||
+ Begin log messages with a lowercase letter and do not end with punctuation. This log formatting guidance applies to all languages, not only Go.
|
||||
|
||||
Format log messages that report errors.
|
||||
|
||||
```go
|
||||
logrus.Errorf("tried a thing and failed: %v", err)
|
||||
```
|
||||
|
||||
Format in-line information in informational log messages.
|
||||
|
||||
```go
|
||||
logrus.Infof("the expected value '%v' arrived as '%v'", expected, actual)
|
||||
```
|
||||
|
||||
Format in-line information in error log messages.
|
||||
|
||||
```go
|
||||
logrus.Errorf("the expected value '%v did not compute: %v", value, err)
|
||||
```
|
||||
|
||||
+ Format log messages with format strings and arguments like 'tried a thing and failed: %s'.
|
||||
|
||||
### Python
|
||||
|
||||
+ This project uses [Python](https://www.python.org/) language conventions PEP-8.
|
||||
+ Use [flake8](https://flake8.pycqa.org/en/latest/) with [the configuration file](.flake8) committed to this repository to find formatting problems.
|
||||
+ Use Go log formatting guidance for Python too.
|
||||
|
||||
### Docusaurus
|
||||
|
||||
+ This project uses [Docusaurus](https://docusaurus.io/) with NodeJS 18 to build static content for docs.zrok.io.
|
||||
+ Use `npm` to manage Node modules, not `yarn` (Ken plans to switch from `npm` to `yarn` if no one else does).
|
||||
|
@ -11,6 +11,10 @@ command -v openapi >/dev/null 2>&1 || {
|
||||
echo >&2 "command 'openapi' not installed. see: https://www.npmjs.com/package/openapi-client for installation"
|
||||
}
|
||||
|
||||
command -v swagger-codegen 2>&1 || {
|
||||
echo >&2 "command 'swagger-codegen. see: https://github.com/swagger-api/swagger-codegen for installation"
|
||||
}
|
||||
|
||||
scriptPath=$(realpath $0)
|
||||
scriptDir=$(dirname "$scriptPath")
|
||||
|
||||
@ -18,6 +22,8 @@ zrokDir=$(realpath "$scriptDir/..")
|
||||
|
||||
zrokSpec=$(realpath "$zrokDir/specs/zrok.yml")
|
||||
|
||||
pythonConfig=$(realpath "$zrokDir/bin/python_config.json")
|
||||
|
||||
echo "...generating zrok server"
|
||||
swagger generate server -P rest_model_zrok.Principal -f "$zrokSpec" -s rest_server_zrok -t "$zrokDir" -m "rest_model_zrok" --exclude-main
|
||||
|
||||
@ -30,4 +36,7 @@ openapi -s specs/zrok.yml -o ui/src/api -l js
|
||||
echo "...generating ts client"
|
||||
openapi-generator-cli generate -i specs/zrok.yml -o sdk/node/sdk/src/zrok/api -g typescript-node
|
||||
|
||||
echo "...generating python client"
|
||||
swagger-codegen generate -i specs/zrok.yml -o sdk/python/sdk/zrok -c $pythonConfig -l python
|
||||
|
||||
git checkout rest_server_zrok/configure_zrok.go
|
||||
|
4
bin/python_config.json
Normal file
4
bin/python_config.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"packageName":"zrok_api",
|
||||
"projectName":"zrok_sdk"
|
||||
}
|
@ -143,6 +143,28 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
}()
|
||||
|
||||
case "socks":
|
||||
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
|
||||
BindAddress: cmd.bindAddress,
|
||||
IdentityName: env.EnvironmentIdentityName(),
|
||||
ShrToken: args[0],
|
||||
RequestsChan: requests,
|
||||
})
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to create private access", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
if err := fe.Run(); err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error starting access", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
default:
|
||||
cfg := proxy.DefaultFrontendConfig(env.EnvironmentIdentityName())
|
||||
cfg.ShrToken = shrToken
|
||||
|
66
cmd/zrok/adminCreateAccount.go
Normal file
66
cmd/zrok/adminCreateAccount.go
Normal file
@ -0,0 +1,66 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/controller"
|
||||
"github.com/openziti/zrok/controller/config"
|
||||
"github.com/openziti/zrok/controller/store"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
adminCreateCmd.AddCommand(newAdminCreateAccount().cmd)
|
||||
}
|
||||
|
||||
type adminCreateAccount struct {
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newAdminCreateAccount() *adminCreateAccount {
|
||||
cmd := &cobra.Command{
|
||||
Use: "account <configPath}> <email> <password>",
|
||||
Short: "Pre-populate an account in the database; returns an enable token for the account",
|
||||
Args: cobra.ExactArgs(3),
|
||||
}
|
||||
command := &adminCreateAccount{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *adminCreateAccount) run(_ *cobra.Command, args []string) {
|
||||
cfg, err := config.LoadConfig(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
str, err := store.Open(cfg.Store)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
token, err := controller.CreateToken()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hpwd, err := controller.HashPassword(args[2])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
trx, err := str.Begin()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := trx.Commit(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
a := &store.Account{
|
||||
Email: args[1],
|
||||
Salt: hpwd.Salt,
|
||||
Password: hpwd.Password,
|
||||
Token: token,
|
||||
}
|
||||
if _, err := str.CreateAccount(a, trx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(token)
|
||||
}
|
106
cmd/zrok/copy.go
Normal file
106
cmd/zrok/copy.go
Normal file
@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/drives/sync"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/spf13/cobra"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(newCopyCommand().cmd)
|
||||
}
|
||||
|
||||
type copyCommand struct {
|
||||
cmd *cobra.Command
|
||||
sync bool
|
||||
basicAuth string
|
||||
}
|
||||
|
||||
func newCopyCommand() *copyCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "copy <source> [<target>] (<target> defaults to 'file://.`)",
|
||||
Short: "Copy (unidirectional sync) zrok drive contents from <source> to <target> ('http://', 'file://', and 'zrok://' supported)",
|
||||
Aliases: []string{"cp"},
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
}
|
||||
command := ©Command{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
cmd.Flags().BoolVarP(&command.sync, "sync", "s", false, "Only copy modified files (one-way synchronize)")
|
||||
cmd.Flags().StringVarP(&command.basicAuth, "basic-auth", "a", "", "Basic authentication <username:password>")
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *copyCommand) run(_ *cobra.Command, args []string) {
|
||||
if cmd.basicAuth == "" {
|
||||
cmd.basicAuth = os.Getenv("ZROK_DRIVES_BASIC_AUTH")
|
||||
}
|
||||
|
||||
sourceUrl, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("invalid source '%v'", args[0]), err)
|
||||
}
|
||||
if sourceUrl.Scheme == "" {
|
||||
sourceUrl.Scheme = "file"
|
||||
}
|
||||
|
||||
targetStr := "."
|
||||
if len(args) == 2 {
|
||||
targetStr = args[1]
|
||||
}
|
||||
targetUrl, err := url.Parse(targetStr)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("invalid target '%v'", targetStr), err)
|
||||
}
|
||||
if targetUrl.Scheme == "" {
|
||||
targetUrl.Scheme = "file"
|
||||
}
|
||||
|
||||
root, err := environment.LoadRoot()
|
||||
if err != nil {
|
||||
tui.Error("error loading root", err)
|
||||
}
|
||||
|
||||
var allocatedAccesses []*sdk.Access
|
||||
if sourceUrl.Scheme == "zrok" {
|
||||
access, err := sdk.CreateAccess(root, &sdk.AccessRequest{ShareToken: sourceUrl.Host})
|
||||
if err != nil {
|
||||
tui.Error("error creating access", err)
|
||||
}
|
||||
allocatedAccesses = append(allocatedAccesses, access)
|
||||
}
|
||||
if targetUrl.Scheme == "zrok" {
|
||||
access, err := sdk.CreateAccess(root, &sdk.AccessRequest{ShareToken: targetUrl.Host})
|
||||
if err != nil {
|
||||
tui.Error("error creating access", err)
|
||||
}
|
||||
allocatedAccesses = append(allocatedAccesses, access)
|
||||
}
|
||||
defer func() {
|
||||
for _, access := range allocatedAccesses {
|
||||
err := sdk.DeleteAccess(root, access)
|
||||
if err != nil {
|
||||
tui.Warning("error deleting target access", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
source, err := sync.TargetForURL(sourceUrl, root, cmd.basicAuth)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("error creating target for '%v'", sourceUrl), err)
|
||||
}
|
||||
target, err := sync.TargetForURL(targetUrl, root, cmd.basicAuth)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("error creating target for '%v'", targetUrl), err)
|
||||
}
|
||||
|
||||
if err := sync.OneWay(source, target, cmd.sync); err != nil {
|
||||
tui.Error("error copying", err)
|
||||
}
|
||||
|
||||
fmt.Println("copy complete!")
|
||||
}
|
@ -56,13 +56,19 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var username string
|
||||
user, err := user2.Current()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
username := os.Getenv("USER")
|
||||
if username == "" {
|
||||
logrus.Panicf("unable to determine the current user: %v", err)
|
||||
}
|
||||
} else {
|
||||
username = user.Username
|
||||
}
|
||||
hostDetail = fmt.Sprintf("%v; %v", user.Username, hostDetail)
|
||||
hostDetail = fmt.Sprintf("%v; %v", username, hostDetail)
|
||||
if cmd.description == "<user>@<hostname>" {
|
||||
cmd.description = fmt.Sprintf("%v@%v", user.Username, hostName)
|
||||
cmd.description = fmt.Sprintf("%v@%v", username, hostName)
|
||||
}
|
||||
zrok, err := env.Client()
|
||||
if err != nil {
|
||||
|
95
cmd/zrok/ls.go
Normal file
95
cmd/zrok/ls.go
Normal file
@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/openziti/zrok/drives/sync"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/openziti/zrok/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(newLsCommand().cmd)
|
||||
}
|
||||
|
||||
type lsCommand struct {
|
||||
cmd *cobra.Command
|
||||
basicAuth string
|
||||
}
|
||||
|
||||
func newLsCommand() *lsCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls <target>",
|
||||
Short: "List the contents of drive <target> ('http://', 'zrok://','file://')",
|
||||
Aliases: []string{"dir"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
command := &lsCommand{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
cmd.Flags().StringVarP(&command.basicAuth, "basic-auth", "a", "", "Basic authentication <username:password>")
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *lsCommand) run(_ *cobra.Command, args []string) {
|
||||
if cmd.basicAuth == "" {
|
||||
cmd.basicAuth = os.Getenv("ZROK_DRIVES_BASIC_AUTH")
|
||||
}
|
||||
|
||||
targetUrl, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("invalid target '%v'", args[0]), err)
|
||||
}
|
||||
if targetUrl.Scheme == "" {
|
||||
targetUrl.Scheme = "file"
|
||||
}
|
||||
|
||||
root, err := environment.LoadRoot()
|
||||
if err != nil {
|
||||
tui.Error("error loading root", err)
|
||||
}
|
||||
|
||||
if targetUrl.Scheme == "zrok" {
|
||||
access, err := sdk.CreateAccess(root, &sdk.AccessRequest{ShareToken: targetUrl.Host})
|
||||
if err != nil {
|
||||
tui.Error("error creating access", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sdk.DeleteAccess(root, access); err != nil {
|
||||
logrus.Warningf("error freeing access: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
target, err := sync.TargetForURL(targetUrl, root, cmd.basicAuth)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("error creating target for '%v'", targetUrl), err)
|
||||
}
|
||||
|
||||
objects, err := target.Dir("/")
|
||||
if err != nil {
|
||||
tui.Error("error listing directory", err)
|
||||
}
|
||||
sort.Slice(objects, func(i, j int) bool {
|
||||
return objects[i].Path < objects[j].Path
|
||||
})
|
||||
|
||||
tw := table.NewWriter()
|
||||
tw.SetOutputMirror(os.Stdout)
|
||||
tw.SetStyle(table.StyleLight)
|
||||
tw.AppendHeader(table.Row{"type", "Name", "Size", "Modified"})
|
||||
for _, object := range objects {
|
||||
if object.IsDir {
|
||||
tw.AppendRow(table.Row{"DIR", object.Path, "", ""})
|
||||
} else {
|
||||
tw.AppendRow(table.Row{"", object.Path, util.BytesToSize(object.Size), object.Modified.Local()})
|
||||
}
|
||||
}
|
||||
tw.Render()
|
||||
}
|
@ -26,6 +26,7 @@ func init() {
|
||||
testCmd.AddCommand(loopCmd)
|
||||
rootCmd.AddCommand(adminCmd)
|
||||
rootCmd.AddCommand(configCmd)
|
||||
rootCmd.AddCommand(modifyCmd)
|
||||
rootCmd.AddCommand(shareCmd)
|
||||
rootCmd.AddCommand(testCmd)
|
||||
transport.AddAddressParser(tcp.AddressParser{})
|
||||
@ -85,6 +86,12 @@ var loopCmd = &cobra.Command{
|
||||
Short: "Loopback testing utilities",
|
||||
}
|
||||
|
||||
var modifyCmd = &cobra.Command{
|
||||
Use: "modify",
|
||||
Aliases: []string{"mod"},
|
||||
Short: "Modify resources",
|
||||
}
|
||||
|
||||
var shareCmd = &cobra.Command{
|
||||
Use: "share",
|
||||
Short: "Create backend access for shares",
|
||||
|
75
cmd/zrok/md.go
Normal file
75
cmd/zrok/md.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/drives/sync"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(newMdCommand().cmd)
|
||||
}
|
||||
|
||||
type mdCommand struct {
|
||||
cmd *cobra.Command
|
||||
basicAuth string
|
||||
}
|
||||
|
||||
func newMdCommand() *mdCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "md <target>",
|
||||
Short: "Make directory at <target> ('http://', 'zrok://', 'file://')",
|
||||
Aliases: []string{"mkdir"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
command := &mdCommand{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
cmd.Flags().StringVarP(&command.basicAuth, "basic-auth", "a", "", "Basic authentication <username:password>")
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *mdCommand) run(_ *cobra.Command, args []string) {
|
||||
if cmd.basicAuth == "" {
|
||||
cmd.basicAuth = os.Getenv("ZROK_DRIVES_BASIC_AUTH")
|
||||
}
|
||||
|
||||
targetUrl, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("invalid target '%v'", args[0]), err)
|
||||
}
|
||||
if targetUrl.Scheme == "" {
|
||||
targetUrl.Scheme = "file"
|
||||
}
|
||||
|
||||
root, err := environment.LoadRoot()
|
||||
if err != nil {
|
||||
tui.Error("error loading root", err)
|
||||
}
|
||||
|
||||
if targetUrl.Scheme == "zrok" {
|
||||
access, err := sdk.CreateAccess(root, &sdk.AccessRequest{ShareToken: targetUrl.Host})
|
||||
if err != nil {
|
||||
tui.Error("error creating access", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sdk.DeleteAccess(root, access); err != nil {
|
||||
logrus.Warningf("error freeing access: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
target, err := sync.TargetForURL(targetUrl, root, cmd.basicAuth)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("error creating target for '%v'", targetUrl), err)
|
||||
}
|
||||
|
||||
if err := target.Mkdir("/"); err != nil {
|
||||
tui.Error("error creating directory", err)
|
||||
}
|
||||
}
|
75
cmd/zrok/modifyShare.go
Normal file
75
cmd/zrok/modifyShare.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti/zrok/rest_model_zrok"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
modifyCmd.AddCommand(newModifyShareCommand().cmd)
|
||||
}
|
||||
|
||||
type modifyShareCommand struct {
|
||||
addAccessGrants []string
|
||||
removeAccessGrants []string
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newModifyShareCommand() *modifyShareCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "share <shareToken>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Modify a share",
|
||||
}
|
||||
command := &modifyShareCommand{cmd: cmd}
|
||||
cmd.Flags().StringArrayVar(&command.addAccessGrants, "add-access-grant", []string{}, "Add an access grant (email address)")
|
||||
cmd.Flags().StringArrayVar(&command.removeAccessGrants, "remove-access-grant", []string{}, "Remove an access grant (email address)")
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *modifyShareCommand) run(_ *cobra.Command, args []string) {
|
||||
shrToken := args[0]
|
||||
|
||||
root, err := environment.LoadRoot()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error loading environment", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !root.IsEnabled() {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zrok, err := root.Client()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().Token)
|
||||
|
||||
if len(cmd.addAccessGrants) > 0 || len(cmd.removeAccessGrants) > 0 {
|
||||
req := share.NewUpdateShareParams()
|
||||
req.Body = &rest_model_zrok.UpdateShareRequest{
|
||||
ShrToken: shrToken,
|
||||
AddAccessGrants: cmd.addAccessGrants,
|
||||
RemoveAccessGrants: cmd.removeAccessGrants,
|
||||
}
|
||||
if _, err := zrok.Share.UpdateShare(req, auth); err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to update share", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("updated")
|
||||
}
|
||||
}
|
75
cmd/zrok/mv.go
Normal file
75
cmd/zrok/mv.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/drives/sync"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(newMvCommand().cmd)
|
||||
}
|
||||
|
||||
type mvCommand struct {
|
||||
cmd *cobra.Command
|
||||
basicAuth string
|
||||
}
|
||||
|
||||
func newMvCommand() *mvCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "mv <target> <newPath>",
|
||||
Short: "Move the drive <target> to <newPath> ('http://', 'zrok://', 'file://')",
|
||||
Aliases: []string{"move"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
}
|
||||
command := &mvCommand{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
cmd.Flags().StringVarP(&command.basicAuth, "basic-auth", "a", "", "Basic authentication <username:password>")
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *mvCommand) run(_ *cobra.Command, args []string) {
|
||||
if cmd.basicAuth == "" {
|
||||
cmd.basicAuth = os.Getenv("ZROK_DRIVES_BASIC_AUTH")
|
||||
}
|
||||
|
||||
targetUrl, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("invalid target '%v'", args[0]), err)
|
||||
}
|
||||
if targetUrl.Scheme == "" {
|
||||
targetUrl.Scheme = "file"
|
||||
}
|
||||
|
||||
root, err := environment.LoadRoot()
|
||||
if err != nil {
|
||||
tui.Error("error loading root", err)
|
||||
}
|
||||
|
||||
if targetUrl.Scheme == "zrok" {
|
||||
access, err := sdk.CreateAccess(root, &sdk.AccessRequest{ShareToken: targetUrl.Host})
|
||||
if err != nil {
|
||||
tui.Error("error creating access", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sdk.DeleteAccess(root, access); err != nil {
|
||||
logrus.Warningf("error freeing access: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
target, err := sync.TargetForURL(targetUrl, root, cmd.basicAuth)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("error creating target for '%v'", targetUrl), err)
|
||||
}
|
||||
|
||||
if err := target.Move("/", args[1]); err != nil {
|
||||
tui.Error("error moving", err)
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -4,12 +4,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/openziti/zrok/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"time"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -17,31 +18,37 @@ func init() {
|
||||
}
|
||||
|
||||
type reserveCommand struct {
|
||||
basicAuth []string
|
||||
frontendSelection []string
|
||||
backendMode string
|
||||
jsonOutput bool
|
||||
oauthProvider string
|
||||
oauthEmailDomains []string
|
||||
oauthCheckInterval time.Duration
|
||||
cmd *cobra.Command
|
||||
uniqueName string
|
||||
basicAuth []string
|
||||
frontendSelection []string
|
||||
backendMode string
|
||||
jsonOutput bool
|
||||
oauthProvider string
|
||||
oauthEmailAddressPatterns []string
|
||||
oauthCheckInterval time.Duration
|
||||
closed bool
|
||||
accessGrants []string
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newReserveCommand() *reserveCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "reserve <public|private> <target>",
|
||||
Use: "reserve <public|private> [<target>]",
|
||||
Short: "Create a reserved share",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
}
|
||||
command := &reserveCommand{cmd: cmd}
|
||||
cmd.Flags().StringVarP(&command.uniqueName, "unique-name", "n", "", "A unique name for the reserved share (defaults to generated identifier)")
|
||||
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel)")
|
||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel, socks)")
|
||||
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
||||
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
||||
cmd.Flags().StringArrayVar(&command.oauthEmailDomains, "oauth-email-domains", []string{}, "Allow only these email domains to authenticate via OAuth")
|
||||
cmd.Flags().StringArrayVar(&command.oauthEmailAddressPatterns, "oauth-email-address-patterns", []string{}, "Allow only these email domains to authenticate via OAuth")
|
||||
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
|
||||
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
|
||||
cmd.Flags().BoolVar(&command.closed, "closed", false, "Enable closed permission mode (see --access-grant)")
|
||||
cmd.Flags().StringArrayVar(&command.accessGrants, "access-grant", []string{}, "zrok accounts that are allowed to access this share (see --closed)")
|
||||
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
@ -49,16 +56,23 @@ func newReserveCommand() *reserveCommand {
|
||||
|
||||
func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||
shareMode := sdk.ShareMode(args[0])
|
||||
privateOnlyModes := []string{"tcpTunnel", "udpTunnel"}
|
||||
privateOnlyModes := []string{"tcpTunnel", "udpTunnel", "socks"}
|
||||
if shareMode != sdk.PublicShareMode && shareMode != sdk.PrivateShareMode {
|
||||
tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil)
|
||||
} else if shareMode == sdk.PublicShareMode && slices.Contains(privateOnlyModes, cmd.backendMode) {
|
||||
tui.Error(fmt.Sprintf("invalid sharing mode for a %s share: %s", sdk.PublicShareMode, cmd.backendMode), nil)
|
||||
}
|
||||
|
||||
if cmd.uniqueName != "" && !util.IsValidUniqueName(cmd.uniqueName) {
|
||||
tui.Error("invalid unique name; must be lowercase alphanumeric, between 4 and 32 characters in length, screened for profanity", nil)
|
||||
}
|
||||
|
||||
var target string
|
||||
switch cmd.backendMode {
|
||||
case "proxy":
|
||||
if len(args) != 2 {
|
||||
tui.Error("the 'proxy' backend mode expects a <target>", nil)
|
||||
}
|
||||
v, err := parseUrl(args[1])
|
||||
if err != nil {
|
||||
tui.Error("invalid target endpoint URL", err)
|
||||
@ -66,22 +80,42 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||
target = v
|
||||
|
||||
case "web":
|
||||
if len(args) != 2 {
|
||||
tui.Error("the 'web' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[1]
|
||||
|
||||
case "tcpTunnel":
|
||||
if len(args) != 2 {
|
||||
tui.Error("the 'tcpTunnel' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[1]
|
||||
|
||||
case "udpTunnel":
|
||||
if len(args) != 2 {
|
||||
tui.Error("the 'udpTunnel' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[1]
|
||||
|
||||
case "caddy":
|
||||
if len(args) != 2 {
|
||||
tui.Error("the 'caddy' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[1]
|
||||
|
||||
case "drive":
|
||||
if len(args) != 2 {
|
||||
tui.Error("the 'drive' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[1]
|
||||
|
||||
case "socks":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'socks' backend mode does not expect <target>", nil)
|
||||
}
|
||||
|
||||
default:
|
||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
|
||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks}", cmd.backendMode), nil)
|
||||
}
|
||||
|
||||
env, err := environment.LoadRoot()
|
||||
@ -95,6 +129,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||
|
||||
req := &sdk.ShareRequest{
|
||||
Reserved: true,
|
||||
UniqueName: cmd.uniqueName,
|
||||
BackendMode: sdk.BackendMode(cmd.backendMode),
|
||||
ShareMode: shareMode,
|
||||
BasicAuth: cmd.basicAuth,
|
||||
@ -108,9 +143,13 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||
tui.Error("--oauth-provider only supported for public shares", nil)
|
||||
}
|
||||
req.OauthProvider = cmd.oauthProvider
|
||||
req.OauthEmailDomains = cmd.oauthEmailDomains
|
||||
req.OauthEmailAddressPatterns = cmd.oauthEmailAddressPatterns
|
||||
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
|
||||
}
|
||||
if cmd.closed {
|
||||
req.PermissionMode = sdk.ClosedPermissionMode
|
||||
req.AccessGrants = cmd.accessGrants
|
||||
}
|
||||
shr, err := sdk.CreateShare(env, req)
|
||||
if err != nil {
|
||||
tui.Error("unable to create share", err)
|
||||
|
75
cmd/zrok/rm.go
Normal file
75
cmd/zrok/rm.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/drives/sync"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(newRmCommand().cmd)
|
||||
}
|
||||
|
||||
type rmCommand struct {
|
||||
cmd *cobra.Command
|
||||
basicAuth string
|
||||
}
|
||||
|
||||
func newRmCommand() *rmCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "rm <target>",
|
||||
Short: "Remove (delete) the contents of drive <target> ('http://', 'zrok://', 'file://')",
|
||||
Aliases: []string{"del"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
command := &rmCommand{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
cmd.Flags().StringVarP(&command.basicAuth, "basic-auth", "a", "", "Basic authentication <username:password>")
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *rmCommand) run(_ *cobra.Command, args []string) {
|
||||
if cmd.basicAuth == "" {
|
||||
cmd.basicAuth = os.Getenv("ZROK_DRIVES_BASIC_AUTH")
|
||||
}
|
||||
|
||||
targetUrl, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("invalid target '%v'", args[0]), err)
|
||||
}
|
||||
if targetUrl.Scheme == "" {
|
||||
targetUrl.Scheme = "file"
|
||||
}
|
||||
|
||||
root, err := environment.LoadRoot()
|
||||
if err != nil {
|
||||
tui.Error("error loading root", err)
|
||||
}
|
||||
|
||||
if targetUrl.Scheme == "zrok" {
|
||||
access, err := sdk.CreateAccess(root, &sdk.AccessRequest{ShareToken: targetUrl.Host})
|
||||
if err != nil {
|
||||
tui.Error("error creating access", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sdk.DeleteAccess(root, access); err != nil {
|
||||
logrus.Warningf("error freeing access: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
target, err := sync.TargetForURL(targetUrl, root, cmd.basicAuth)
|
||||
if err != nil {
|
||||
tui.Error(fmt.Sprintf("error creating target for '%v'", targetUrl), err)
|
||||
}
|
||||
|
||||
if err := target.Rm("/"); err != nil {
|
||||
tui.Error("error removing", err)
|
||||
}
|
||||
}
|
@ -6,11 +6,12 @@ import (
|
||||
"github.com/openziti/zrok/endpoints"
|
||||
"github.com/openziti/zrok/endpoints/drive"
|
||||
"github.com/openziti/zrok/endpoints/proxy"
|
||||
"github.com/openziti/zrok/endpoints/socks"
|
||||
"github.com/openziti/zrok/endpoints/tcpTunnel"
|
||||
"github.com/openziti/zrok/endpoints/udpTunnel"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/environment/env_core"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@ -24,24 +25,28 @@ func init() {
|
||||
}
|
||||
|
||||
type sharePrivateCommand struct {
|
||||
basicAuth []string
|
||||
backendMode string
|
||||
headless bool
|
||||
insecure bool
|
||||
cmd *cobra.Command
|
||||
basicAuth []string
|
||||
backendMode string
|
||||
headless bool
|
||||
insecure bool
|
||||
closed bool
|
||||
accessGrants []string
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newSharePrivateCommand() *sharePrivateCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "private <target>",
|
||||
Use: "private [<target>]",
|
||||
Short: "Share a target resource privately",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
}
|
||||
command := &sharePrivateCommand{cmd: cmd}
|
||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...")
|
||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy}")
|
||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, tcpTunnel, udpTunnel, caddy, drive, socks}")
|
||||
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
|
||||
cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>")
|
||||
cmd.Flags().BoolVar(&command.closed, "closed", false, "Enable closed permission mode (see --access-grant)")
|
||||
cmd.Flags().StringArrayVar(&command.accessGrants, "access-grant", []string{}, "zrok accounts that are allowed to access this share (see --closed)")
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
@ -51,6 +56,9 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
|
||||
switch cmd.backendMode {
|
||||
case "proxy":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'proxy' backend mode expects a <target>", nil)
|
||||
}
|
||||
v, err := parseUrl(args[0])
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
@ -61,21 +69,42 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
target = v
|
||||
|
||||
case "web":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'web' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[0]
|
||||
|
||||
case "tcpTunnel":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'tcpTunnel' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[0]
|
||||
|
||||
case "udpTunnel":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'udpTunnel' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[0]
|
||||
|
||||
case "caddy":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'caddy' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[0]
|
||||
cmd.headless = true
|
||||
|
||||
case "drive":
|
||||
if len(args) != 1 {
|
||||
tui.Error("the 'drive' backend mode expects a <target>", nil)
|
||||
}
|
||||
target = args[0]
|
||||
|
||||
case "socks":
|
||||
if len(args) != 0 {
|
||||
tui.Error("the 'socks' backend mode does not expect <target>", nil)
|
||||
}
|
||||
target = "socks"
|
||||
|
||||
default:
|
||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
|
||||
}
|
||||
@ -106,6 +135,10 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
BasicAuth: cmd.basicAuth,
|
||||
Target: target,
|
||||
}
|
||||
if cmd.closed {
|
||||
req.PermissionMode = sdk.ClosedPermissionMode
|
||||
req.AccessGrants = cmd.accessGrants
|
||||
}
|
||||
shr, err := sdk.CreateShare(root, req)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
@ -264,6 +297,27 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
}()
|
||||
|
||||
case "socks":
|
||||
cfg := &socks.BackendConfig{
|
||||
IdentityPath: zif,
|
||||
ShrToken: shr.Token,
|
||||
Requests: requests,
|
||||
}
|
||||
|
||||
be, err := socks.NewBackend(cfg)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error creating socks backend", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := be.Run(); err != nil {
|
||||
logrus.Errorf("error running socks backend: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
default:
|
||||
tui.Error("invalid backend mode", nil)
|
||||
}
|
||||
|
@ -3,12 +3,13 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/openziti/zrok/endpoints"
|
||||
drive "github.com/openziti/zrok/endpoints/drive"
|
||||
"github.com/openziti/zrok/endpoints/proxy"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/environment/env_core"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@ -24,15 +25,17 @@ func init() {
|
||||
}
|
||||
|
||||
type sharePublicCommand struct {
|
||||
basicAuth []string
|
||||
frontendSelection []string
|
||||
backendMode string
|
||||
headless bool
|
||||
insecure bool
|
||||
oauthProvider string
|
||||
oauthEmailDomains []string
|
||||
oauthCheckInterval time.Duration
|
||||
cmd *cobra.Command
|
||||
basicAuth []string
|
||||
frontendSelection []string
|
||||
backendMode string
|
||||
headless bool
|
||||
insecure bool
|
||||
oauthProvider string
|
||||
oauthEmailAddressPatterns []string
|
||||
oauthCheckInterval time.Duration
|
||||
closed bool
|
||||
accessGrants []string
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newSharePublicCommand() *sharePublicCommand {
|
||||
@ -46,10 +49,12 @@ func newSharePublicCommand() *sharePublicCommand {
|
||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, caddy, drive}")
|
||||
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
|
||||
cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>")
|
||||
cmd.Flags().BoolVar(&command.closed, "closed", false, "Enable closed permission mode (see --access-grant)")
|
||||
cmd.Flags().StringArrayVar(&command.accessGrants, "access-grant", []string{}, "zrok accounts that are allowed to access this share (see --closed)")
|
||||
|
||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
||||
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
||||
cmd.Flags().StringArrayVar(&command.oauthEmailDomains, "oauth-email-domains", []string{}, "Allow only these email domains to authenticate via OAuth")
|
||||
cmd.Flags().StringArrayVar(&command.oauthEmailAddressPatterns, "oauth-email-address-patterns", []string{}, "Allow only these email domain globs to authenticate via OAuth")
|
||||
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
|
||||
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
|
||||
|
||||
@ -112,10 +117,24 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
||||
BasicAuth: cmd.basicAuth,
|
||||
Target: target,
|
||||
}
|
||||
if cmd.closed {
|
||||
req.PermissionMode = sdk.ClosedPermissionMode
|
||||
req.AccessGrants = cmd.accessGrants
|
||||
}
|
||||
if cmd.oauthProvider != "" {
|
||||
req.OauthProvider = cmd.oauthProvider
|
||||
req.OauthEmailDomains = cmd.oauthEmailDomains
|
||||
req.OauthEmailAddressPatterns = cmd.oauthEmailAddressPatterns
|
||||
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
|
||||
|
||||
for _, g := range cmd.oauthEmailAddressPatterns {
|
||||
_, err := glob.Compile(g)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error(fmt.Sprintf("unable to create share, invalid oauth email glob (%v)", g), err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
shr, err := sdk.CreateShare(root, req)
|
||||
if err != nil {
|
||||
|
@ -7,13 +7,14 @@ import (
|
||||
"github.com/openziti/zrok/endpoints"
|
||||
"github.com/openziti/zrok/endpoints/drive"
|
||||
"github.com/openziti/zrok/endpoints/proxy"
|
||||
"github.com/openziti/zrok/endpoints/socks"
|
||||
"github.com/openziti/zrok/endpoints/tcpTunnel"
|
||||
"github.com/openziti/zrok/endpoints/udpTunnel"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/rest_client_zrok/metadata"
|
||||
"github.com/openziti/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti/zrok/rest_model_zrok"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@ -92,23 +93,25 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logrus.Infof("sharing target: '%v'", target)
|
||||
if resp.Payload.BackendMode != "socks" {
|
||||
logrus.Infof("sharing target: '%v'", target)
|
||||
|
||||
if resp.Payload.BackendProxyEndpoint != target {
|
||||
upReq := share.NewUpdateShareParams()
|
||||
upReq.Body = &rest_model_zrok.UpdateShareRequest{
|
||||
ShrToken: shrToken,
|
||||
BackendProxyEndpoint: target,
|
||||
}
|
||||
if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to update backend proxy endpoint", err)
|
||||
if resp.Payload.BackendProxyEndpoint != target {
|
||||
upReq := share.NewUpdateShareParams()
|
||||
upReq.Body = &rest_model_zrok.UpdateShareRequest{
|
||||
ShrToken: shrToken,
|
||||
BackendProxyEndpoint: target,
|
||||
}
|
||||
panic(err)
|
||||
if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to update backend proxy endpoint", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
logrus.Infof("updated backend proxy endpoint to: %v", target)
|
||||
} else {
|
||||
logrus.Infof("using existing backend proxy endpoint: %v", target)
|
||||
}
|
||||
logrus.Infof("updated backend proxy endpoint to: %v", target)
|
||||
} else {
|
||||
logrus.Infof("using existing backend proxy endpoint: %v", target)
|
||||
}
|
||||
|
||||
var shareDescription string
|
||||
@ -258,6 +261,27 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
}()
|
||||
|
||||
case "socks":
|
||||
cfg := &socks.BackendConfig{
|
||||
IdentityPath: zif,
|
||||
ShrToken: shrToken,
|
||||
Requests: requests,
|
||||
}
|
||||
|
||||
be, err := socks.NewBackend(cfg)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error creating socks backend", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := be.Run(); err != nil {
|
||||
logrus.Errorf("error running socks backend: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
default:
|
||||
tui.Error("invalid backend mode", nil)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"github.com/openziti/zrok/rest_client_zrok"
|
||||
"github.com/openziti/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti/zrok/rest_model_zrok"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/tui"
|
||||
"github.com/openziti/zrok/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -136,35 +136,42 @@ func (l *looper) run() {
|
||||
|
||||
l.startup()
|
||||
logrus.Infof("looper #%d, shrToken: %v, frontend: %v", l.id, l.shrToken, l.proxyEndpoint)
|
||||
go l.serviceListener()
|
||||
l.dwell()
|
||||
l.iterate()
|
||||
if l.serviceListener() {
|
||||
l.dwell()
|
||||
l.iterate()
|
||||
}
|
||||
logrus.Infof("looper #%d: complete", l.id)
|
||||
l.shutdown()
|
||||
}
|
||||
|
||||
func (l *looper) serviceListener() {
|
||||
func (l *looper) serviceListener() bool {
|
||||
zcfg, err := ziti.NewConfigFromFile(l.zif)
|
||||
if err != nil {
|
||||
logrus.Errorf("error opening ziti config '%v': %v", l.zif, err)
|
||||
return
|
||||
return false
|
||||
}
|
||||
opts := ziti.ListenOptions{
|
||||
ConnectTimeout: 5 * time.Minute,
|
||||
MaxConnections: 10,
|
||||
options := ziti.ListenOptions{
|
||||
ConnectTimeout: 5 * time.Minute,
|
||||
WaitForNEstablishedListeners: 1,
|
||||
}
|
||||
zctx, err := ziti.NewContext(zcfg)
|
||||
if err != nil {
|
||||
logrus.Errorf("error loading ziti context: %v", err)
|
||||
return
|
||||
return false
|
||||
}
|
||||
if l.listener, err = zctx.ListenWithOptions(l.shrToken, &opts); err == nil {
|
||||
|
||||
if l.listener, err = zctx.ListenWithOptions(l.shrToken, &options); err != nil {
|
||||
logrus.Errorf("looper #%d, error listening: %v", l.id, err)
|
||||
return false
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := http.Serve(l.listener, l); err != nil {
|
||||
logrus.Errorf("looper #%d, error serving: %v", l.id, err)
|
||||
}
|
||||
} else {
|
||||
logrus.Errorf("looper #%d, error listening: %v", l.id, err)
|
||||
}
|
||||
}()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *looper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
@ -239,6 +246,9 @@ func (l *looper) iterate() {
|
||||
if req, err := http.NewRequest("POST", l.proxyEndpoint, bytes.NewBufferString(outbase64)); err == nil {
|
||||
client := &http.Client{Timeout: time.Second * time.Duration(l.cmd.timeoutSeconds)}
|
||||
if resp, err := client.Do(req); err == nil {
|
||||
if resp.StatusCode != 200 {
|
||||
logrus.Errorf("looper #%d unexpected response status code %v!", l.id, resp.StatusCode)
|
||||
}
|
||||
inpayload := new(bytes.Buffer)
|
||||
io.Copy(inpayload, resp.Body)
|
||||
inbase64 := inpayload.String()
|
||||
|
@ -87,7 +87,7 @@ func (cmd *testWebsocketCommand) run(_ *cobra.Command, args []string) {
|
||||
addr = cmd.serviceName
|
||||
} else {
|
||||
if len(args) == 0 {
|
||||
logrus.Error("Address required if not using ziti")
|
||||
logrus.Error("address required if not using ziti")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -102,13 +102,13 @@ func (cmd *testWebsocketCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
defer c.Close(websocket.StatusInternalError, "the sky is falling")
|
||||
|
||||
logrus.Info("Writing to server...")
|
||||
logrus.Info("writing to server...")
|
||||
err = wsjson.Write(ctx, c, "hi")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
logrus.Info("Reading response...")
|
||||
logrus.Info("reading response...")
|
||||
typ, dat, err := c.Read(ctx)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
|
@ -49,7 +49,7 @@ func (h *accessHandler) Handle(params share.AccessParams, principal *rest_model_
|
||||
shrToken := params.Body.ShrToken
|
||||
shr, err := str.FindShareWithToken(shrToken, trx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error finding share")
|
||||
logrus.Errorf("error finding share with token '%v': %v", shrToken, err)
|
||||
return share.NewAccessNotFound()
|
||||
}
|
||||
if shr == nil {
|
||||
@ -57,12 +57,25 @@ func (h *accessHandler) Handle(params share.AccessParams, principal *rest_model_
|
||||
return share.NewAccessNotFound()
|
||||
}
|
||||
|
||||
if shr.PermissionMode == store.ClosedPermissionMode {
|
||||
shrEnv, err := str.GetEnvironment(shr.EnvironmentId, trx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error getting environment for share '%v': %v", shrToken, err)
|
||||
return share.NewAccessInternalServerError()
|
||||
}
|
||||
|
||||
if err := h.checkAccessGrants(shr, *shrEnv.AccountId, principal, trx); err != nil {
|
||||
logrus.Errorf("closed permission mode for '%v' fails for '%v': %v", shr.Token, principal.Email, err)
|
||||
return share.NewAccessUnauthorized()
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.checkLimits(shr, trx); err != nil {
|
||||
logrus.Errorf("cannot access limited share for '%v': %v", principal.Email, err)
|
||||
return share.NewAccessNotFound()
|
||||
}
|
||||
|
||||
feToken, err := createToken()
|
||||
feToken, err := CreateToken()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return share.NewAccessInternalServerError()
|
||||
@ -111,3 +124,20 @@ func (h *accessHandler) checkLimits(shr *store.Share, trx *sqlx.Tx) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *accessHandler) checkAccessGrants(shr *store.Share, ownerAccountId int, principal *rest_model_zrok.Principal, trx *sqlx.Tx) error {
|
||||
if int(principal.ID) == ownerAccountId {
|
||||
logrus.Infof("accessing own share '%v' for '%v'", shr.Token, principal.Email)
|
||||
return nil
|
||||
}
|
||||
count, err := str.CheckAccessGrantForShareAndAccount(shr.Id, int(principal.ID), trx)
|
||||
if err != nil {
|
||||
logrus.Infof("error checking access grants for '%v': %v", shr.Token, err)
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
logrus.Infof("found '%d' grants for '%v'", count, principal.Email)
|
||||
return nil
|
||||
}
|
||||
return errors.Errorf("access denied for '%v' accessing '%v'", principal.Email, shr.Token)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
"github.com/openziti/zrok/controller/store"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/environment"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"time"
|
||||
|
75
controller/changePassword.go
Normal file
75
controller/changePassword.go
Normal file
@ -0,0 +1,75 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/openziti/zrok/controller/config"
|
||||
"github.com/openziti/zrok/rest_model_zrok"
|
||||
"github.com/openziti/zrok/rest_server_zrok/operations/account"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type changePasswordHandler struct {
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
func newChangePasswordHandler(cfg *config.Config) *changePasswordHandler {
|
||||
return &changePasswordHandler{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *changePasswordHandler) Handle(params account.ChangePasswordParams, principal *rest_model_zrok.Principal) middleware.Responder {
|
||||
if params.Body == nil || params.Body.Email == "" || params.Body.OldPassword == "" || params.Body.NewPassword == "" {
|
||||
logrus.Error("missing email, old, or new password")
|
||||
return account.NewChangePasswordUnauthorized()
|
||||
}
|
||||
logrus.Infof("received change password request for email '%v'", params.Body.Email)
|
||||
|
||||
tx, err := str.Begin()
|
||||
if err != nil {
|
||||
logrus.Errorf("error starting transaction: %v", err)
|
||||
return account.NewChangePasswordUnauthorized()
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
a, err := str.FindAccountWithEmail(params.Body.Email, tx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error finding account '%v': %v", params.Body.Email, err)
|
||||
return account.NewChangePasswordUnauthorized()
|
||||
}
|
||||
ohpwd, err := rehashPassword(params.Body.OldPassword, a.Salt)
|
||||
if err != nil {
|
||||
logrus.Errorf("error hashing password for '%v': %v", params.Body.Email, err)
|
||||
return account.NewChangePasswordUnauthorized()
|
||||
}
|
||||
if a.Password != ohpwd.Password {
|
||||
logrus.Errorf("password mismatch for account '%v'", params.Body.Email)
|
||||
return account.NewChangePasswordUnauthorized()
|
||||
}
|
||||
|
||||
if err := validatePassword(handler.cfg, params.Body.NewPassword); err != nil {
|
||||
logrus.Errorf("password not valid for request '%v': %v", a.Email, err)
|
||||
return account.NewChangePasswordUnprocessableEntity().WithPayload(rest_model_zrok.ErrorMessage(err.Error()))
|
||||
}
|
||||
|
||||
nhpwd, err := HashPassword(params.Body.NewPassword)
|
||||
if err != nil {
|
||||
logrus.Errorf("error hashing password for '%v': %v", a.Email, err)
|
||||
return account.NewChangePasswordInternalServerError()
|
||||
}
|
||||
a.Salt = nhpwd.Salt
|
||||
a.Password = nhpwd.Password
|
||||
|
||||
if _, err := str.UpdateAccount(a, tx); err != nil {
|
||||
logrus.Errorf("error updating for '%v': %v", a.Email, err)
|
||||
return account.NewChangePasswordInternalServerError()
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
logrus.Errorf("error committing '%v': %v", a.Email, err)
|
||||
return account.NewChangePasswordInternalServerError()
|
||||
}
|
||||
|
||||
logrus.Infof("change password for '%v'", a.Email)
|
||||
return account.NewChangePasswordOK()
|
||||
}
|
@ -31,6 +31,7 @@ type Config struct {
|
||||
ResetPassword *ResetPasswordConfig
|
||||
Store *store.Config
|
||||
Ziti *zrokEdgeSdk.Config
|
||||
Tls *TlsConfig
|
||||
}
|
||||
|
||||
type AdminConfig struct {
|
||||
@ -83,6 +84,11 @@ type ResetPasswordMaintenanceConfig struct {
|
||||
BatchLimit int
|
||||
}
|
||||
|
||||
type TlsConfig struct {
|
||||
CertPath string
|
||||
KeyPath string
|
||||
}
|
||||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Limits: limits.DefaultConfig(),
|
||||
|
@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/openziti/zrok/controller/config"
|
||||
"github.com/openziti/zrok/controller/limits"
|
||||
"github.com/openziti/zrok/controller/metrics"
|
||||
@ -43,8 +44,10 @@ func Run(inCfg *config.Config) error {
|
||||
|
||||
api := operations.NewZrokAPI(swaggerSpec)
|
||||
api.KeyAuth = newZrokAuthenticator(cfg).authenticate
|
||||
api.AccountChangePasswordHandler = newChangePasswordHandler(cfg)
|
||||
api.AccountInviteHandler = newInviteHandler(cfg)
|
||||
api.AccountLoginHandler = account.LoginHandlerFunc(loginHandler)
|
||||
api.AccountRegenerateTokenHandler = newRegenerateTokenHandler()
|
||||
api.AccountRegisterHandler = newRegisterHandler(cfg)
|
||||
api.AccountResetPasswordHandler = newResetPasswordHandler(cfg)
|
||||
api.AccountResetPasswordRequestHandler = newResetPasswordRequestHandler()
|
||||
@ -128,8 +131,16 @@ func Run(inCfg *config.Config) error {
|
||||
|
||||
server := rest_server_zrok.NewServer(api)
|
||||
defer func() { _ = server.Shutdown() }()
|
||||
server.Host = cfg.Endpoint.Host
|
||||
server.Port = cfg.Endpoint.Port
|
||||
if cfg.Tls != nil {
|
||||
server.TLSHost = cfg.Endpoint.Host
|
||||
server.TLSPort = cfg.Endpoint.Port
|
||||
server.TLSCertificate = flags.Filename(cfg.Tls.CertPath)
|
||||
server.TLSCertificateKey = flags.Filename(cfg.Tls.KeyPath)
|
||||
server.EnabledListeners = []string{"https"}
|
||||
} else {
|
||||
server.Host = cfg.Endpoint.Host
|
||||
server.Port = cfg.Endpoint.Port
|
||||
}
|
||||
rest_server_zrok.HealthCheck = HealthCheckHTTP
|
||||
server.ConfigureAPI()
|
||||
if err := server.Serve(); err != nil {
|
||||
|
@ -50,7 +50,7 @@ func (h *createFrontendHandler) Handle(params admin.CreateFrontendParams, princi
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
feToken, err := createToken()
|
||||
feToken, err := CreateToken()
|
||||
if err != nil {
|
||||
logrus.Errorf("error creating frontend token: %v", err)
|
||||
return admin.NewCreateFrontendInternalServerError()
|
||||
|
@ -47,6 +47,7 @@ func (h *getFrontendDetailHandler) Handle(params metadata.GetFrontendDetailParam
|
||||
}
|
||||
payload := &rest_model_zrok.Frontend{
|
||||
ID: int64(fe.Id),
|
||||
Token: fe.Token,
|
||||
ZID: fe.ZId,
|
||||
CreatedAt: fe.CreatedAt.UnixMilli(),
|
||||
UpdatedAt: fe.UpdatedAt.UnixMilli(),
|
||||
|
@ -55,7 +55,7 @@ func (h *inviteHandler) Handle(params account.InviteParams) middleware.Responder
|
||||
logrus.Infof("using invite token '%v' to process invite request for '%v'", inviteToken.Token, params.Body.Email)
|
||||
}
|
||||
|
||||
token, err = createToken()
|
||||
token, err = CreateToken()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return account.NewInviteInternalServerError()
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/openziti/zrok/controller/store"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/openziti/zrok/controller/store"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"github.com/openziti/edge-api/rest_management_api_client"
|
||||
"github.com/openziti/zrok/controller/store"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -95,6 +95,7 @@ func (h *overviewHandler) Handle(_ metadata.OverviewParams, principal *rest_mode
|
||||
for _, fe := range fes {
|
||||
envFe := &rest_model_zrok.Frontend{
|
||||
ID: int64(fe.Id),
|
||||
Token: fe.Token,
|
||||
ZID: fe.ZId,
|
||||
CreatedAt: fe.CreatedAt.UnixMilli(),
|
||||
UpdatedAt: fe.UpdatedAt.UnixMilli(),
|
||||
|
@ -24,7 +24,7 @@ func salt() string {
|
||||
return base64.StdEncoding.EncodeToString(buf)
|
||||
}
|
||||
|
||||
func hashPassword(password string) (*hashedPassword, error) {
|
||||
func HashPassword(password string) (*hashedPassword, error) {
|
||||
return rehashPassword(password, salt())
|
||||
}
|
||||
|
||||
|
63
controller/regenerateToken.go
Normal file
63
controller/regenerateToken.go
Normal file
@ -0,0 +1,63 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/openziti/zrok/rest_model_zrok"
|
||||
"github.com/openziti/zrok/rest_server_zrok/operations/account"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type regenerateTokenHandler struct{}
|
||||
|
||||
func newRegenerateTokenHandler() *regenerateTokenHandler {
|
||||
return ®enerateTokenHandler{}
|
||||
}
|
||||
|
||||
func (handler *regenerateTokenHandler) Handle(params account.RegenerateTokenParams, principal *rest_model_zrok.Principal) middleware.Responder {
|
||||
logrus.Infof("received token regeneration request for email '%v'", principal.Email)
|
||||
|
||||
if params.Body.EmailAddress != principal.Email {
|
||||
logrus.Errorf("mismatched account '%v' for '%v'", params.Body.EmailAddress, principal.Email)
|
||||
return account.NewRegenerateTokenNotFound()
|
||||
}
|
||||
|
||||
tx, err := str.Begin()
|
||||
if err != nil {
|
||||
logrus.Errorf("error starting transaction for '%v': %v", params.Body.EmailAddress, err)
|
||||
return account.NewRegenerateTokenInternalServerError()
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
a, err := str.FindAccountWithEmail(params.Body.EmailAddress, tx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error finding account for '%v': %v", params.Body.EmailAddress, err)
|
||||
return account.NewRegenerateTokenNotFound()
|
||||
}
|
||||
if a.Deleted {
|
||||
logrus.Errorf("account '%v' for '%v' deleted", a.Email, a.Token)
|
||||
return account.NewRegenerateTokenNotFound()
|
||||
}
|
||||
|
||||
// Need to create new token and invalidate all other resources
|
||||
token, err := CreateToken()
|
||||
if err != nil {
|
||||
logrus.Errorf("error creating token for request '%v': %v", params.Body.EmailAddress, err)
|
||||
return account.NewRegenerateTokenInternalServerError()
|
||||
}
|
||||
|
||||
a.Token = token
|
||||
|
||||
if _, err := str.UpdateAccount(a, tx); err != nil {
|
||||
logrus.Errorf("error updating account for request '%v': %v", params.Body.EmailAddress, err)
|
||||
return account.NewRegenerateTokenInternalServerError()
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
logrus.Errorf("error committing '%v' (%v): %v", params.Body.EmailAddress, a.Email, err)
|
||||
return account.NewRegenerateTokenInternalServerError()
|
||||
}
|
||||
|
||||
logrus.Infof("regenerated token '%v' for '%v'", a.Token, a.Email)
|
||||
|
||||
return account.NewRegenerateTokenOK().WithPayload(&account.RegenerateTokenOKBody{Token: token})
|
||||
}
|
@ -38,7 +38,7 @@ func (h *registerHandler) Handle(params account.RegisterParams) middleware.Respo
|
||||
return account.NewRegisterNotFound()
|
||||
}
|
||||
|
||||
token, err := createToken()
|
||||
token, err := CreateToken()
|
||||
if err != nil {
|
||||
logrus.Errorf("error creating token for request '%v' (%v): %v", params.Body.Token, ar.Email, err)
|
||||
return account.NewRegisterInternalServerError()
|
||||
@ -49,7 +49,7 @@ func (h *registerHandler) Handle(params account.RegisterParams) middleware.Respo
|
||||
return account.NewRegisterUnprocessableEntity().WithPayload(rest_model_zrok.ErrorMessage(err.Error()))
|
||||
}
|
||||
|
||||
hpwd, err := hashPassword(params.Body.Password)
|
||||
hpwd, err := HashPassword(params.Body.Password)
|
||||
if err != nil {
|
||||
logrus.Errorf("error hashing password for request '%v' (%v): %v", params.Body.Token, ar.Email, err)
|
||||
return account.NewRegisterInternalServerError()
|
||||
|
@ -53,7 +53,7 @@ func (handler *resetPasswordHandler) Handle(params account.ResetPasswordParams)
|
||||
return account.NewResetPasswordUnprocessableEntity().WithPayload(rest_model_zrok.ErrorMessage(err.Error()))
|
||||
}
|
||||
|
||||
hpwd, err := hashPassword(params.Body.Password)
|
||||
hpwd, err := HashPassword(params.Body.Password)
|
||||
if err != nil {
|
||||
logrus.Errorf("error hashing password for '%v' (%v): %v", params.Body.Token, a.Email, err)
|
||||
return account.NewResetPasswordRequestInternalServerError()
|
||||
|
@ -34,7 +34,7 @@ func (handler *resetPasswordRequestHandler) Handle(params account.ResetPasswordR
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
token, err = createToken()
|
||||
token, err = CreateToken()
|
||||
if err != nil {
|
||||
logrus.Errorf("error creating token for '%v': %v", params.Body.EmailAddress, err)
|
||||
return account.NewResetPasswordRequestInternalServerError()
|
||||
|
@ -7,7 +7,8 @@ import (
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/rest_model_zrok"
|
||||
"github.com/openziti/zrok/rest_server_zrok/operations/share"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/openziti/zrok/util"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -33,14 +34,14 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
||||
found := false
|
||||
for _, env := range envs {
|
||||
if env.ZId == envZId {
|
||||
logrus.Debugf("found identity '%v' for user '%v'", envZId, principal.Email)
|
||||
logrus.Debugf("found identity '%v' for account '%v'", envZId, principal.Email)
|
||||
envId = env.Id
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
logrus.Errorf("environment '%v' not found for user '%v'", envZId, principal.Email)
|
||||
logrus.Errorf("environment '%v' not found for account '%v'", envZId, principal.Email)
|
||||
return share.NewShareUnauthorized()
|
||||
}
|
||||
} else {
|
||||
@ -53,16 +54,48 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
||||
return share.NewShareUnauthorized()
|
||||
}
|
||||
|
||||
var accessGrantAcctIds []int
|
||||
if store.PermissionMode(params.Body.PermissionMode) == store.ClosedPermissionMode {
|
||||
for _, email := range params.Body.AccessGrants {
|
||||
acct, err := str.FindAccountWithEmail(email, trx)
|
||||
if err != nil {
|
||||
logrus.Errorf("unable to find account '%v' for share request from '%v'", email, principal.Email)
|
||||
return share.NewShareNotFound()
|
||||
}
|
||||
logrus.Debugf("found id '%d' for '%v'", acct.Id, acct.Email)
|
||||
accessGrantAcctIds = append(accessGrantAcctIds, acct.Id)
|
||||
}
|
||||
}
|
||||
|
||||
edge, err := zrokEdgeSdk.Client(cfg.Ziti)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return share.NewShareInternalServerError()
|
||||
}
|
||||
|
||||
reserved := params.Body.Reserved
|
||||
uniqueName := params.Body.UniqueName
|
||||
shrToken, err := createShareToken()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return share.NewShareInternalServerError()
|
||||
}
|
||||
if reserved && uniqueName != "" {
|
||||
if !util.IsValidUniqueName(uniqueName) {
|
||||
logrus.Errorf("invalid unique name '%v' for account '%v'", uniqueName, principal.Email)
|
||||
return share.NewShareUnprocessableEntity()
|
||||
}
|
||||
shareExists, err := str.ShareWithTokenExists(uniqueName, trx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error checking share for token collision: %v", err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
}
|
||||
if shareExists {
|
||||
logrus.Errorf("token '%v' already exists; cannot create share", uniqueName)
|
||||
return share.NewShareConflict()
|
||||
}
|
||||
shrToken = uniqueName
|
||||
}
|
||||
|
||||
var shrZId string
|
||||
var frontendEndpoints []string
|
||||
@ -94,7 +127,6 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
||||
}
|
||||
|
||||
case string(sdk.PrivateShareMode):
|
||||
logrus.Info("doing private")
|
||||
shrZId, frontendEndpoints, err = newPrivateResourceAllocator().allocate(envZId, shrToken, params, edge)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
@ -108,7 +140,6 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
||||
|
||||
logrus.Debugf("allocated share '%v'", shrToken)
|
||||
|
||||
reserved := params.Body.Reserved
|
||||
sshr := &store.Share{
|
||||
ZId: shrZId,
|
||||
Token: shrToken,
|
||||
@ -116,6 +147,10 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
||||
BackendMode: params.Body.BackendMode,
|
||||
BackendProxyEndpoint: ¶ms.Body.BackendProxyEndpoint,
|
||||
Reserved: reserved,
|
||||
PermissionMode: store.OpenPermissionMode,
|
||||
}
|
||||
if params.Body.PermissionMode != "" {
|
||||
sshr.PermissionMode = store.PermissionMode(params.Body.PermissionMode)
|
||||
}
|
||||
if len(params.Body.FrontendSelection) > 0 {
|
||||
sshr.FrontendSelection = ¶ms.Body.FrontendSelection[0]
|
||||
@ -132,6 +167,16 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
||||
return share.NewShareInternalServerError()
|
||||
}
|
||||
|
||||
if sshr.PermissionMode == store.ClosedPermissionMode {
|
||||
for _, acctId := range accessGrantAcctIds {
|
||||
_, err := str.CreateAccessGrant(sid, acctId, trx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error creating access grant for '%v': %v", principal.Email, err)
|
||||
return share.NewShareInternalServerError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := trx.Commit(); err != nil {
|
||||
logrus.Errorf("error committing share record: %v", err)
|
||||
return share.NewShareInternalServerError()
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"github.com/openziti/edge-api/rest_management_api_client"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/rest_server_zrok/operations/share"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
)
|
||||
|
||||
type privateResourceAllocator struct{}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"github.com/openziti/edge-api/rest_management_api_client"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/rest_server_zrok/operations/share"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
)
|
||||
|
||||
type publicResourceAllocator struct{}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/openziti/edge-api/rest_management_api_client"
|
||||
"github.com/openziti/edge-api/rest_management_api_client/config"
|
||||
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"time"
|
||||
|
57
controller/store/accessGrant.go
Normal file
57
controller/store/accessGrant.go
Normal file
@ -0,0 +1,57 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type AccessGrant struct {
|
||||
Model
|
||||
ShareId int
|
||||
AccountId int
|
||||
}
|
||||
|
||||
func (str *Store) CreateAccessGrant(shareId, accountId int, tx *sqlx.Tx) (int, error) {
|
||||
stmt, err := tx.Prepare("insert into access_grants (share_id, account_id) values ($1, $2) returning id")
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error preparing access_grant insert statement")
|
||||
}
|
||||
var id int
|
||||
if err := stmt.QueryRow(shareId, accountId).Scan(&id); err != nil {
|
||||
return 0, errors.Wrap(err, "error executing access_grant insert statement")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (str *Store) CheckAccessGrantForShareAndAccount(shrId, acctId int, tx *sqlx.Tx) (int, error) {
|
||||
count := 0
|
||||
err := tx.QueryRowx("select count(0) from access_grants where share_id = $1 and account_id = $2 and not deleted", shrId, acctId).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error selecting access_grants by share_id and account_id")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (str *Store) DeleteAccessGrantsForShare(shrId int, tx *sqlx.Tx) error {
|
||||
stmt, err := tx.Prepare("update access_grants set updated_at = current_timestamp, deleted = true where share_id = $1")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error preparing access_grants delete for shares statement")
|
||||
}
|
||||
_, err = stmt.Exec(shrId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error executing access_grants delete for shares statement")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (str *Store) DeleteAccessGrantsForShareAndAccount(shrId, acctId int, tx *sqlx.Tx) error {
|
||||
stmt, err := tx.Prepare("update access_grants set updated_at = current_timestamp, deleted = true where share_id = $1 and account_id = $2")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error preparing access_grants delete for share and account statement")
|
||||
}
|
||||
_, err = stmt.Exec(shrId, acctId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error executing access_grants delete for share and account statement")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -16,7 +16,7 @@ type Account struct {
|
||||
}
|
||||
|
||||
func (str *Store) CreateAccount(a *Account, tx *sqlx.Tx) (int, error) {
|
||||
stmt, err := tx.Prepare("insert into accounts (email, salt, password, token, limitless) values ($1, $2, $3, $4, $5) returning id")
|
||||
stmt, err := tx.Prepare("insert into accounts (email, salt, password, token, limitless) values (lower($1), $2, $3, $4, $5) returning id")
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error preparing accounts insert statement")
|
||||
}
|
||||
@ -37,7 +37,7 @@ func (str *Store) GetAccount(id int, tx *sqlx.Tx) (*Account, error) {
|
||||
|
||||
func (str *Store) FindAccountWithEmail(email string, tx *sqlx.Tx) (*Account, error) {
|
||||
a := &Account{}
|
||||
if err := tx.QueryRowx("select * from accounts where email = $1 and not deleted", email).StructScan(a); err != nil {
|
||||
if err := tx.QueryRowx("select * from accounts where email = lower($1) and not deleted", email).StructScan(a); err != nil {
|
||||
return nil, errors.Wrap(err, "error selecting account by email")
|
||||
}
|
||||
return a, nil
|
||||
@ -45,7 +45,7 @@ func (str *Store) FindAccountWithEmail(email string, tx *sqlx.Tx) (*Account, err
|
||||
|
||||
func (str *Store) FindAccountWithEmailAndDeleted(email string, tx *sqlx.Tx) (*Account, error) {
|
||||
a := &Account{}
|
||||
if err := tx.QueryRowx("select * from accounts where email = $1", email).StructScan(a); err != nil {
|
||||
if err := tx.QueryRowx("select * from accounts where email = lower($1)", email).StructScan(a); err != nil {
|
||||
return nil, errors.Wrap(err, "error selecting acount by email")
|
||||
}
|
||||
return a, nil
|
||||
@ -60,7 +60,7 @@ func (str *Store) FindAccountWithToken(token string, tx *sqlx.Tx) (*Account, err
|
||||
}
|
||||
|
||||
func (str *Store) UpdateAccount(a *Account, tx *sqlx.Tx) (int, error) {
|
||||
stmt, err := tx.Prepare("update accounts set email=$1, salt=$2, password=$3, token=$4, limitless=$5 where id = $6")
|
||||
stmt, err := tx.Prepare("update accounts set email=lower($1), salt=$2, password=$3, token=$4, limitless=$5 where id = $6")
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error preparing accounts update statement")
|
||||
}
|
||||
|
@ -7,3 +7,10 @@ const (
|
||||
WarningAction LimitJournalAction = "warning"
|
||||
ClearAction LimitJournalAction = "clear"
|
||||
)
|
||||
|
||||
type PermissionMode string
|
||||
|
||||
const (
|
||||
OpenPermissionMode PermissionMode = "open"
|
||||
ClosedPermissionMode PermissionMode = "closed"
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type PasswordResetRequest struct {
|
||||
@ -17,7 +18,11 @@ type PasswordResetRequest struct {
|
||||
}
|
||||
|
||||
func (str *Store) CreatePasswordResetRequest(prr *PasswordResetRequest, tx *sqlx.Tx) (int, error) {
|
||||
stmt, err := tx.Prepare("insert into password_reset_requests (account_id, token) values ($1, $2) ON CONFLICT(account_id) DO UPDATE SET token=$2 returning id")
|
||||
if err := str.DeletePasswordResetRequestsByAccountId(prr.AccountId, tx); err != nil {
|
||||
logrus.Errorf("unable to delete old password reset requests for account '%v', but continuing: %v", prr.AccountId, err)
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare("insert into password_reset_requests (account_id, token) values ($1, $2) returning id")
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error preparing password_reset_requests insert statement")
|
||||
}
|
||||
@ -98,3 +103,15 @@ func (str *Store) DeleteMultiplePasswordResetRequests(ids []int, tx *sqlx.Tx) er
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (str *Store) DeletePasswordResetRequestsByAccountId(accountId int, tx *sqlx.Tx) error {
|
||||
stmt, err := tx.Prepare("update password_reset_requests set updated_at = current_timestamp, deleted = true where account_id = $1")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error preparing password_reset_requests delete by account_id statement")
|
||||
}
|
||||
_, err = stmt.Exec(accountId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error executing password_reset_requests delete by account_id statement")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -16,16 +16,17 @@ type Share struct {
|
||||
FrontendEndpoint *string
|
||||
BackendProxyEndpoint *string
|
||||
Reserved bool
|
||||
PermissionMode PermissionMode
|
||||
Deleted bool
|
||||
}
|
||||
|
||||
func (str *Store) CreateShare(envId int, shr *Share, tx *sqlx.Tx) (int, error) {
|
||||
stmt, err := tx.Prepare("insert into shares (environment_id, z_id, token, share_mode, backend_mode, frontend_selection, frontend_endpoint, backend_proxy_endpoint, reserved) values ($1, $2, $3, $4, $5, $6, $7, $8, $9) returning id")
|
||||
stmt, err := tx.Prepare("insert into shares (environment_id, z_id, token, share_mode, backend_mode, frontend_selection, frontend_endpoint, backend_proxy_endpoint, reserved, permission_mode) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) returning id")
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "error preparing shares insert statement")
|
||||
}
|
||||
var id int
|
||||
if err := stmt.QueryRow(envId, shr.ZId, shr.Token, shr.ShareMode, shr.BackendMode, shr.FrontendSelection, shr.FrontendEndpoint, shr.BackendProxyEndpoint, shr.Reserved).Scan(&id); err != nil {
|
||||
if err := stmt.QueryRow(envId, shr.ZId, shr.Token, shr.ShareMode, shr.BackendMode, shr.FrontendSelection, shr.FrontendEndpoint, shr.BackendProxyEndpoint, shr.Reserved, shr.PermissionMode).Scan(&id); err != nil {
|
||||
return 0, errors.Wrap(err, "error executing shares insert statement")
|
||||
}
|
||||
return id, nil
|
||||
@ -63,6 +64,14 @@ func (str *Store) FindShareWithToken(shrToken string, tx *sqlx.Tx) (*Share, erro
|
||||
return shr, nil
|
||||
}
|
||||
|
||||
func (str *Store) ShareWithTokenExists(shrToken string, tx *sqlx.Tx) (bool, error) {
|
||||
count := 0
|
||||
if err := tx.QueryRowx("select count(0) from shares where token = $1 and not deleted", shrToken).Scan(&count); err != nil {
|
||||
return true, errors.Wrap(err, "error selecting share count by token")
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (str *Store) FindShareWithZIdAndDeleted(zId string, tx *sqlx.Tx) (*Share, error) {
|
||||
shr := &Share{}
|
||||
if err := tx.QueryRowx("select * from shares where z_id = $1", zId).StructScan(shr); err != nil {
|
||||
@ -88,12 +97,12 @@ func (str *Store) FindSharesForEnvironment(envId int, tx *sqlx.Tx) ([]*Share, er
|
||||
}
|
||||
|
||||
func (str *Store) UpdateShare(shr *Share, tx *sqlx.Tx) error {
|
||||
sql := "update shares set z_id = $1, token = $2, share_mode = $3, backend_mode = $4, frontend_selection = $5, frontend_endpoint = $6, backend_proxy_endpoint = $7, reserved = $8, updated_at = current_timestamp where id = $9"
|
||||
sql := "update shares set z_id = $1, token = $2, share_mode = $3, backend_mode = $4, frontend_selection = $5, frontend_endpoint = $6, backend_proxy_endpoint = $7, reserved = $8, permission_mode = $9, updated_at = current_timestamp where id = $10"
|
||||
stmt, err := tx.Prepare(sql)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error preparing shares update statement")
|
||||
}
|
||||
_, err = stmt.Exec(shr.ZId, shr.Token, shr.ShareMode, shr.BackendMode, shr.FrontendSelection, shr.FrontendEndpoint, shr.BackendProxyEndpoint, shr.Reserved, shr.Id)
|
||||
_, err = stmt.Exec(shr.ZId, shr.Token, shr.ShareMode, shr.BackendMode, shr.FrontendSelection, shr.FrontendEndpoint, shr.BackendProxyEndpoint, shr.Reserved, shr.PermissionMode, shr.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error executing shares update statement")
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
-- +migrate Up
|
||||
|
||||
-- remove the old unique index (which did not respect the deleted flag)
|
||||
ALTER TABLE shares DROP CONSTRAINT shares_token_key;
|
||||
|
||||
-- add a new unique index which only constrains uniqueness for not-deleted rows
|
||||
CREATE UNIQUE INDEX shares_token_idx ON shares(token) WHERE deleted is false;
|
@ -0,0 +1,3 @@
|
||||
-- +migrate Up
|
||||
|
||||
update accounts set email = lower(email);
|
@ -0,0 +1,3 @@
|
||||
-- +migrate Up
|
||||
|
||||
alter type backend_mode add value 'socks';
|
@ -0,0 +1,7 @@
|
||||
-- +migrate Up
|
||||
|
||||
-- remove the old unique index (users might need multiple password resets)
|
||||
ALTER TABLE password_reset_requests DROP CONSTRAINT password_reset_requests_account_id_key;
|
||||
|
||||
-- add new constraint which doesnt mind having multiple resets for account ids
|
||||
ALTER TABLE password_reset_requests ADD CONSTRAINT password_reset_requests_account_id_key FOREIGN KEY (account_id) REFERENCES accounts (id);
|
@ -0,0 +1,14 @@
|
||||
-- +migrate Up
|
||||
|
||||
create type permission_mode_type as enum('open', 'closed');
|
||||
|
||||
alter table shares add column permission_mode permission_mode_type not null default('open');
|
||||
|
||||
create table access_grants (
|
||||
id serial primary key,
|
||||
share_id integer references shares(id),
|
||||
account_id integer references accounts(id),
|
||||
created_at timestamptz not null default(current_timestamp),
|
||||
updated_at timestamptz not null default(current_timestamp),
|
||||
deleted boolean not null default(false)
|
||||
);
|
@ -0,0 +1,57 @@
|
||||
-- +migrate Up
|
||||
|
||||
alter table shares rename to shares_old;
|
||||
create table shares (
|
||||
id integer primary key,
|
||||
environment_id integer constraint fk_environments_shares references environments on delete cascade,
|
||||
z_id string not null unique,
|
||||
token string not null,
|
||||
share_mode string not null,
|
||||
backend_mode string not null,
|
||||
frontend_selection string,
|
||||
frontend_endpoint string,
|
||||
backend_proxy_endpoint string,
|
||||
reserved boolean not null default(false),
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
deleted boolean not null default(false),
|
||||
|
||||
constraint chk_z_id check (z_id <> ''),
|
||||
constraint chk_token check (token <> ''),
|
||||
constraint chk_share_mode check (share_mode == 'public' or share_mode == 'private'),
|
||||
constraint chk_backend_mode check (backend_mode == 'proxy' or backend_mode == 'web' or backend_mode == 'tcpTunnel' or backend_mode == 'udpTunnel' or backend_mode == 'caddy' or backend_mode == 'drive')
|
||||
);
|
||||
insert into shares select * from shares_old;
|
||||
create unique index shares_token_idx ON shares(token) WHERE deleted is false;
|
||||
|
||||
alter table frontends rename to frontends_old;
|
||||
create table frontends (
|
||||
id integer primary key,
|
||||
environment_id integer references environments(id),
|
||||
token varchar(32) not null unique,
|
||||
z_id varchar(32) not null,
|
||||
public_name varchar(64) unique,
|
||||
url_template varchar(1024),
|
||||
reserved boolean not null default(false),
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
deleted boolean not null default(false),
|
||||
private_share_id integer references shares(id)
|
||||
);
|
||||
insert into frontends select * from frontends_old;
|
||||
drop table frontends_old;
|
||||
|
||||
alter table share_limit_journal rename to share_limit_journal_old;
|
||||
create table share_limit_journal (
|
||||
id integer primary key,
|
||||
share_id integer references shares(id),
|
||||
rx_bytes bigint not null,
|
||||
tx_bytes bigint not null,
|
||||
action limit_action_type not null,
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now'))
|
||||
);
|
||||
insert into share_limit_journal select * from share_limit_journal_old;
|
||||
drop table share_limit_journal_old;
|
||||
|
||||
drop table shares_old;
|
@ -0,0 +1,3 @@
|
||||
-- +migrate Up
|
||||
|
||||
update accounts set email = lower(email);
|
@ -0,0 +1,58 @@
|
||||
-- +migrate Up
|
||||
|
||||
alter table shares rename to shares_old;
|
||||
create table shares (
|
||||
id integer primary key,
|
||||
environment_id integer constraint fk_environments_shares references environments on delete cascade,
|
||||
z_id string not null unique,
|
||||
token string not null,
|
||||
share_mode string not null,
|
||||
backend_mode string not null,
|
||||
frontend_selection string,
|
||||
frontend_endpoint string,
|
||||
backend_proxy_endpoint string,
|
||||
reserved boolean not null default(false),
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
deleted boolean not null default(false),
|
||||
|
||||
constraint chk_z_id check (z_id <> ''),
|
||||
constraint chk_token check (token <> ''),
|
||||
constraint chk_share_mode check (share_mode == 'public' or share_mode == 'private'),
|
||||
constraint chk_backend_mode check (backend_mode == 'proxy' or backend_mode == 'web' or backend_mode == 'tcpTunnel' or backend_mode == 'udpTunnel' or backend_mode == 'caddy' or backend_mode == 'drive' or backend_mode == 'socks')
|
||||
);
|
||||
insert into shares select * from shares_old;
|
||||
drop index shares_token_idx;
|
||||
create unique index shares_token_idx ON shares(token) WHERE deleted is false;
|
||||
|
||||
alter table frontends rename to frontends_old;
|
||||
create table frontends (
|
||||
id integer primary key,
|
||||
environment_id integer references environments(id),
|
||||
token varchar(32) not null unique,
|
||||
z_id varchar(32) not null,
|
||||
public_name varchar(64) unique,
|
||||
url_template varchar(1024),
|
||||
reserved boolean not null default(false),
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
deleted boolean not null default(false),
|
||||
private_share_id integer references shares(id)
|
||||
);
|
||||
insert into frontends select * from frontends_old;
|
||||
drop table frontends_old;
|
||||
|
||||
alter table share_limit_journal rename to share_limit_journal_old;
|
||||
create table share_limit_journal (
|
||||
id integer primary key,
|
||||
share_id integer references shares(id),
|
||||
rx_bytes bigint not null,
|
||||
tx_bytes bigint not null,
|
||||
action limit_action_type not null,
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now'))
|
||||
);
|
||||
insert into share_limit_journal select * from share_limit_journal_old;
|
||||
drop table share_limit_journal_old;
|
||||
|
||||
drop table shares_old;
|
@ -0,0 +1,17 @@
|
||||
-- +migrate Up
|
||||
|
||||
alter table password_reset_requests rename to password_reset_requests_old;
|
||||
|
||||
CREATE TABLE password_reset_requests (
|
||||
id integer primary key,
|
||||
token string not null unique,
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
account_id integer not null constraint fk_accounts_password_reset_requests references accounts,
|
||||
deleted boolean not null default(false),
|
||||
|
||||
constraint chk_token check(token <> '')
|
||||
);
|
||||
|
||||
insert into password_reset_requests select * from password_reset_requests_old;
|
||||
drop table password_reset_requests_old;
|
@ -0,0 +1,12 @@
|
||||
-- +migrate Up
|
||||
|
||||
alter table shares add column permission_mode string not null default('open');
|
||||
|
||||
create table access_grants (
|
||||
id integer primary key,
|
||||
share_id integer references shares(id),
|
||||
account_id integer references accounts(id),
|
||||
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
||||
deleted boolean not null default(false)
|
||||
);
|
@ -76,15 +76,15 @@ func (h *unshareHandler) Handle(params share.UnshareParams, principal *rest_mode
|
||||
|
||||
if sshr.Reserved == params.Body.Reserved {
|
||||
// single tag-based share deallocator; should work regardless of sharing mode
|
||||
if err := h.deallocateResources(senv, shrToken, shrZId, edge); err != nil {
|
||||
logrus.Errorf("error unsharing ziti resources for '%v': %v", sshr, err)
|
||||
return share.NewUnshareInternalServerError()
|
||||
}
|
||||
|
||||
h.deallocateResources(senv, shrToken, shrZId, edge)
|
||||
logrus.Debugf("deallocated share '%v'", shrToken)
|
||||
|
||||
if err := str.DeleteAccessGrantsForShare(sshr.Id, tx); err != nil {
|
||||
logrus.Errorf("error deleting access grants for share '%v': %v", shrToken, err)
|
||||
return share.NewUnshareInternalServerError()
|
||||
}
|
||||
if err := str.DeleteShare(sshr.Id, tx); err != nil {
|
||||
logrus.Errorf("error deactivating share '%v': %v", shrZId, err)
|
||||
logrus.Errorf("error deleting share '%v': %v", shrToken, err)
|
||||
return share.NewUnshareInternalServerError()
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
@ -120,21 +120,20 @@ func (h *unshareHandler) findShareZId(shrToken string, edge *rest_management_api
|
||||
return "", errors.Errorf("share '%v' not found", shrToken)
|
||||
}
|
||||
|
||||
func (h *unshareHandler) deallocateResources(senv *store.Environment, shrToken, shrZId string, edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||
func (h *unshareHandler) deallocateResources(senv *store.Environment, shrToken, shrZId string, edge *rest_management_api_client.ZitiEdgeManagement) {
|
||||
if err := zrokEdgeSdk.DeleteServiceEdgeRouterPolicy(senv.ZId, shrToken, edge); err != nil {
|
||||
return err
|
||||
logrus.Warnf("error deleting service edge router policies for share '%v' in environment '%v': %v", shrToken, senv.ZId, err)
|
||||
}
|
||||
if err := zrokEdgeSdk.DeleteServicePoliciesDial(senv.ZId, shrToken, edge); err != nil {
|
||||
return err
|
||||
logrus.Warnf("error deleting dial service policies for share '%v' in environment '%v': %v", shrToken, senv.ZId, err)
|
||||
}
|
||||
if err := zrokEdgeSdk.DeleteServicePoliciesBind(senv.ZId, shrToken, edge); err != nil {
|
||||
return err
|
||||
logrus.Warnf("error deleting bind service policies for share '%v' in environment '%v': %v", shrToken, senv.ZId, err)
|
||||
}
|
||||
if err := zrokEdgeSdk.DeleteConfig(senv.ZId, shrToken, edge); err != nil {
|
||||
return err
|
||||
logrus.Warnf("error deleting config for share '%v' in environment '%v': %v", shrToken, senv.ZId, err)
|
||||
}
|
||||
if err := zrokEdgeSdk.DeleteService(senv.ZId, shrZId, edge); err != nil {
|
||||
return err
|
||||
logrus.Warnf("error deleting service '%v' for share '%v' in environment '%v': %v", shrZId, shrToken, senv.ZId, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -48,15 +48,49 @@ func (h *updateShareHandler) Handle(params share.UpdateShareParams, principal *r
|
||||
return share.NewUpdateShareNotFound()
|
||||
}
|
||||
|
||||
sshr.BackendProxyEndpoint = &backendProxyEndpoint
|
||||
if err := str.UpdateShare(sshr, tx); err != nil {
|
||||
logrus.Errorf("error updating share '%v': %v", shrToken, err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
doCommit := false
|
||||
if backendProxyEndpoint != "" {
|
||||
sshr.BackendProxyEndpoint = &backendProxyEndpoint
|
||||
if err := str.UpdateShare(sshr, tx); err != nil {
|
||||
logrus.Errorf("error updating share '%v': %v", shrToken, err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
}
|
||||
doCommit = true
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
logrus.Errorf("error committing transaction for share '%v' update: %v", shrToken, err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
for _, addr := range params.Body.AddAccessGrants {
|
||||
acct, err := str.FindAccountWithEmail(addr, tx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error looking up account by email '%v' for user '%v': %v", addr, principal.Email, err)
|
||||
return share.NewUpdateShareBadRequest()
|
||||
}
|
||||
if _, err := str.CreateAccessGrant(sshr.Id, acct.Id, tx); err != nil {
|
||||
logrus.Errorf("error adding access grant '%v' for share '%v': %v", acct.Email, shrToken, err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
}
|
||||
logrus.Infof("added access grant '%v' to share '%v'", acct.Email, shrToken)
|
||||
doCommit = true
|
||||
}
|
||||
|
||||
for _, addr := range params.Body.RemoveAccessGrants {
|
||||
acct, err := str.FindAccountWithEmail(addr, tx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error looking up account by email '%v' for user '%v': %v", addr, principal.Email, err)
|
||||
return share.NewUpdateShareBadRequest()
|
||||
}
|
||||
if err := str.DeleteAccessGrantsForShareAndAccount(sshr.Id, acct.Id, tx); err != nil {
|
||||
logrus.Errorf("error removing access grant '%v' for share '%v': %v", acct.Email, shrToken, err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
}
|
||||
logrus.Infof("removed access grant '%v' from share '%v'", acct.Email, shrToken)
|
||||
doCommit = true
|
||||
}
|
||||
|
||||
if doCommit {
|
||||
if err := tx.Commit(); err != nil {
|
||||
logrus.Errorf("error committing transaction for share '%v' update: %v", shrToken, err)
|
||||
return share.NewUpdateShareInternalServerError()
|
||||
}
|
||||
}
|
||||
|
||||
return share.NewUpdateShareOK()
|
||||
|
@ -65,7 +65,7 @@ func createShareToken() (string, error) {
|
||||
return gen(), nil
|
||||
}
|
||||
|
||||
func createToken() (string, error) {
|
||||
func CreateToken() (string, error) {
|
||||
gen, err := nanoid.CustomASCII("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 12)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/openziti/edge-api/rest_management_api_client"
|
||||
"github.com/openziti/edge-api/rest_management_api_client/config"
|
||||
"github.com/openziti/edge-api/rest_model"
|
||||
"github.com/openziti/zrok/sdk"
|
||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||
"github.com/sirupsen/logrus"
|
||||
"time"
|
||||
)
|
||||
|
2
docker/compose/.gitignore
vendored
2
docker/compose/.gitignore
vendored
@ -1,2 +1,2 @@
|
||||
.env
|
||||
compose.override.yml
|
||||
*compose.override.yml
|
@ -7,31 +7,24 @@ services:
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
|
||||
# enable zrok environment
|
||||
zrok-enable:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
depends_on:
|
||||
zrok-init:
|
||||
condition: service_completed_successfully
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
if [[ -n "$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)" ]]; then
|
||||
echo "INFO: zrok environment is already enabled"
|
||||
exit 0
|
||||
else
|
||||
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
|
||||
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
|
||||
exec zrok "$${@}"
|
||||
fi
|
||||
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker private access}" ${ZROK_ENABLE_TOKEN}
|
||||
entrypoint: zrok-enable.bash
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
STATE_DIRECTORY: /mnt
|
||||
ZROK_ENABLE_TOKEN:
|
||||
ZROK_API_ENDPOINT:
|
||||
ZROK_ENVIRONMENT_NAME: docker-private-access
|
||||
|
||||
zrok-access:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
restart: unless-stopped
|
||||
command: access private --headless --bind 0.0.0.0:9191 ${ZROK_ACCESS_TOKEN}
|
||||
depends_on:
|
||||
zrok-enable:
|
||||
@ -39,7 +32,7 @@ services:
|
||||
ports:
|
||||
- 9191:9191 # expose the zrok private access proxy to the Docker host
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
PFXLOG_NO_JSON: "true"
|
||||
|
@ -7,42 +7,42 @@ services:
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
|
||||
# enable zrok environment
|
||||
zrok-enable:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
depends_on:
|
||||
zrok-init:
|
||||
condition: service_completed_successfully
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
if [[ -n "$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)" ]]; then
|
||||
echo "INFO: zrok environment is already enabled"
|
||||
exit 0
|
||||
else
|
||||
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
|
||||
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
|
||||
exec zrok "$${@}"
|
||||
fi
|
||||
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker private share}" ${ZROK_ENABLE_TOKEN}
|
||||
entrypoint: zrok-enable.bash
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
STATE_DIRECTORY: /mnt
|
||||
ZROK_ENABLE_TOKEN:
|
||||
ZROK_API_ENDPOINT:
|
||||
ZROK_ENVIRONMENT_NAME: docker-private-share
|
||||
|
||||
zrok-share:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
command: share private --headless --backend-mode proxy ${ZROK_TARGET:-http://zrok-test:9090/}
|
||||
restart: no
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euxc
|
||||
- |
|
||||
echo "DEBUG: HOME=$${HOME}"
|
||||
ls -lA /mnt/.zrok/
|
||||
exec zrok $${@}
|
||||
command: -- share private --headless --backend-mode proxy ${ZROK_TARGET:-http://zrok-test:9090/}
|
||||
depends_on:
|
||||
zrok-enable:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
PFXLOG_NO_JSON: "true"
|
||||
|
||||
# demo servers you can share with zrok
|
||||
# demo server you can share with zrok
|
||||
zrok-test:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
command: test endpoint --address 0.0.0.0 # 9090
|
||||
|
@ -1,46 +1,7 @@
|
||||
services:
|
||||
# create Caddyfile
|
||||
zrok-caddyfile:
|
||||
image: busybox
|
||||
# create Caddyfile
|
||||
entrypoint:
|
||||
- sh
|
||||
- -euc
|
||||
- |
|
||||
ZROK_UPSTREAM_URL="${ZROK_TARGET:-http://zrok-test:9090}"
|
||||
ZROK_UPSTREAM_HOST="$(echo $${ZROK_UPSTREAM_URL}|sed -E 's#^https?://([^/:]+).*#\1#')"
|
||||
mkdir -p /mnt/.zrok
|
||||
cat <<CADDYFILE >| /mnt/.zrok/Caddyfile
|
||||
{
|
||||
# GET /config/ and POST /load on this API to reload Caddy config
|
||||
admin 0.0.0.0:2019
|
||||
}
|
||||
http:// {
|
||||
bind {{ .ZrokBindAddress }}
|
||||
handle_path /zrok-test/* {
|
||||
reverse_proxy http://zrok-test:9090 {
|
||||
header_up Host zrok-test
|
||||
}
|
||||
}
|
||||
handle_path /zrok-static/* {
|
||||
root * /mnt/.zrok/html
|
||||
file_server browse
|
||||
}
|
||||
reverse_proxy /* $${ZROK_UPSTREAM_URL} {
|
||||
header_up Host $${ZROK_UPSTREAM_HOST}
|
||||
}
|
||||
}
|
||||
CADDYFILE
|
||||
user: root
|
||||
volumes:
|
||||
- zrok_env:/mnt
|
||||
|
||||
# set file ownership
|
||||
zrok-init:
|
||||
image: busybox
|
||||
depends_on:
|
||||
zrok-caddyfile:
|
||||
condition: service_completed_successfully
|
||||
# matches uid:gid of "nobody" in zrok container image
|
||||
command: chown -Rc 65534:65534 /mnt/
|
||||
user: root
|
||||
@ -53,116 +14,43 @@ services:
|
||||
depends_on:
|
||||
zrok-init:
|
||||
condition: service_completed_successfully
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
if [[ -s ~/.zrok/environment.json ]]; then
|
||||
ZITI_ID="$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)"
|
||||
if [[ -z "$${ZITI_ID}" || "$${ZITI_ID}" == null ]]; then
|
||||
echo "ERROR: invalid environment; consider a reset with 'docker compose down --volumes'" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "INFO: zrok environment is already enabled"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
if [[ -z "${ZROK_ENABLE_TOKEN}" ]]; then
|
||||
echo "ERROR: ZROK_ENABLE_TOKEN is not defined" >&2
|
||||
exit 1
|
||||
else
|
||||
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
|
||||
echo "INFO: running: zrok $(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
|
||||
exec zrok "$${@}"
|
||||
fi
|
||||
fi
|
||||
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker reserved public share}" ${ZROK_ENABLE_TOKEN}
|
||||
entrypoint: zrok-enable.bash
|
||||
volumes:
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
STATE_DIRECTORY: /mnt
|
||||
ZROK_ENABLE_TOKEN:
|
||||
ZROK_API_ENDPOINT:
|
||||
ZROK_ENVIRONMENT_NAME:
|
||||
|
||||
# reserve zrok frontend url for the zrok backend config
|
||||
zrok-reserve:
|
||||
# reserve zrok frontend subdomain and start sharing the target
|
||||
zrok-share:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
if [[ -s ~/.zrok/reserved.json ]]; then
|
||||
ZROK_RESERVED_TOKEN="$(jq '.token' ~/.zrok/reserved.json 2>/dev/null)"
|
||||
if [[ -z "$${ZROK_RESERVED_TOKEN}" || "$${ZROK_RESERVED_TOKEN}" == null ]]; then
|
||||
echo "ERROR: invalid reserved.json: $(jq -c . ~/.zrok/reserved.json)" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "INFO: zrok backend is already reserved: $${ZROK_RESERVED_TOKEN}"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
set -o pipefail
|
||||
ZROK_CMD="reserve public --json-output"
|
||||
if [[ -n "${ZROK_SHARE_OPTS:-}" ]]; then
|
||||
ZROK_CMD+=" ${ZROK_SHARE_OPTS}"
|
||||
fi
|
||||
if [[ -n "${ZROK_OAUTH_PROVIDER:-}" ]]; then
|
||||
ZROK_CMD+=" --oauth-provider ${ZROK_OAUTH_PROVIDER}"
|
||||
fi
|
||||
if [[ -n "${ZROK_BACKEND_MODE:-}" && "${ZROK_BACKEND_MODE}" != caddy ]]; then
|
||||
ZROK_CMD+=" --backend-mode ${ZROK_BACKEND_MODE} ${ZROK_TARGET:-http://zrok-test:9090}"
|
||||
else
|
||||
ZROK_CMD+=" --backend-mode caddy /mnt/.zrok/Caddyfile"
|
||||
fi
|
||||
echo "INFO: running: zrok $${ZROK_CMD}"
|
||||
zrok $${ZROK_CMD} | jq -rc | tee ~/.zrok/reserved.json
|
||||
fi
|
||||
restart: unless-stopped
|
||||
entrypoint: zrok-share.bash
|
||||
depends_on:
|
||||
zrok-enable:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
# internal configuration
|
||||
STATE_DIRECTORY: /mnt # zrok homedir in container
|
||||
|
||||
# start share on reserved public frontend url
|
||||
zrok-share:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
if ! [[ -s ~/.zrok/reserved.json ]]; then
|
||||
echo "ERROR: empty or missing reserved.json" >&2
|
||||
exit 1
|
||||
else
|
||||
ZROK_PUBLIC_URLS=$(jq -cr '.frontend_endpoints' ~/.zrok/reserved.json 2>/dev/null)
|
||||
if [[ -z "$${ZROK_PUBLIC_URLS}" || "$${ZROK_PUBLIC_URLS}" == null ]]; then
|
||||
echo "ERROR: frontend endpoints not defined" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "INFO: zrok public URLs: $${ZROK_PUBLIC_URLS}"
|
||||
fi
|
||||
ZROK_RESERVED_TOKEN=$(jq -r '.token' ~/.zrok/reserved.json 2>/dev/null)
|
||||
if [[ -z "$${ZROK_RESERVED_TOKEN}" && "$${ZROK_RESERVED_TOKEN}" == null ]]; then
|
||||
echo "ERROR: zrok reservation token not defined" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "INFO: zrok reservation token: $${ZROK_RESERVED_TOKEN}"
|
||||
fi
|
||||
# most relevant options
|
||||
ZROK_UNIQUE_NAME: # name is used to construct frontend domain name, e.g. "myapp" in "myapp.share.zrok.io"
|
||||
ZROK_BACKEND_MODE: # web, caddy, drive, proxy
|
||||
ZROK_TARGET: # backend target, is a path in container filesystem unless proxy mode
|
||||
ZROK_INSECURE: # "--insecure" if proxy target has unverifiable TLS server certificate
|
||||
ZROK_OAUTH_PROVIDER: # google, github
|
||||
ZROK_OAUTH_EMAILS: # allow space-separated list of OAuth email address glob patterns
|
||||
ZROK_BASIC_AUTH: # username:password, mutually-exclusive with ZROK_OAUTH_PROVIDER
|
||||
|
||||
echo "INFO: running: zrok $${@} $${ZROK_RESERVED_TOKEN}"
|
||||
exec zrok "$${@}" $${ZROK_RESERVED_TOKEN}
|
||||
fi
|
||||
command: -- share reserved --headless
|
||||
depends_on:
|
||||
zrok-reserve:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- zrok_env:/mnt
|
||||
ports:
|
||||
- 127.0.0.1:2019:2019
|
||||
environment:
|
||||
HOME: /mnt
|
||||
PFXLOG_NO_JSON: "true"
|
||||
# least relevant options
|
||||
ZROK_VERBOSE: # "--verbose"
|
||||
ZROK_SHARE_OPTS: # additional arguments to "zrok reserve public" command
|
||||
ZROK_FRONTENDS: # "public"
|
||||
PFXLOG_NO_JSON: "true" # suppress JSON logging format
|
||||
|
||||
# demo server
|
||||
zrok-test:
|
||||
|
@ -15,52 +15,45 @@ services:
|
||||
depends_on:
|
||||
zrok-init:
|
||||
condition: service_completed_successfully
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
if [[ -n "$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)" ]]; then
|
||||
echo "INFO: zrok environment is already enabled"
|
||||
exit 0
|
||||
else
|
||||
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
|
||||
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
|
||||
exec zrok "$${@}"
|
||||
fi
|
||||
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker temp public share}" ${ZROK_ENABLE_TOKEN}
|
||||
entrypoint: zrok-enable.bash
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
STATE_DIRECTORY: /mnt
|
||||
ZROK_ENABLE_TOKEN:
|
||||
ZROK_API_ENDPOINT:
|
||||
ZROK_ENVIRONMENT_NAME: docker-public-share
|
||||
|
||||
# start share on temporary public frontend url
|
||||
# provision a temporary zrok frontend subdomain and start sharing the backend target
|
||||
zrok-share:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
entrypoint:
|
||||
- bash
|
||||
- -euc
|
||||
- |
|
||||
set -o pipefail
|
||||
ZROK_CMD="share public --headless"
|
||||
if [[ -n "${ZROK_SHARE_OPTS:-}" ]]; then
|
||||
ZROK_CMD+=" ${ZROK_SHARE_OPTS}"
|
||||
fi
|
||||
if [[ -n "${ZROK_OAUTH_PROVIDER:-}" ]]; then
|
||||
ZROK_CMD+=" --oauth-provider ${ZROK_OAUTH_PROVIDER}"
|
||||
fi
|
||||
ZROK_CMD+=" --backend-mode proxy ${ZROK_TARGET:-http://zrok-test:9090/}"
|
||||
echo "INFO: running: zrok $${ZROK_CMD}"
|
||||
exec zrok $${ZROK_CMD}
|
||||
restart: no
|
||||
entrypoint: zrok-share.bash
|
||||
depends_on:
|
||||
zrok-enable:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- zrok_env:/mnt/.zrok
|
||||
- zrok_env:/mnt
|
||||
environment:
|
||||
HOME: /mnt
|
||||
PFXLOG_NO_JSON: "true"
|
||||
# internal configuration
|
||||
STATE_DIRECTORY: /mnt # zrok homedir in container
|
||||
ZROK_FRONTEND_MODE: temp-public # tells zrok-share.bash to create a temporary subdomain and share until exit
|
||||
|
||||
# demo servers you can share with zrok
|
||||
# most relevant options
|
||||
ZROK_BACKEND_MODE: proxy # web, caddy, drive, proxy
|
||||
ZROK_TARGET: http://zrok-test:9090 # backend target, is a path in container filesystem unless proxy mode
|
||||
ZROK_INSECURE: # "--insecure" if proxy target has unverifiable TLS server certificate
|
||||
ZROK_OAUTH_PROVIDER: # google, github
|
||||
ZROK_OAUTH_EMAILS: # allow space-separated list of OAuth email address glob patterns
|
||||
ZROK_BASIC_AUTH: # username:password, mutually-exclusive with ZROK_OAUTH_PROVIDER
|
||||
|
||||
# least relevant options
|
||||
ZROK_VERBOSE: # "--verbose"
|
||||
ZROK_SHARE_OPTS: # additional arguments to "zrok share public" command
|
||||
ZROK_FRONTENDS: # "public"
|
||||
PFXLOG_NO_JSON: "true" # suppress JSON logging format
|
||||
|
||||
# demo server you can share with zrok
|
||||
zrok-test:
|
||||
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
|
||||
command: test endpoint --address 0.0.0.0 # 9090
|
||||
|
@ -1,3 +1,4 @@
|
||||
# Stage 1: Install Node.js with nvm
|
||||
FROM debian:bullseye-slim
|
||||
#
|
||||
# this file mirrors the build params used in the GitHub Actions and enables
|
||||
@ -12,23 +13,31 @@ ARG go_root=/usr/local/go
|
||||
ARG go_cache=/usr/share/go_cache
|
||||
ARG uid=1000
|
||||
ARG gid=1000
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gcc-aarch64-linux-gnu
|
||||
RUN apt-get -y install wget build-essential
|
||||
RUN apt-get -y update \
|
||||
&& apt-get -y install \
|
||||
gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gcc-aarch64-linux-gnu \
|
||||
wget build-essential
|
||||
|
||||
COPY ./linux-build.sh /usr/local/bin/
|
||||
RUN wget -q https://go.dev/dl/${go_distribution_file}
|
||||
RUN tar -xzf ${go_distribution_file} -C /usr/local/
|
||||
|
||||
RUN wget -qO- https://deb.nodesource.com/setup_18.x | bash \
|
||||
&& apt-get -y update \
|
||||
&& apt-get -y install \
|
||||
nodejs
|
||||
|
||||
RUN mkdir ${go_path} ${go_cache}
|
||||
RUN chown -R ${uid}:${gid} ${go_path} ${go_cache}
|
||||
|
||||
COPY ./linux-build.sh /usr/local/bin/
|
||||
|
||||
USER ${uid}:${gid}
|
||||
ENV TARGETARCH=${TARGETARCH}
|
||||
ENV GOPATH=${go_path}
|
||||
ENV GOROOT=${go_root}
|
||||
ENV GOCACHE=${go_cache}
|
||||
ENV PATH=${go_path}/bin:${go_root}/bin:$PATH
|
||||
|
||||
RUN go install github.com/mitchellh/gox@latest
|
||||
WORKDIR /mnt
|
||||
ENTRYPOINT ["linux-build.sh"]
|
||||
|
@ -6,7 +6,10 @@
|
||||
#
|
||||
#
|
||||
|
||||
set -o pipefail -e -u
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
set -o xtrace
|
||||
|
||||
# if no architectures supplied then default list of three
|
||||
if (( ${#} )); then
|
||||
@ -31,6 +34,16 @@ else
|
||||
PROCS_PER_JOB=0 # invokes gox default to use all CPUs-1
|
||||
fi
|
||||
|
||||
(
|
||||
HOME=/tmp/builder
|
||||
# Navigate to the "ui" directory and run npm commands
|
||||
npm config set cache /mnt/.npm
|
||||
cd ./ui/
|
||||
mkdir -p $HOME
|
||||
npm install
|
||||
npm run build
|
||||
)
|
||||
|
||||
for ARCH in ${JOBS[@]}; do
|
||||
GOX_CMD="
|
||||
gox \
|
||||
|
@ -1,5 +1,5 @@
|
||||
# this builds docker.io/openziti/zrok
|
||||
ARG ZITI_CLI_TAG="0.30.5"
|
||||
ARG ZITI_CLI_TAG="0.32.1"
|
||||
ARG ZITI_CLI_IMAGE="docker.io/openziti/ziti-cli"
|
||||
# this builds docker.io/openziti/ziti-controller
|
||||
FROM ${ZITI_CLI_IMAGE}:${ZITI_CLI_TAG}
|
||||
@ -20,8 +20,9 @@ LABEL name="openziti/zrok" \
|
||||
|
||||
USER root
|
||||
|
||||
### install packages (jq introduced in source image in next release 0.30.6)
|
||||
RUN INSTALL_PKGS="jq" && \
|
||||
### install packages: findutils provides xargs which is used by the zrok Helm chart's controller bootstrapping script to
|
||||
#create the default account enable token
|
||||
RUN INSTALL_PKGS="findutils" && \
|
||||
microdnf -y update --setopt=install_weak_deps=0 --setopt=tsflags=nodocs && \
|
||||
microdnf -y install --setopt=install_weak_deps=0 --setopt=tsflags=nodocs ${INSTALL_PKGS}
|
||||
|
||||
@ -30,8 +31,14 @@ RUN mkdir -p -m0755 /licenses
|
||||
COPY ./LICENSE /licenses/apache.txt
|
||||
|
||||
RUN mkdir -p /usr/local/bin
|
||||
COPY ${ARTIFACTS_DIR}/${TARGETARCH}/${TARGETOS}/zrok /usr/local/bin/
|
||||
RUN chmod 0755 /usr/local/bin/zrok
|
||||
COPY ${ARTIFACTS_DIR}/${TARGETARCH}/${TARGETOS}/zrok \
|
||||
./nfpm/zrok-enable.bash \
|
||||
./nfpm/zrok-share.bash \
|
||||
/usr/local/bin/
|
||||
RUN chmod 0755 \
|
||||
/usr/local/bin/zrok \
|
||||
/usr/local/bin/zrok-enable.bash \
|
||||
/usr/local/bin/zrok-share.bash
|
||||
|
||||
USER nobody
|
||||
ENTRYPOINT [ "zrok" ]
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"label": "Network",
|
||||
"position": 60,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
}
|
||||
{
|
||||
"label": "Network",
|
||||
"position": 60,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"label": "Sharing",
|
||||
"position": 20,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
}
|
||||
{
|
||||
"label": "Sharing",
|
||||
"position": 20,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
}
|
||||
}
|
8
docs/concepts/_category_.json
Normal file
8
docs/concepts/_category_.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"label": "Concepts",
|
||||
"position": 30,
|
||||
"link": {
|
||||
"type": "doc",
|
||||
"id": "concepts/index"
|
||||
}
|
||||
}
|
@ -1,50 +1,52 @@
|
||||
---
|
||||
sidebar_position: 30
|
||||
---
|
||||
# Sharing Websites and Files
|
||||
|
||||
With `zrok` it is possible to share files quickly and easily as well. To share files using `zrok` use
|
||||
the `--backend-mode web`, for example: `zrok share private . --backend-mode web`.
|
||||
|
||||
Running with this mode will make it trivially easy to share files from the directory which the command
|
||||
was run from.
|
||||
|
||||
For example if you have a directory with a structure like this:
|
||||
```shell
|
||||
-rw-r--r--+ 1 Michael None 7090 Apr 17 12:53 CHANGELOG.md
|
||||
-rw-r--r--+ 1 Michael None 11346 Apr 17 12:53 LICENSE
|
||||
-rw-r--r--+ 1 Michael None 2885 Apr 17 12:53 README.md
|
||||
-rwxr-xr-x+ 1 Michael None 44250624 Apr 17 13:00 zrok.exe*
|
||||
```
|
||||
|
||||
The files can be shared using a command such as:
|
||||
```shell
|
||||
zrok share public --backend-mode web .
|
||||
```
|
||||
|
||||
Then the files can be access with a `private` or `public` share, for example as shown:
|
||||
|
||||
![zrok_share_web_files](../images/zrok_share_web_files.png)
|
||||
|
||||
`zrok` will automatically provide a stock website, which will allow the accessing user to browse and navigate the file tree. Clicking the files allows the user to download them.
|
||||
|
||||
`zrok` can also share a pre-rendered static HTML website. If you have a directory like this:
|
||||
|
||||
```shell
|
||||
-rw-rw-r--+ 1 Michael None 56 Jun 26 13:23 index.html
|
||||
```
|
||||
|
||||
If `index.html` contains valid HTML, like this:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<h1>Hello <code>zrok</code></h1>
|
||||
</html>
|
||||
```
|
||||
|
||||
Sharing the directory will result in the following when you access the share in a web browser:
|
||||
|
||||
![zrok_share_web_website](../images/zrok_share_web_website.png)
|
||||
|
||||
---
|
||||
title: Sharing Websites and Files
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
With `zrok` it is possible to share files quickly and easily as well. To share files using `zrok` use
|
||||
the `--backend-mode web`, for example: `zrok share private . --backend-mode web`.
|
||||
|
||||
Running with this mode will make it trivially easy to share files from the directory which the command
|
||||
was run from.
|
||||
|
||||
For example if you have a directory with a structure like this:
|
||||
|
||||
```shell
|
||||
-rw-r--r--+ 1 Michael None 7090 Apr 17 12:53 CHANGELOG.md
|
||||
-rw-r--r--+ 1 Michael None 11346 Apr 17 12:53 LICENSE
|
||||
-rw-r--r--+ 1 Michael None 2885 Apr 17 12:53 README.md
|
||||
-rwxr-xr-x+ 1 Michael None 44250624 Apr 17 13:00 zrok.exe*
|
||||
```
|
||||
|
||||
The files can be shared using a command such as:
|
||||
|
||||
```shell
|
||||
zrok share public --backend-mode web .
|
||||
```
|
||||
|
||||
Then the files can be access with a `private` or `public` share, for example as shown:
|
||||
|
||||
![zrok_share_web_files](../images/zrok_share_web_files.png)
|
||||
|
||||
`zrok` will automatically provide a stock website, which will allow the accessing user to browse and navigate the file tree. Clicking the files allows the user to download them.
|
||||
|
||||
`zrok` can also share a pre-rendered static HTML website. If you have a directory like this:
|
||||
|
||||
```shell
|
||||
-rw-rw-r--+ 1 Michael None 56 Jun 26 13:23 index.html
|
||||
```
|
||||
|
||||
If `index.html` contains valid HTML, like this:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
<h1>Hello <code>zrok</code></h1>
|
||||
</html>
|
||||
```
|
||||
|
||||
Sharing the directory will result in the following when you access the share in a web browser:
|
||||
|
||||
![zrok_share_web_website](../images/zrok_share_web_website.png)
|
||||
|
||||
`zrok` contains a built-in web server, which you can use to serve static websites as a share.
|
@ -1,15 +1,16 @@
|
||||
---
|
||||
sidebar_position: 200
|
||||
---
|
||||
# Hosting
|
||||
|
||||
## Self-Hosted
|
||||
|
||||
`zrok` is not limited to a managed offering. You can [host your own](../guides/self-hosting/self_hosting_guide.md) instance of `zrok` as well. `zrok` is
|
||||
also freely available as open source software hosted by GitHub under a very permissive Apache v2 license.
|
||||
|
||||
## Managed Service
|
||||
|
||||
`zrok` is also offered as a cloud service, making it instantly accessible to a large population immediately.
|
||||
NetFoundry provides a manged version of `zrok` at https://zrok.io. This provides the easy-to-use,
|
||||
quick to demonstrate features of `zrok` without needing to deploy and host `zrok` yourself.
|
||||
---
|
||||
sidebar_position: 200
|
||||
---
|
||||
|
||||
# Hosting
|
||||
|
||||
## Self-Hosted
|
||||
|
||||
`zrok` is not limited to a managed offering. You can [host your own](../guides/self-hosting/self_hosting_guide.md) instance of `zrok` as well. `zrok` is
|
||||
also freely available as open source software hosted by GitHub under a very permissive Apache v2 license.
|
||||
|
||||
## Managed Service
|
||||
|
||||
`zrok` is also offered as a cloud service, making it instantly accessible to a large population immediately.
|
||||
NetFoundry provides a manged version of `zrok` at https://zrok.io. This provides the easy-to-use,
|
||||
quick to demonstrate features of `zrok` without needing to deploy and host `zrok` yourself.
|
||||
|
@ -1,12 +1,13 @@
|
||||
---
|
||||
sidebar_title: Core Features
|
||||
sidebar_position: 25
|
||||
---
|
||||
# Concepts
|
||||
|
||||
`zrok` was designed to make sharing local resources both secure and easy. In this section of the `zrok` documentation, we'll tour through all of the most important features.
|
||||
|
||||
Sharing with `zrok` can be either [`public`](./sharing-public.md) or [`private`](./sharing-private.md).
|
||||
Naturally, regular web-based resources can be shared but `zrok` also includes support for sharing raw [TCP](./tunnels.md) and [UDP](./tunnels.md) network connections, and also includes a [website and file sharing](./files.md) feature.
|
||||
|
||||
Learn about `zrok` [hosting here](./hosting.md), including instructions on how to [install your own `zrok` instance](../guides/self-hosting/self_hosting_guide.md).
|
||||
---
|
||||
sidebar_title: Core Features
|
||||
sidebar_position: 25
|
||||
---
|
||||
|
||||
# Concepts
|
||||
|
||||
`zrok` was designed to make sharing local resources both secure and easy. In this section of the `zrok` documentation, we'll tour through all of the most important features.
|
||||
|
||||
Sharing with `zrok` can be either [`public`](./sharing-public.md) or [`private`](./sharing-private.md).
|
||||
Naturally, regular web-based resources can be shared but `zrok` also includes support for sharing raw [TCP](./tunnels.md) and [UDP](./tunnels.md) network connections, and also includes a [website and file sharing](./files.md) feature.
|
||||
|
||||
Learn about `zrok` [hosting here](./hosting.md), including instructions on how to [install your own `zrok` instance](../guides/self-hosting/self_hosting_guide.md).
|
||||
|
@ -1,23 +1,24 @@
|
||||
---
|
||||
sidebar_position: 100
|
||||
---
|
||||
# Open Source
|
||||
|
||||
It's important to the `zrok` project that it remain free and open source software. The code is available on [GitHub](https://github.com/openziti/zrok)
|
||||
for the world to use, inspect, and build upon!
|
||||
|
||||
Check out the repository over on GitHub at https://github.com/openziti/zrok. If you find `zrok` to be useful, and
|
||||
you want to help spread the word of `zrok` give the project a star. It really does help get the word out about the
|
||||
project.
|
||||
|
||||
The project also uses a very permissive license: Apache v2. We encourage people to fork the repo and use `zrok` for your own purposes how you see fit or contribute back to the project.
|
||||
|
||||
## Built on OpenZiti
|
||||
|
||||
The power of `zrok` really lies in `private` sharing. It's increasingly clear that security needs to be a first-class
|
||||
member of any organization. To enable `private` sharing, `zrok` was built on top of another excellent open source project named OpenZiti.
|
||||
|
||||
OpenZiti is a secure overlay network focusing on bringing zero trust to applications. It is the __backbone__ of `zrok`.
|
||||
In fact, `zrok` proudly proclaims itself as an Ziti _native_ application.
|
||||
|
||||
If you are interested in learning more about OpenZiti head over to [the docs](https://docs.openziti.io/docs/learn/introduction/), try the quickstart, and don't forget to star that project too. We couldn't build `zrok` without OpenZiti!
|
||||
---
|
||||
sidebar_position: 100
|
||||
---
|
||||
|
||||
# Open Source
|
||||
|
||||
It's important to the `zrok` project that it remain free and open source software. The code is available on [GitHub](https://github.com/openziti/zrok)
|
||||
for the world to use, inspect, and build upon!
|
||||
|
||||
Check out the repository over on GitHub at [https://github.com/openziti/zrok](https://github.com/openziti/zrok). If you find `zrok` to be useful, and
|
||||
you want to help spread the word of `zrok` give the project a star. It really does help get the word out about the
|
||||
project.
|
||||
|
||||
The project also uses a very permissive license: Apache v2. We encourage people to fork the repo and use `zrok` for your own purposes how you see fit or contribute back to the project.
|
||||
|
||||
## Built on OpenZiti
|
||||
|
||||
The power of `zrok` really lies in `private` sharing. It's increasingly clear that security needs to be a first-class
|
||||
member of any organization. To enable `private` sharing, `zrok` was built on top of another excellent open source project named OpenZiti.
|
||||
|
||||
OpenZiti is a secure overlay network focusing on bringing zero trust to applications. It is the __backbone__ of `zrok`.
|
||||
In fact, `zrok` proudly proclaims itself as an Ziti _native_ application.
|
||||
|
||||
If you are interested in learning more about OpenZiti head over to [the docs](https://docs.openziti.io/docs/learn/introduction/), try the quickstart, and don't forget to star that project too. We couldn't build `zrok` without OpenZiti!
|
||||
|
@ -1,29 +1,29 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
---
|
||||
# Private Shares
|
||||
|
||||
`zrok` was built to share and access digital resources. A `private` share allows a resource to be
|
||||
accessed on another user's system as if it were local to them. Privately shared resources can only be accessed by another `zrok` user who has the details of your unique share. You are in control of who can access your `private` shares by sharing the the share token.
|
||||
|
||||
Peer-to-peer private resource sharing is one of the things that makes `zrok` unique.
|
||||
|
||||
`zrok` also provides `public` sharing of resources with non-`zrok` users. Public resource sharing is limited to only resources that can be accessed over `HTTP` or `HTTPS`. `private` sharing works with all of the resources types that `zrok` supports.
|
||||
|
||||
Here's how private sharing works:
|
||||
|
||||
# Peer to Peer
|
||||
|
||||
![zrok_public_share](../images/zrok_private_share.png)
|
||||
|
||||
`private` shares are accessed using the `zrok access` command, and require the accessing user to have a `zrok enable`-d account on the same service instance where the share was created.
|
||||
|
||||
The `private` share is identified by a _share token_. The accessing user will use the share token, along with the `zrok access` command to create a local endpoint on their system, which lets them use the shared resource as if it were local to their system.
|
||||
|
||||
`zrok` does not require you to open any firewall ports or otherwise compromise the security of your local system; there is never an attack surface open to the public internet. As soon as you terminate the `zrok share` process, you immediately terminate any possible access to your shared resource.
|
||||
|
||||
The shared resource can be a development web server to share with friends and colleagues, a webhook from a server running in the cloud which has `zrok` running and has been instructed to `access` the private resource. `zrok` can also share files, websites, and low-level TCP and UDP network connections using the `tunnel` backend. What matters is that the access to the shared resource is not done in a public way, and can only be accessed by other `zrok` users that have access to your share token.
|
||||
|
||||
The peer-to-peer capabilities of `zrok` are an important property of the underlying [OpenZiti](https://docs.openziti.io/docs/learn/introduction/) network that `zrok` uses to provide connectivity between users and resources.
|
||||
|
||||
---
|
||||
sidebar_position: 0
|
||||
---
|
||||
# Private Shares
|
||||
|
||||
`zrok` was built to share and access digital resources. A `private` share allows a resource to be
|
||||
accessed on another user's system as if it were local to them. Privately shared resources can only be accessed by another `zrok` user who has the details of your unique share. You are in control of who can access your `private` shares by sharing the the share token.
|
||||
|
||||
Peer-to-peer private resource sharing is one of the things that makes `zrok` unique.
|
||||
|
||||
`zrok` also provides `public` sharing of resources with non-`zrok` users. Public resource sharing is limited to only resources that can be accessed over `HTTP` or `HTTPS`. `private` sharing works with all of the resources types that `zrok` supports.
|
||||
|
||||
Here's how private sharing works:
|
||||
|
||||
# Peer to Peer
|
||||
|
||||
![zrok_public_share](../images/zrok_private_share.png)
|
||||
|
||||
`private` shares are accessed using the `zrok access` command, and require the accessing user to have a `zrok enable`-d account on the same service instance where the share was created.
|
||||
|
||||
The `private` share is identified by a _share token_. The accessing user will use the share token, along with the `zrok access` command to create a local endpoint on their system, which lets them use the shared resource as if it were local to their system.
|
||||
|
||||
`zrok` does not require you to open any firewall ports or otherwise compromise the security of your local system; there is never an attack surface open to the public internet. As soon as you terminate the `zrok share` process, you immediately terminate any possible access to your shared resource.
|
||||
|
||||
The shared resource can be a development web server to share with friends and colleagues, a webhook from a server running in the cloud which has `zrok` running and has been instructed to `access` the private resource. `zrok` can also share files, websites, and low-level TCP and UDP network connections using the `tunnel` backend. What matters is that the access to the shared resource is not done in a public way, and can only be accessed by other `zrok` users that have access to your share token.
|
||||
|
||||
The peer-to-peer capabilities of `zrok` are an important property of the underlying [OpenZiti](https://docs.openziti.io/docs/learn/introduction/) network that `zrok` uses to provide connectivity between users and resources.
|
||||
|
||||
Creating `private` shares is easy and is accomplished using the `zrok share private` command. Run `zrok share private` to see the usage output and to further learn how to use the command.
|
@ -1,16 +1,16 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
# Public Shares
|
||||
|
||||
`zrok` supports `public` sharing for web-based (HTTP and HTTPS) resources. These resources are easily shared with the general internet through public access points.
|
||||
|
||||
## Peer to Public
|
||||
|
||||
![zrok_public_share](../images/zrok_public_share.png)
|
||||
|
||||
`public` sharing is most useful when the person or service accessing your resources does not have `zrok` running locally and cannot make use of the `private` sharing mode built into `zrok`. Many users share development web servers, webhooks, and other HTTP/HTTPS resources.
|
||||
|
||||
As with `private` sharing, `public` sharing does not require you to open any firewall ports or otherwise compromise the security of your local environments. A `public` share goes away as soon as you terminate the `zrok share` command.
|
||||
|
||||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
# Public Shares
|
||||
|
||||
`zrok` supports `public` sharing for web-based (HTTP and HTTPS) resources. These resources are easily shared with the general internet through public access points.
|
||||
|
||||
## Peer to Public
|
||||
|
||||
![zrok_public_share](../images/zrok_public_share.png)
|
||||
|
||||
`public` sharing is most useful when the person or service accessing your resources does not have `zrok` running locally and cannot make use of the `private` sharing mode built into `zrok`. Many users share development web servers, webhooks, and other HTTP/HTTPS resources.
|
||||
|
||||
As with `private` sharing, `public` sharing does not require you to open any firewall ports or otherwise compromise the security of your local environments. A `public` share goes away as soon as you terminate the `zrok share` command.
|
||||
|
||||
Using `public` shares is easy and is accomplished using the `zrok share public` command. Run `zrok share public` to see the command-line help and to learn how to use `public` shares.
|
@ -1,14 +1,14 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
# Reserved Shares
|
||||
|
||||
By default a `public` or `private` share is assigned a _share token_ when you create a share using the `zrok share` command. The `zrok share` command is the bridge between your local environment and the users you are sharing with. When you terminate the `zrok share`, the bridge is eliminated and the _share token_ is deleted. If you run `zrok share` again, you will be allocated a brand new _share token_.
|
||||
|
||||
You can use a `reserved` share to persist your _share token_ across multiple runs of the `zrok share` bridge. When you use a `reserved` share, the share token will not be deleted between multiple runs of `zrok share`.
|
||||
|
||||
To use a `reserved` share, you will first run the `zrok reserve` command to create the reserved share (see `zrok reserve --help` for details). Once you've created your `reserved` share, you will use the `zrok share reserved` command (see `--help` for details) to run the bridge for the shared resource.
|
||||
|
||||
This pattern works for both `public` and `private` shares, and for all resource types supported by `zrok`.
|
||||
|
||||
To delete your `reserved` share use the `zrok release` command or click the delete button in the share's _Actions_ tab in the web console.
|
||||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
# Reserved Shares
|
||||
|
||||
By default a `public` or `private` share is assigned a _share token_ when you create a share using the `zrok share` command. The `zrok share` command is the bridge between your local environment and the users you are sharing with. When you terminate the `zrok share`, the bridge is eliminated and the _share token_ is deleted. If you run `zrok share` again, you will be allocated a brand new _share token_.
|
||||
|
||||
You can use a `reserved` share to persist your _share token_ across multiple runs of the `zrok share` bridge. When you use a `reserved` share, the share token will not be deleted between multiple runs of `zrok share`.
|
||||
|
||||
To use a `reserved` share, you will first run the `zrok reserve` command to create the reserved share (see `zrok reserve --help` for details). Once you've created your `reserved` share, you will use the `zrok share reserved` command (see `--help` for details) to run the bridge for the shared resource.
|
||||
|
||||
This pattern works for both `public` and `private` shares, and for all resource types supported by `zrok`.
|
||||
|
||||
To delete your `reserved` share use the `zrok release` command or click the delete button in the share's _Actions_ tab in the web console.
|
||||
|
@ -1,17 +0,0 @@
|
||||
---
|
||||
sidebar_position: 100
|
||||
---
|
||||
|
||||
# Downloads
|
||||
|
||||
Right now all `zrok` binaries are delivered from the release page at GitHub.
|
||||
|
||||
Head over to https://github.com/openziti/zrok/releases/latest to find the latest downloads.
|
||||
|
||||
You need the right download for your OS and CPU. This can be confusing because the OS, e.g., Raspberry Pi OS, could be 32bit even if you have a 64bit Pi (v3, 4, or Zero 2). Linux users can always find the right version by looking up the result of `uname -m` in this table.
|
||||
|
||||
| Result |Linux Download Name |
|
||||
|------------------|--------------------|
|
||||
| x86_64 |linux-amd64 |
|
||||
| aarch64, arm/v8 |linux-arm64 |
|
||||
| armhf, arm/v7 |linux-armv7 |
|
@ -1,150 +1,77 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
title: Getting Started with zrok
|
||||
sidebar_label: Getting Started
|
||||
sidebar_position: 10
|
||||
---
|
||||
# Getting Started with zrok
|
||||
|
||||
`zrok` is a next-generation sharing platform, designed to make sharing network and file resources simple and secure. `zrok` is a _Ziti Native Application_, built on top of the [OpenZiti](https://docs.openziti.io/docs/learn/introduction/) programmable zero trust network overlay. `zrok` is open source, licensed under the Apache v2 license. You can choose to self-host `zrok` or leverage the free, managed offering provided by NetFoundry at https://zrok.io.
|
||||
import { AssetsProvider } from '@site/src/components/assets-context';
|
||||
import DownloadCard from '@site/src/components/download-card';
|
||||
import styles from '@site/src/css/download-card.module.css';
|
||||
|
||||
As of version `v0.4.0`, `zrok` provides the ability to:
|
||||
## What's a zrok?
|
||||
|
||||
* share resources [publicly](./concepts/sharing-public.md), similar to other distributed reverse proxies; this allows you to easily expose your private HTTP/S resources to the public internet without changing your network security
|
||||
* share resources [privately](./concepts/sharing-private.md); private sharing uses peer-to-peer connectivity between two parties by leveraging the OpenZiti overlay. We believe the private sharing offered by `zrok` provides a unique level of security and privacy for this type of sharing.
|
||||
`zrok` (*/ziːɹɒk/ ZEE-rock*) is a secure, open-source, self-hostable sharing platform that simplifies shielding and sharing network services or files. There's a hardened zrok-as-a-service offering available at [zrok.io](https://zrok.io) with a generous free tier.
|
||||
|
||||
As of version `v0.4.0`, `zrok` allows sharing these kinds of resources:
|
||||
## Open Source
|
||||
|
||||
* HTTP/S resources; `zrok` provides reverse proxy capabilities for your HTTP/S endpoints, both publicly and privately
|
||||
* file resources; `zrok` provides built in `web` capabilities, allowing you to share your files with other users, both publicly and privately
|
||||
* TCP and UDP tunnels; `zrok` provides built-in `tunnel` capabilities, allowing you to share your TCP and UDP endpoints directly with other users privately (`zrok` does not currently offer public sharing of these kinds of resources)
|
||||
`zrok` is licensed under Apache 2.0.
|
||||
|
||||
Let's take a look at how to get started with `zrok`.
|
||||
Check [the roadmap](https://github.com/orgs/openziti/projects/16) if you're thinking about the future. We would love to hear your ideas for `zrok`!
|
||||
|
||||
:::note `zrok` moves fast!
|
||||
The best ways to engage are [Discourse](https://openziti.discourse.group/) for questions and [GitHub Issues](https://github.com/openziti/zrok/issues) for documenting problems.
|
||||
|
||||
`zrok` is an open source project and is in its early development phases. We're doing our development publicly. See the [roadmap](https://github.com/orgs/openziti/projects/16) for details about the project. We are highly interested in feedback as we continue to iterate quickly. Please provide feedback in [Discourse](https://openziti.discourse.group/), raise [GitHub Issues](https://github.com/openziti/zrok/issues), or reach out directly.
|
||||
[Read more about zrok open source](/concepts/opensource.md).
|
||||
|
||||
:::
|
||||
### Ziti native
|
||||
|
||||
## Downloading zrok
|
||||
`zrok` is a _Ziti Native Application_, built on the [OpenZiti](https://openziti.io) platform, and supported by the OpenZiti community and NetFoundry team.
|
||||
|
||||
Releases are also available from the `zrok` project repository on GitHub at https://github.com/openziti/zrok/releases/latest. If you're a Linux user and you're not sure which download to use then check out the hints on [the Downloads page](./downloads.md).
|
||||
## What's it for?
|
||||
|
||||
### Extract zrok Distribution
|
||||
Use `zrok` to share a running service, like a web server or a network socket, or to share a directory of static files.
|
||||
|
||||
Move the downloaded `zrok` distribution into a directory on your system. In my case, I've placed it in my home directory:
|
||||
If [sharing publicly](./concepts/sharing-public.md), you can reserve a subdomain, enable authentication options, or both. Public shares proxy HTTPS to your service or files.
|
||||
|
||||
```
|
||||
$ ls -lF zrok*
|
||||
-rwxr-xr-x 1 michael michael 14459159 May 31 13:46 zrok_0.4.0-rc6_linux_amd64.tar.gz*
|
||||
```
|
||||
If [sharing privately](./concepts/sharing-private.md), only users with the share token can access your share. In addition to what you can share publicly, private shares can include TCP and UDP services.
|
||||
|
||||
Create a directory where the extracted distribution will sit:
|
||||
## Installing the zrok Command
|
||||
|
||||
```
|
||||
$ mkdir zrok
|
||||
$ cd zrok/
|
||||
```
|
||||
|
||||
Extract the `zrok` distribution:
|
||||
|
||||
```
|
||||
$ tar zxvf ../zrok_0.4.0-rc1_linux_amd64.tar.gz
|
||||
CHANGELOG.md
|
||||
README.md
|
||||
zrok
|
||||
```
|
||||
|
||||
> NOTE: On Windows platforms the distribution is shipped as a `zip` archive. Windows Explorer includes support for extracting `zip` archives natively.
|
||||
|
||||
Add `zrok` to your shell's environment.
|
||||
|
||||
For Linux or macos:
|
||||
|
||||
```
|
||||
$ export PATH=`pwd`:$PATH
|
||||
```
|
||||
|
||||
For Windows (using Command Prompt):
|
||||
|
||||
```
|
||||
> set PATH=%CD%;%PATH%
|
||||
```
|
||||
|
||||
For Windows (using PowerShell):
|
||||
|
||||
```
|
||||
$env:path += ";"+$pwd.Path
|
||||
```
|
||||
|
||||
With the `zrok` executable in your path, you can then execute the `zrok` command from your shell:
|
||||
|
||||
```
|
||||
$ ./zrok version
|
||||
_
|
||||
_____ __ ___ | | __
|
||||
|_ / '__/ _ \| |/ /
|
||||
/ /| | | (_) | <
|
||||
/___|_| \___/|_|\_\
|
||||
|
||||
v0.4.0-rc6 [c889005]
|
||||
```
|
||||
|
||||
## Configure Your zrok Service Instance
|
||||
|
||||
:::note
|
||||
Most users can safely skip this section and proceed to "Generating an Invitation" below.
|
||||
|
||||
This section is relevant if you want to use the `zrok` CLI with an alternate service instance (in the case of self-hosting, etc.).
|
||||
:::
|
||||
|
||||
`zrok` is both an installable utility that you interact with from your local computer, and also a _service_ that exists on the network. NetFoundry operates the public _service instance_ that is available at `api.zrok.io`, but because `zrok` is open source and self-hostable, you're free to create your own `zrok` service instance.
|
||||
|
||||
The `zrok` executable defaults to using the `zrok` service instance at `api.zrok.io`. Should you need to change the endpoint to use a different service instance, you can do that with the following command:
|
||||
|
||||
```
|
||||
$ zrok config set apiEndpoint https://zrok.mydomain.com
|
||||
[WARNING]: unable to open environment metadata; ignoring
|
||||
|
||||
zrok configuration updated
|
||||
```
|
||||
|
||||
:::note
|
||||
The `WARNING` about `environment metadata` is ignorable. Running the `zrok config set` command writes a small piece of metadata into a `.zrok` folder inside your home directory. This allows `zrok` to identify the version of its settings, providing a mechanism to upgrade your installation as new versions are released. This `WARNING` is letting you know that your current environment has not been initialized by `zrok`.
|
||||
:::
|
||||
|
||||
You can use the `zrok status` command to inspect the state of your local _environment_. `zrok` refers to each shell where you install and `enable` a copy of `zrok` as as an _environment_.
|
||||
|
||||
```
|
||||
$ zrok status
|
||||
|
||||
Config:
|
||||
|
||||
CONFIG VALUE SOURCE
|
||||
apiEndpoint https://zrok.mydomain.com config
|
||||
|
||||
[WARNING]: Unable to load your local environment!
|
||||
|
||||
To create a local environment use the zrok enable command.
|
||||
```
|
||||
|
||||
:::note
|
||||
The `WARNING` about being `unable to load your local environment` will go away once you've successfully enabled (`zrok enable`) for your shell (we'll get to that below). For now, this warning is ignorable.
|
||||
:::
|
||||
|
||||
The `zrok status` command shows the configured API service that your environment is using, as well as the `SOURCE` where the setting was retrieved. In this case, `config` means that the setting was set into the environment using the `zrok config` command.
|
||||
<AssetsProvider>
|
||||
<div className={styles.downloadContainer}>
|
||||
<DownloadCard
|
||||
osName="Windows"
|
||||
osLogo="/img/logo-windows.svg"
|
||||
infoText="Binary executable"
|
||||
guideLink="/docs/guides/install/windows"
|
||||
/>
|
||||
<DownloadCard
|
||||
osName="macOS"
|
||||
osLogo="/img/logo-apple.svg"
|
||||
infoText="Binary executable"
|
||||
guideLink="/docs/guides/install/macos"
|
||||
/>
|
||||
<DownloadCard
|
||||
osName="Linux"
|
||||
osLogo="/img/logo-linux.svg"
|
||||
infoText="DEB, RPM packages"
|
||||
guideLink="/docs/guides/install/linux"
|
||||
/>
|
||||
</div>
|
||||
</AssetsProvider>
|
||||
|
||||
## Generating an Invitation
|
||||
|
||||
In order to create an account with the `zrok` service instance, you will need to create an invitation.
|
||||
|
||||
:::note
|
||||
Some environments take advantage of _invitation tokens_, which limit who is able to request an invitation on the service instance. If your service uses invitation tokens, the administrator of your instance will include details about how to use your token to generate your invitation.
|
||||
If not using `zrok.io` (zrok-as-a-service), you must configure the `zrok` command to use your instance. See the [instance configuration guide](/guides/self-hosting/instance-configuration.mdx) in the self-hosting section for details.
|
||||
:::
|
||||
|
||||
We generate an invitation with the `zrok invite` command. A service instance that allows open registration will provide an input form like this:
|
||||
Invite yourself to `zrok` by running the `zrok invite` command:
|
||||
|
||||
```text
|
||||
zrok invite
|
||||
```
|
||||
$ zrok invite
|
||||
|
||||
```buttonless title="Output"
|
||||
enter and confirm your email address...
|
||||
|
||||
> user@domain.com
|
||||
@ -155,30 +82,13 @@ enter and confirm your email address...
|
||||
invitation sent to 'user@domain.com'!
|
||||
```
|
||||
|
||||
A service instance that requires token-based invitation authentication will present a form that looks like this:
|
||||
|
||||
```
|
||||
$ zrok invite
|
||||
|
||||
enter and confirm your email address...
|
||||
|
||||
If you don't already have one, request an invite token at: michael@quigley.com
|
||||
|
||||
> Email Address
|
||||
> Confirm Email
|
||||
> Token
|
||||
|
||||
|
||||
[ Submit ]
|
||||
```
|
||||
|
||||
The `zrok invite` command presents a small form that allows you to enter (and then confirm) your email address. Tabbing to the `[ Submit ]` button will send the request to your configured `zrok` service.
|
||||
|
||||
Next, check the email where you sent the invite. You should receive a message asking you to click a link to create your `zrok` account. When you click that link, you will be brought to a web page that will allow you to set a password for your new account:
|
||||
|
||||
![Enter a Password](images/zrok_verify.png)
|
||||
|
||||
Enter a password and it's confirmation, and click the `Register Account` button. You'll see the following:
|
||||
Enter a password and its confirmation, and click the `Register Account` button. You'll see the following:
|
||||
|
||||
![Successful Registration](images/zrok_registration_success.png)
|
||||
|
||||
@ -206,23 +116,25 @@ This dialog box shows you the `zrok enable` command that you can use to enable a
|
||||
|
||||
Let's copy that command and paste it into your shell:
|
||||
|
||||
```
|
||||
```buttonless title="Example"
|
||||
$ zrok enable klFEoIi0QAg7
|
||||
⣻ contacting the zrok service...
|
||||
```
|
||||
|
||||
After a few seconds, the message will change and indicate that the enable operation succeeded:
|
||||
|
||||
```
|
||||
```buttonless title="Example"
|
||||
$ zrok enable klFEoIi0QAg7
|
||||
⣻ the zrok environment was successfully enabled...
|
||||
```
|
||||
|
||||
Now, if we run a `zrok status` command, you will see the details of your environment:
|
||||
|
||||
```txt
|
||||
zrok status
|
||||
```
|
||||
$ zrok status
|
||||
|
||||
```buttonless title="Output"
|
||||
Config:
|
||||
|
||||
CONFIG VALUE SOURCE
|
||||
@ -273,21 +185,22 @@ Shared resources are _ephemeral_ by default; as soon as you terminate the `zrok
|
||||
|
||||
### Public Shares and Frontends
|
||||
|
||||
Resources that are shared _publicly_ are exposed to any users on the internet who have access to the `zrok` service instance's "frontend".
|
||||
Resources that are shared _publicly_ are exposed to any users on the internet who have access to the `zrok` instance's "frontend".
|
||||
|
||||
A frontend is an HTTPS listener exposed to the internet, that lets any user with your ephemeral share token access your publicly shared resources.
|
||||
|
||||
For example, I might create a public share using the `zrok share public` command, which results in my `zrok` service instance exposing the following URL to access my resources:
|
||||
For example, I might create a public share using the `zrok share public` command, which results in my `zrok` instance exposing a URL like `https://2ptgbr8tlfvk.share.zrok.io` to access my resources.
|
||||
|
||||
https://2ptgbr8tlfvk.share.zrok.io
|
||||
|
||||
In this case my share was given the "share token" of `2ptgbr8tlfvk`. That URL can be given to any user, allowing them to immediately access the shared resources directly from my local environment, all without exposing any access to my private, secure environment. The physical network location of my environment is not exposed to anonymous consumers of my resources.
|
||||
In this case, my share was given the "share token" of `2ptgbr8tlfvk`. That URL can be given to any user, allowing them to immediately access the shared resources directly from my local environment, all without exposing any access to my private, secure environment. The physical network location of my environment is not exposed to anonymous consumers of my resources.
|
||||
|
||||
:::note
|
||||
Here is the `--help` output from `zrok share public`:
|
||||
|
||||
```text
|
||||
zrok share public
|
||||
```
|
||||
$ zrok share public
|
||||
|
||||
```buttonless title="Output"
|
||||
Error: accepts 1 arg(s), received 0
|
||||
Usage:
|
||||
zrok share public <target> [flags]
|
||||
@ -338,13 +251,13 @@ If we try to reload the frontend endpoint in our web browser, we'll see:
|
||||
|
||||
`zrok` also provides a powerful _private_ sharing model. If I execute the following command:
|
||||
|
||||
```
|
||||
```buttonless title="Example"
|
||||
$ zrok share private http://localhost:8080
|
||||
```
|
||||
|
||||
The `zrok` service will respond with the following:
|
||||
|
||||
```
|
||||
```buttonless title="Output"
|
||||
access your share with: zrok access private wvszln4dyz9q
|
||||
```
|
||||
|
||||
@ -370,7 +283,7 @@ A reserved share can be re-used multiple times; it will survive termination of t
|
||||
|
||||
The first step is to create the reserved share:
|
||||
|
||||
```
|
||||
```txt title="Example"
|
||||
$ zrok reserve public --backend-mode web v0.3_getting_started
|
||||
[ 0.275] INFO main.(*reserveCommand).run: your reserved share token is 'mltwsinym1s2'
|
||||
[ 0.275] INFO main.(*reserveCommand).run: reserved frontend endpoint: https://mltwsinym1s2.share.zrok.io
|
||||
@ -388,7 +301,7 @@ This is the `404` error message returned by the `zrok` frontend. We're getting t
|
||||
|
||||
This command:
|
||||
|
||||
```
|
||||
```txt title="Example"
|
||||
$ zrok share reserved mltwsinym1s2
|
||||
```
|
||||
|
||||
@ -398,13 +311,13 @@ $ zrok share reserved mltwsinym1s2
|
||||
|
||||
And now if we refresh the frontend endpoint URL in the web browser, we'll see an index of the `docs` directory:
|
||||
|
||||
![zrok docs share](images/zrok_docs_share.png)
|
||||
![zrok docs share](images/zrok_web_console_share_frontend.png)
|
||||
|
||||
With the reserved share, we're free to stop and restart the `zrok share reserved` command as many times as we want, without losing the token for our share.
|
||||
|
||||
When we're done with the reserved share, we can _release_ it using this command:
|
||||
|
||||
```
|
||||
```txt title="Example"
|
||||
$ zrok release mltwsinym1s2
|
||||
[ 0.230] INFO main.(*releaseCommand).run: reserved share 'mltwsinym1s2' released
|
||||
```
|
||||
@ -415,11 +328,11 @@ In summary, `zrok` lets you easily and securely share resources with both genera
|
||||
|
||||
Here's a quick review of the `zrok` mental model and the vocabulary.
|
||||
|
||||
### Service Instance and Account
|
||||
### Instance and Account
|
||||
|
||||
You create an _account_ with a `zrok` _service instance_. Your account is identified by a username and a password, which you use to log into the _web console_. Your account also has a _secret token_, which you will use to authenticate from the `zrok` command-line to interact with the _service instance_.
|
||||
You create an _account_ with a `zrok` _instance_. Your account is identified by a username and a password, which you use to log into the _web console_. Your account also has a _secret token_, which you will use to authenticate from the `zrok` command-line to interact with the _instance_.
|
||||
|
||||
You create a new _account_ with a `zrok` _service instance_ through the `zrok invite` command.
|
||||
You create a new _account_ with a `zrok` _instance_ through the `zrok invite` command.
|
||||
|
||||
### Environment
|
||||
|
||||
@ -431,7 +344,7 @@ You create a new _environment_ by using the `zrok enable` command.
|
||||
|
||||
Once you've enabled an _environment_, you then create one or more _shares_. Shares have either a _public_ or _private_ _sharing mode_. _Shares_ share a specific type of resource using a _backend mode_. As of this writing `zrok` supports a `proxy` _backend mode_ to share local HTTP resources as a _reverse proxy_. `zrok` also supports a `web` _backend mode_ to share local file and HTML resources by enabling a basic HTTP server.
|
||||
|
||||
Every _share_ is identified by a _share token_. _Public shares_ can be accessed through either a _frontend_ instance offered through the `zrok` _service instance_, or through the `zrok access` command. _Private shares_ can only be accessed through the `zrok access` command.
|
||||
Every _share_ is identified by a _share token_. _Public shares_ can be accessed through either a _frontend_ instance offered through the `zrok` _instance_, or through the `zrok access` command. _Private shares_ can only be accessed through the `zrok access` command.
|
||||
|
||||
You use the `zrok share` command to create and enable _ephemeral shares_.
|
||||
|
||||
@ -441,9 +354,9 @@ You use the `zrok share` command to create and enable _ephemeral shares_.
|
||||
|
||||
You use the `zrok reserve` command to create _reserved shares_. Reserved shares last until you use the `zrok release` command to delete them.
|
||||
|
||||
## Self-Hosting a Service Instance
|
||||
## Self-Hosting an Instance
|
||||
|
||||
Interested in self-hosting your own `zrok` service instance? See the [self-hosting guide](./guides/self-hosting/self_hosting_guide.md) for details.
|
||||
Interested in self-hosting your own `zrok` instance? See the [self-hosting guide](./guides/self-hosting/self_hosting_guide.md) for details.
|
||||
|
||||
[openziti]: https://docs.openziti.io/docs/learn/introduction/ "OpenZiti"
|
||||
[ zrok-download]: https://zrok.io "zrok Download"
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"label": "Guides",
|
||||
"position": 30,
|
||||
"link": {
|
||||
"type": "generated-index"
|
||||
}
|
||||
}
|
||||
{
|
||||
"label": "Guides",
|
||||
"position": 50,
|
||||
"link": {
|
||||
"type": "generated-index"
|
||||
}
|
||||
}
|
||||
|
134
docs/guides/_frontdoor-docker.mdx
Normal file
134
docs/guides/_frontdoor-docker.mdx
Normal file
@ -0,0 +1,134 @@
|
||||
## Goal
|
||||
|
||||
Proxy a reserved public subdomain to a backend target with an always-on Docker Compose service.
|
||||
|
||||
## How it Works
|
||||
|
||||
The Docker Compose project uses your zrok account token to reserve a public subdomain and keep sharing the backend
|
||||
target.
|
||||
|
||||
When the project runs it will:
|
||||
|
||||
1. enable a zrok environment unless `/mnt/.zrok/environment.json` exists in the `zrok_env` volume
|
||||
1. reserve a public subdomain for the service unless `/mnt/.zrok/reserved.json` exists
|
||||
1. start sharing the target specified in the `ZROK_TARGET` environment variable
|
||||
|
||||
## Create the Docker Project
|
||||
|
||||
1. Make a folder on your computer to use as a Docker Compose project for your zrok public share with a reserved subdomain and switch to the new directory in your terminal.
|
||||
1. Download [the reserved public share `compose.yml` project file](pathname:///zrok-public-reserved/compose.yml) into the same directory.
|
||||
1. Copy your zrok account's enable token from the zrok web console to your clipboard and paste it in a file named `.env` in the same folder like this:
|
||||
|
||||
```bash title=".env"
|
||||
ZROK_ENABLE_TOKEN="8UL9-48rN0ua"
|
||||
```
|
||||
1. Name the Share
|
||||
|
||||
This unique name becomes part of the domain name of the share, e.g. `https://my-prod-app.in.zrok.io`. A random name is generated if you don't specify one.
|
||||
|
||||
```bash title=".env"
|
||||
ZROK_UNIQUE_NAME="my-prod-app"
|
||||
```
|
||||
|
||||
1. Run the Compose project to start sharing the built-in demo web server. Be sure to `--detach` so the project runs in the background if you want it to auto-restart when your computer reboots.
|
||||
|
||||
```bash
|
||||
docker compose up --detach
|
||||
```
|
||||
|
||||
1. Get the public share URL from the output of the `zrok-share` service or by peeking in the zrok console where the share will appear in the graph.
|
||||
|
||||
```bash
|
||||
docker compose logs zrok-share
|
||||
```
|
||||
|
||||
```buttonless title="Output"
|
||||
zrok-public-share-1 | https://w6r1vesearkj.in.zrok.io/
|
||||
```
|
||||
|
||||
This concludes the minimum steps to begin sharing the demo web server. Read on to learn how to pivot to sharing any website or web service by leveraging additional zrok backend modes.
|
||||
|
||||
## Proxy Any Web Server
|
||||
|
||||
The simplest way to share your existing HTTP server is to set `ZROK_TARGET` (e.g. `https://example.com`) in the environment of the `docker compose up` command. When you restart the share will auto-configure for that URL.
|
||||
|
||||
```bash title=".env"
|
||||
ZROK_TARGET="http://example.com:8080"
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose down && docker compose up
|
||||
```
|
||||
|
||||
## Require Authentication
|
||||
|
||||
You can require a password or an OAuth login with certain email addresses.
|
||||
|
||||
### OAuth Email
|
||||
|
||||
You can allow specific email addresses or an email domain by setting `ZROK_OAUTH_PROVIDER` to `github` or `google` and
|
||||
`ZROK_SHARE_OPTS` to specify additional command-line options to `zrok reserve public`. Read more about the OAuth
|
||||
features in [this blog post](https://blog.openziti.io/the-zrok-oauth-public-frontend).
|
||||
|
||||
```bash title=".env"
|
||||
ZROK_OAUTH_PROVIDER="github"
|
||||
ZROK_OAUTH_EMAILS="alice@example.com *@acme.example.com"
|
||||
```
|
||||
|
||||
## Caddy is Powerful
|
||||
|
||||
The reserved public share project uses zrok's default backend mode, `proxy`. Another backend mode, `caddy`, accepts a path to [a Caddyfile](https://caddyserver.com/docs/caddyfile) as the value of `ZROK_TARGET` ([zrok Caddyfile examples](https://github.com/openziti/zrok/tree/main/etc/caddy)).
|
||||
|
||||
Caddy is the most powerful and flexible backend mode in zrok. You must reserve a new public subdomain whenever you switch the backend mode, so using `caddy` reduces the risk that you'll have to share a new frontend URL with your users.
|
||||
|
||||
With Caddy, you can balance the workload for websites or web services or share static sites and files or all of the above at the same time. You can update the Caddyfile and restart the Docker Compose project to start sharing the new configuration with the same reserved public subdomain.
|
||||
|
||||
1. Create a Caddyfile. This example demonstrates proxying two HTTP servers with a weighted round-robin load balancer.
|
||||
|
||||
```console title="Caddyfile"
|
||||
http:// {
|
||||
# zrok requires this bind address template
|
||||
bind {{ .ZrokBindAddress }}
|
||||
reverse_proxy /* {
|
||||
to http://httpbin1:8080 http://httpbin2:8080
|
||||
lb_policy weighted_round_robin 3 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Create a file `compose.override.yml`. This example adds two `httpbin` containers for load balancing, and mounts the Caddyfile into the container.
|
||||
|
||||
```yaml title="compose.override.yml"
|
||||
services:
|
||||
httpbin1:
|
||||
image: mccutchen/go-httpbin # 8080/tcp
|
||||
httpbin2:
|
||||
image: mccutchen/go-httpbin # 8080/tcp
|
||||
zrok-share:
|
||||
volumes:
|
||||
- ./Caddyfile:/mnt/.zrok/Caddyfile
|
||||
```
|
||||
|
||||
1. Start a new Docker Compose project or delete the existing state volume.
|
||||
|
||||
```bash
|
||||
docker compose down --volumes
|
||||
```
|
||||
|
||||
If you prefer to keep using the same zrok environment with the new share then delete `/mnt/.zrok/reserved.json` instead of the entire volume.
|
||||
|
||||
1. Run the project to load the new configuration.
|
||||
|
||||
```bash
|
||||
docker compose up --detach
|
||||
```
|
||||
|
||||
1. Note the new reserved share URL from the log.
|
||||
|
||||
```bash
|
||||
docker compose logs zrok-share
|
||||
```
|
||||
|
||||
```buttonless title="Output"
|
||||
INFO: zrok public URL: https://88s803f2qvao.in.zrok.io/
|
||||
```
|
198
docs/guides/_frontdoor-linux.mdx
Normal file
198
docs/guides/_frontdoor-linux.mdx
Normal file
@ -0,0 +1,198 @@
|
||||
import AnsibleRepoSetup from './install/_ansible_repo_setup.yaml'
|
||||
import ConcatenateYamlSnippets from '@site/src/components/cat-yaml.jsx'
|
||||
|
||||
## Goal
|
||||
|
||||
Proxy a reserved public subdomain to a backend target with an always-on Linux system service.
|
||||
|
||||
## How it Works
|
||||
|
||||
The `zrok-share` package creates a `zrok-share.service` unit in systemd. The administrator edits the service's configuration file to specify the:
|
||||
|
||||
1. zrok environment enable token
|
||||
1. target URL or files to be shared and backend mode, e.g. `proxy`
|
||||
1. authentication options, if wanted
|
||||
|
||||
When the service starts it will:
|
||||
|
||||
1. enable the zrok environment unless `/var/lib/zrok-share/.zrok/environment.json` exists
|
||||
1. reserve a public subdomain for the service unless `/var/lib/zrok-share/.zrok/reserved.json` exists
|
||||
1. start sharing the target specified as `ZROK_TARGET` in the environment file
|
||||
|
||||
## Installation
|
||||
|
||||
1. Set up `zrok`'s Linux package repository by following [the Linux install guide](/guides/install/linux.mdx#install-zrok-from-the-repository), or run this one-liner to complete the repo setup and install packages.
|
||||
|
||||
```bash
|
||||
curl -sSLf https://get.openziti.io/install.bash \
|
||||
| sudo bash -s zrok-share
|
||||
```
|
||||
|
||||
1. If you set up the repository by following the guide, then also install the `zrok-share` package. This package provides the systemd service.
|
||||
|
||||
```bash title="Ubuntu, Debian"
|
||||
sudo apt install zrok-share
|
||||
```
|
||||
|
||||
```bash title="Fedora, Rocky"
|
||||
sudo dnf install zrok-share
|
||||
```
|
||||
|
||||
<Details>
|
||||
<summary>Ansible Playbook</summary>
|
||||
|
||||
<ConcatenateYamlSnippets
|
||||
title="Set up package repository and install zrok-share"
|
||||
>
|
||||
{AnsibleRepoSetup}
|
||||
{`
|
||||
- name: Install zrok-share package
|
||||
gather_facts: false
|
||||
hosts: all
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install zrok-share
|
||||
ansible.builtin.package:
|
||||
name: zrok-share
|
||||
state: present
|
||||
|
||||
- name: Copy env config from Ansible controller to target
|
||||
copy:
|
||||
dest: /opt/openziti/etc/zrok/zrok-share.env
|
||||
src: /opt/openziti/etc/zrok/zrok-share.env
|
||||
|
||||
- name: Enable and restart service
|
||||
systemd:
|
||||
name: zrok-share
|
||||
enabled: yes
|
||||
state: restarted
|
||||
daemon_reload: yes
|
||||
|
||||
- name: Wait for service
|
||||
systemd:
|
||||
name: zrok-share
|
||||
state: started
|
||||
register: service_status
|
||||
until: service_status.status.ActiveState == 'active'
|
||||
retries: 30
|
||||
delay: 1
|
||||
`}
|
||||
</ConcatenateYamlSnippets>
|
||||
|
||||
</Details>
|
||||
|
||||
## Enable
|
||||
|
||||
Save the enable token from the zrok console in the configuration file.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_ENABLE_TOKEN="14cbfca9772f"
|
||||
```
|
||||
|
||||
## Name your Share
|
||||
|
||||
This unique name becomes part of the domain name of the share, e.g. `https://my-prod-app.in.zrok.io`. A random name is generated if you don't specify one.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_UNIQUE_NAME="my-prod-app"
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
You may change the target for the current backend mode, e.g. `proxy`, by editing the configuration file and restarting the service. The reserved subdomain will remain the same.
|
||||
|
||||
You may switch between backend modes or change authentication options by deleting `/var/lib/zrok-share/.zrok/reserved.json` and restarting the service. A new subdomain will be reserved.
|
||||
|
||||
### Proxy a Web Server
|
||||
|
||||
Proxy a reserved subdomain to an existing web server. The web server could be on a private network or on the same host as zrok.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_TARGET="http://127.0.0.1:3000"
|
||||
ZROK_BACKEND_MODE="proxy"
|
||||
```
|
||||
|
||||
If your HTTPS server has an unverifiable TLS server certificate then you must set `--insecure`.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_INSECURE="--insecure"
|
||||
```
|
||||
|
||||
### Serve Static Files
|
||||
|
||||
Run zrok's embedded web server to serve the files in a directory. If there's an `index.html` file in the directory then visitors will see that web page in their browser, otherwise they'll see a generated index of the files. The directory must be readable by 'other', e.g. `chmod -R o+rX /var/www/html`.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_TARGET="/var/www/html"
|
||||
ZROK_BACKEND_MODE="web"
|
||||
```
|
||||
|
||||
### Caddy Server
|
||||
|
||||
Use zrok's built-in Caddy server to serve static files or as a reverse proxy to multiple web servers with various HTTP routes or as a load-balanced set. A sample Caddyfile is available in the path shown.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_TARGET="/opt/openziti/etc/zrok/multiple_upstream.Caddyfile"
|
||||
ZROK_BACKEND_MODE="caddy"
|
||||
```
|
||||
|
||||
### Network Drive
|
||||
|
||||
This uses zrok's `drive` backend mode to serve a directory of static files as a virtual network drive. The directory must be readable by 'other', e.g. `chmod -R o+rX /usr/share/doc`.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_TARGET="/usr/share/doc"
|
||||
ZROK_BACKEND_MODE="drive"
|
||||
```
|
||||
|
||||
[Learn more about this feature in this blog post](https://blog.openziti.io/zrok-drives-an-early-preview).
|
||||
|
||||
## Authentication
|
||||
|
||||
You can limit access to certain email addresses with OAuth or require a password.
|
||||
|
||||
### OAuth
|
||||
|
||||
You can require that visitors authenticate with an email address that matches at least one of the suffixes you specify. Add the following to the configuration file.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_OAUTH_PROVIDER="github" # or google
|
||||
ZROK_OAUTH_EMAILS="alice@example.com *@acme.example.com"
|
||||
```
|
||||
|
||||
### Password
|
||||
|
||||
Enable HTTP basic authentication by adding the following to the configuration file.
|
||||
|
||||
```bash title="/opt/openziti/etc/zrok/zrok-share.env"
|
||||
ZROK_BASIC_AUTH="user:passwd"
|
||||
```
|
||||
|
||||
## Start the Service
|
||||
|
||||
Start the service, and check the zrok console or the service log for the reserved subdomain.
|
||||
|
||||
```bash title="run now and at startup"
|
||||
sudo systemctl enable --now zrok-share.service
|
||||
```
|
||||
|
||||
```bash title="run now"
|
||||
sudo systemctl restart zrok-share.service
|
||||
```
|
||||
|
||||
```bash
|
||||
journalctl -u zrok-share.service
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
The Linux distribution must have a package manager that understands the `.deb` or `.rpm` format and be running systemd v232 or newer. The service was tested with:
|
||||
|
||||
* Ubuntu 20.04, 22.04, 23.04
|
||||
* Debian 11 12
|
||||
* Rocky 8, 9
|
||||
* Fedora 37, 38
|
||||
|
||||
## Package Contents
|
||||
|
||||
The files included in the `zrok-share` package are sourced [here in GitHub](https://github.com/openziti/zrok/tree/main/nfpm).
|
@ -8,6 +8,8 @@ sidebar_label: Private Share
|
||||
|
||||
With zrok, you can privately share a server app that's running in Docker, or any server that's reachable by the zrok container. Then, a zrok private access running somewhere else can use the private share. In this guide we'll cover both sides: the private share and the private access.
|
||||
|
||||
Here's a short article with an overview of [private sharing with zrok](/concepts/sharing-private.md).
|
||||
|
||||
## Walkthrough Video
|
||||
|
||||
<iframe width="100%" height="315" src="https://www.youtube.com/embed/HxyvtFAvwUE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
@ -18,7 +20,7 @@ To follow this guide you will need [Docker](https://docs.docker.com/get-docker/)
|
||||
|
||||
If you have installed Docker Desktop on macOS or Windows then you are all set.
|
||||
|
||||
## Private Share with Docker Compose
|
||||
## Begin Sharing Privately with zrok in Docker
|
||||
|
||||
First, let's create the private share.
|
||||
|
||||
@ -53,9 +55,9 @@ First, let's create the private share.
|
||||
|
||||
Keep track of this token so you can use it in your zrok private access project.
|
||||
|
||||
## Private Access with Docker Compose
|
||||
## Access the Private Share
|
||||
|
||||
Now that we have a private share we can access it with zrok running in Docker. Next, let's access the demo web server in a web browser.
|
||||
Now that we have a private share we can access it with the zrok command or by running a separate Docker Compose project.
|
||||
|
||||
1. Make a folder on your computer to use as a Docker Compose project for your zrok private access.
|
||||
1. In your terminal, change directory to your newly-created project folder.
|
||||
|
@ -1,11 +1,12 @@
|
||||
---
|
||||
title: Docker Public Share
|
||||
sidebar_position: 10
|
||||
sidebar_label: Public Share
|
||||
---
|
||||
|
||||
# Docker Public Share
|
||||
With zrok and Docker, you can publicly share a web server that's running in a local container or anywhere that's reachable by the zrok container. The share can be reached through a temporary public URL that expires when the container is stopped. If you're looking for a reserved subdomain for the share, check out [zrok frontdoor](/guides/frontdoor.mdx).
|
||||
|
||||
With zrok and Docker, you can publicly share a web server that's running in a local container or anywhere that's reachable by the zrok container. The share can be reached through a public URL thats temporary or reserved (reusable).
|
||||
Here's a short article with an overview of [public sharing with zrok](/concepts/sharing-public.md).
|
||||
|
||||
## Walkthrough Video
|
||||
|
||||
@ -15,13 +16,13 @@ With zrok and Docker, you can publicly share a web server that's running in a lo
|
||||
|
||||
To follow this guide you will need [Docker](https://docs.docker.com/get-docker/) and [the Docker Compose plugin](https://docs.docker.com/compose/install/) for running `docker compose` commands in your terminal.
|
||||
|
||||
## Temporary or Reserved Public Share
|
||||
## Begin Sharing with Docker Compose
|
||||
|
||||
A temporary public share is a great way to share a web server running in a container with someone else for a short time. A reserved public share is a great way to share a reliable web server running in a container with someone else for a long time.
|
||||
A temporary public share is a great way to share a web server running in a container with someone else for a short time.
|
||||
|
||||
1. Make a folder on your computer to use as a Docker Compose project for your zrok public share.
|
||||
1. In your terminal, change directory to the newly-created project folder.
|
||||
1. Download either [the temporary public share project file](pathname:///zrok-public-share/compose.yml) or [the reserved public share project file](pathname:///zrok-public-reserved/compose.yml) into the project folder.
|
||||
1. Download [the temporary public share project file](pathname:///zrok-public-share/compose.yml).
|
||||
1. Copy your zrok environment token from the zrok web console to your clipboard and paste it in a file named `.env` in the same folder like this:
|
||||
|
||||
```bash title=".env"
|
||||
@ -54,7 +55,7 @@ This concludes sharing the demo web server. Read on to learn how to pivot to sha
|
||||
|
||||
## Proxy Any Web Server
|
||||
|
||||
The simplest way to share your web server is to set `ZROK_TARGET` (e.g. `https://example.com`) in the environment of the `docker compose up` command. When you restart the share will auto-configure for that upstream server URL. This applies to both temporary and reserved public shares.
|
||||
The simplest way to share your web server is to set `ZROK_TARGET` (e.g. `https://example.com`) in the environment file.
|
||||
|
||||
```bash title=".env"
|
||||
ZROK_TARGET="http://example.com:8080"
|
||||
@ -62,7 +63,7 @@ ZROK_TARGET="http://example.com:8080"
|
||||
|
||||
## Require Authentication
|
||||
|
||||
You can require authentication for your public share by setting `ZROK_OAUTH_PROVIDER` to `github` or `google` if you're using our hosted zrok.io, and any OIDC provider you've configured if self-hosting. You can parse the authenticated email address from the request cookie. Read more about the OAuth features in [this blog post](https://blog.openziti.io/the-zrok-oauth-public-frontend). This applies to both temporary and reserved public shares.
|
||||
You can require authentication for your public share by setting `ZROK_OAUTH_PROVIDER` to `github` or `google` with zrok.io. You could parse the authenticated email address from the request cookie if you're building a custom server app. Read more about the OAuth features in [this blog post](https://blog.openziti.io/the-zrok-oauth-public-frontend).
|
||||
|
||||
```bash title=".env"
|
||||
ZROK_OAUTH_PROVIDER="github"
|
||||
@ -70,6 +71,12 @@ ZROK_OAUTH_PROVIDER="github"
|
||||
|
||||
## Customize Temporary Public Share
|
||||
|
||||
This technique is useful for adding a containerized service to the project, or mounting a filesystem directory into the container to share as a static website or file server.
|
||||
|
||||
Any additional services specified in the override file will be merged with `compose.yml` when you `up` the project.
|
||||
|
||||
You may override individual values from in `compose.yml` by specifying them in the override file.
|
||||
|
||||
1. Create a file `compose.override.yml`. This example demonstrates sharing a static HTML directory `/tmp/html` from the Docker host's filesystem.
|
||||
|
||||
```yaml title="compose.override.yml"
|
||||
@ -96,52 +103,6 @@ ZROK_OAUTH_PROVIDER="github"
|
||||
zrok-public-share-1 | https://w6r1vesearkj.in.zrok.io/
|
||||
```
|
||||
|
||||
## Customize Reserved Public Share
|
||||
|
||||
The reserved public share project uses zrok's `caddy` mode. Caddy accepts configuration as a Caddyfile that is mounted into the container ([zrok Caddyfile examples](https://github.com/openziti/zrok/tree/main/etc/caddy)).
|
||||
|
||||
1. Create a Caddyfile. This example demonstrates proxying two HTTP servers with a weighted round-robin load balancer.
|
||||
|
||||
```console title="Caddyfile"
|
||||
http:// {
|
||||
# zrok requires this bind address template
|
||||
bind {{ .ZrokBindAddress }}
|
||||
reverse_proxy /* {
|
||||
to http://httpbin1:8080 http://httpbin2:8080
|
||||
lb_policy weighted_round_robin 3 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Create a file `compose.override.yml`. This example adds two `httpbin` containers for Caddy load balance, and masks the default Caddyfile with our custom one.
|
||||
|
||||
```yaml title="compose.override.yml"
|
||||
services:
|
||||
httpbin1:
|
||||
image: mccutchen/go-httpbin # 8080/tcp
|
||||
httpbin2:
|
||||
image: mccutchen/go-httpbin # 8080/tcp
|
||||
zrok-share:
|
||||
volumes:
|
||||
- ./Caddyfile:/mnt/.zrok/Caddyfile
|
||||
```
|
||||
|
||||
1. Re-run the project to load the new configuration.
|
||||
|
||||
```bash
|
||||
docker compose up --force-recreate --detach
|
||||
```
|
||||
|
||||
1. Recall the reserved share URL from the log.
|
||||
|
||||
```bash
|
||||
docker compose logs zrok-share
|
||||
```
|
||||
|
||||
```buttonless title="Output"
|
||||
INFO: zrok public URL: https://88s803f2qvao.in.zrok.io/
|
||||
```
|
||||
|
||||
## Destroy the zrok Environment
|
||||
|
||||
This destroys the Docker volumes containing the zrok environment secrets. The zrok environment can also be destroyed in the web console.
|
||||
|
314
docs/guides/drives/cli.md
Normal file
314
docs/guides/drives/cli.md
Normal file
@ -0,0 +1,314 @@
|
||||
# The Drives CLI
|
||||
|
||||
The zrok drives CLI tools allow for simple, ergonomic management and synchronization of local and remote files.
|
||||
|
||||
## Sharing a Drive
|
||||
|
||||
Virtual drives are shared through the `zrok` CLI using the `--backend-mode drive` flag through the `zrok share` command, using either the `public` or `private` sharing modes. We'll use the `private` sharing mode for this example:
|
||||
|
||||
```
|
||||
$ mkdir /tmp/junk
|
||||
$ zrok share private --headless --backend-mode drive /tmp/junk
|
||||
[ 0.124] INFO sdk-golang/ziti.(*listenerManager).createSessionWithBackoff: {session token=[cf640aac-2706-49ae-9cc9-9a497d67d9c5]} new service session
|
||||
[ 0.145] INFO main.(*sharePrivateCommand).run: allow other to access your share with the following command:
|
||||
zrok access private wkcfb58vj51l
|
||||
```
|
||||
|
||||
The command shown above creates an ephemeral, `private` drive share pointed at the local `/tmp/junk` folder.
|
||||
|
||||
Notice that the share token allocated by `zrok` is `wkcfb58vj51l`. We'll use that share token to identify our virtual drive in the following operations.
|
||||
|
||||
## Working with a Private Drive Share
|
||||
|
||||
First, let's copy a file into our virtual drive using the `zrok copy` command:
|
||||
|
||||
```
|
||||
$ zrok copy LICENSE zrok://wkcfb58vj51l
|
||||
[ 0.119] INFO zrok/drives/sync.OneWay: => /LICENSE
|
||||
copy complete!
|
||||
```
|
||||
|
||||
We used the URL scheme `zrok://<shareToken>` to refer to the private virtual drive we allocated above using the `zrok share private` command. Use `zrok://` URLs with the drives CLI tools to refer to contents of private virtual drives.
|
||||
|
||||
Next, let's get a directory listing of the virtual drive:
|
||||
|
||||
```
|
||||
$ zrok ls zrok://wkcfb58vj51l
|
||||
┌──────┬─────────┬─────────┬───────────────────────────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼─────────┼─────────┼───────────────────────────────┤
|
||||
│ │ LICENSE │ 11.3 kB │ 2024-01-19 12:16:46 -0500 EST │
|
||||
└──────┴─────────┴─────────┴───────────────────────────────┘
|
||||
```
|
||||
|
||||
We can make directories on the virtual drive:
|
||||
|
||||
```
|
||||
$ zrok mkdir zrok://wkcfb58vj51l/stuff
|
||||
$ zrok ls zrok://wkcfb58vj51l
|
||||
┌──────┬─────────┬─────────┬───────────────────────────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼─────────┼─────────┼───────────────────────────────┤
|
||||
│ │ LICENSE │ 11.3 kB │ 2024-01-19 12:16:46 -0500 EST │
|
||||
│ DIR │ stuff │ │ │
|
||||
└──────┴─────────┴─────────┴───────────────────────────────┘
|
||||
```
|
||||
|
||||
We can copy the contents of a local directory into the new directory on the virtual drive:
|
||||
|
||||
```
|
||||
$ ls -l util/
|
||||
total 20
|
||||
-rw-rw-r-- 1 michael michael 329 Jul 21 13:17 email.go
|
||||
-rw-rw-r-- 1 michael michael 456 Jul 21 13:17 headers.go
|
||||
-rw-rw-r-- 1 michael michael 609 Jul 21 13:17 proxy.go
|
||||
-rw-rw-r-- 1 michael michael 361 Jul 21 13:17 size.go
|
||||
-rw-rw-r-- 1 michael michael 423 Jan 2 11:57 uniqueName.go
|
||||
$ zrok copy util/ zrok://wkcfb58vj51l/stuff
|
||||
[ 0.123] INFO zrok/drives/sync.OneWay: => /email.go
|
||||
[ 0.194] INFO zrok/drives/sync.OneWay: => /headers.go
|
||||
[ 0.267] INFO zrok/drives/sync.OneWay: => /proxy.go
|
||||
[ 0.337] INFO zrok/drives/sync.OneWay: => /size.go
|
||||
[ 0.408] INFO zrok/drives/sync.OneWay: => /uniqueName.go
|
||||
copy complete!
|
||||
$ zrok ls zrok://wkcfb58vj51l/stuff
|
||||
┌──────┬───────────────┬───────┬───────────────────────────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼───────────────┼───────┼───────────────────────────────┤
|
||||
│ │ email.go │ 329 B │ 2024-01-19 12:26:45 -0500 EST │
|
||||
│ │ headers.go │ 456 B │ 2024-01-19 12:26:45 -0500 EST │
|
||||
│ │ proxy.go │ 609 B │ 2024-01-19 12:26:45 -0500 EST │
|
||||
│ │ size.go │ 361 B │ 2024-01-19 12:26:45 -0500 EST │
|
||||
│ │ uniqueName.go │ 423 B │ 2024-01-19 12:26:45 -0500 EST │
|
||||
└──────┴───────────────┴───────┴───────────────────────────────┘
|
||||
```
|
||||
|
||||
And we can remove files and directories from the virtual drive:
|
||||
|
||||
```
|
||||
$ zrok rm zrok://wkcfb58vj51l/LICENSE
|
||||
$ zrok ls zrok://wkcfb58vj51l
|
||||
┌──────┬───────┬──────┬──────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼───────┼──────┼──────────┤
|
||||
│ DIR │ stuff │ │ │
|
||||
└──────┴───────┴──────┴──────────┘
|
||||
$ zrok rm zrok://wkcfb58vj51l/stuff
|
||||
$ zrok ls zrok://wkcfb58vj51l
|
||||
┌──────┬──────┬──────┬──────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼──────┼──────┼──────────┤
|
||||
└──────┴──────┴──────┴──────────┘
|
||||
```
|
||||
|
||||
## Working with Public Shares
|
||||
|
||||
Public shares work very similarly to private shares, they just use a different URL scheme:
|
||||
|
||||
```
|
||||
$ zrok share public --headless --backend-mode drive /tmp/junk
|
||||
[ 0.708] INFO sdk-golang/ziti.(*listenerManager).createSessionWithBackoff: {session token=[05e0f48b-242b-4fd9-8edb-259488535c47]} new service session
|
||||
[ 0.878] INFO main.(*sharePublicCommand).run: access your zrok share at the following endpoints:
|
||||
https://6kiww4bn7iok.share.zrok.io
|
||||
```
|
||||
|
||||
The same commands, with a different URL scheme work with the `zrok` drives CLI:
|
||||
|
||||
```
|
||||
$ zrok copy util/ https://6kiww4bn7iok.share.zrok.io
|
||||
[ 0.268] INFO zrok/drives/sync.OneWay: => /email.go
|
||||
[ 0.406] INFO zrok/drives/sync.OneWay: => /headers.go
|
||||
[ 0.530] INFO zrok/drives/sync.OneWay: => /proxy.go
|
||||
[ 0.655] INFO zrok/drives/sync.OneWay: => /size.go
|
||||
[ 0.714] INFO zrok/drives/sync.OneWay: => /uniqueName.go
|
||||
copy complete!
|
||||
michael@fourtyfour Fri Jan 19 12:42:52 ~/Repos/nf/zrok
|
||||
$ zrok ls https://6kiww4bn7iok.share.zrok.io
|
||||
┌──────┬───────────────┬───────┬───────────────────────────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼───────────────┼───────┼───────────────────────────────┤
|
||||
│ │ email.go │ 329 B │ 2023-07-21 13:17:56 -0400 EDT │
|
||||
│ │ headers.go │ 456 B │ 2023-07-21 13:17:56 -0400 EDT │
|
||||
│ │ proxy.go │ 609 B │ 2023-07-21 13:17:56 -0400 EDT │
|
||||
│ │ size.go │ 361 B │ 2023-07-21 13:17:56 -0400 EDT │
|
||||
│ │ uniqueName.go │ 423 B │ 2024-01-02 11:57:14 -0500 EST │
|
||||
└──────┴───────────────┴───────┴───────────────────────────────┘
|
||||
```
|
||||
|
||||
For basic authentication provided by public shares, the `zrok` drives CLI offers the `--basic-auth` flag, which accepts a `<username>:<password>` parameter to specify the authentication for the public virtual drive (if it's required).
|
||||
|
||||
Alternatively, the authentication can be set using the `ZROK_DRIVES_BASIC_AUTH` environment variable:
|
||||
|
||||
```
|
||||
$ export ZROK_DRIVES_BASIC_AUTH=username:password
|
||||
```
|
||||
|
||||
## One-way Synchronization
|
||||
|
||||
The `zrok copy` command includes a `--sync` flag, which only copies files detected as _modified_. `zrok` considers a file with the same modification timestamp and size to be the same. Of course, this is not a strong guarantee that the files are equivalent. Future `zrok` drives versions will provide a cryptographically strong mechanism (a-la `rsync` and friends) to guarantee that files and trees of files are synchronized.
|
||||
|
||||
For now, the `--sync` flag provides a convenience mechanism to allow resuming copies of large file trees and provide a reasonable guarantee that the trees are in sync.
|
||||
|
||||
Let's take a look at `zrok copy --sync` in action:
|
||||
|
||||
```
|
||||
$ zrok copy --sync docs/ https://glmv049c62p7.share.zrok.io
|
||||
[ 0.636] INFO zrok/drives/sync.OneWay: => /_attic/
|
||||
[ 0.760] INFO zrok/drives/sync.OneWay: => /_attic/network/
|
||||
[ 0.816] INFO zrok/drives/sync.OneWay: => /_attic/network/_category_.json
|
||||
[ 0.928] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/
|
||||
[ 0.987] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/ziti-ctrl.service
|
||||
[ 1.048] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/ziti-ctrl.yml
|
||||
[ 1.107] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/ziti-router0.service
|
||||
[ 1.167] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/ziti-router0.yml
|
||||
[ 1.218] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/zrok-access-public.service
|
||||
[ 1.273] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/zrok-ctrl.service
|
||||
[ 1.328] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/zrok-ctrl.yml
|
||||
[ 1.382] INFO zrok/drives/sync.OneWay: => /_attic/network/prod/zrok.io-network-skeleton.md
|
||||
[ 1.447] INFO zrok/drives/sync.OneWay: => /_attic/overview.md
|
||||
[ 1.572] INFO zrok/drives/sync.OneWay: => /_attic/sharing/
|
||||
[ 1.622] INFO zrok/drives/sync.OneWay: => /_attic/sharing/_category_.json
|
||||
[ 1.673] INFO zrok/drives/sync.OneWay: => /_attic/sharing/reserved_services.md
|
||||
[ 1.737] INFO zrok/drives/sync.OneWay: => /_attic/sharing/sharing_modes.md
|
||||
[ 1.793] INFO zrok/drives/sync.OneWay: => /_attic/v0.2_account_requests.md
|
||||
[ 1.902] INFO zrok/drives/sync.OneWay: => /_attic/v0.4_limits.md
|
||||
...
|
||||
[ 9.691] INFO zrok/drives/sync.OneWay: => /images/zrok_web_ui_empty_shares.png
|
||||
[ 9.812] INFO zrok/drives/sync.OneWay: => /images/zrok_web_ui_new_environment.png
|
||||
[ 9.870] INFO zrok/drives/sync.OneWay: => /images/zrok_zoom_to_fit.png
|
||||
copy complete!
|
||||
```
|
||||
|
||||
Because the target drive was empty, `zrok copy --sync` copied the entire contents of the local `docs/` tree into the virtual drive. However, if we run that command again, we get:
|
||||
|
||||
```
|
||||
$ zrok copy --sync docs/ https://glmv049c62p7.share.zrok.io
|
||||
copy complete!
|
||||
```
|
||||
|
||||
The virtual drive contents are already in sync with the local filesystem tree, so there is nothing for it to copy.
|
||||
|
||||
Let's alter the contents of the drive and run the `--sync` again:
|
||||
|
||||
```
|
||||
$ zrok rm https://glmv049c62p7.share.zrok.io/images
|
||||
$ zrok copy --sync docs/ https://glmv049c62p7.share.zrok.io
|
||||
[ 0.364] INFO zrok/drives/sync.OneWay: => /images/
|
||||
[ 0.456] INFO zrok/drives/sync.OneWay: => /images/zrok.png
|
||||
[ 0.795] INFO zrok/drives/sync.OneWay: => /images/zrok_cover.png
|
||||
[ 0.866] INFO zrok/drives/sync.OneWay: => /images/zrok_deployment.drawio
|
||||
...
|
||||
[ 2.254] INFO zrok/drives/sync.OneWay: => /images/zrok_web_ui_empty_shares.png
|
||||
[ 2.340] INFO zrok/drives/sync.OneWay: => /images/zrok_web_ui_new_environment.png
|
||||
[ 2.391] INFO zrok/drives/sync.OneWay: => /images/zrok_zoom_to_fit.png
|
||||
copy complete!
|
||||
```
|
||||
|
||||
Because we removed the `images/` tree from the virtual drive, `zrok copy --sync` detected this and copied the local `images/` tree back onto the virtual drive.
|
||||
|
||||
## Drive-to-Drive Copies and Synchronization
|
||||
|
||||
The `zrok copy` CLI can operate on pairs of virtual drives remotely, without ever having to store files locally. This allow for drive-to-drive copies and synchronization.
|
||||
|
||||
Here are a couple of examples:
|
||||
|
||||
```
|
||||
$ zrok copy --sync https://glmv049c62p7.share.zrok.io https://glmv049c62p7.share.zrok.io
|
||||
copy complete!
|
||||
```
|
||||
|
||||
Specifying the same URL for both the source and the target of a `--sync` operation should always result in nothing being copied... they are the same drive with the same state.
|
||||
|
||||
We can copy files between two virtual drives with a single command:
|
||||
|
||||
```
|
||||
$ zrok copy --sync https://glmv049c62p7.share.zrok.io zrok://hsml272j3xzf
|
||||
[ 1.396] INFO zrok/drives/sync.OneWay: => /_attic/
|
||||
[ 2.083] INFO zrok/drives/sync.OneWay: => /_attic/overview.md
|
||||
[ 2.704] INFO zrok/drives/sync.OneWay: => /_attic/sharing/
|
||||
...
|
||||
[ 118.240] INFO zrok/drives/sync.OneWay: => /images/zrok_web_console_empty.png
|
||||
[ 118.920] INFO zrok/drives/sync.OneWay: => /images/zrok_enable_modal.png
|
||||
[ 119.589] INFO zrok/drives/sync.OneWay: => /images/zrok_cover.png
|
||||
[ 120.214] INFO zrok/drives/sync.OneWay: => /getting-started.mdx
|
||||
copy complete!
|
||||
$ zrok copy --sync https://glmv049c62p7.share.zrok.io zrok://hsml272j3xzf
|
||||
copy complete!
|
||||
```
|
||||
|
||||
## Copying from Drives to the Local Filesystem
|
||||
|
||||
In the current version of the drives CLI, `zrok copy` always assumes the destination is a directory. There is currently no way to do:
|
||||
|
||||
```
|
||||
$ zrok copy somefile someotherfile
|
||||
```
|
||||
|
||||
What you'll end up with on the local filesystem is:
|
||||
|
||||
```
|
||||
somefile
|
||||
someotherfile/somefile
|
||||
```
|
||||
|
||||
It's in the backlog to support file destinations in a future release of `zrok`. So, when using `zrok copy`, always take note of the destination.
|
||||
|
||||
`zrok copy` supports a default destination of `file://.`, so you can do single parameter `zrok copy` commands like this:
|
||||
|
||||
```
|
||||
$ zrok ls https://azc47r3cwjds.share.zrok.io
|
||||
┌──────┬─────────┬─────────┬───────────────────────────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼─────────┼─────────┼───────────────────────────────┤
|
||||
│ │ LICENSE │ 11.3 kB │ 2023-07-21 13:17:56 -0400 EDT │
|
||||
└──────┴─────────┴─────────┴───────────────────────────────┘
|
||||
$ zrok copy https://azc47r3cwjds.share.zrok.io/LICENSE
|
||||
[ 0.260] INFO zrok/drives/sync.OneWay: => /LICENSE
|
||||
copy complete!
|
||||
$ ls -l
|
||||
total 12
|
||||
-rw-rw-r-- 1 michael michael 11346 Jan 19 13:29 LICENSE
|
||||
```
|
||||
|
||||
You can also specify a local folder as the destination for your copy:
|
||||
|
||||
```
|
||||
$ zrok copy https://azc47r3cwjds.share.zrok.io/LICENSE /tmp/inbox
|
||||
[ 0.221] INFO zrok/drives/sync.OneWay: => /LICENSE
|
||||
copy complete!
|
||||
$ l /tmp/inbox
|
||||
total 12
|
||||
-rw-rw-r-- 1 michael michael 11346 Jan 19 13:30 LICENSE
|
||||
```
|
||||
|
||||
## Unique Names and Reserved Shares
|
||||
|
||||
Private reserved shares with unque names can be particularly useful with the drives CLI:
|
||||
|
||||
```
|
||||
$ zrok reserve private -b drive --unique-name mydrive /tmp/junk
|
||||
[ 0.315] INFO main.(*reserveCommand).run: your reserved share token is 'mydrive'
|
||||
$ zrok share reserved --headless mydrive
|
||||
[ 0.289] INFO main.(*shareReservedCommand).run: sharing target: '/tmp/junk'
|
||||
[ 0.289] INFO main.(*shareReservedCommand).run: using existing backend proxy endpoint: /tmp/junk
|
||||
[ 0.767] INFO sdk-golang/ziti.(*listenerManager).createSessionWithBackoff: {session token=[d519a436-9fb5-4207-afd5-7cbc28fb779a]} new service session
|
||||
[ 0.927] INFO main.(*shareReservedCommand).run: use this command to access your zrok share: 'zrok access private mydrive'
|
||||
```
|
||||
|
||||
This makes working with `zrok://` URLs particularly convenient:
|
||||
|
||||
```
|
||||
$ zrok ls zrok://mydrive
|
||||
┌──────┬─────────┬─────────┬───────────────────────────────┐
|
||||
│ TYPE │ NAME │ SIZE │ MODIFIED │
|
||||
├──────┼─────────┼─────────┼───────────────────────────────┤
|
||||
│ │ LICENSE │ 11.3 kB │ 2023-07-21 13:17:56 -0400 EDT │
|
||||
└──────┴─────────┴─────────┴───────────────────────────────┘
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Coming in a future release of `zrok` drives are features like:
|
||||
|
||||
* two-way synchronization between multiple hosts... allowing for shared "dropbox-like" usage scenarios between multiple environments
|
||||
* better ergonomics for single-file destinations
|
75
docs/guides/frontdoor.mdx
Normal file
75
docs/guides/frontdoor.mdx
Normal file
@ -0,0 +1,75 @@
|
||||
---
|
||||
title: zrok frontdoor
|
||||
sidebar_label: frontdoor
|
||||
sidebar_position: 20
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import OsTabs from '@theme/OsTabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import LinuxService from './_frontdoor-linux.mdx';
|
||||
import ReservedDocker from './_frontdoor-docker.mdx';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
**zrok frontdoor** is the heavy-duty front door to your app or site. It makes your website or app available to your online audience through the shield of zrok.io's hardened, managed frontends.
|
||||
|
||||
<iframe width="100%" height="315" src="https://www.youtube.com/embed/5Vi8GKuTi_I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
## Overview
|
||||
|
||||
zrok frontends are the parts of zrok that proxy incoming public web traffic to zrok backend shares via OpenZiti. When you use zrok with a `zrok.io` frontend, you're using **zrok frontdoor**. `zrok.io` is zrok-as-a-service by NetFoundry, the team behind OpenZiti. You need a free account to use **zrok frontdoor**.
|
||||
|
||||
|
||||
<ThemedImage
|
||||
alt="frontdoor diagram"
|
||||
sources={{
|
||||
light: useBaseUrl('/img/zrok-frontdoor-light-mode.svg'),
|
||||
dark: useBaseUrl('/img/zrok-frontdoor-dark-mode.svg'),
|
||||
}}
|
||||
/>
|
||||
|
||||
## Choose your OS
|
||||
|
||||
Choose between installing the Linux package or running zrok with Docker (Linux, macOS, or Windows).
|
||||
|
||||
<OsTabs
|
||||
queryString="os"
|
||||
values={[
|
||||
{ label: 'Linux', value: 'Linux', },
|
||||
{ label: 'macOS', value: 'Mac OS', },
|
||||
{ label: 'Windows', value: 'Windows', },
|
||||
]}
|
||||
>
|
||||
|
||||
<TabItem value="Linux">
|
||||
|
||||
On Linux, zrok frontdoor is implemented natively as a system service provided by the `zrok-share` DEB or RPM package.
|
||||
|
||||
If you'd prefer to run zrok in Docker instead of installing the package then you can follow the Docker instructions. With Docker, the steps are the same for Linux, [macOS](./?os=Mac+OS), and [Windows](./?os=Windows).
|
||||
|
||||
<LinuxService/>
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="Mac OS">
|
||||
|
||||
On macOS, zrok frontdoor is implemented as a Docker Compose project which reserves a public subdomain for your website or service.
|
||||
|
||||
<ReservedDocker/>
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="Windows">
|
||||
|
||||
On Windows, zrok frontdoor is implemented as a Docker Compose project which reserves a public subdomain for your website or service.
|
||||
|
||||
<ReservedDocker/>
|
||||
|
||||
</TabItem>
|
||||
|
||||
</OsTabs>
|
||||
|
||||
## Concepts
|
||||
|
||||
Overview of [zrok reserved shares](/concepts/sharing-reserved.md)
|
55
docs/guides/install/_ansible_repo_setup.yaml
Normal file
55
docs/guides/install/_ansible_repo_setup.yaml
Normal file
@ -0,0 +1,55 @@
|
||||
- name: Set up zrok Package Repo
|
||||
gather_facts: true
|
||||
hosts: all
|
||||
become: true
|
||||
tasks:
|
||||
- name: Set up apt repo
|
||||
when: ansible_os_family == "Debian"
|
||||
block:
|
||||
- name: Install playbook dependencies
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- gnupg
|
||||
state: present
|
||||
|
||||
- name: Fetch armored pubkey
|
||||
ansible.builtin.uri:
|
||||
url: https://get.openziti.io/tun/package-repos.gpg
|
||||
return_content: yes
|
||||
register: armored_pubkey
|
||||
|
||||
- name: Dearmor pubkey
|
||||
ansible.builtin.shell: |
|
||||
gpg --dearmor --output /usr/share/keyrings/openziti.gpg <<< "{{ armored_pubkey.content }}"
|
||||
args:
|
||||
creates: /usr/share/keyrings/openziti.gpg
|
||||
executable: /bin/bash
|
||||
|
||||
- name: Set pubkey filemode
|
||||
ansible.builtin.file:
|
||||
path: /usr/share/keyrings/openziti.gpg
|
||||
mode: 'a+rX'
|
||||
|
||||
- name: Install OpenZiti repo deb source
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/apt/sources.list.d/openziti-release.list
|
||||
content: |
|
||||
deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main
|
||||
|
||||
- name: Refresh Repo Sources
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Set up yum repo
|
||||
when: ansible_os_family == "RedHat"
|
||||
block:
|
||||
- name: Install OpenZiti repo rpm source
|
||||
ansible.builtin.yum_repository:
|
||||
name: OpenZitiRelease
|
||||
description: OpenZiti Release
|
||||
baseurl: https://packages.openziti.org/zitipax-openziti-rpm-stable/redhat/$basearch
|
||||
enabled: yes
|
||||
gpgkey: https://packages.openziti.org/zitipax-openziti-rpm-stable/redhat/$basearch/repodata/repomd.xml.key
|
||||
repo_gpgcheck: yes
|
||||
gpgcheck: no
|
8
docs/guides/install/_category_.json
Normal file
8
docs/guides/install/_category_.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"label": "Install",
|
||||
"position": 10,
|
||||
"link": {
|
||||
"type": "doc",
|
||||
"id": "guides/install/index"
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user