[[TOC]]
Banjo is a CLI for executing deployment operations against an Auth0 tenant. It lets you define Auth0 resources as json files (templates) that are read and used to drive Auth0 Management API calls to create or update Auth0 resources.
Banjo is designed from the ground up to support defining and deploying Auth0 resources for different environments, for example, deploying similar sets of resources to support DEV, TEST, and STAGING environments in one Auth0 tenant and PROD in another tenant.
Banjo is built as a DotNet Core Global Tool meaning that we can install/run it on any platform. It is ideally suited to being used in CI/CD pipelines.
Status | |
---|---|
Release (master) | |
Continuous Deployment (rc) | |
Build |
Banjo is published as a dotnet global tool on nuget.org.
To install:
> dotnet tool install -g banjo.cli
If you want to install the Banjo CLI as a global tool that's built from your own local sources, there's a bit of command line-fu needed. (see this blog post)
Individual commands are below, but there's an all-in-one PowerShell script that builds, packages, and installs (or updates) the new build;
# from the Banjo.CLI project directory
.\reinstall-cli.ps1
You should now be able to run the tool from anywhere with
banjo {arguments}
List the current installed global tools. You're looking for banjo.cli
dotnet tool list -g
The manual build process involve;
- uninstall the tool if it exists,
- build the new one (using GitVersion to generate a semantic version number),
- publish locally,
- then install from local
# from the Banjo.CLI project directory
dotnet tool uninstall -g banjo.cli
dotnet build
dotnet pack --output ./
dotnet tool install -g banjo.cli --add-source ./
Or to update an already installed tool from locally built source
dotnet tool update -g banjo.cli --add-source ./
- You've installed Banjo as a dotnet global tool
- You have an Auth0 tenant available
- You've gone through the steps to authorise an application to access the Auth0 Management API
- Instructions can be found at https://auth0.com/docs/api/management/v2/tokens
- At the end you'll have your Auth0 domain (eg,
my-domain.au.auth0.com
), a client id, and client secret
- Set the Auth0 domain, client id, and client secret so Banjo can access them
There are two ways you can provide Banjo with your Auth0 domain, client id and client secret. The preferred way, and the best way for CI/CD pipelines is to use environment variables:
AUTH0__DOMAIN={domain}
- double underscore!AUTH0__CLIENTID={client id}
- double underscore!AUTH0__CLIENTSECRET={client secret}
- double underscore!
Note the double-underscore, that's important as Banjo uses the ASP.NET style of hierarchical configuration, see the ASP.NET docs
An alternative method that's best for local dev is to set the dotnet environment to "Development" and use dotnet user-secrets.
- Tell dotnet that its environment is set to "Development", which is what tells Banjo to enable the user-secrets storage.
- set env var
DOTNET_ENVIRONMENT=Development
- set env var
- (once off)
cd {banjo clone location}/Banjo.CLI
, thendotnet user-secrets init
.- Alternatively, create an empty json document
{}
at%APPDATA%\Microsoft\UserSecrets\Banjo.CLI\secrets.json
(Windows) or~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
(*nix/MacOS)
- Alternatively, create an empty json document
dotnet user-secrets set Auth0:Domain {domain}
dotnet user-secrets set Auth0:ClientId {client_id}
dotnet user-secrets set Auth0:ClientSecret {client_secret}
Once you've installed Banjo as a global tool and configured your Auth0 domain, client id, and client secret;
$> banjo process --help
Usage: banjo process [options]
Options:
--help Show help information
-t|--template <TEMPLATES_PATH> The path to a directory of input templates
-o|--override <OVERRIDE_PATH> The path to an override file
-out|--output <PROCESSED_OUTPUT_PATH> The output path for writing the effective templates
-d|--dry-run Process the templates, plan the mutation operations to make (which may include some Auth0 API calls), but do not create/update any Auth0 resources.
-v|--verbose Enable Verbose level output
$> banjo process -t {path-to-templates-directory} -o {path-to-override-file}
Banjo has two key file types;
- Template - Banjo works from a set of template files, each one representing an Auth0 resource you want to be deployed. The structure of the json file depends on Auth0 resource type.
- Overrides - Banjo supports an optional overrides file that can alter the contents of templates before making the API calls to create/update the Auth0 resources defined by the templates.
The template models for each resource type closely follows the output from the Auth0 Deploy CLI tool, which in turn generally mirrors the Auth0 Management API model.
A Banjo template is a declarative file that defines what the Auth0 resource should look like, similar to an Azure ARM template or AWS CloudFormation template, except that Banjo requires one resource per file.
You point Banjo at a directory containing templates (-t|--template {path-to-templates}
), an optional overrides file (-o|--override {path-to-overrides-file}
), and other optional arguments. Banjo will process the templates, apply changes based on the overrides file, discover the current state of the Auth0 resources, and plan the create (POST) or update (PATCH) operations it needs to make.
Banjo currently supports the following Auth0 resources:
Resource/API name | Alternative name | Banjo template directory | Overrides element name |
---|---|---|---|
Clients | Applications | {templates}/clients | clients |
Resource Servers | APIs | {templates}/resource-servers | resource-servers |
Client Grants | n/a - Auth0 shows them as on/off sliders on the Applications->APIs tab | {templates}/grants | grants |
Connections | Connections | {templates}/connections | connections |
Pages* | n/a - Auth0 shows them in different places depending on the page type | {templates}/pages | pages |
Roles | Roles | {template}/roles | roles |
Rules | Rules | {template}/rules | rules |
Tenant Settings | Settings | {templates}/template-settings | template-settings |
- Banjo only supports the following pages: Login, Password Reset, and Multifactor. It does not (yet!) support a custom Error page.
You can find more resource-type-specific details below.
An overrides file is a json document that defines changes that Banjo should make to the templates before figuring out the API calls to make. A typical usage would be to have the same set of templates but use different overrides files per environment to change some aspect of the templated resources so it's unique for the environment, such as including the environment name in a resource name or a clients callback uri's.
The overrides file allows you to define several different ways you can override some aspect of a template;
- String token replacements - You can define simple replacement tokens, so that any occurrence of of a token gets replaced with a replacement value.
- JsonPath expressions - For more complex substitutions you can also specify a jsonpath expression to select a token in the template, and an entire json entity to replace it with
This is an example of an overrides file that shows the two ways you can define string token replacements, and a jsonpath replacement in a specific client template.
{
"replacements": [
{
"token": "EnvironmentName", //will allow you to use replacement tokens %%EnvironmentName%%, %%ENVIRONMENTNAME%%, or %%environmentname%%
"value": "DEV" //literal replacement value
},
{
"token": "BuildVersion", //%%BuildVersion%%, %%BUILDVERSION%%, or %%buildversion%%
"environment-variable": "AZDO_VERSION" //use the value of the AZDO_VERSION environment variable as the replacement value
}
],
"clients": [
{
"name": "my-awesome-application.template.json", //applies to a client template with this filename
"overrides": [
{
//Replace the allowed_origins property value with the "replacement" array.
//The "replacement" value could be anything, an array, number, string, boolean, object, etc.
"jsonpath": "allowed_origins",
"replacement": [ "https://origin1.example.com", "https://my-awesome-client.azurewebsites.net" ]
}
]
}
],
"resource-servers": [],
"pages": [],
"connections": [],
//...and any other supported resource type
}
In the example overrides file above;
- anywhere in a template that the replacement tokens
%%EnvironmentName%%
,%%ENVIRONMENTNAME%%
, or%%environmentname%%
appear, they will be replaced with the valueDEV
. For example,"My Awesome Application - %%ENVIRONMENTNAME%%"
would become"My Awesome Application - DEV"
- similarly,
%%BuildVersion%%
,%%BUILDVERSION%%
, or%%buildversion%%
would be replaced with the value of theAZDO_VERSION
environment variable - In a client template file at
{templates}/clients/my-awesome-application.template.json
, the value of theallowed_origins
property would be completely replaced with"replacement"
array
Note: JsonPath expressions can get very complex. The "jsonpath"
property in the override for a specific template is generally only intended to select a single value and replace it with the "replacement"
value. In general, you should stick to simple '.' notation path traversal paths, like jwt_configuration.alg
or options.mfa.active
, but if you wanted to select, say, and specific element in an array of allowed_origins
, you could. The dry-run -d|--dry-run
and output -out|--output
arguments are your friend 😃
As noted above, the template models for each resource type closely follows the output from the Auth0 Deploy CLI tool, which in turn generally (but not always) mirrors the Auth0 Management API model.
A few things to note:
- Template
json
files MUST have the extension.template.json
. Any file that does not end with.template.json
will be ignored. - Use the dry-run
-d|--dry-run
argument to not perform any create/update operations. Banjo will still make GET operations to query the current state in order to plan the operations, will not make any POST/PUT requests. - Use the output
-out|--output {output-directory}
argument to have Banjo write the 'effective' templates to disk after applying overrides and string replacements. - jsonpath-based overrides applied to the templates before token replacements, so you can use replacement tokens in the template-specific overrides if you want to.
The easiest way to get a template as a starting point for further customising with overrides replacements is to create the resource in the Auth0 management dashboard and then export the resources.
- Install and configure the Auth0 Deploy CLI tool, https://auth0.com/docs/extensions/deploy-cli
- Run the Auth0 Deploy CLI tool
export
command with--format directory
to export the resources as a directory tree containing 1 file per resource
The exported .json files form the basis of your template files.
$> a0deploy export --config_file {path-to-a0-secrets-file} --format directory --output_folder {output-folder}
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Clients | Applications | {templates}/clients | clients | GET Clients |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
No known differences. However the API response and a0deploy export includes a jwt_config
property that's not listed in the API model documentation.
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Resource Servers | APIs | {templates}/resource-servers | resource-servers | GET Resource Servers |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
No known differences.
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Client Grants | n/a - Auth0 shows them as on/off sliders on the Applications->APIs tab | {templates}/grants | grants | GET Client Grants |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
No known structural differences.
The meaning of the client_id
property is different.
- In Management API,
client_id
property is the id of the client. - In Banjo and a0deploy,
client_id
is the client name, not its id.- At runtime, Banjo will use the result of GET Clients to look up the id of the matching client and replace the
client_id
value in the template with the actual id of the matching client.
- At runtime, Banjo will use the result of GET Clients to look up the id of the matching client and replace the
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Connections | Connections | {templates}/connections | connections | GET Connections |
Banjo vs a0deploy
Mostly the same, however the treatment of enabled_clients
is different.
a0deploy defines an array of enabled_clients
containing the names of all the clients that the connection should be enabled for. Banjo does not use enabled_clients
.
Instead of enabled_clients
, Banjo uses enabled_clients_match_conditions
, which is an array of regex expressions that client names are matched to. This allows clients that are not known at template-authoring-time to still match.
For example, suppose a connection represents an Azure AD connection, and you want the connection to be enabled for all client resources for a specific service across all environments to match, you might define this;
{
//a connection template
//snip other properties
"enabled_clients_match_conditions": [
"My Awesome Web App - [A-Z]+", //matches "My Awesome Web App - DEV", "My Awesome Web App - TEST", etc
"Some Other Backend Service - %%CLIENTID%% - [A-Z]+" //only match Some Other Backend Service instances for a given %%CLIENTID%% replacement token
]
}
At runtime, Banjo will query the available clients to populate the enabled_clients
property that the management API needs.
Note that enabled_clients_match_conditions
are also treated for verbatim string matches as well as regex matches, so you don't need to go to special lengths to write properly escaped regexes if you're not aiming for a regex match.
Banjo vs Management API
The meaning of the enabled_clients
property is different.
- In Management API,
enabled_clients
property is the ids of the clients the connection should be enabled for. - In a0deploy,
enabled_clients
is the client names, not their ids. - In Banjo,
enabled_clients_match_conditions
is used instead, as described above.
Notes:
A connection type (username-password-database, Azure AD, GCloud, Facebook, etc) is defined by its strategy
, and every strategy has its own set of required attributes which don't appear to be documented anywhere. The best approach is set one up manually in the dashboard, then export it with a0deploy
.
Connections are a perfect place to use environment variable token overrides, as many connection strategies will require you to specify a sensitive secret or api key or similar. For example, an Azure Active Directory enterprise connection ("strategy": "waad"
) requires a "client_secret
' property, which is the client secret for your AAD App Registration.
$> set APP_REGISTRATION_SECRET=super_sekrit_client_secret_dont_tell_anyone
//overrides.json
{
"replacements": [
{
"token": "AppRegistrationSecret", //%%AppRegistrationSecret%%, %%APPREGISTRATIONSECRET%%, or %%appregistrationsecret%%
"environment-variable": "APP_REGISTRATION_SECRET"
}
]
}
//{templates}/connections/aad-connection.template.json
{
//snip lots more properties
"strategy": "waad",
"client_id": "not_so_secret_client_id",
"client_secret": "%%AppRegistrationSecret%%",
//snip lots more
}
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Pages* | n/a - Auth0 shows them in different places depending on the page type | {templates}/pages | pages | n/a |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
Pages are handled very differently in Banjo and a0deploy compared to the Management API. a0deploy (and by extension, Banjo) defines a unified model of the pages, while the management api puts the pages in different parts of the API depending on the page type.
In Banjo and a0deploy, pages are defined as a json file + html file. For example;
{templates}/pages
/loginpage.template.json
/loginpage.html
//{pagename}.template.json
{
"name": "login", //"login", "password_reset", or "guardian_multifactor". Any other value will error
"enabled": true,
"html": "./loginpage.html"
}
The filenames don't matter, as long as the html filename is the same as the value of the "html"
property in the {pagename}.template.json
file.
Banjo supports the following file types (the "name"
property):
login
- Management Dashboard -> Universal Login -> Login. In the API, it's thecustom_login_page
property on the global client.password_reset
- Management Dashboard -> Universal Login -> Password Reset. In the API, it's thechange_password
property on the Tenant Settings (which is not documented on the API docs).guardian_multifactor
- Management Dashboard -> Universal Login -> Multifactor. In the API, it's theguardian_mfa_page
property on the Tenant Settings (which is not documented on the API docs).
You can only have one of each page type, so don't, for instance, define 2 pairs of login
page template files. (Banjo will let you do it, but the second one Banjo processes will win)
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Roles | Roles | {template}/roles | roles | GET Roles |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
No known differences.
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Rules | Rules | {template}/rules | rules | GET Rules |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
Although the Management API defines a single Rules resource type (see GET Rules), it includes the script content in the HTTP request/response bodies.
Similar to Pages, Rules consist of a json template file and a .js
script file.
{templates}/rules
/my-rule.template.json
/my-rule.js
//{pagename}.template.json
{
"enabled": true,
"script": "./my-rule.js",
"name": "My Empty Rule %%NAME%%",
"order": 2,
"stage": "login_success"
}
The filenames don't matter, as long as the js filename is the same as the value of the "script"
property in the {rule}.template.json
file.
Resource/API name | Alternative name | Banjo template directory | Overrides element name | API Docs |
---|---|---|---|---|
Tenant Settings | Settings | {templates}/template-settings | template-settings | GET Tenant Settings |
Banjo vs a0deploy
No known differences. An a0deploy export will work as input to Banjo.
Banjo vs Management API
No known differences.
You can only have one Tenant Settings template file, as there is only one tenant settings entity per tenant.
The Continuous deployment (rc) worfkflow is configured for continuous deployment. All pushes/merges to master
automatically upload a release candidate (with an -rcNNNN suffix) that is available in the Github package feed for this project. These should not be considered stable.
The Release (nuget) workflow is triggered when a Release is created. The master
branch is configured for continuous delivery with release candidatess (as above) and a manual choice when to release. When a Release is tagged and published, the workflow is run and will automatically uploaded the new package to Nuget.
Copyright (C) 2020 Telstra Purple
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.